Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 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.model; |
12 |
|
13 |
import java.io.File; |
14 |
import java.io.IOException; |
15 |
import java.io.StringBufferInputStream; |
16 |
import java.net.URL; |
17 |
import java.util.Hashtable; |
18 |
|
19 |
import junit.framework.Test; |
20 |
|
21 |
import org.eclipse.core.resources.IFile; |
22 |
import org.eclipse.core.resources.IMarker; |
23 |
import org.eclipse.core.resources.IResource; |
24 |
import org.eclipse.core.resources.IncrementalProjectBuilder; |
25 |
import org.eclipse.core.runtime.CoreException; |
26 |
import org.eclipse.core.runtime.FileLocator; |
27 |
import org.eclipse.core.runtime.Platform; |
28 |
import org.eclipse.jdt.core.ICompilationUnit; |
29 |
import org.eclipse.jdt.core.IJavaModelMarker; |
30 |
import org.eclipse.jdt.core.IJavaProject; |
31 |
import org.eclipse.jdt.core.JavaCore; |
32 |
import org.eclipse.jdt.core.compiler.IProblem; |
33 |
import org.eclipse.jdt.core.dom.AST; |
34 |
import org.eclipse.jdt.core.dom.ASTParser; |
35 |
import org.eclipse.jdt.core.dom.CompilationUnit; |
36 |
|
37 |
public class NullAnnotationModelTests extends ReconcilerTests { |
38 |
|
39 |
String ANNOTATION_LIB; |
40 |
|
41 |
public static Test suite() { |
42 |
return buildModelTestSuite(NullAnnotationModelTests.class); |
43 |
} |
44 |
|
45 |
public NullAnnotationModelTests(String name) { |
46 |
super(name); |
47 |
} |
48 |
|
49 |
static { |
50 |
// TESTS_NAMES = new String[] { "testMissingAnnotation5" }; |
51 |
} |
52 |
|
53 |
public void setUp() throws Exception { |
54 |
super.setUp(); |
55 |
File bundleFile = FileLocator.getBundleFile(Platform.getBundle("org.eclipse.jdt.annotation.null")); |
56 |
this.ANNOTATION_LIB = bundleFile.isDirectory() ? bundleFile.getPath()+"/bin" : bundleFile.getPath(); |
57 |
} |
58 |
|
59 |
protected String testJarPath(String jarName) throws IOException { |
60 |
URL libEntry = Platform.getBundle("org.eclipse.jdt.core.tests.model").getEntry("/workspace/NullAnnotations/lib/"+jarName); |
61 |
return FileLocator.toFileURL(libEntry).getPath(); |
62 |
} |
63 |
|
64 |
|
65 |
public void testConvertedSourceType1() throws CoreException, InterruptedException { |
66 |
try { |
67 |
// Resources creation |
68 |
IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); |
69 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
70 |
p.setOption(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); |
71 |
|
72 |
this.createFolder("/P/p1"); |
73 |
String c1SourceString = |
74 |
"package p1;\n" + |
75 |
"import org.eclipse.jdt.annotation.*;\n" + |
76 |
"public class C1 {\n" + |
77 |
" public String foo(@Nullable Object arg) {\n" + // this is consumed via SourceTypeConverter |
78 |
" return arg == null ? \"\" : arg.toString();\n" + |
79 |
" }\n" + |
80 |
"}\n"; |
81 |
this.createFile( |
82 |
"/P/p1/C1.java", |
83 |
c1SourceString); |
84 |
|
85 |
this.createFolder("/P/p2"); |
86 |
String c2SourceString = |
87 |
"package p2;\n" + |
88 |
"public class C2 {\n" + |
89 |
" String bar(p1.C1 c, C2 c2) {;\n" + |
90 |
" return c.foo(null);\n" + // don't complain despite default nonnull, foo has explicit @Nullable |
91 |
" }\n" + |
92 |
" String foo(Object arg) {\n" + |
93 |
" return arg == null ? null : arg.toString();\n" + |
94 |
" }\n" + |
95 |
"}\n"; |
96 |
this.createFile( |
97 |
"/P/p2/C2.java", |
98 |
c2SourceString); |
99 |
|
100 |
char[] c2SourceChars = c2SourceString.toCharArray(); |
101 |
this.problemRequestor.initialize(c2SourceChars); |
102 |
|
103 |
getCompilationUnit("/P/p2/C2.java").getWorkingCopy(this.wcOwner, null); |
104 |
|
105 |
assertProblems("Unexpected problems", "----------\n" + |
106 |
"1. WARNING in /P/p2/C2.java (at line 7)\n" + |
107 |
" return arg == null ? null : arg.toString();\n" + |
108 |
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + |
109 |
"Potential type mismatch: required \'@NonNull String\' but nullness of the provided value is unknown\n" + |
110 |
"----------\n"); |
111 |
} finally { |
112 |
deleteProject("P"); |
113 |
} |
114 |
} |
115 |
|
116 |
public void testBinaryType1() throws CoreException, InterruptedException, IOException { |
117 |
try { |
118 |
// Resources creation |
119 |
IJavaProject p = createJavaProject("P", new String[] {""}, |
120 |
new String[] {"JCL15_LIB", this.ANNOTATION_LIB, testJarPath("example.jar")}, |
121 |
"bin", "1.5"); |
122 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
123 |
p.setOption(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); |
124 |
|
125 |
// example.jar contains p1/C1.java just like testConvertedSourceType1() |
126 |
|
127 |
this.createFolder("/P/p2"); |
128 |
String c2SourceString = |
129 |
"package p2;\n" + |
130 |
"public class C2 {\n" + |
131 |
" String bar(p1.C1 c) {;\n" + |
132 |
" return c.foo(null);\n" + // don't complain despite default nonnull, foo has explicit @Nullable |
133 |
" }\n" + |
134 |
" String foo(Object arg) {\n" + |
135 |
" return arg == null ? null : arg.toString();\n" + |
136 |
" }\n" + |
137 |
"}\n"; |
138 |
this.createFile( |
139 |
"/P/p2/C2.java", |
140 |
c2SourceString); |
141 |
|
142 |
char[] c2SourceChars = c2SourceString.toCharArray(); |
143 |
this.problemRequestor.initialize(c2SourceChars); |
144 |
|
145 |
getCompilationUnit("/P/p2/C2.java").getWorkingCopy(this.wcOwner, null); |
146 |
|
147 |
assertProblems("Unexpected problems", "----------\n" + |
148 |
"1. WARNING in /P/p2/C2.java (at line 7)\n" + |
149 |
" return arg == null ? null : arg.toString();\n" + |
150 |
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + |
151 |
"Potential type mismatch: required \'@NonNull String\' but nullness of the provided value is unknown\n" + |
152 |
"----------\n"); |
153 |
} finally { |
154 |
deleteProject("P"); |
155 |
} |
156 |
} |
157 |
|
158 |
public void testMissingAnnotation1() throws CoreException { |
159 |
try { |
160 |
// Resources creation |
161 |
IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); |
162 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
163 |
p.setOption(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "in.valid"); |
164 |
|
165 |
this.createFolder("/P/p1"); |
166 |
String c1SourceString = |
167 |
"package p1;\n" + |
168 |
"@org.eclipse.jdt.annotation.NonNullByDefault\n" + |
169 |
"public class C1 {\n" + |
170 |
" public String foo(Object arg) {\n" + |
171 |
" return arg == null ? \"\" : arg.toString();\n" + |
172 |
" }\n" + |
173 |
"}\n"; |
174 |
this.createFile( |
175 |
"/P/p1/C1.java", |
176 |
c1SourceString); |
177 |
|
178 |
this.problemRequestor.initialize(c1SourceString.toCharArray()); |
179 |
|
180 |
getCompilationUnit("/P/p1/C1.java").getWorkingCopy(this.wcOwner, null); |
181 |
|
182 |
assertProblems("Unexpected problems", |
183 |
"----------\n" + |
184 |
"1. ERROR in /P/p1/C1.java (at line 1)\n" + |
185 |
" package p1;\n" + |
186 |
" ^\n" + |
187 |
"Buildpath problem: the type in.valid, which is configured as a null annotation type, cannot be resolved\n" + |
188 |
"----------\n"); |
189 |
} finally { |
190 |
deleteProject("P"); |
191 |
} |
192 |
} |
193 |
|
194 |
public void testMissingAnnotation2() throws CoreException { |
195 |
Hashtable javaOptions = JavaCore.getOptions(); |
196 |
try { |
197 |
// Resources creation |
198 |
IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); |
199 |
IFile settings = (IFile) p.getProject().findMember(".settings/org.eclipse.jdt.core.prefs"); |
200 |
settings.appendContents(new StringBufferInputStream("\norg.eclipse.jdt.core.compiler.annotation.nonnull=not.valid\n"), 0, null); |
201 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
202 |
|
203 |
this.createFolder("/P/p1"); |
204 |
String c1SourceString = |
205 |
"package p1;\n" + |
206 |
"@org.eclipse.jdt.annotation.NonNullByDefault\n" + |
207 |
"public class C1 {\n" + |
208 |
" public String foo(Object arg) {\n" + |
209 |
" return arg == null ? \"\" : arg.toString();\n" + |
210 |
" }\n" + |
211 |
"}\n"; |
212 |
this.createFile( |
213 |
"/P/p1/C1.java", |
214 |
c1SourceString); |
215 |
|
216 |
this.problemRequestor.initialize(c1SourceString.toCharArray()); |
217 |
|
218 |
getCompilationUnit("/P/p1/C1.java").getWorkingCopy(this.wcOwner, null); |
219 |
|
220 |
assertProblems("Unexpected problems", |
221 |
"----------\n" + |
222 |
"1. ERROR in /P/p1/C1.java (at line 1)\n" + |
223 |
" package p1;\n" + |
224 |
" ^\n" + |
225 |
"Buildpath problem: the type not.valid, which is configured as a null annotation type, cannot be resolved\n" + |
226 |
"----------\n"); |
227 |
} finally { |
228 |
deleteProject("P"); |
229 |
JavaCore.setOptions(javaOptions); |
230 |
// work against side-effect of JavaRuntime listening to change of prefs-file. |
231 |
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=302850#c25 |
232 |
} |
233 |
} |
234 |
|
235 |
// Bug 363858 - [dom] early throwing of AbortCompilation causes NPE in CompilationUnitResolver |
236 |
public void testMissingAnnotation3() throws CoreException { |
237 |
try { |
238 |
// Resources creation |
239 |
IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); |
240 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
241 |
p.setOption(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "invalid"); |
242 |
|
243 |
this.createFolder("/P/p1"); |
244 |
String c1SourceString = |
245 |
"package p1;\n" + |
246 |
"@org.eclipse.jdt.annotation.NonNullByDefault\n" + |
247 |
"public class C1 {\n" + |
248 |
" public String foo(Object arg) {\n" + |
249 |
" return arg == null ? \"\" : arg.toString();\n" + |
250 |
" }\n" + |
251 |
"}\n"; |
252 |
this.createFile( |
253 |
"/P/p1/C1.java", |
254 |
c1SourceString); |
255 |
|
256 |
this.problemRequestor.initialize(c1SourceString.toCharArray()); |
257 |
|
258 |
final ICompilationUnit unit = getCompilationUnit("/P/p1/C1.java").getWorkingCopy(this.wcOwner, null); |
259 |
assertProblems("Unexpected problems", |
260 |
"----------\n" + |
261 |
"1. ERROR in /P/p1/C1.java (at line 0)\n" + |
262 |
" package p1;\n" + |
263 |
" ^\n" + |
264 |
"Cannot use the unqualified name \'invalid\' as an annotation name for null specification\n" + |
265 |
"----------\n"); |
266 |
|
267 |
ASTParser parser = ASTParser.newParser(AST.JLS4); |
268 |
parser.setProject(p); |
269 |
parser.setResolveBindings(true); |
270 |
parser.setSource(unit); |
271 |
CompilationUnit ast = (CompilationUnit) parser.createAST(null); |
272 |
assertNotNull("ast should not be null", ast); |
273 |
this.problemRequestor.reset(); |
274 |
this.problemRequestor.beginReporting(); |
275 |
IProblem[] problems = ast.getProblems(); |
276 |
for (int i=0; i<problems.length; i++) |
277 |
this.problemRequestor.acceptProblem(problems[i]); |
278 |
assertProblems("Unexpected problems (2)", |
279 |
"----------\n" + |
280 |
"1. ERROR in /P/p1/C1.java (at line 0)\n" + |
281 |
" package p1;\n" + |
282 |
" ^\n" + |
283 |
"Cannot use the unqualified name \'invalid\' as an annotation name for null specification\n" + |
284 |
"----------\n"); |
285 |
} finally { |
286 |
deleteProject("P"); |
287 |
} |
288 |
} |
289 |
|
290 |
// initialization of null annotations is triggered from package-info.java: illegal simple name |
291 |
public void testMissingAnnotation4() throws CoreException { |
292 |
try { |
293 |
// Resources creation |
294 |
IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); |
295 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
296 |
p.setOption(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "invalid"); |
297 |
|
298 |
this.createFolder("/P/p1"); |
299 |
String piSourceString = |
300 |
"@org.eclipse.jdt.annotation.NonNullByDefault\n" + |
301 |
"package p1;\n"; |
302 |
this.createFile( |
303 |
"/P/p1/package-info.java", |
304 |
piSourceString); |
305 |
|
306 |
this.problemRequestor.initialize(piSourceString.toCharArray()); |
307 |
|
308 |
// Challenge CompilationUnitProblemFinder: |
309 |
final ICompilationUnit unit = getCompilationUnit("/P/p1/package-info.java").getWorkingCopy(this.wcOwner, null); |
310 |
String expectedError = "----------\n" + |
311 |
"1. ERROR in /P/p1/package-info.java (at line 0)\n" + |
312 |
" @org.eclipse.jdt.annotation.NonNullByDefault\n" + |
313 |
" ^\n" + |
314 |
"Cannot use the unqualified name \'invalid\' as an annotation name for null specification\n" + |
315 |
"----------\n"; |
316 |
assertProblems("Unexpected problems from CompilationUnitProblemFinder", expectedError); |
317 |
|
318 |
// Challenge JavaBuilder: |
319 |
p.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); |
320 |
IMarker[] markers = p.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); |
321 |
assertMarkers("Unexpected markers", |
322 |
"Cannot use the unqualified name 'invalid' as an annotation name for null specification", |
323 |
markers); |
324 |
assertEquals("Unexpected marker path", "/P", markers[0].getResource().getFullPath().toString()); |
325 |
|
326 |
// Challenge CompilationUnitResolver: |
327 |
ASTParser parser = ASTParser.newParser(AST.JLS4); |
328 |
parser.setProject(p); |
329 |
parser.setResolveBindings(true); |
330 |
parser.setSource(unit); |
331 |
CompilationUnit ast = (CompilationUnit) parser.createAST(null); |
332 |
assertNotNull("ast should not be null", ast); |
333 |
this.problemRequestor.reset(); |
334 |
this.problemRequestor.beginReporting(); |
335 |
IProblem[] problems = ast.getProblems(); |
336 |
for (int i=0; i<problems.length; i++) |
337 |
this.problemRequestor.acceptProblem(problems[i]); |
338 |
assertProblems("Unexpected problems from CompilationUnitResolver", expectedError); |
339 |
} finally { |
340 |
deleteProject("P"); |
341 |
} |
342 |
} |
343 |
|
344 |
// initialization of null annotations is |
345 |
// - triggered from resolveTypesFor(MethodBinding) |
346 |
// - default is defined in package-info.java: |
347 |
// must detect missing non-null annotation and report against the project |
348 |
public void testMissingAnnotation5() throws CoreException, InterruptedException { |
349 |
try { |
350 |
// Resources creation |
351 |
IJavaProject p = createJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB", this.ANNOTATION_LIB}, "bin", "1.5"); |
352 |
p.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED); |
353 |
p.setOption(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "pack.Missing"); |
354 |
|
355 |
this.createFolder("/P/p1"); |
356 |
String piSourceString = |
357 |
"@org.eclipse.jdt.annotation.NonNullByDefault\n" + |
358 |
"package p1;\n"; |
359 |
this.createFile("/P/p1/package-info.java", piSourceString); |
360 |
|
361 |
String c1SourceString = |
362 |
"package p1;\n" + |
363 |
"public class C1 {\n" + |
364 |
" String foo(String arg) { return arg; }\n" + |
365 |
"}\n"; |
366 |
this.createFile("/P/p1/C1.java", c1SourceString); |
367 |
|
368 |
this.problemRequestor.initialize(piSourceString.toCharArray()); |
369 |
|
370 |
// Challenge CompilationUnitProblemFinder: |
371 |
assertNoProblem(piSourceString.toCharArray(), getCompilationUnit("/P/p1/package-info.java")); |
372 |
|
373 |
this.problemRequestor.initialize(c1SourceString.toCharArray()); |
374 |
|
375 |
// Challenge CompilationUnitProblemFinder: |
376 |
ICompilationUnit unit = getCompilationUnit("/P/p1/C1.java").getWorkingCopy(this.wcOwner, null); |
377 |
String expectedError = "----------\n" + |
378 |
"1. ERROR in /P/p1/C1.java (at line 1)\n" + |
379 |
" package p1;\n" + |
380 |
" ^\n" + |
381 |
"Buildpath problem: the type pack.Missing, which is configured as a null annotation type, cannot be resolved\n" + |
382 |
"----------\n"; |
383 |
assertProblems("Unexpected problems", expectedError); |
384 |
|
385 |
// Challenge JavaBuilder: |
386 |
p.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); |
387 |
IMarker[] markers = p.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); |
388 |
assertMarkers("Unexpected markers", |
389 |
"Buildpath problem: the type pack.Missing, which is configured as a null annotation type, cannot be resolved", |
390 |
markers); |
391 |
assertEquals("Unexpected marker path", "/P", markers[0].getResource().getFullPath().toString()); |
392 |
|
393 |
// Challenge CompilationUnitResolver: |
394 |
ASTParser parser = ASTParser.newParser(AST.JLS4); |
395 |
parser.setProject(p); |
396 |
parser.setResolveBindings(true); |
397 |
parser.setSource(unit); |
398 |
CompilationUnit ast = (CompilationUnit) parser.createAST(null); |
399 |
assertNotNull("ast should not be null", ast); |
400 |
this.problemRequestor.reset(); |
401 |
this.problemRequestor.beginReporting(); |
402 |
IProblem[] problems = ast.getProblems(); |
403 |
for (int i=0; i<problems.length; i++) |
404 |
this.problemRequestor.acceptProblem(problems[i]); |
405 |
assertProblems("Unexpected problems (2)", expectedError); |
406 |
} finally { |
407 |
deleteProject("P"); |
408 |
} |
409 |
} |
410 |
} |