Versions: Error Prone error_prone_core 2.41.0, JDK 25, invoked via javac (CLI).
Description
DoubleCheckedLocking matches the guard by its syntactic form. Rewriting the outer null check from baz == null to the logically-equivalent !(baz != null) makes the check stop firing, even though the double-checked locking on the non-volatile field — and its unsafe publication — is entirely unchanged. The two programs are behaviourally identical.
Reproducer (reported):
public class DclSeed {
Object baz;
Object bar() {
if (baz == null) { // reported here (line 5)
synchronized (this) {
if (baz == null) {
baz = new Object();
}
}
}
return baz;
}
}
Reproducer (NOT reported — the only change is the outer guard):
public class DclVariant {
Object baz;
Object bar() {
if (!(baz != null)) { // equivalent to `baz == null`; no diagnostic
synchronized (this) {
if (baz == null) {
baz = new Object();
}
}
}
return baz;
}
}
How to run (the -J--add-exports/--add-opens and -XDcompilePolicy=simple --should-stop=ifError=FLOW flags are required for Error Prone on a modern JDK; without them the plugin does not run):
javac \
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
-XDcompilePolicy=simple --should-stop=ifError=FLOW \
-processorpath error_prone_core-2.41.0-with-dependencies.jar -Xplugin:ErrorProne \
-d out DclSeed.java
# DclSeed.java:5: warning: [DoubleCheckedLocking] Double-checked locking on non-volatile fields is unsafe
# (running the same command on DclVariant.java produces no DoubleCheckedLocking diagnostic)
Expected: Error Prone should emit [DoubleCheckedLocking] on DclVariant.java line 5, but does not.
Versions: Error Prone
error_prone_core2.41.0, JDK 25, invoked viajavac(CLI).Description
DoubleCheckedLockingmatches the guard by its syntactic form. Rewriting the outer null check frombaz == nullto the logically-equivalent!(baz != null)makes the check stop firing, even though the double-checked locking on the non-volatile field — and its unsafe publication — is entirely unchanged. The two programs are behaviourally identical.Reproducer (reported):
Reproducer (NOT reported — the only change is the outer guard):
How to run (the
-J--add-exports/--add-opensand-XDcompilePolicy=simple --should-stop=ifError=FLOWflags are required for Error Prone on a modern JDK; without them the plugin does not run):Expected: Error Prone should emit
[DoubleCheckedLocking]onDclVariant.javaline 5, but does not.