View | Details | Raw Unified | Return to bug 363858 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java (-1 / +1 lines)
Lines 1530-1536 public void test_illegal_annotation_002() { Link Here
1530
		},
1530
		},
1531
		customOptions,
1531
		customOptions,
1532
		"----------\n" + 
1532
		"----------\n" + 
1533
		"1. ERROR in X.java (at line 0)\n" + 
1533
		"1. ERROR in X.java (at line 1)\n" + 
1534
		"	public class X {\n" + 
1534
		"	public class X {\n" + 
1535
		"	^\n" + 
1535
		"	^\n" + 
1536
		"Cannot use the unqualified name \'NichtNull\' as an annotation name for null specification\n" + 
1536
		"Cannot use the unqualified name \'NichtNull\' as an annotation name for null specification\n" + 
(-)a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java (-1 / +4 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 185-190 private static Class[] getAllTestClasses() { Link Here
185
		UtilTests.class,
185
		UtilTests.class,
186
		
186
		
187
		JavaCoreOptionsTests.class,
187
		JavaCoreOptionsTests.class,
188
		
189
		// Tests regarding null-annotations:
190
		NullAnnotationModelTests.class,
188
	};
191
	};
189
192
190
	Class[] deprecatedClasses = getDeprecatedJDOMTestClasses();
193
	Class[] deprecatedClasses = getDeprecatedJDOMTestClasses();
(-)a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java (+410 lines)
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
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java (-2 / +7 lines)
Lines 695-700 public class Compiler implements ITypeRequestor, ProblemSeverities { Link Here
695
695
696
		// Switch the current policy and compilation result for this unit to the requested one.
696
		// Switch the current policy and compilation result for this unit to the requested one.
697
		for (int i = 0; i < maxUnits; i++) {
697
		for (int i = 0; i < maxUnits; i++) {
698
			CompilationResult unitResult = null;
698
			try {
699
			try {
699
				if (this.options.verbose) {
700
				if (this.options.verbose) {
700
					this.out.println(
701
					this.out.println(
Lines 707-714 public class Compiler implements ITypeRequestor, ProblemSeverities { Link Here
707
				}
708
				}
708
				// diet parsing for large collection of units
709
				// diet parsing for large collection of units
709
				CompilationUnitDeclaration parsedUnit;
710
				CompilationUnitDeclaration parsedUnit;
710
				CompilationResult unitResult =
711
				unitResult = new CompilationResult(sourceUnits[i], i, maxUnits, this.options.maxProblemsPerUnit);
711
					new CompilationResult(sourceUnits[i], i, maxUnits, this.options.maxProblemsPerUnit);
712
				long parseStart = System.currentTimeMillis();
712
				long parseStart = System.currentTimeMillis();
713
				if (this.totalUnits < this.parseThreshold) {
713
				if (this.totalUnits < this.parseThreshold) {
714
					parsedUnit = this.parser.parse(sourceUnits[i], unitResult);
714
					parsedUnit = this.parser.parse(sourceUnits[i], unitResult);
Lines 727-732 public class Compiler implements ITypeRequestor, ProblemSeverities { Link Here
727
				}
727
				}
728
				//} catch (AbortCompilationUnit e) {
728
				//} catch (AbortCompilationUnit e) {
729
				//	requestor.acceptResult(unitResult.tagAsAccepted());
729
				//	requestor.acceptResult(unitResult.tagAsAccepted());
730
			} catch (AbortCompilation a) {
731
				// best effort to find a way for reporting this problem:
732
				if (a.compilationResult == null)
733
					a.compilationResult = unitResult;
734
				throw a;
730
			} finally {
735
			} finally {
731
				sourceUnits[i] = null; // no longer hold onto the unit
736
				sourceUnits[i] = null; // no longer hold onto the unit
732
			}
737
			}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java (-42 / +52 lines)
Lines 78-84 public class LookupEnvironment implements ProblemReasons, TypeConstants { Link Here
78
	public boolean isProcessingAnnotations = false;
78
	public boolean isProcessingAnnotations = false;
79
	public boolean mayTolerateMissingType = false;
79
	public boolean mayTolerateMissingType = false;
80
80
81
	boolean nullAnnotationsInitialized = false;
81
	private char[][][] nullAnnotationPackageNames = null; 	// package parts of globalOptions.{nullableAnnotationName,nonNullAnnotationName,nonNullByDefaultAnnotationName}
82
	private char[][] nullAnnotationSimpleNames = null;	 	// type parts of    globalOptions.{nullableAnnotationName,nonNullAnnotationName,nonNullByDefaultAnnotationName}
82
83
83
	final static int BUILD_FIELDS_AND_METHODS = 4;
84
	final static int BUILD_FIELDS_AND_METHODS = 4;
84
	final static int BUILD_TYPE_HIERARCHY = 1;
85
	final static int BUILD_TYPE_HIERARCHY = 1;
Lines 728-735 public MissingTypeBinding createMissingType(PackageBinding packageBinding, char[ Link Here
728
* 3. Create the method bindings
729
* 3. Create the method bindings
729
*/
730
*/
730
public PackageBinding createPackage(char[][] compoundName) {
731
public PackageBinding createPackage(char[][] compoundName) {
731
	if (!this.nullAnnotationsInitialized)
732
		initNullAnnotationPackages();
733
	PackageBinding packageBinding = getPackage0(compoundName[0]);
732
	PackageBinding packageBinding = getPackage0(compoundName[0]);
734
	if (packageBinding == null || packageBinding == TheNotFoundPackage) {
733
	if (packageBinding == null || packageBinding == TheNotFoundPackage) {
735
		packageBinding = new PackageBinding(compoundName[0], this);
734
		packageBinding = new PackageBinding(compoundName[0], this);
Lines 1128-1133 public TypeBinding getNullAnnotationBindingFromDefault(long defaultTagBit, boole Link Here
1128
	return null;
1127
	return null;
1129
}
1128
}
1130
1129
1130
/** answer the simple names of annotation types nullable/nonnull/nonnullbydefault if their package is packageName. */
1131
char[][] getNullAnnotationNames(char[][] packageName) {
1132
	if (this.nullAnnotationPackageNames == null) {
1133
		// fetch and split names from globalOptions to local fields nullAnnotationPackageNames & nullAnnotationsSimpleNames:
1134
		this.nullAnnotationPackageNames = new char[3][][];
1135
		this.nullAnnotationSimpleNames = new char[3][];
1136
		char[][][] compoundNames = new char[][][] {getNullableAnnotationName(), getNonNullAnnotationName(), getNonNullByDefaultAnnotationName() };
1137
		for (int i=0; i<3; i++) {
1138
			int len = compoundNames[i].length;
1139
			if (len < 2) {
1140
				this.problemReporter.nullAnnotationNameMustBeQualified(compoundNames[i], this.unitBeingCompleted);
1141
				// the above error may or may not throw AbortCompilation (is problemReporter.referenceContext set?)
1142
				continue;
1143
			}
1144
			this.nullAnnotationPackageNames[i] = CharOperation.subarray(compoundNames[i], 0, len-1);
1145
			this.nullAnnotationSimpleNames[i] = compoundNames[i][len-1];
1146
		}
1147
	}
1148
	// search in local storage:
1149
	boolean found = false;
1150
	char[][] simpleNames = new char[3][];
1151
	for (int i=0; i<3; i++) {
1152
		if (CharOperation.equals(packageName, this.nullAnnotationPackageNames[i])) {
1153
			simpleNames[i] = this.nullAnnotationSimpleNames[i];
1154
			found = true;
1155
		}
1156
	}
1157
	if (found)
1158
		return simpleNames;
1159
	else
1160
		return null;
1161
}
1162
1163
TypeBinding getNullAnnotationResolved(TypeBinding nullAnnotation, Scope scope) {
1164
	// avoid unspecific error "The type in.valid cannot be resolved. It is indirectly referenced from required .class files"
1165
	boolean tolerateMissing = this.mayTolerateMissingType;
1166
	this.mayTolerateMissingType = true;
1167
	try {
1168
		nullAnnotation = BinaryTypeBinding.resolveType(nullAnnotation, this, false);
1169
	} finally {
1170
		this.mayTolerateMissingType = tolerateMissing;
1171
	}
1172
	if (nullAnnotation instanceof MissingTypeBinding) {
1173
		// convert error into a specific one:
1174
		scope.problemReporter().missingNullAnnotationType(((MissingTypeBinding)nullAnnotation).compoundName);
1175
		return null;
1176
	}
1177
	return nullAnnotation;
1178
}
1179
1131
/* Answer the top level package named name if it exists in the cache.
1180
/* Answer the top level package named name if it exists in the cache.
1132
* Answer theNotFoundPackage if it could not be resolved the first time
1181
* Answer theNotFoundPackage if it could not be resolved the first time
1133
* it was looked up, otherwise answer null.
1182
* it was looked up, otherwise answer null.
Lines 1161-1168 public ReferenceBinding getResolvedType(char[][] compoundName, Scope scope) { Link Here
1161
* Answer null if the package cannot be found.
1210
* Answer null if the package cannot be found.
1162
*/
1211
*/
1163
PackageBinding getTopLevelPackage(char[] name) {
1212
PackageBinding getTopLevelPackage(char[] name) {
1164
	if (!this.nullAnnotationsInitialized)
1165
		initNullAnnotationPackages();
1166
	PackageBinding packageBinding = getPackage0(name);
1213
	PackageBinding packageBinding = getPackage0(name);
1167
	if (packageBinding != null) {
1214
	if (packageBinding != null) {
1168
		if (packageBinding == TheNotFoundPackage)
1215
		if (packageBinding == TheNotFoundPackage)
Lines 1444-1484 TypeBinding getTypeFromVariantTypeSignature( Link Here
1444
	}
1491
	}
1445
}
1492
}
1446
1493
1447
private void initNullAnnotationPackages() {
1448
	this.nullAnnotationsInitialized = true;
1449
	if (!this.globalOptions.isAnnotationBasedNullAnalysisEnabled)
1450
		return;
1451
	char[][] compoundName = getNullableAnnotationName();
1452
	if (compoundName != null)
1453
		initNullAnnotationPackage(compoundName, TypeIds.T_ConfiguredAnnotationNullable);
1454
	compoundName = getNonNullAnnotationName();
1455
	if (compoundName != null)
1456
		initNullAnnotationPackage(compoundName, TypeIds.T_ConfiguredAnnotationNonNull);
1457
	compoundName = getNonNullByDefaultAnnotationName();
1458
	if (compoundName != null)
1459
		initNullAnnotationPackage(compoundName, TypeIds.T_ConfiguredAnnotationNonNullByDefault);
1460
}
1461
1462
/** 
1463
 * Create or retrieve the package holding the specified type and store the type name.
1464
 */
1465
void initNullAnnotationPackage(char[][] typeName, int typeId) {
1466
	if (typeName.length < 2) {
1467
		this.problemReporter.nullAnnotationNameMustBeQualified(typeName);
1468
		return;
1469
	}
1470
	char[][] packageName = CharOperation.subarray(typeName, 0, typeName.length-1);
1471
	PackageBinding packageBinding = createPackage(packageName);
1472
	char[] simpleTypeName = typeName[typeName.length-1];
1473
	if (typeId == TypeIds.T_ConfiguredAnnotationNullable)
1474
		packageBinding.nullableName = simpleTypeName;
1475
	else if (typeId == TypeIds.T_ConfiguredAnnotationNonNull)
1476
		packageBinding.nonNullName = simpleTypeName;
1477
	else if (typeId == TypeIds.T_ConfiguredAnnotationNonNullByDefault)
1478
		packageBinding.nonNullByDefaultName = simpleTypeName;
1479
}
1480
1481
1482
boolean isMissingType(char[] typeName) {
1494
boolean isMissingType(char[] typeName) {
1483
	for (int i = this.missingTypes == null ? 0 : this.missingTypes.size(); --i >= 0;) {
1495
	for (int i = this.missingTypes == null ? 0 : this.missingTypes.size(); --i >= 0;) {
1484
		MissingTypeBinding missingType = (MissingTypeBinding) this.missingTypes.get(i);
1496
		MissingTypeBinding missingType = (MissingTypeBinding) this.missingTypes.get(i);
Lines 1546-1553 public void reset() { Link Here
1546
	this.unitBeingCompleted = null; // in case AbortException occurred
1558
	this.unitBeingCompleted = null; // in case AbortException occurred
1547
1559
1548
	this.classFilePool.reset();
1560
	this.classFilePool.reset();
1549
	
1550
	this.nullAnnotationsInitialized = false;
1551
1561
1552
	// name environment has a longer life cycle, and must be reset in
1562
	// name environment has a longer life cycle, and must be reset in
1553
	// the code which created it.
1563
	// the code which created it.
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java (-2 / +19 lines)
Lines 24-32 public class PackageBinding extends Binding implements TypeConstants { Link Here
24
	HashtableOfType knownTypes;
24
	HashtableOfType knownTypes;
25
	HashtableOfPackage knownPackages;
25
	HashtableOfPackage knownPackages;
26
26
27
	// if this package contains configured null-annotations, store their simple names here:
27
	protected char[] nullableName = null;
28
	protected char[] nullableName = null;
28
	protected char[] nonNullName = null;
29
	protected char[] nonNullName = null;
29
	protected char[] nonNullByDefaultName = null;
30
	protected char[] nonNullByDefaultName = null;
31
	// annotation type binding representing the default that has been defined for this package (using @NonNullByDefault)
30
	protected TypeBinding nullnessDefaultAnnotation;
32
	protected TypeBinding nullnessDefaultAnnotation;
31
33
32
protected PackageBinding() {
34
protected PackageBinding() {
Lines 43-48 public PackageBinding(char[][] compoundName, PackageBinding parent, LookupEnviro Link Here
43
	this.environment = environment;
45
	this.environment = environment;
44
	this.knownTypes = null; // initialized if used... class counts can be very large 300-600
46
	this.knownTypes = null; // initialized if used... class counts can be very large 300-600
45
	this.knownPackages = new HashtableOfPackage(3); // sub-package counts are typically 0-3
47
	this.knownPackages = new HashtableOfPackage(3); // sub-package counts are typically 0-3
48
	if (compoundName != CharOperation.NO_CHAR_CHAR && environment.globalOptions.isAnnotationBasedNullAnalysisEnabled)
49
		initNullAnnotationPackage();
46
}
50
}
47
51
48
public PackageBinding(LookupEnvironment environment) {
52
public PackageBinding(LookupEnvironment environment) {
Lines 213-218 public Binding getTypeOrPackage(char[] name) { Link Here
213
217
214
	return null;
218
	return null;
215
}
219
}
220
221
private void initNullAnnotationPackage() {
222
	char[][] simpleAnnotNames = this.environment.getNullAnnotationNames(this.compoundName);
223
	if (simpleAnnotNames == null)
224
		return;
225
	if (simpleAnnotNames[0] != null)
226
		this.nullableName = simpleAnnotNames[0];
227
	if (simpleAnnotNames[1] != null)
228
		this.nonNullName = simpleAnnotNames[1];
229
	if (simpleAnnotNames[2] != null)
230
		this.nonNullByDefaultName = simpleAnnotNames[2];
231
}
232
216
public final boolean isViewedAsDeprecated() {
233
public final boolean isViewedAsDeprecated() {
217
	if ((this.tagBits & TagBits.DeprecatedAnnotationResolved) == 0) {
234
	if ((this.tagBits & TagBits.DeprecatedAnnotationResolved) == 0) {
218
		this.tagBits |= TagBits.DeprecatedAnnotationResolved;
235
		this.tagBits |= TagBits.DeprecatedAnnotationResolved;
Lines 253-261 void setupNullAnnotationType(ReferenceBinding type) { Link Here
253
	type.id = id;	// ensure annotations of this type are detected as standard annotations.
270
	type.id = id;	// ensure annotations of this type are detected as standard annotations.
254
}
271
}
255
272
256
public TypeBinding getNullnessDefaultAnnotation() {
273
public TypeBinding getNullnessDefaultAnnotation(Scope scope) {
257
	if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding)
274
	if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding)
258
		return this.nullnessDefaultAnnotation = BinaryTypeBinding.resolveType(this.nullnessDefaultAnnotation, this.environment, false);
275
		return this.nullnessDefaultAnnotation = this.environment.getNullAnnotationResolved(this.nullnessDefaultAnnotation, scope);
259
	return this.nullnessDefaultAnnotation;
276
	return this.nullnessDefaultAnnotation;
260
}
277
}
261
278
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java (-5 / +3 lines)
Lines 1640-1647 private void evaluateNullAnnotations(long annotationTagBits) { Link Here
1640
}
1640
}
1641
private TypeBinding getNullnessDefaultAnnotation() {
1641
private TypeBinding getNullnessDefaultAnnotation() {
1642
	if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding)
1642
	if (this.nullnessDefaultAnnotation instanceof UnresolvedReferenceBinding)
1643
		return this.nullnessDefaultAnnotation =
1643
		this.nullnessDefaultAnnotation = this.scope.environment().getNullAnnotationResolved(this.nullnessDefaultAnnotation, this.scope);
1644
				BinaryTypeBinding.resolveType(this.nullnessDefaultAnnotation, getPackage().environment, false);
1645
	return this.nullnessDefaultAnnotation;
1644
	return this.nullnessDefaultAnnotation;
1646
}
1645
}
1647
/**
1646
/**
Lines 1671-1683 private TypeBinding findDefaultNullness(MethodBinding methodBinding, LookupEnvir Link Here
1671
	}
1670
	}
1672
	
1671
	
1673
	// package
1672
	// package
1674
	annotationBinding = type.getPackage().getNullnessDefaultAnnotation();
1673
	annotationBinding = type.getPackage().getNullnessDefaultAnnotation(this.scope);
1675
	if (annotationBinding != null)
1674
	if (annotationBinding != null)
1676
		return annotationBinding;
1675
		return annotationBinding;
1677
	
1676
	
1678
	// global
1677
	// global
1679
	long defaultNullness = environment.globalOptions.defaultNonNullness;
1678
	long defaultNullness = environment.globalOptions.defaultNonNullness;
1680
	if (defaultNullness != 0) {
1679
	if (defaultNullness != 0) {
1680
		// we have a default, so we need an annotation type to record this during compile and in the byte code
1681
		annotationBinding = environment.getNullAnnotationBinding(defaultNullness, true/*resolve*/);
1681
		annotationBinding = environment.getNullAnnotationBinding(defaultNullness, true/*resolve*/);
1682
		if (annotationBinding != null)
1682
		if (annotationBinding != null)
1683
			return annotationBinding;
1683
			return annotationBinding;
Lines 1685-1692 private TypeBinding findDefaultNullness(MethodBinding methodBinding, LookupEnvir Link Here
1685
		// on this branch default was not defined using an annotation, thus annotation type can still be missing
1685
		// on this branch default was not defined using an annotation, thus annotation type can still be missing
1686
		if (defaultNullness == TagBits.AnnotationNonNull)
1686
		if (defaultNullness == TagBits.AnnotationNonNull)
1687
			this.scope.problemReporter().missingNullAnnotationType(environment.getNonNullAnnotationName());
1687
			this.scope.problemReporter().missingNullAnnotationType(environment.getNonNullAnnotationName());
1688
		else if (defaultNullness == TagBits.AnnotationNullable)
1689
			this.scope.problemReporter().missingNullAnnotationType(environment.getNullableAnnotationName());
1690
		else
1688
		else
1691
			this.scope.problemReporter().abortDueToInternalError("Illegal default nullness value: "+defaultNullness); //$NON-NLS-1$
1689
			this.scope.problemReporter().abortDueToInternalError("Illegal default nullness value: "+defaultNullness); //$NON-NLS-1$
1692
		// reset default to avoid duplicate errors:
1690
		// reset default to avoid duplicate errors:
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java (-1 / +2 lines)
Lines 8191-8197 public void cannotImplementIncompatibleNullness(MethodBinding currentMethod, Met Link Here
8191
			sourceEnd);
8191
			sourceEnd);
8192
}
8192
}
8193
8193
8194
public void nullAnnotationNameMustBeQualified(char[][] typeName) {
8194
public void nullAnnotationNameMustBeQualified(char[][] typeName, CompilationUnitDeclaration unitBeingCompleted) {
8195
	this.referenceContext = unitBeingCompleted;
8195
	String[] name = {new String(typeName[0])};
8196
	String[] name = {new String(typeName[0])};
8196
	this.handle(IProblem.NullAnnotationNameMustBeQualified, name, name, 0, 0);
8197
	this.handle(IProblem.NullAnnotationNameMustBeQualified, name, name, 0, 0);
8197
}
8198
}
(-)a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java (-5 / +12 lines)
Lines 99-104 class CompilationUnitResolver extends Compiler { Link Here
99
	DefaultBindingResolver.BindingTables bindingTables;
99
	DefaultBindingResolver.BindingTables bindingTables;
100
100
101
	boolean hasCompilationAborted;
101
	boolean hasCompilationAborted;
102
	CategorizedProblem abortProblem;
102
103
103
	private IProgressMonitor monitor;
104
	private IProgressMonitor monitor;
104
	
105
	
Lines 364-369 class CompilationUnitResolver extends Compiler { Link Here
364
			removeUnresolvedBindings(unit);
365
			removeUnresolvedBindings(unit);
365
		}
366
		}
366
		this.hasCompilationAborted = true;
367
		this.hasCompilationAborted = true;
368
		this.abortProblem = abortException.problem;
367
	}
369
	}
368
370
369
	public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) {
371
	public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) {
Lines 689-699 class CompilationUnitResolver extends Compiler { Link Here
689
				// the bindings could not be resolved due to missing types in name environment
691
				// the bindings could not be resolved due to missing types in name environment
690
				// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541
692
				// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541
691
				CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags);
693
				CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags);
692
				final int problemCount = unit.compilationResult.problemCount;
694
				if (unit != null) {
693
				if (problemCount != 0) {
695
					final int problemCount = unit.compilationResult.problemCount;
694
					unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount];
696
					if (problemCount != 0) {
695
					System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount);
697
						unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount];
696
					unitDeclaration.compilationResult.problemCount = problemCount;
698
						System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount);
699
						unitDeclaration.compilationResult.problemCount = problemCount;
700
					}
701
				} else if (resolver.abortProblem != null) {
702
					unitDeclaration.compilationResult.problemCount = 1;
703
					unitDeclaration.compilationResult.problems = new CategorizedProblem[] { resolver.abortProblem };
697
				}
704
				}
698
				return unitDeclaration;
705
				return unitDeclaration;
699
			}
706
			}
(-)a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ReconcileWorkingCopyOperation.java (-1 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 132-137 public class ReconcileWorkingCopyOperation extends JavaModelOperation { Link Here
132
				if (categorizedProblems == null) continue;
132
				if (categorizedProblems == null) continue;
133
				for (int i = 0, length = categorizedProblems.length; i < length; i++) {
133
				for (int i = 0, length = categorizedProblems.length; i < length; i++) {
134
					CategorizedProblem problem = categorizedProblems[i];
134
					CategorizedProblem problem = categorizedProblems[i];
135
					if (problem.getCategoryID() == CategorizedProblem.CAT_BUILDPATH)
136
						continue;	// don't report these problems against any CU, are already reported against the project
135
					if (JavaModelManager.VERBOSE){
137
					if (JavaModelManager.VERBOSE){
136
						System.out.println("PROBLEM FOUND while reconciling : " + problem.getMessage());//$NON-NLS-1$
138
						System.out.println("PROBLEM FOUND while reconciling : " + problem.getMessage());//$NON-NLS-1$
137
					}
139
					}
(-)a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java (-1 / +4 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 700-705 protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] prob Link Here
700
			);
700
			);
701
			// even if we're not keeping more markers, still fall through rest of the problem reporting, so that offending
701
			// even if we're not keeping more markers, still fall through rest of the problem reporting, so that offending
702
			// IsClassPathCorrect problem gets recorded since it may help locate the offending reference
702
			// IsClassPathCorrect problem gets recorded since it may help locate the offending reference
703
		} else if (problem.getCategoryID() == CategorizedProblem.CAT_BUILDPATH) {
704
			// also report other build-path problems against the project, but using a normal problem marker
705
			resource = this.javaBuilder.currentProject;
703
		}
706
		}
704
707
705
		String markerType = problem.getMarkerType();
708
		String markerType = problem.getMarkerType();

Return to bug 363858