Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2010, 2011 GK Software AG and others. |
3 |
* All rights reserved. This program and the accompanying materials |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
5 |
* which accompanies this distribution, and is available at |
6 |
* http://www.eclipse.org/legal/epl-v10.html |
7 |
* |
8 |
* Contributors: |
9 |
* Stephan Herrmann - initial API and implementation |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.jdt.core.tests.compiler.regression; |
12 |
|
13 |
import java.util.Map; |
14 |
|
15 |
import junit.framework.Test; |
16 |
|
17 |
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
18 |
|
19 |
public class NullAnnotationTest extends AbstractComparableTest { |
20 |
|
21 |
public NullAnnotationTest(String name) { |
22 |
super(name); |
23 |
} |
24 |
|
25 |
// Static initializer to specify tests subset using TESTS_* static variables |
26 |
// All specified tests which do not belong to the class are skipped... |
27 |
static { |
28 |
// TESTS_NAMES = new String[] { "test_parameter_contract_inheritance_008" }; |
29 |
// TESTS_NUMBERS = new int[] { 561 }; |
30 |
// TESTS_RANGE = new int[] { 1, 2049 }; |
31 |
} |
32 |
|
33 |
public static Test suite() { |
34 |
return buildComparableTestSuite(testClass()); |
35 |
} |
36 |
|
37 |
public static Class testClass() { |
38 |
return NullAnnotationTest.class; |
39 |
} |
40 |
|
41 |
// Conditionally augment problem detection settings |
42 |
static boolean setNullRelatedOptions = true; |
43 |
protected Map getCompilerOptions() { |
44 |
Map defaultOptions = super.getCompilerOptions(); |
45 |
if (setNullRelatedOptions) { |
46 |
defaultOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
47 |
defaultOptions.put(CompilerOptions.OPTION_ReportPotentialNullReference, CompilerOptions.ERROR); |
48 |
defaultOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR); |
49 |
defaultOptions.put(CompilerOptions.OPTION_ReportRawTypeReference, CompilerOptions.IGNORE); |
50 |
defaultOptions.put(CompilerOptions.OPTION_IncludeNullInfoFromAsserts, CompilerOptions.ENABLED); |
51 |
|
52 |
defaultOptions.put(CompilerOptions.OPTION_ReportMissingOverrideAnnotationForInterfaceMethodImplementation, CompilerOptions.DISABLED); |
53 |
|
54 |
// enable null annotations: |
55 |
defaultOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.ENABLED); |
56 |
defaultOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); |
57 |
// leave other new options at these defaults: |
58 |
// defaultOptions.put(CompilerOptions.OPTION_ReportNullContractViolation, CompilerOptions.ERROR); |
59 |
// defaultOptions.put(CompilerOptions.OPTION_ReportPotentialNullContractViolation, CompilerOptions.ERROR); |
60 |
// defaultOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.WARNING); |
61 |
|
62 |
// defaultOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.eclipse.jdt.annotation.Nullable"); |
63 |
// defaultOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.eclipse.jdt.annotation.NonNull"); |
64 |
} |
65 |
return defaultOptions; |
66 |
} |
67 |
// a nullable argument is dereferenced without a check |
68 |
public void test_nullable_paramter_001() { |
69 |
runNegativeTest( |
70 |
new String[] { |
71 |
"X.java", |
72 |
"public class X {\n" + |
73 |
" void foo(@Nullable Object o) {\n" + |
74 |
" System.out.print(o.toString());\n" + |
75 |
" }\n" + |
76 |
"}\n"}, |
77 |
"----------\n" + |
78 |
"1. ERROR in X.java (at line 3)\n" + |
79 |
" System.out.print(o.toString());\n" + |
80 |
" ^\n" + |
81 |
"Potential null pointer access: The variable o may be null at this location\n" + |
82 |
"----------\n", |
83 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
84 |
} |
85 |
|
86 |
// a null value is passed to a nullable argument |
87 |
public void test_nullable_paramter_002() { |
88 |
runConformTest( |
89 |
new String[] { |
90 |
"X.java", |
91 |
"public class X {\n" + |
92 |
" void foo(@Nullable Object o) {\n" + |
93 |
" // nop\n" + |
94 |
" }\n" + |
95 |
" void bar() {\n" + |
96 |
" foo(null);\n" + |
97 |
" }\n" + |
98 |
"}\n"}, |
99 |
""); |
100 |
} |
101 |
|
102 |
// a non-null argument is checked for null |
103 |
public void test_nonnull_parameter_001() { |
104 |
runNegativeTest( |
105 |
new String[] { |
106 |
"X.java", |
107 |
"public class X {\n" + |
108 |
" void foo(@NonNull Object o) {\n" + |
109 |
" if (o != null)\n" + |
110 |
" System.out.print(o.toString());\n" + |
111 |
" }\n" + |
112 |
"}\n"}, |
113 |
"----------\n" + |
114 |
"1. ERROR in X.java (at line 3)\n" + |
115 |
" if (o != null)\n" + |
116 |
" ^\n" + |
117 |
"Redundant null check: The variable o cannot be null at this location\n" + |
118 |
"----------\n", |
119 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
120 |
} |
121 |
// a non-null argument is dereferenced without a check |
122 |
public void test_nonnull_parameter_002() { |
123 |
runConformTest( |
124 |
new String[] { |
125 |
"X.java", |
126 |
"public class X {\n" + |
127 |
" void foo(@NonNull Object o) {\n" + |
128 |
" System.out.print(o.toString());\n" + |
129 |
" }\n" + |
130 |
" public static void main(String... args) {\n" + |
131 |
" new X().foo(\"OK\");\n" + |
132 |
" }\n" + |
133 |
"}\n"}, |
134 |
"OK"); |
135 |
} |
136 |
// passing null to nonnull parameter |
137 |
public void test_nonnull_parameter_003() { |
138 |
runNegativeTest( |
139 |
new String[] { |
140 |
"X.java", |
141 |
"public class X {\n" + |
142 |
" void foo(@NonNull Object o) {\n" + |
143 |
" System.out.print(o.toString());\n" + |
144 |
" }\n" + |
145 |
" void bar() {\n" + |
146 |
" foo(null);\n" + |
147 |
" }\n" + |
148 |
"}\n"}, |
149 |
"----------\n" + |
150 |
"1. ERROR in X.java (at line 6)\n" + |
151 |
" foo(null);\n" + |
152 |
" ^^^^\n" + |
153 |
"Null contract violation: passing null to a parameter declared as @NonNull.\n" + |
154 |
"----------\n", |
155 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
156 |
} |
157 |
// passing potential null to nonnull parameter - target method is consumed from .class |
158 |
public void test_nonnull_parameter_004() { |
159 |
runConformTest( |
160 |
new String[] { |
161 |
"Lib.java", |
162 |
"public class Lib {\n" + |
163 |
" void setObject(@NonNull Object o) { }\n" + |
164 |
"}\n" |
165 |
}); |
166 |
runNegativeTest( |
167 |
false /* flush output directory */, |
168 |
new String[] { |
169 |
"X.java", |
170 |
"public class X {\n" + |
171 |
" void bar(Lib l, boolean b) {\n" + |
172 |
" Object o = null;\n" + |
173 |
" if (b) o = new Object();\n" + |
174 |
" l.setObject(o);\n" + |
175 |
" }\n" + |
176 |
"}\n"}, |
177 |
null /* no class libraries */, |
178 |
null /* no custom options */, |
179 |
"----------\n" + |
180 |
"1. ERROR in X.java (at line 5)\n" + |
181 |
" l.setObject(o);\n" + |
182 |
" ^\n" + |
183 |
"Null contract violation: potentially passing null to a parameter declared as @NonNull.\n" + |
184 |
"----------\n", |
185 |
"",/* expected output */ |
186 |
"",/* expected error */ |
187 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
188 |
} |
189 |
// passing unknown value to nonnull parameter - target method is consumed from .class |
190 |
public void test_nonnull_parameter_005() { |
191 |
runConformTest( |
192 |
new String[] { |
193 |
"Lib.java", |
194 |
"public class Lib {\n" + |
195 |
" void setObject(@NonNull Object o) { }\n" + |
196 |
"}\n" |
197 |
}); |
198 |
runConformTest( |
199 |
false /* flush output directory */, |
200 |
new String[] { |
201 |
"X.java", |
202 |
"public class X {\n" + |
203 |
" void bar(Lib l, Object o) {\n" + |
204 |
" l.setObject(o);\n" + |
205 |
" }\n" + |
206 |
"}\n"}, |
207 |
null /* no class libraries */, |
208 |
null /* no custom options */, |
209 |
"----------\n" + |
210 |
"1. WARNING in X.java (at line 3)\n" + |
211 |
" l.setObject(o);\n" + |
212 |
" ^\n" + |
213 |
"Potential null contract violation: insufficient nullness information regarding a value that is passed to a parameter declared as @NonNull.\n" + |
214 |
"----------\n", |
215 |
"",/* expected output */ |
216 |
"",/* expected error */ |
217 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
218 |
} |
219 |
|
220 |
// assigning potential null to a nonnull local variable |
221 |
public void test_nonnull_local_001() { |
222 |
runNegativeTest( |
223 |
new String[] { |
224 |
"X.java", |
225 |
"public class X {\n" + |
226 |
" void foo(boolean b, Object p) {\n" + |
227 |
" @NonNull Object o1 = b ? null : new Object();\n" + |
228 |
" @NonNull String o2 = \"\";\n" + |
229 |
" o2 = null;\n" + |
230 |
" @NonNull Object o3 = p;\n" + |
231 |
" }\n" + |
232 |
"}\n"}, |
233 |
"----------\n" + |
234 |
"1. ERROR in X.java (at line 3)\n" + |
235 |
" @NonNull Object o1 = b ? null : new Object();\n" + |
236 |
" ^^^^^^^^^^^^^^^^^^^^^^^\n" + |
237 |
"Null contract violation: potentially assigning null to local variable o1, which is declared as @NonNull.\n" + |
238 |
"----------\n" + |
239 |
"2. ERROR in X.java (at line 5)\n" + |
240 |
" o2 = null;\n" + |
241 |
" ^^^^\n" + |
242 |
"Null contract violation: assigning null to local variable o2, which is declared as @NonNull.\n" + |
243 |
"----------\n" + |
244 |
"3. WARNING in X.java (at line 6)\n" + |
245 |
" @NonNull Object o3 = p;\n" + |
246 |
" ^\n" + |
247 |
"Potential null contract violation: insufficient nullness information regarding a value that is assigned to local variable o3, which is declared as @NonNull.\n" + |
248 |
"----------\n", |
249 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
250 |
} |
251 |
|
252 |
// a method tries to tighten the null contract, super declares parameter o as @Nullable |
253 |
// other parameters: s is redefined from not constrained to @Nullable which is OK |
254 |
// third is redefined from not constrained to @NonNull which is bad, too |
255 |
public void test_parameter_contract_inheritance_001() { |
256 |
runConformTest( |
257 |
new String[] { |
258 |
"Lib.java", |
259 |
"public class Lib {\n" + |
260 |
" void foo(String s, @Nullable Object o, Object third) { }\n" + |
261 |
"}\n" |
262 |
}); |
263 |
runNegativeTest( |
264 |
false /* flush output directory */, |
265 |
new String[] { |
266 |
"X.java", |
267 |
"public class X extends Lib {\n" + |
268 |
" @Override\n" + |
269 |
" void foo(@Nullable String s, @NonNull Object o, @NonNull Object third) { System.out.print(o.toString()); }\n" + |
270 |
"}\n" |
271 |
}, |
272 |
// compiler options |
273 |
null /* no class libraries */, |
274 |
null /* no custom options */, |
275 |
"----------\n" + |
276 |
"1. ERROR in X.java (at line 3)\n" + |
277 |
" void foo(@Nullable String s, @NonNull Object o, @NonNull Object third) { System.out.print(o.toString()); }\n" + |
278 |
" ^\n" + |
279 |
"Cannot tighten null contract for parameter o, inherited method from Lib declares this parameter as @Nullable.\n" + |
280 |
"----------\n" + |
281 |
"2. ERROR in X.java (at line 3)\n" + |
282 |
" void foo(@Nullable String s, @NonNull Object o, @NonNull Object third) { System.out.print(o.toString()); }\n" + |
283 |
" ^^^^^\n" + |
284 |
"Cannot tighten null contract for parameter third, inherited method from Lib does not constrain this parameter.\n" + |
285 |
"----------\n", |
286 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
287 |
} |
288 |
// a method body fails to handle the inherited null contract, super declares parameter as @Nullable |
289 |
public void test_parameter_contract_inheritance_002() { |
290 |
runConformTest( |
291 |
new String[] { |
292 |
"Lib.java", |
293 |
"public class Lib {\n" + |
294 |
" void foo(@Nullable Object o) { }\n" + |
295 |
"}\n" |
296 |
}); |
297 |
runNegativeTest( |
298 |
false /* flush output directory */, |
299 |
new String[] { |
300 |
"X.java", |
301 |
"public class X extends Lib {\n" + |
302 |
" @Override\n" + |
303 |
" void foo(Object o) {\n" + |
304 |
" System.out.print(o.toString());\n" + |
305 |
" }\n" + |
306 |
"}\n" |
307 |
}, |
308 |
// compiler options |
309 |
null /* no class libraries */, |
310 |
null /* no custom options */, |
311 |
"----------\n" + |
312 |
"1. ERROR in X.java (at line 4)\n" + |
313 |
" System.out.print(o.toString());\n" + |
314 |
" ^\n" + |
315 |
"Potential null pointer access: The variable o may be null at this location\n" + |
316 |
"----------\n", |
317 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
318 |
} |
319 |
// a method relaxes the parameter null contract, super interface declares parameter o as @NonNull |
320 |
// other (first) parameter just repeats the inherited @NonNull |
321 |
public void test_parameter_contract_inheritance_003() { |
322 |
runConformTest( |
323 |
new String[] { |
324 |
"IX.java", |
325 |
"public interface IX {\n" + |
326 |
" void foo(@NonNull String s, @NonNull Object o);\n" + |
327 |
"}\n", |
328 |
"X.java", |
329 |
"public class X implements IX {\n" + |
330 |
" public void foo(@NonNull String s, @Nullable Object o) { ; }\n" + |
331 |
" void bar() { foo(\"OK\", null); }\n" + |
332 |
"}\n" |
333 |
}, |
334 |
""); |
335 |
} |
336 |
// a method adds a @NonNull annotation, super interface has no null annotation |
337 |
// changing other from unconstrained to @Nullable is OK |
338 |
public void test_parameter_contract_inheritance_004() { |
339 |
runConformTest( |
340 |
new String[] { |
341 |
"IX.java", |
342 |
"public interface IX {\n" + |
343 |
" void foo(Object o, Object other);\n" + |
344 |
"}\n" |
345 |
}); |
346 |
runNegativeTest( |
347 |
false /* flush output directory */, |
348 |
new String[] { |
349 |
"X.java", |
350 |
"public class X implements IX {\n" + |
351 |
" public void foo(@NonNull Object o, @Nullable Object other) { System.out.print(o.toString()); }\n" + |
352 |
"}\n" |
353 |
}, |
354 |
// compiler options |
355 |
null /* no class libraries */, |
356 |
null /* no custom options */, |
357 |
"----------\n" + |
358 |
"1. ERROR in X.java (at line 2)\n" + |
359 |
" public void foo(@NonNull Object o, @Nullable Object other) { System.out.print(o.toString()); }\n" + |
360 |
" ^\n" + |
361 |
"Cannot tighten null contract for parameter o, inherited method from IX does not constrain this parameter.\n" + |
362 |
"----------\n", |
363 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
364 |
} |
365 |
// a method tries to relax the null contract, super declares @NonNull return |
366 |
public void test_parameter_contract_inheritance_005() { |
367 |
runConformTest( |
368 |
new String[] { |
369 |
"Lib.java", |
370 |
"public class Lib {\n" + |
371 |
" @NonNull Object getObject() { return new Object(); }\n" + |
372 |
"}\n" |
373 |
}); |
374 |
runNegativeTest( |
375 |
false /* flush output directory */, |
376 |
new String[] { |
377 |
"X.java", |
378 |
"public class X extends Lib {\n" + |
379 |
" @Override\n" + |
380 |
" @Nullable Object getObject() { return null; }\n" + |
381 |
"}\n" |
382 |
}, |
383 |
// compiler options |
384 |
null /* no class libraries */, |
385 |
null /* no custom options */, |
386 |
"----------\n" + |
387 |
"1. ERROR in X.java (at line 3)\n" + |
388 |
" @Nullable Object getObject() { return null; }\n" + |
389 |
" ^^^^^^^^^^^\n" + |
390 |
"Cannot relax null contract for method return, inherited method from Lib is declared as @NonNull.\n" + |
391 |
"----------\n", |
392 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
393 |
} |
394 |
// super has no contraint for return, sub method confirms the null contract as @Nullable |
395 |
public void test_parameter_contract_inheritance_006() { |
396 |
runConformTest( |
397 |
new String[] { |
398 |
"Lib.java", |
399 |
"public class Lib {\n" + |
400 |
" Object getObject() { return null; }\n" + |
401 |
"}\n" |
402 |
}); |
403 |
runConformTest( |
404 |
new String[] { |
405 |
"X.java", |
406 |
"public class X extends Lib {\n" + |
407 |
" @Override\n" + |
408 |
" @Nullable Object getObject() { return null; }\n" + |
409 |
"}\n" |
410 |
}, |
411 |
"", |
412 |
null/*classLibs*/, |
413 |
false /* flush output directory */, |
414 |
null/*vmArguments*/, |
415 |
null/*customOptions*/, |
416 |
null/*compilerRequestor*/); |
417 |
} |
418 |
// a method body violates the inherited null contract, super declares @NonNull return |
419 |
public void test_parameter_contract_inheritance_007() { |
420 |
runConformTest( |
421 |
new String[] { |
422 |
"Lib.java", |
423 |
"public class Lib {\n" + |
424 |
" @NonNull Object getObject() { return new Object(); }\n" + |
425 |
"}\n" |
426 |
}); |
427 |
runNegativeTest( |
428 |
false /* flush output directory */, |
429 |
new String[] { |
430 |
"X.java", |
431 |
"public class X extends Lib {\n" + |
432 |
" @Override\n" + |
433 |
" Object getObject() { return null; }\n" + |
434 |
"}\n" |
435 |
}, |
436 |
// compiler options |
437 |
null /* no class libraries */, |
438 |
null /* no custom options */, |
439 |
"----------\n" + |
440 |
"1. ERROR in X.java (at line 3)\n" + |
441 |
" Object getObject() { return null; }\n" + |
442 |
" ^^^^^^^^^^^^\n" + |
443 |
"Null contract violation: returning null from a method declared as @NonNull.\n" + |
444 |
"----------\n", |
445 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
446 |
} |
447 |
// a client potentially violates the inherited null contract, super interface declares @NonNull parameter |
448 |
public void test_parameter_contract_inheritance_008() { |
449 |
Map options = getCompilerOptions(); |
450 |
options.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.ERROR); |
451 |
runConformTest( |
452 |
new String[] { |
453 |
"IX.java", |
454 |
"public interface IX {\n" + |
455 |
" void printObject(@NonNull Object o);\n" + |
456 |
"}\n" |
457 |
}); |
458 |
runNegativeTest( |
459 |
false /* flush output directory */, |
460 |
new String[] { |
461 |
"X.java", |
462 |
"public class X implements IX {\n" + |
463 |
" public void printObject(Object o) { System.out.print(o.toString()); }\n" + |
464 |
"}\n", |
465 |
"M.java", |
466 |
"public class M{\n" + |
467 |
" void foo(X x, Object o) {\n" + |
468 |
" x.printObject(o);\n" + |
469 |
" }\n" + |
470 |
"}\n" |
471 |
}, |
472 |
// compiler options |
473 |
null /* no class libraries */, |
474 |
options, |
475 |
"----------\n" + |
476 |
"1. ERROR in M.java (at line 3)\n" + |
477 |
" x.printObject(o);\n" + |
478 |
" ^\n" + |
479 |
"Potential null contract violation: insufficient nullness information regarding a value that is passed to a parameter declared as @NonNull.\n" + |
480 |
"----------\n", |
481 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
482 |
} |
483 |
// a nullable return value is dereferenced without a check |
484 |
public void test_nullable_return_001() { |
485 |
runNegativeTest( |
486 |
new String[] { |
487 |
"X.java", |
488 |
"public class X {\n" + |
489 |
" @Nullable Object getObject() { return null; }\n" + |
490 |
" void foo() {\n" + |
491 |
" Object o = getObject();\n" + |
492 |
" System.out.print(o.toString());\n" + |
493 |
" }\n" + |
494 |
"}\n" |
495 |
}, |
496 |
"----------\n" + |
497 |
"1. ERROR in X.java (at line 5)\n" + |
498 |
" System.out.print(o.toString());\n" + |
499 |
" ^\n" + |
500 |
"Potential null pointer access: The variable o may be null at this location\n" + |
501 |
"----------\n", |
502 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
503 |
} |
504 |
// a nullable return value is dereferenced without a check, method is read from .class file |
505 |
public void test_nullable_return_002() { |
506 |
runConformTest( |
507 |
new String[] { |
508 |
"Lib.java", |
509 |
"public class Lib {\n" + |
510 |
" @Nullable Object getObject() { return null; }\n" + |
511 |
"}\n" |
512 |
}); |
513 |
runNegativeTest( |
514 |
false /* flush output directory */, |
515 |
new String[] { |
516 |
"X.java", |
517 |
"public class X {\n" + |
518 |
" void foo(Lib l) {\n" + |
519 |
" Object o = l.getObject();\n" + |
520 |
" System.out.print(o.toString());\n" + |
521 |
" }\n" + |
522 |
"}\n" |
523 |
}, |
524 |
// compiler options |
525 |
null /* no class libraries */, |
526 |
null /* no custom options */, |
527 |
"----------\n" + |
528 |
"1. ERROR in X.java (at line 4)\n" + |
529 |
" System.out.print(o.toString());\n" + |
530 |
" ^\n" + |
531 |
"Potential null pointer access: The variable o may be null at this location\n" + |
532 |
"----------\n", |
533 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
534 |
} |
535 |
// a non-null return value is checked for null, method is read from .class file |
536 |
public void test_nonnull_return_001() { |
537 |
runConformTest( |
538 |
new String[] { |
539 |
"Lib.java", |
540 |
"public class Lib {\n" + |
541 |
" @NonNull Object getObject() { return new Object(); }\n" + |
542 |
"}\n" |
543 |
}); |
544 |
runNegativeTest( |
545 |
false /* flush output directory */, |
546 |
new String[] { |
547 |
"X.java", |
548 |
"public class X {\n" + |
549 |
" void foo(Lib l) {\n" + |
550 |
" Object o = l.getObject();\n" + |
551 |
" if (o != null)\n" + |
552 |
" System.out.print(o.toString());\n" + |
553 |
" }\n" + |
554 |
"}\n" |
555 |
}, |
556 |
// compiler options |
557 |
null /* no class libraries */, |
558 |
null /* no custom options */, |
559 |
"----------\n" + |
560 |
"1. ERROR in X.java (at line 4)\n" + |
561 |
" if (o != null)\n" + |
562 |
" ^\n" + |
563 |
"Redundant null check: The variable o cannot be null at this location\n" + |
564 |
"----------\n", |
565 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
566 |
} |
567 |
// a non-null method returns null |
568 |
public void test_nonnull_return_003() { |
569 |
runNegativeTest( |
570 |
new String[] { |
571 |
"X.java", |
572 |
"public class X {\n" + |
573 |
" @NonNull Object getObject(boolean b) {\n" + |
574 |
" if (b)\n" + |
575 |
" return null;\n" + // definite contract violation despite enclosing "if" |
576 |
" return new Object();\n" + |
577 |
" }\n" + |
578 |
"}\n" |
579 |
}, |
580 |
"----------\n" + |
581 |
"1. ERROR in X.java (at line 4)\n" + |
582 |
" return null;\n" + |
583 |
" ^^^^^^^^^^^^\n" + |
584 |
"Null contract violation: returning null from a method declared as @NonNull.\n" + |
585 |
"----------\n", |
586 |
JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); |
587 |
} |
588 |
// a non-null method potentially returns null |
589 |
public void test_nonnull_return_004() { |
590 |
runNegativeTest( |
591 |
new String[] { |
592 |
"X.java", |
593 |
"public class X {\n" + |
594 |
" @NonNull Object getObject(@Nullable Object o) {\n" + |
595 |
" return o;\n" + // 'o' is only potentially null |
596 |
" }\n" + |
597 |
"}\n" |
598 |
}, |
599 |
"----------\n" + |
600 |
"1. ERROR in X.java (at line 3)\n" + |
601 |
" return o;\n" + |
602 |
" ^^^^^^^^^\n" + |
603 |
"Null contract violation: return value can be null but method is declared as @NonNull.\n" + |
604 |
"----------\n"); |
605 |
} |
606 |
// a non-null method returns its non-null argument |
607 |
public void test_nonnull_return_005() { |
608 |
Map customOptions = getCompilerOptions(); |
609 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
610 |
runConformTest( |
611 |
new String[] { |
612 |
"X.java", |
613 |
"public class X {\n" + |
614 |
" @NonNull Object getObject(@NonNull Object o) {\n" + |
615 |
" return o;\n" + |
616 |
" }\n" + |
617 |
"}\n" |
618 |
}, |
619 |
"", |
620 |
null/*classLibs*/, |
621 |
true/*shouldFlushOutputDirectory*/, |
622 |
null/*vmArguments*/, |
623 |
customOptions, |
624 |
null/*compilerRequestor*/); |
625 |
} |
626 |
//a non-null method has insufficient nullness info for its return value |
627 |
public void test_nonnull_return_006() { |
628 |
runNegativeTest( |
629 |
new String[] { |
630 |
"X.java", |
631 |
"public class X {\n" + |
632 |
" @NonNull Object getObject(Object o) {\n" + |
633 |
" return o;\n" + |
634 |
" }\n" + |
635 |
"}\n" |
636 |
}, |
637 |
"----------\n" + |
638 |
"1. WARNING in X.java (at line 3)\n" + |
639 |
" return o;\n" + |
640 |
" ^^^^^^^^^\n" + |
641 |
"Potential null contract violation: insufficient nullness information regarding return value while the method is declared as @NonNull.\n" + |
642 |
"----------\n"); |
643 |
} |
644 |
// mixed use of fully qualified name / explicit import |
645 |
public void test_annotation_import_001() { |
646 |
Map customOptions = getCompilerOptions(); |
647 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
648 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.Nullable"); |
649 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.NonNull"); |
650 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.DISABLED); |
651 |
runConformTest( |
652 |
new String[] { |
653 |
"Lib.java", |
654 |
"public class Lib {\n" + |
655 |
" @org.foo.NonNull Object getObject() { return new Object(); }\n" + // FQN |
656 |
"}\n", |
657 |
"X.java", |
658 |
"import org.foo.NonNull;\n" + // explicit import |
659 |
"public class X {\n" + |
660 |
" @NonNull Object getObject(@NonNull Lib l) {\n" + |
661 |
" return l.getObject();\n" + |
662 |
" }\n" + |
663 |
"}\n" |
664 |
}, |
665 |
"", |
666 |
null/*classLibs*/, |
667 |
true/*shouldFlushOutputDirectory*/, |
668 |
null/*vmArguments*/, |
669 |
customOptions, |
670 |
null/*compilerRequestor*/); |
671 |
} |
672 |
|
673 |
// use of explicit imports throughout |
674 |
public void test_annotation_import_002() { |
675 |
Map customOptions = getCompilerOptions(); |
676 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
677 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.Nullable"); |
678 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.NonNull"); |
679 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.DISABLED); |
680 |
runConformTest( |
681 |
new String[] { |
682 |
"Lib.java", |
683 |
"import org.foo.NonNull;\n" + |
684 |
"public class Lib {\n" + |
685 |
" @NonNull Object getObject() { return new Object(); }\n" + |
686 |
"}\n", |
687 |
"X.java", |
688 |
"import org.foo.NonNull;\n" + |
689 |
"public class X {\n" + |
690 |
" @NonNull Object getObject(@org.foo.Nullable String dummy, @NonNull Lib l) {\n" + |
691 |
" Object o = l.getObject();" + |
692 |
" return o;\n" + |
693 |
" }\n" + |
694 |
"}\n" |
695 |
}, |
696 |
"", |
697 |
null/*classLibs*/, |
698 |
true/*shouldFlushOutputDirectory*/, |
699 |
null/*vmArguments*/, |
700 |
customOptions, |
701 |
null/*compilerRequestor*/); |
702 |
} |
703 |
// default import plus explicit ones |
704 |
public void test_annotation_import_003() { |
705 |
Map customOptions = getCompilerOptions(); |
706 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
707 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.Nullable"); |
708 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.NonNull"); |
709 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); |
710 |
runConformTest( |
711 |
new String[] { |
712 |
"libpack/Lib.java", |
713 |
"package libpack;\n" + |
714 |
"public class Lib {\n" + |
715 |
" public @NonNull Object getObject() { return new Object(); }\n" + |
716 |
"}\n", |
717 |
"X.java", |
718 |
"import libpack.Lib;\n" + |
719 |
"public class X {\n" + |
720 |
" @NonNull Object getObject(@NonNull Lib l) {\n" + |
721 |
" return l.getObject();\n" + |
722 |
" }\n" + |
723 |
"}\n" |
724 |
}, |
725 |
"", |
726 |
null/*classLibs*/, |
727 |
true/*shouldFlushOutputDirectory*/, |
728 |
null/*vmArguments*/, |
729 |
customOptions, |
730 |
null/*compilerRequestor*/); |
731 |
} |
732 |
// default import but unspecified annotation names |
733 |
public void test_annotation_import_004() { |
734 |
Map customOptions = getCompilerOptions(); |
735 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
736 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, null); |
737 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, null); |
738 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); |
739 |
runConformTest( |
740 |
new String[] { |
741 |
"libpack/Lib.java", |
742 |
"package libpack;\n" + |
743 |
"public class Lib {\n" + |
744 |
" public @NonNull Object getObject() { return new Object(); }\n" + |
745 |
"}\n", |
746 |
"X.java", |
747 |
"import libpack.Lib;\n" + |
748 |
"public class X {\n" + |
749 |
" @NonNull Object getObject(@NonNull Lib l) {\n" + |
750 |
" return l.getObject();\n" + |
751 |
" }\n" + |
752 |
"}\n" |
753 |
}, |
754 |
"", |
755 |
null/*classLibs*/, |
756 |
true/*shouldFlushOutputDirectory*/, |
757 |
null/*vmArguments*/, |
758 |
customOptions, |
759 |
null/*compilerRequestor*/); |
760 |
} |
761 |
// default import of existing annotation types |
762 |
public void test_annotation_import_005() { |
763 |
Map customOptions = getCompilerOptions(); |
764 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
765 |
customOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.ERROR); |
766 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.MayBeNull"); |
767 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.MustNotBeNull"); |
768 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); |
769 |
customOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.DISABLED); |
770 |
runNegativeTest( |
771 |
true/*shouldFlushOutputDirectory*/, |
772 |
new String[] { |
773 |
"Lib.java", |
774 |
"public class Lib {\n" + |
775 |
" Object getObject() { return new Object(); }\n" + |
776 |
"}\n", |
777 |
"X.java", |
778 |
"public class X {\n" + |
779 |
" @MustNotBeNull Object getObject(@MustNotBeNull Lib l) {\n" + |
780 |
" return l.getObject();\n" + |
781 |
" }\n" + |
782 |
"}\n", |
783 |
|
784 |
"org/foo/MayBeNull.java", |
785 |
"package org.foo;\n" + |
786 |
"import java.lang.annotation.*;\n" + |
787 |
"@Retention(RetentionPolicy.CLASS)\n" + |
788 |
"public @interface MayBeNull {}\n", |
789 |
|
790 |
"org/foo/MustNotBeNull.java", |
791 |
"package org.foo;\n" + |
792 |
"import java.lang.annotation.*;\n" + |
793 |
"@Retention(RetentionPolicy.CLASS)\n" + |
794 |
"public @interface MustNotBeNull {}\n", |
795 |
}, |
796 |
null/*classLibs*/, |
797 |
customOptions, |
798 |
"----------\n" + |
799 |
"1. ERROR in X.java (at line 3)\n" + |
800 |
" return l.getObject();\n" + |
801 |
" ^^^^^^^^^^^^^^^^^^^^^\n" + |
802 |
"Potential null contract violation: insufficient nullness information regarding return value while the method is declared as @MustNotBeNull.\n" + |
803 |
// "Potential null contract violation: insufficient nullness information for checking return value against declaration as @MustNotBeNull.\n" + |
804 |
"----------\n", |
805 |
JavacTestOptions.SKIP); |
806 |
} |
807 |
// a non-null method returns a value obtained from an unannotated method, default import of missing annotation types |
808 |
public void test_annotation_import_006() { |
809 |
Map customOptions = getCompilerOptions(); |
810 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
811 |
customOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.ERROR); |
812 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.MayBeNull"); |
813 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.MustNotBeNull"); |
814 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); |
815 |
customOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.DISABLED); |
816 |
runNegativeTest( |
817 |
true/*shouldFlushOutputDirectory*/, |
818 |
new String[] { |
819 |
"Lib.java", |
820 |
"public class Lib {\n" + |
821 |
" Object getObject() { return new Object(); }\n" + |
822 |
"}\n", |
823 |
"X.java", |
824 |
"public class X {\n" + |
825 |
" @MustNotBeNull Object getObject(@MustNotBeNull Lib l) {\n" + |
826 |
" return l.getObject();\n" + |
827 |
" }\n" + |
828 |
"}\n" |
829 |
}, |
830 |
null/*classLibs*/, |
831 |
customOptions, |
832 |
"----------\n" + |
833 |
"1. ERROR in Lib.java (at line 0)\n" + |
834 |
" public class Lib {\n" + |
835 |
" ^\n" + |
836 |
"Buildpath problem: the type org.foo.MayBeNull which is configured as a null annotation type cannot be resolved.\n" + |
837 |
"----------\n", |
838 |
JavacTestOptions.SKIP); |
839 |
} |
840 |
// emulation names conflict with existing types |
841 |
public void test_annotation_emulation_001() { |
842 |
Map customOptions = getCompilerOptions(); |
843 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
844 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "libpack.Lib"); |
845 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "libpack.Lib"); |
846 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); |
847 |
runNegativeTest( |
848 |
true/*shouldFlushOutputDirectory*/, |
849 |
new String[] { |
850 |
"libpack/Lib.java", |
851 |
"package libpack;\n" + |
852 |
"public class Lib {\n" + |
853 |
"}\n", |
854 |
}, |
855 |
null/*classLibs*/, |
856 |
customOptions, |
857 |
"----------\n" + |
858 |
"1. ERROR in libpack\\Lib.java (at line 0)\n" + |
859 |
" package libpack;\n" + |
860 |
" ^\n" + |
861 |
"Buildpath problem: emulation of type libpack.Lib is requested (for null annotations) but a type of this name exists on the build path.\n" + |
862 |
"----------\n", |
863 |
JavacTestOptions.SKIP); |
864 |
} |
865 |
// regular use (explicit import/FQN) of existing annotation types (=no emulation) |
866 |
public void test_annotation_emulation_002() { |
867 |
Map customOptions = getCompilerOptions(); |
868 |
customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); |
869 |
customOptions.put(CompilerOptions.OPTION_ReportPotentialNullContractViolation, CompilerOptions.ERROR); |
870 |
customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.MayBeNull"); |
871 |
customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.MustNotBeNull"); |
872 |
customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.DISABLED); |
873 |
customOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.DISABLED); |
874 |
runNegativeTest( |
875 |
true/*shouldFlushOutputDirectory*/, |
876 |
new String[] { |
877 |
"Lib.java", |
878 |
"public class Lib {\n" + |
879 |
" @org.foo.MayBeNull Object getObject() { return new Object(); }\n" + // FQN |
880 |
"}\n", |
881 |
"X.java", |
882 |
"import org.foo.MustNotBeNull;\n" + // explicit import |
883 |
"public class X {\n" + |
884 |
" @MustNotBeNull Object getObject(@MustNotBeNull Lib l) {\n" + |
885 |
" return l.getObject();\n" + |
886 |
" }\n" + |
887 |
"}\n", |
888 |
|
889 |
"org/foo/MayBeNull.java", |
890 |
"package org.foo;\n" + |
891 |
"import java.lang.annotation.*;\n" + |
892 |
"@Retention(RetentionPolicy.CLASS)\n" + |
893 |
"public @interface MayBeNull {}\n", |
894 |
|
895 |
"org/foo/MustNotBeNull.java", |
896 |
"package org.foo;\n" + |
897 |
"import java.lang.annotation.*;\n" + |
898 |
"@Retention(RetentionPolicy.CLASS)\n" + |
899 |
"public @interface MustNotBeNull {}\n", |
900 |
}, |
901 |
null/*classLibs*/, |
902 |
customOptions, |
903 |
"----------\n" + |
904 |
"1. ERROR in X.java (at line 4)\n" + |
905 |
" return l.getObject();\n" + |
906 |
" ^^^^^^^^^^^^^^^^^^^^^\n" + |
907 |
"Null contract violation: return value can be null but method is declared as @MustNotBeNull.\n" + |
908 |
"----------\n", |
909 |
JavacTestOptions.SKIP); |
910 |
} |
911 |
|
912 |
// a default null annotation is illegally used on a class: |
913 |
public void test_illegal_annotation_001() { |
914 |
runNegativeTest( |
915 |
new String[] { |
916 |
"X.java", |
917 |
"@NonNull public class X {\n" + |
918 |
"}\n" |
919 |
}, |
920 |
"----------\n" + |
921 |
"1. ERROR in X.java (at line 1)\n" + |
922 |
" @NonNull public class X {\n" + |
923 |
" ^^^^^^^^\n" + |
924 |
"The annotation @NonNull is disallowed for this location\n" + |
925 |
"----------\n"); |
926 |
} |
927 |
} |