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

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java (+6 lines)
Lines 161-166 Link Here
161
			case TypeIds.T_JavaLangSuppressWarnings :
161
			case TypeIds.T_JavaLangSuppressWarnings :
162
				tagBits |= TagBits.AnnotationSuppressWarnings;
162
				tagBits |= TagBits.AnnotationSuppressWarnings;
163
				break;
163
				break;
164
			case TypeIds.T_ConfiguredAnnotationNullable :
165
				tagBits |= TagBits.AnnotationNullable;
166
				break;
167
			case TypeIds.T_ConfiguredAnnotationNonNull :
168
				tagBits |= TagBits.AnnotationNonNull;
169
				break;
164
		}
170
		}
165
		return tagBits;
171
		return tagBits;
166
	}
172
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java (+5 lines)
Lines 78-83 Link Here
78
			if (this.arguments != null) {
78
			if (this.arguments != null) {
79
				for (int i = 0, count = this.arguments.length; i < count; i++) {
79
				for (int i = 0, count = this.arguments.length; i < count; i++) {
80
					flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding);
80
					flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding);
81
					long argumentTagBits = this.arguments[i].binding.tagBits;
82
					if ((argumentTagBits & TagBits.AnnotationNullable) != 0)
83
						flowInfo.markPotentiallyNullBit(this.arguments[i].binding);
84
					else if ((argumentTagBits & TagBits.AnnotationNonNull) != 0)
85
						flowInfo.markAsDefinitelyNonNull(this.arguments[i].binding);
81
				}
86
				}
82
			}
87
			}
83
			// propagate to statements
88
			// propagate to statements
(-)compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java (+55 lines)
Lines 138-143 Link Here
138
	public static final String OPTION_ReportMissingAnnotation = "org.eclipse.jdt.core.compiler.problem.missingAnnotation"; //$NON-NLS-1$
138
	public static final String OPTION_ReportMissingAnnotation = "org.eclipse.jdt.core.compiler.problem.missingAnnotation"; //$NON-NLS-1$
139
	public static final String OPTION_ReportMissingJavadoc = "org.eclipse.jdt.core.compiler.problem.missingJavadoc"; //$NON-NLS-1$
139
	public static final String OPTION_ReportMissingJavadoc = "org.eclipse.jdt.core.compiler.problem.missingJavadoc"; //$NON-NLS-1$
140
140
141
	public static final String OPTION_NullableAnnotationNames = "org.eclipse.jdt.core.compiler.annotation.nullable"; //$NON-NLS-1$
142
	public static final String OPTION_NonNullAnnotationNames = "org.eclipse.jdt.core.compiler.annotation.nonnull"; //$NON-NLS-1$
143
	public static final String OPTION_EmulateNullAnnotationTypes = "org.eclipse.jdt.core.compiler.annotation.emulate"; //$NON-NLS-1$
144
	public static final String OPTION_DefaultImportNullAnnotationTypes = "org.eclipse.jdt.core.compiler.annotation.defaultImport"; //$NON-NLS-1$
145
141
	/**
146
	/**
142
	 * Possible values for configurable options
147
	 * Possible values for configurable options
143
	 */
148
	 */
Lines 357-362 Link Here
357
	public boolean ignoreMethodBodies;
362
	public boolean ignoreMethodBodies;
358
	/** Raise null related warnings for variables tainted inside an assert statement (java 1.4 and above)*/
363
	/** Raise null related warnings for variables tainted inside an assert statement (java 1.4 and above)*/
359
	public boolean includeNullInfoFromAsserts;
364
	public boolean includeNullInfoFromAsserts;
365
	/** List of fully qualified annotation names to use as marker for nullable types. */
366
	public char[][][] nullableAnnotationNames;
367
	/** List of fully qualified annotation names to use as marker for nonnull types. */
368
	public char[][][] nonNullAnnotationNames;
369
	/** Should null annotation types be emulated by synthetic bindings? */
370
	public boolean emulateNullAnnotationTypes;
371
	/** Should null annotation types be imported by default? */
372
	public boolean defaultImportNullAnnotationTypes;
360
373
361
	// keep in sync with warningTokenToIrritant and warningTokenFromIrritant
374
	// keep in sync with warningTokenToIrritant and warningTokenFromIrritant
362
	public final static String[] warningTokens = {
375
	public final static String[] warningTokens = {
Lines 921-926 Link Here
921
		optionsMap.put(OPTION_ReportTasks, getSeverityString(Tasks));
934
		optionsMap.put(OPTION_ReportTasks, getSeverityString(Tasks));
922
		optionsMap.put(OPTION_ReportUnusedObjectAllocation, getSeverityString(UnusedObjectAllocation));
935
		optionsMap.put(OPTION_ReportUnusedObjectAllocation, getSeverityString(UnusedObjectAllocation));
923
		optionsMap.put(OPTION_IncludeNullInfoFromAsserts, this.includeNullInfoFromAsserts ? ENABLED : DISABLED);
936
		optionsMap.put(OPTION_IncludeNullInfoFromAsserts, this.includeNullInfoFromAsserts ? ENABLED : DISABLED);
937
		if (this.nullableAnnotationNames != null) {
938
			char[][] compoundNames = new char[this.nullableAnnotationNames.length][];
939
			for (int i = 0; i < this.nullableAnnotationNames.length; i++)
940
				compoundNames[i] = CharOperation.concatWith(this.nullableAnnotationNames[i], '.');
941
			char[] allNames = CharOperation.concatWith(compoundNames, ',');
942
			optionsMap.put(OPTION_NullableAnnotationNames, String.valueOf(allNames));
943
		}
944
		if (this.nonNullAnnotationNames != null) {
945
			char[][] compoundNames = new char[this.nonNullAnnotationNames.length][];
946
			for (int i = 0; i < this.nonNullAnnotationNames.length; i++)
947
				compoundNames[i] = CharOperation.concatWith(this.nonNullAnnotationNames[i], '.');
948
			char[] allNames = CharOperation.concatWith(compoundNames, ',');
949
			optionsMap.put(OPTION_NonNullAnnotationNames, String.valueOf(allNames));
950
		}
951
		optionsMap.put(OPTION_EmulateNullAnnotationTypes, this.emulateNullAnnotationTypes ? ENABLED : DISABLED);
952
		optionsMap.put(OPTION_DefaultImportNullAnnotationTypes, this.defaultImportNullAnnotationTypes ? ENABLED : DISABLED);
924
		return optionsMap;
953
		return optionsMap;
925
	}
954
	}
926
955
Lines 1452-1457 Link Here
1452
				this.storeAnnotations = false;
1481
				this.storeAnnotations = false;
1453
			}
1482
			}
1454
		}
1483
		}
1484
		if ((optionValue = optionsMap.get(OPTION_NullableAnnotationNames)) != null) {
1485
			String[] allNames = ((String)optionValue).split(","); //$NON-NLS-1$
1486
			this.nullableAnnotationNames = new char[allNames.length][][];
1487
			for (int i = 0; i < allNames.length; i++)				
1488
				this.nullableAnnotationNames[i] = CharOperation.splitAndTrimOn('.', allNames[i].toCharArray());
1489
		}
1490
		if ((optionValue = optionsMap.get(OPTION_NonNullAnnotationNames)) != null) {
1491
			String[] allNames = ((String)optionValue).split(","); //$NON-NLS-1$
1492
			this.nonNullAnnotationNames = new char[allNames.length][][];
1493
			for (int i = 0; i < allNames.length; i++)				
1494
				this.nonNullAnnotationNames[i] = CharOperation.splitAndTrimOn('.', allNames[i].toCharArray());
1495
		}
1496
		if ((optionValue = optionsMap.get(OPTION_EmulateNullAnnotationTypes)) != null) {
1497
			if (ENABLED.equals(optionValue)) {
1498
				this.emulateNullAnnotationTypes = true;
1499
			} else if (DISABLED.equals(optionValue)) {
1500
				this.emulateNullAnnotationTypes = false;
1501
			}
1502
		}
1503
		if ((optionValue = optionsMap.get(OPTION_DefaultImportNullAnnotationTypes)) != null) {
1504
			if (ENABLED.equals(optionValue)) {
1505
				this.defaultImportNullAnnotationTypes = true;
1506
			} else if (DISABLED.equals(optionValue)) {
1507
				this.defaultImportNullAnnotationTypes = false;
1508
			}
1509
		}
1455
	}
1510
	}
1456
	public String toString() {
1511
	public String toString() {
1457
		StringBuffer buf = new StringBuffer("CompilerOptions:"); //$NON-NLS-1$
1512
		StringBuffer buf = new StringBuffer("CompilerOptions:"); //$NON-NLS-1$
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java (-2 / +20 lines)
Lines 303-308 Link Here
303
		return; // can be called when a field constant is resolved before static imports
303
		return; // can be called when a field constant is resolved before static imports
304
	if (this.referenceContext.imports == null) {
304
	if (this.referenceContext.imports == null) {
305
		this.typeOrPackageCache = new HashtableOfObject(1);
305
		this.typeOrPackageCache = new HashtableOfObject(1);
306
		for (int i = 0; i < this.imports.length; i++) {
307
			// cache default-imported null annotation types:
308
			if (!this.imports[i].onDemand) {
309
				char[][] importName = this.imports[i].compoundName;
310
				this.typeOrPackageCache.put(importName[importName.length-1], this.imports[i].resolvedImport);
311
			}
312
		}
306
		return;
313
		return;
307
	}
314
	}
308
315
Lines 612-619 Link Here
612
		BinaryTypeBinding missingObject = this.environment.createMissingType(null, TypeConstants.JAVA_LANG_OBJECT);
619
		BinaryTypeBinding missingObject = this.environment.createMissingType(null, TypeConstants.JAVA_LANG_OBJECT);
613
		importBinding = missingObject.fPackage;
620
		importBinding = missingObject.fPackage;
614
	}
621
	}
615
622
	ImportBinding javaLangImport = new ImportBinding(TypeConstants.JAVA_LANG, true, importBinding, null);
616
	return this.environment.defaultImports = new ImportBinding[] {new ImportBinding(TypeConstants.JAVA_LANG, true, importBinding, null)};
623
	ImportBinding[] nullAnnotationImports = this.environment.makeNullAnnotationTypeImports(); // trigger regardless of option below
624
	if (this.environment.globalOptions.defaultImportNullAnnotationTypes) {
625
		ImportBinding[] allDefaultImports = new ImportBinding[nullAnnotationImports.length+1];
626
		allDefaultImports[0] = javaLangImport;
627
		System.arraycopy(nullAnnotationImports, 0,
628
						 allDefaultImports, 1, 
629
						 nullAnnotationImports.length);
630
		this.environment.defaultImports = allDefaultImports;
631
	} else {
632
		this.environment.defaultImports = new ImportBinding[] {javaLangImport};
633
	}
634
	return this.environment.defaultImports;
617
}
635
}
618
// NOT Public API
636
// NOT Public API
619
public final Binding getImport(char[][] compoundName, boolean onDemand, boolean isStaticImport) {
637
public final Binding getImport(char[][] compoundName, boolean onDemand, boolean isStaticImport) {
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java (+47 lines)
Lines 1314-1319 Link Here
1314
		return this.nameEnvironment.isPackage(null, name);
1314
		return this.nameEnvironment.isPackage(null, name);
1315
	return this.nameEnvironment.isPackage(compoundName, name);
1315
	return this.nameEnvironment.isPackage(compoundName, name);
1316
}
1316
}
1317
1318
private ReferenceBinding makeNullAnnotationType(char[][] compoundName) {
1319
	if (!this.globalOptions.emulateNullAnnotationTypes)
1320
		return getType(compoundName);
1321
	BinaryTypeBinding emulatedType = new BinaryTypeBinding();
1322
	emulatedType.compoundName = compoundName;
1323
	emulatedType.modifiers = ClassFileConstants.AccAnnotation | ClassFileConstants.AccPublic;
1324
	emulatedType.fields = Binding.NO_FIELDS;
1325
	emulatedType.methods = Binding.NO_METHODS;
1326
	emulatedType.memberTypes = Binding.NO_MEMBER_TYPES;
1327
	emulatedType.superclass = getType(TypeConstants.JAVA_LANG_OBJECT);
1328
	emulatedType.superInterfaces = Binding.NO_SUPERINTERFACES;
1329
	emulatedType.fPackage = new PackageBinding(CharOperation.subarray(compoundName, 0, compoundName.length-2), null, this);
1330
	emulatedType.typeVariables = Binding.NO_TYPE_VARIABLES;
1331
	emulatedType.tagBits = TagBits.AreFieldsComplete | TagBits.AreFieldsSorted 
1332
							| TagBits.AreMethodsComplete | TagBits.AreMethodsSorted 
1333
							| TagBits.HasNoMemberTypes | TagBits.TypeVariablesAreConnected
1334
							| TagBits.AnnotationClassRetention 
1335
							| TagBits.AnnotationForMethod | TagBits.AnnotationForParameter ;
1336
1337
	// TODO(SH): make emulated type visible via knownPackages, too
1338
	return emulatedType;
1339
}
1340
1341
protected ImportBinding[] makeNullAnnotationTypeImports() {
1342
	char[][][] nullableAnnotationNames = this.globalOptions.nullableAnnotationNames;
1343
	char[][][] nonNullAnnotationNames = this.globalOptions.nonNullAnnotationNames;
1344
	if (nullableAnnotationNames == null || nonNullAnnotationNames == null) {
1345
		// TODO(SH): check and report inconsistency with other options
1346
		return new ImportBinding[0];
1347
	}
1348
	int totalImports = nullableAnnotationNames.length + nonNullAnnotationNames.length;
1349
	ImportBinding[] emulatedNullAnnotationImports = new ImportBinding[totalImports];
1350
	for (int i = 0; i < nullableAnnotationNames.length; i++) {
1351
		ReferenceBinding annotationType = makeNullAnnotationType(nullableAnnotationNames[i]);
1352
		annotationType.id = TypeIds.T_ConfiguredAnnotationNullable;
1353
		emulatedNullAnnotationImports[i] = new ImportBinding(nullableAnnotationNames[i], false, annotationType, null);
1354
	}
1355
	int offset = nullableAnnotationNames.length;
1356
	for (int i = 0; i < nonNullAnnotationNames.length; i++) {
1357
		ReferenceBinding annotationType = makeNullAnnotationType(nonNullAnnotationNames[i]);
1358
		annotationType.id = TypeIds.T_ConfiguredAnnotationNonNull;
1359
		emulatedNullAnnotationImports[i+offset] = new ImportBinding(nonNullAnnotationNames[i], false, annotationType, null);
1360
	}
1361
	return emulatedNullAnnotationImports;
1362
}
1363
1317
// The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready.
1364
// The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready.
1318
public MethodVerifier methodVerifier() {
1365
public MethodVerifier methodVerifier() {
1319
	if (this.verifier == null)
1366
	if (this.verifier == null)
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java (-3 / +6 lines)
Lines 116-125 Link Here
116
	long AnnotationInherited = ASTNode.Bit49L;
116
	long AnnotationInherited = ASTNode.Bit49L;
117
	long AnnotationOverride = ASTNode.Bit50L;
117
	long AnnotationOverride = ASTNode.Bit50L;
118
	long AnnotationSuppressWarnings = ASTNode.Bit51L;
118
	long AnnotationSuppressWarnings = ASTNode.Bit51L;
119
	long AllStandardAnnotationsMask = AnnotationTargetMASK | AnnotationRetentionMASK | AnnotationDeprecated | AnnotationDocumented | AnnotationInherited |  AnnotationOverride | AnnotationSuppressWarnings;
119
	long AnnotationNullable = ASTNode.Bit52L;
120
	long AnnotationNonNull = ASTNode.Bit53L;
121
	long AllStandardAnnotationsMask = AnnotationTargetMASK | AnnotationRetentionMASK | AnnotationDeprecated | AnnotationDocumented 
122
				| AnnotationInherited |  AnnotationOverride | AnnotationSuppressWarnings | AnnotationNullable | AnnotationNonNull;
120
123
121
	long DefaultValueResolved = ASTNode.Bit52L;
124
	long DefaultValueResolved = ASTNode.Bit54L;
122
125
123
	// set when type contains non-private constructor(s)
126
	// set when type contains non-private constructor(s)
124
	long HasNonPrivateConstructor = ASTNode.Bit53L;
127
	long HasNonPrivateConstructor = ASTNode.Bit55L;
125
}
128
}
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java (+3 lines)
Lines 89-94 Link Here
89
	
89
	
90
	final int T_JavaUtilCollection = 59;
90
	final int T_JavaUtilCollection = 59;
91
91
92
	final int T_ConfiguredAnnotationNullable = 60;
93
	final int T_ConfiguredAnnotationNonNull = 61;
94
92
	final int NoId = Integer.MAX_VALUE;
95
	final int NoId = Integer.MAX_VALUE;
93
96
94
	public static final int IMPLICIT_CONVERSION_MASK = 0xFF;
97
	public static final int IMPLICIT_CONVERSION_MASK = 0xFF;
(-)src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java (+114 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation 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 <stephan@cs.tu-berlin.de> - 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 does not belong to the class are skipped...
27
// Only the highest compliance level is run; add the VM argument
28
// -Dcompliance=1.4 (for example) to lower it if needed
29
static {
30
//		TESTS_NAMES = new String[] { "testBug325229" };
31
//		TESTS_NUMBERS = new int[] { 561 };
32
//		TESTS_RANGE = new int[] { 1, 2049 };
33
}
34
35
public static Test suite() {
36
	return buildComparableTestSuite(testClass());
37
}
38
39
public static Class testClass() {
40
	return NullAnnotationTest.class;
41
}
42
43
// Conditionally augment problem detection settings
44
static boolean setNullRelatedOptions = true;
45
protected Map getCompilerOptions() {
46
    Map defaultOptions = super.getCompilerOptions();
47
    if (setNullRelatedOptions) {
48
	    defaultOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR);
49
	    defaultOptions.put(CompilerOptions.OPTION_ReportPotentialNullReference, CompilerOptions.ERROR);
50
	    defaultOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR);
51
		defaultOptions.put(CompilerOptions.OPTION_ReportRawTypeReference, CompilerOptions.IGNORE);
52
		defaultOptions.put(CompilerOptions.OPTION_IncludeNullInfoFromAsserts, CompilerOptions.ENABLED);
53
		
54
		defaultOptions.put(CompilerOptions.OPTION_NullableAnnotationNames, "org.eclipse.jdt.annotation.Nullable");
55
		defaultOptions.put(CompilerOptions.OPTION_NonNullAnnotationNames, "org.eclipse.jdt.annotation.NonNull");
56
		defaultOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.ENABLED);
57
		defaultOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED);
58
    }
59
    return defaultOptions;
60
}
61
62
// 
63
public void test0001_nonnull_parameter() {
64
	runNegativeTest(
65
		new String[] {
66
			"X.java",
67
			  "public class X {\n" +
68
			  "    void foo(@NonNull Object o) {\n" +
69
			  "        if (o != null)\n" +
70
			  "              System.out.print(o.toString());\n" +
71
			  "    }\n" +
72
			  "}\n"},
73
	    "----------\n" + 
74
		"1. ERROR in X.java (at line 3)\n" + 
75
		"	if (o != null)\n" + 
76
		"	    ^\n" + 
77
		"Redundant null check: The variable o cannot be null at this location\n" + 
78
		"----------\n",
79
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
80
}
81
//
82
public void test0002_nonnull_parameter() {
83
	runConformTest(
84
		new String[] {
85
			"X.java",
86
			  "public class X {\n" +
87
			  "    void foo(@NonNull Object o) {\n" +
88
			  "        System.out.print(o.toString());\n" +
89
			  "    }\n" +
90
			  "    public static void main(String... args) {\n" +
91
			  "        new X().foo(\"OK\");\n" +
92
			  "    }\n" +
93
			  "}\n"},
94
	    "OK");
95
}
96
//
97
public void test0003_nullable_paramter() {
98
	runNegativeTest(
99
		new String[] {
100
			"X.java",
101
			  "public class X {\n" +
102
			  "    void foo(@Nullable Object o) {\n" +
103
			  "        System.out.print(o.toString());\n" +
104
			  "    }\n" +
105
			  "}\n"},
106
	    "----------\n" + 
107
		"1. ERROR in X.java (at line 3)\n" + 
108
		"	System.out.print(o.toString());\n" + 
109
		"	                 ^\n" + 
110
		"Potential null pointer access: The variable o may be null at this location\n" + 
111
		"----------\n",
112
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
113
}
114
}

Return to bug 186342