Through a combination of @Contract
annotations and the External Annotations feature, you can now annotate Preconditions
methods such that IntelliJ applies the correct static analysis to calls to these methods.
Let’s say we have this example
public void doSomething(Object someArg) {
Preconditions.checkArgument(someArg != null);
someArg.doSomethingElse(); //currently gives NPE warning
if (someArg != null) {
//no warning that this is always true
}
}
In IntelliJ (I’m using 13):
- Navigate to
Preconditions.checkArgument(boolean)
. - Place your cursor on the method name, and hit Alt–Enter to bring up the intentions popup.
- Select “Add method contract”.
- Use the contract text
false -> fail
. - When prompted, provide a location for the External Annotations file.
Now the warning at someArg.doSomethingElse()
goes away, and IDEA will, in fact, flag the if
branch as always true!
Other contract texts:
Preconditions.checkArgument(boolean, String)
should befalse, _ -> fail
Preconditions.checkNotNull(Object, String)
should benull, _ -> fail
,- etc, etc
Here is my full annotations.xml
file for Preconditions
:
<root>
<item name="com.google.common.base.Preconditions T checkNotNull(T)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""null -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions T checkNotNull(T, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""null, _ -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions T checkNotNull(T, java.lang.String, java.lang.Object...)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""null, _, _ -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions void checkArgument(boolean)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""false -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions void checkArgument(boolean, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""false, _ -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions void checkArgument(boolean, java.lang.String, java.lang.Object...)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""false, _, _ -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions void checkState(boolean)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""false -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions void checkState(boolean, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""false, _ -> fail""/>
</annotation>
</item>
<item name="com.google.common.base.Preconditions void checkState(boolean, java.lang.String, java.lang.Object...)">
<annotation name="org.jetbrains.annotations.Contract">
<val val=""false, _, _ -> fail""/>
</annotation>
</item>
</root>
See Also
- IDEA-113391: Edit Method Contract intention for library methods
- IDEA-93372: Implement something similar to ReSharper contract annotations for Java
- IDEA-60343: False positive NPE warning when using guava Preconditions – Constant conditions & Expectations