Skip to content

Commit a872df0

Browse files
introduce the checker framework
1 parent 786e2ca commit a872df0

File tree

10 files changed

+434
-22
lines changed

10 files changed

+434
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
target/
44
.idea/
55
*.iml
6+
*.md.html

README.md

Lines changed: 137 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
11
# null-pointer-analysis-examples
22

3-
Demonstrates capabilities of eclipse 4.6 for analysis of (potential) null references.
4-
Just open the java source files in eclipse and look at the comments.
3+
Demonstrates capabilities of some java tools to analyze (potential) null references. These tools are:
4+
- [eclipse (4.6)](https://www.eclipse.org)
5+
- [IntelliJ (2017.1)](https://www.jetbrains.com/idea/)
6+
- [The Checker Framework](https://checkerframework.org/)
7+
8+
Open the various java sources and read the comments to have an understanding of various checks that can be done (or not)
9+
by these tools.
10+
11+
:warning: It is NORMAL that your IDE shows errors in the source files if it supports some checks for null reference analysis.:warning:
12+
13+
The default javac compiler does not report any error however.
14+
15+
## Eclipse
16+
Last version tested: eclipse 4.6.3.
517

618
The best analysis is performed using [external annotations](http://help.eclipse.org/neon/topic/org.eclipse.jdt.doc.user/tasks/task-using_external_null_annotations.htm?cp=1_3_9_2).
719

820
[This repository/project](https://github.com/sylvainlaurent/eclipse-external-annotations) contains a (non-exhaustive but growing) number of external annotations for usual classes (e.g. Map, List, some guava classes...).
921

10-
## Inside eclipse IDE
22+
### Inside eclipse IDE
23+
24+
To activate the null reference analysis in this example project, copy ``ide-settings/eclipse-no-npe-analysis/org.eclipse.jdt.core.prefs`` to the ``.settings/`` directory.
25+
1126
To automatically associate an "annotation path" with the "Maven Dependencies" and "JRE" libraries in eclipse build path:
1227
- install eclipse-external-annotations-m2e-plugin from [this p2 repository](http://sylvainlaurent.github.io/eclipse-external-annotations/p2/).
13-
- add a maven property `m2e.jdt.annotationpath` in your pom, as demonstrated in [with-external-annotations/pom.xml](with-external-annotations/pom.xml).
28+
- add a maven property `m2e.jdt.annotationpath` in your pom, as demonstrated in [pom.xml](pom.xml#93).
1429
- perform a full `Maven/Update project...` in eclipse.
1530

1631
Tip: place the property in a `m2e` profile activated only inside eclipse, not in the command-line (see below for command-line usage).
@@ -31,19 +46,14 @@ Using a source project for external annotations in the same eclipse workspace al
3146
</profile>
3247
```
3348

34-
## When running maven from the command-line
35-
To perform null-analysis during a maven build, the jdt compiler must be used in place of the default javac, as demonstrated in the `not-m2e` maven profile of [with-external-annotations/pom.xml](with-external-annotations/pom.xml).
49+
### Using eclipse jdt compiler with maven from the command-line
50+
To perform the same null reference analysis as the eclipse IDE during a maven build, the jdt compiler must be used in place of the default javac, as demonstrated in the `jdt` maven profile of [pom.xml](pom.xml).
3651

3752
```xml
3853
<profile>
39-
<id>not-m2e</id>
40-
<activation>
41-
<property>
42-
<name>!m2e.version</name>
43-
</property>
44-
</activation>
54+
<id>jdt</id>
4555
<properties>
46-
<tycho-version>0.25.0</tycho-version>
56+
<tycho-version>0.26.0</tycho-version>
4757
</properties>
4858
<repositories>
4959
<repository>
@@ -82,7 +92,7 @@ To perform null-analysis during a maven build, the jdt compiler must be used in
8292
<compilerId>jdt</compilerId>
8393
<compilerArgs>
8494
<arg>-properties</arg>
85-
<arg>${project.basedir}/.settings/org.eclipse.jdt.core.prefs</arg>
95+
<arg>${project.basedir}/ide-settings/eclipse-with-npe-analysis/org.eclipse.jdt.core.prefs</arg>
8696
<arg>-annotationpath</arg>
8797
<arg>CLASSPATH</arg>
8898
</compilerArgs>
@@ -102,3 +112,116 @@ To perform null-analysis during a maven build, the jdt compiler must be used in
102112
</build>
103113
</profile>
104114
```
115+
116+
To launch the compilation with this jdt profile, run: ``mvn clean test -P jdt``. The compiler should find the same errors as in eclipse:
117+
```
118+
$ mvn clean test -P jdt
119+
...
120+
[ERROR] COMPILATION ERROR :
121+
[INFO] -------------------------------------------------------------
122+
[ERROR] /Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/packageNonNull/ClassInAnnotatedPackage.java:[13]
123+
echo(null);
124+
^^^^
125+
Null type mismatch: required '@NonNull String' but the provided value is null
126+
[ERROR] /Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/test/EverythingNonNullByDefault.java:[25]
127+
public EverythingNonNullByDefault(String name) {
128+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
129+
The @NonNull field address may not have been initialized
130+
[ERROR] /Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/test/EverythingNonNullByDefault.java:[47]
131+
return city;
132+
^^^^
133+
...
134+
```
135+
136+
## IntelliJ
137+
WIP
138+
139+
## Checker Framework
140+
Though the Checker Framework proposes many checks, we only consider its [Nullness checker](https://checkerframework.org/manual/#nullness-checker) for the purpose of this example project.
141+
142+
In this example project, the ``checker-framework`` maven profile allows to use this nullness checker:
143+
144+
```xml
145+
<profile>
146+
<id>checker-framework</id>
147+
<dependencies>
148+
<dependency>
149+
<groupId>org.checkerframework</groupId>
150+
<artifactId>checker</artifactId>
151+
<version>${checker-framework.version}</version>
152+
</dependency>
153+
<dependency>
154+
<groupId>org.checkerframework</groupId>
155+
<artifactId>jdk8</artifactId>
156+
<version>${checker-framework.version}</version>
157+
</dependency>
158+
</dependencies>
159+
<build>
160+
<plugins>
161+
<plugin>
162+
<artifactId>maven-compiler-plugin</artifactId>
163+
<configuration>
164+
<fork>true</fork>
165+
<annotationProcessors>
166+
<!-- Add all the checkers you want to enable here -->
167+
<annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>
168+
</annotationProcessors>
169+
<compilerArgs>
170+
<!-- location of the annotated JDK, which comes from a Maven dependency -->
171+
<arg>-Xbootclasspath/p:${org.checkerframework:jdk8:jar}</arg>
172+
</compilerArgs>
173+
</configuration>
174+
</plugin>
175+
<plugin>
176+
<!-- This plugin will set properties values using dependency information -->
177+
<groupId>org.apache.maven.plugins</groupId>
178+
<artifactId>maven-dependency-plugin</artifactId>
179+
<version>2.3</version>
180+
<executions>
181+
<execution>
182+
<goals>
183+
<goal>properties</goal>
184+
</goals>
185+
</execution>
186+
</executions>
187+
</plugin>
188+
</plugins>
189+
</build>
190+
</profile>
191+
```
192+
193+
To launch the compilation with this profile, run: ``mvn clean test -P checker-framework``. The compiler should find errors:
194+
```
195+
$ mvn clean test -P checker-framework
196+
...
197+
[INFO] -------------------------------------------------------------
198+
[ERROR] COMPILATION ERROR :
199+
[INFO] -------------------------------------------------------------
200+
[ERROR] /Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/packageNotAnnotated/ClassInNotAnnotatedPackage.java:[10,13] error: [argument.type.incompatible] incompatible types in argument.
201+
[ERROR] found : null
202+
required: @Initialized @NonNull String
203+
/Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/packageNotAnnotated/ClassInNotAnnotatedPackage.java:[16,19] error: [return.type.incompatible] incompatible types in return.
204+
[ERROR] found : null
205+
required: @Initialized @NonNull String
206+
/Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/packageNonNull/ClassInAnnotatedPackage.java:[13,7] error: [argument.type.incompatible] incompatible types in argument.
207+
[ERROR] found : null
208+
required: @Initialized @NonNull String
209+
/Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/packageNonNull/ClassInAnnotatedPackage.java:[19,10] error: [return.type.incompatible] incompatible types in return.
210+
[ERROR] found : null
211+
required: @Initialized @NonNull String
212+
/Users/slaurent/Developer/repos/null-pointer-analysis-examples/src/main/java/test/EverythingNonNullByDefault.java:[25,11] error: [initialization.fields.uninitialized] the constructor does not initialize fields: address
213+
...
214+
```
215+
## Comparison
216+
217+
Feature | Eclipse IDE or jdt | Checker Framework | IntelliJ
218+
------- | ------------------ | ----------------- | --------
219+
IDE support | :white_check_mark::white_check_mark: using plugin | :white_check_mark:
220+
Command line support | :white_check_mark: | :white_check_mark: | :red_circle:
221+
Java 8 type annotations support | :white_check_mark: | :white_check_mark: | :red_circle: ``List<@Nonnull String>`` is the same as ``List<String>``, no error for ``list.add(null)``.
222+
Multiple annotations classes supported | :white_check_mark: | :white_check_mark: | :white_check_mark:
223+
External annotations support | :white_check_mark: using .eea files | :white_check_mark: using stubs files | :white_check_mark: using xml files
224+
External annotations provided for common libraries | :red_circle: community effort with [lastnpe.org](http://lastnpe.org)| :white_check_mark: JDK, Guava | :white_check_mark: JDK
225+
IDE support to create external annotations | :white_check_mark: | :warning: using command line tools | :white_check_mark:
226+
Treat all types as @Nonnull by default, unless annotated wih @Nullable:white_check_mark: using @NonNullByDefault for each package, allows to define the scope: field, parameters, return, generic types, etc... | :white_check_mark: by default, customizable with @DefaultQualifier:white_check_mark: IDE setting :question: global?
227+
@Polynull support | :red_circle::white_check_mark: using [@PolyNull](https://checkerframework.org/manual/#qualifier-polymorphism) | :white_check_mark: using [@Contract](https://www.jetbrains.com/help/idea/2017.1/contract-annotations.html), for instance @Contract("!null->!null;null->null")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Copy the ``org.eclipse.jdt.core.prefs`` to ``null-pointer-analysis-examples/.settings``
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
eclipse.preferences.version=1
2+
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
3+
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
4+
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
5+
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
6+
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
7+
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
8+
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
9+
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
10+
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
11+
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
12+
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
13+
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
14+
org.eclipse.jdt.core.compiler.problem.deadCode=warning
15+
org.eclipse.jdt.core.compiler.problem.deprecation=warning
16+
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
17+
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
18+
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
19+
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
20+
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
21+
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
22+
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
23+
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
24+
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
25+
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
26+
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
27+
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
28+
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
29+
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
30+
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
31+
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
32+
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
33+
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
34+
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
35+
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
36+
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
37+
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
38+
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
39+
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
40+
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
41+
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
42+
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
43+
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
44+
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
45+
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
46+
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
47+
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
48+
org.eclipse.jdt.core.compiler.problem.nullReference=warning
49+
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
50+
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
51+
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
52+
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
53+
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
54+
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
55+
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
56+
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
57+
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
58+
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
59+
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
60+
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
61+
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
62+
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
63+
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
64+
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
65+
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
66+
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
67+
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
68+
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
69+
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
70+
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
71+
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
72+
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
73+
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
74+
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
75+
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
76+
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
77+
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
78+
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
79+
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
80+
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
81+
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
82+
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
83+
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
84+
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
85+
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
86+
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
87+
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
88+
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
89+
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
90+
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
91+
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
92+
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
93+
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
94+
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
95+
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Copy the ``org.eclipse.jdt.core.prefs`` to ``null-pointer-analysis-examples/.settings``

0 commit comments

Comments
 (0)