While checking my work project for warnings I noticed that Eclipse spotted some dead code after a JUnit assertNotNull. Some testing and discussion on twitter with Roy van Rijn led me to tinker a bit with Eclipse's dead code analysis. First the code in question:

    Appointment appointment1 = null;
    Appointment appointment2 = null;
    for(Appointment appointment : appointments) {
        if(appointment.getSomething() == 1)
            appointment1 = appointment;
        if(appointment.getSomething() == 2)
            appointment2 = appointment;
    }
    assertNotNull(appointment1);
    assertNotNull(appointment2);
    if(appointment1 == null || appointment2 == null) {
        throw IllegalStateException();
    }

Eclipse generates a warning on line 11 stating that both appointment1 and appointment2 are both never null at that point. This led me to believe that Eclipse has specific knowledge of JUnit, a point that Roy contests.

Roy's assertion was that Eclipse did a full code path analysis of the call sequence, as JUnit ultimately throws an exception in this case, which could be proven by static analysis.

A short test shows that in fact Eclipse does treat assertNotNull as a special case, and does not perform a full call sequence analysis:

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

public class Test {
    public void deadCodeAfterAssertNotNull() {
        assertNotNull(null);
        fail("");
    }

    public void noDeadCodeAfterFail() {
        fail("");
        assertNotNull(null);
    }
}

Eclipse generates a warning for dead code at line 7, but not at line 12, however assertNotNull ultimately calls fail(String). Thus my conclusion that Eclipse does in fact have a special case for detecting assertNotNull.

Update: It appears that the static analysis checker also has built in support for Guava's Preconditions:

public void deadCodeAfterGuavaAssertion() {
    Preconditions.checkNotNull(null);
    System.out.println("Dead code");
}

The compiler flags line 3 as dead code. However:

public void noDeadCodeAfterMyFail() {
    myFail();
    System.out.println("No dead code");
}

private final void myFail() {
    throw new RuntimeException();
}

Does not make Eclipse's compiler conclude that line 3 is dead code.