Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 186796 Details for
Bug 186342
[compiler][null] Using annotations for null checking
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
tests & implementation v3
Bug_186342_v3.patch (text/plain), 135.06 KB, created by
Stephan Herrmann
on 2011-01-13 18:23:02 EST
(
hide
)
Description:
tests & implementation v3
Filename:
MIME Type:
Creator:
Stephan Herrmann
Created:
2011-01-13 18:23:02 EST
Size:
135.06 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.jdt.core >Index: batch/org/eclipse/jdt/internal/compiler/batch/Main.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java,v >retrieving revision 1.358 >diff -u -r1.358 Main.java >--- batch/org/eclipse/jdt/internal/compiler/batch/Main.java 17 Dec 2010 09:38:57 -0000 1.358 >+++ batch/org/eclipse/jdt/internal/compiler/batch/Main.java 13 Jan 2011 22:58:18 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -10,8 +10,10 @@ > * Tom Tromey - Contribution for bug 125961 > * Tom Tromey - Contribution for bug 159641 > * Benjamin Muskalla - Contribution for bug 239066 >- * Stephan Herrmann - Contribution for bug 236385 >- * Stephan Herrmann - Contribution for bug 295551 >+ * Stephan Herrmann - Contributions for >+ * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used >+ * bug 295551 - Add option to automatically promote all warnings to errors >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.batch; > >@@ -2388,6 +2390,27 @@ > mode = INSIDE_WARNINGS_PROPERTIES; > continue; > } >+ if (currentArg.startsWith("-nullAnnotations:")) { //$NON-NLS-1$ >+ StringTokenizer tokenizer = >+ new StringTokenizer(currentArg.substring("-nullAnnotations:".length()), ","); //$NON-NLS-1$ //$NON-NLS-2$ >+ while (tokenizer.hasMoreTokens()) { >+ String token = tokenizer.nextToken(); >+ if (token.startsWith("nullable=")) { //$NON-NLS-1$ >+ this.options.put(CompilerOptions.OPTION_NullableAnnotationName, token.substring("nullable=".length())); //$NON-NLS-1$ >+ } else if (token.startsWith("nonnull=")) { //$NON-NLS-1$ >+ this.options.put(CompilerOptions.OPTION_NonNullAnnotationName, token.substring("nonnull=".length())); //$NON-NLS-1$ >+ } else if (token.equals("emulate")) { //$NON-NLS-1$ >+ this.options.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.ENABLED); >+ } else if (token.equals("import")) { //$NON-NLS-1$ >+ this.options.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ } else { >+ throw new IllegalArgumentException( >+ this.bind("configure.unrecognized.nullannotation.option", token)); //$NON-NLS-1$ >+ } >+ } >+ mode = DEFAULT; >+ continue; >+ } > break; > case INSIDE_TARGET : > if (this.didSpecifyTarget) { >Index: batch/org/eclipse/jdt/internal/compiler/batch/messages.properties >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties,v >retrieving revision 1.949 >diff -u -r1.949 messages.properties >--- batch/org/eclipse/jdt/internal/compiler/batch/messages.properties 5 Jan 2011 15:04:04 -0000 1.949 >+++ batch/org/eclipse/jdt/internal/compiler/batch/messages.properties 13 Jan 2011 22:58:20 -0000 >@@ -1,5 +1,5 @@ > ############################################################################### >-# Copyright (c) 2000, 2010 IBM Corporation and others. >+# Copyright (c) 2000, 2011 IBM Corporation and others. > # All rights reserved. This program and the accompanying materials > # are made available under the terms of the Eclipse Public License v1.0 > # which accompanies this distribution, and is available at >@@ -8,6 +8,7 @@ > # Contributors: > # IBM Corporation - initial API and implementation > # Benjamin Muskalla - Contribution for bug 239066 >+# Stephan Herrmann - Contribution for bug 186342 - [compiler][null]Using annotations for null checking > ############################################################################### > ### JavaBatchCompiler messages. > >@@ -71,6 +72,7 @@ > > ## configure.directoryNotExist = directory does not exist: {0} > configure.unrecognizedOption = Unrecognized option : {0} >+configure.unrecognized.nullannotation.option = Unrecognized sub-option of -nullAnnotations: {0},\nlegal values are 'nullable=..', 'nonnull=..', 'emulate' and 'import' > configure.noClasspath = no classpath defined, using default directory instead > configure.incorrectClasspath = incorrect classpath: {0} > configure.invalidexpansionargumentname = expansion argument file {0} does not exist or cannot be read >@@ -222,6 +224,22 @@ > \ -classNames <className1[,className2,...]>\n\ > \ qualified names of binary classes to process\n\ > \ \n\ >+\ Null annotation options:\n\ >+\ -nullAnnotations:<suboptions>\n\ >+\ enable use of annotations for specifying null contracts;\n\ >+\ <suboptions> is a non-empty, comma-separated list of:\n\ >+\ nullable=<typename>\n\ >+\ specifies the fully qualified name of an annotation type\n\ >+\ to be used for marking types whose values include null\n\ >+\ nonnull=<typename>\n\ >+\ specifies the fully qualified name of an annotation type\n\ >+\ to be used for marking types whose values cannot be null\n\ >+\ emulate tells the compiler to emulate the above annotation types\n\ >+\ although they do not exist on the classpath\n\ >+\ import tells the compiler to import the above annotation types\n\ >+\ without specific mention in the sources such that their\n\ >+\ simple names can be used without explicit imports\n\ >+\ \n\ > \ Advanced options:\n\ > \ @<file> read command line arguments from file\n\ > \ -maxProblems <n> max number of problems per compilation unit (100 by\n\ >Index: compiler/org/eclipse/jdt/core/compiler/IProblem.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java,v >retrieving revision 1.223 >diff -u -r1.223 IProblem.java >--- compiler/org/eclipse/jdt/core/compiler/IProblem.java 17 Dec 2010 09:38:57 -0000 1.223 >+++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 13 Jan 2011 22:58:22 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -116,7 +116,16 @@ > * Benjamin Muskalla - added the following constants > * MissingSynchronizedModifierInInheritedMethod > * Stephan Herrmann - added the following constants >- * UnusedObjectAllocation >+ * UnusedObjectAllocation >+ * DefiniteNullFromNonNullMethod >+ * PotentialNullFromNonNullMethod >+ * NonNullReturnInsufficientInfo >+ * DefiniteNullToNonnullParameter >+ * PotentialNullToNonnullParameter >+ * NonNullParameterInsufficientInfo >+ * ConflictingTypeEmulation >+ * IllegalRedefinitionToNullableReturn >+ * IllegalRedefinitionToNonNullParameter > *******************************************************************************/ > package org.eclipse.jdt.core.compiler; > >@@ -1340,6 +1349,32 @@ > int JavadocTypeArgumentsForRawGenericConstructor = Javadoc + Internal + 859; > > /** >+ * Null Annotations >+ */ >+ /** @since 3.7 */ >+ int DefiniteNullFromNonNullMethod = MethodRelated + 880; >+ /** @since 3.7 */ >+ int PotentialNullFromNonNullMethod = MethodRelated + 881; >+ /** @since 3.7 */ >+ int NonNullReturnInsufficientInfo = MethodRelated + 882; >+ /** @since 3.7 */ >+ int DefiniteNullToNonnullParameter = MethodRelated + 883; >+ /** @since 3.7 */ >+ int PotentialNullToNonnullParameter = MethodRelated + 884; >+ /** @since 3.7 */ >+ int NonNullParameterInsufficientInfo = MethodRelated + 885; >+ /** @since 3.7 */ >+ int ConflictingTypeEmulation = ImportRelated + 886; >+ /** @since 3.7 */ >+ int MissingNullAnnotationType = ImportRelated + 887; >+ /** @since 3.7 */ >+ int IllegalRedefinitionToNullableReturn = MethodRelated + 888; >+ /** @since 3.7 */ >+ int IllegalRedefinitionToNonNullParameter = MethodRelated + 889; >+ /** @since 3.7 */ >+ int IllegalDefinitionToNonNullParameter = MethodRelated + 890; >+ >+ /** > * External problems -- These are problems defined by other plugins > */ > >Index: compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java,v >retrieving revision 1.110 >diff -u -r1.110 AbstractMethodDeclaration.java >--- compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java 9 Nov 2010 19:59:19 -0000 1.110 >+++ compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java 13 Jan 2011 22:58:22 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -100,6 +101,12 @@ > } else if (paramAnnotations != null) { > paramAnnotations[i] = Binding.NO_ANNOTATIONS; > } >+ // transfer nullness info from the argument to the method: >+ if ((argument.binding.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) != 0) { >+ if (this.binding.parameterNonNullness == null) >+ this.binding.parameterNonNullness = new Boolean[this.arguments.length]; >+ this.binding.parameterNonNullness[i] = Boolean.valueOf((argument.binding.tagBits & TagBits.AnnotationNonNull) != 0); >+ } > } > if (paramAnnotations != null) > this.binding.setParameterAnnotations(paramAnnotations); >@@ -415,7 +422,6 @@ > } > > try { >- bindArguments(); > bindThrownExceptions(); > resolveJavadoc(); > resolveAnnotations(this.scope, this.annotations, this.binding); >Index: compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java,v >retrieving revision 1.67 >diff -u -r1.67 Annotation.java >--- compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java 20 Jul 2010 20:23:19 -0000 1.67 >+++ compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java 13 Jan 2011 22:58:24 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -161,6 +162,12 @@ > case TypeIds.T_JavaLangSuppressWarnings : > tagBits |= TagBits.AnnotationSuppressWarnings; > break; >+ case TypeIds.T_ConfiguredAnnotationNullable : >+ tagBits |= TagBits.AnnotationNullable; >+ break; >+ case TypeIds.T_ConfiguredAnnotationNonNull : >+ tagBits |= TagBits.AnnotationNonNull; >+ break; > } > return tagBits; > } >Index: compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java,v >retrieving revision 1.149 >diff -u -r1.149 MessageSend.java >--- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 17 Dec 2010 09:38:55 -0000 1.149 >+++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 13 Jan 2011 22:58:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -8,7 +8,9 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) >- * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE >+ * Stephan Herrmann - Contributions for >+ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -80,6 +82,15 @@ > this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); > } > flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); >+ // compare actual null-status against parameter annotations of the called method: >+ int nullStatus = this.arguments[i].nullStatus(flowInfo); >+ if (nullStatus != FlowInfo.NON_NULL >+ && this.binding.parameterNonNullness != null >+ && this.binding.parameterNonNullness[i].booleanValue()) // if @NonNull is required >+ { >+ char[][] annotationName = currentScope.environment().globalOptions.nonNullAnnotationName; >+ currentScope.problemReporter().possiblyNullToNonNullParameter(this.arguments[i], nullStatus, annotationName[annotationName.length-1]); >+ } > } > } > ReferenceBinding[] thrownExceptions; >@@ -250,6 +261,14 @@ > } > } > public int nullStatus(FlowInfo flowInfo) { >+ if (this.binding.isValidBinding()) { >+ // try to retrieve null status of this message send from an annotation of the called method: >+ long tagBits = this.binding.tagBits; >+ if ((tagBits & TagBits.AnnotationNonNull) != 0) >+ return FlowInfo.NON_NULL; >+ if ((tagBits & TagBits.AnnotationNullable) != 0) >+ return FlowInfo.POTENTIALLY_NULL; >+ } > return FlowInfo.UNKNOWN; > } > >Index: compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java,v >retrieving revision 1.77 >diff -u -r1.77 MethodDeclaration.java >--- compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 17 Dec 2010 09:38:53 -0000 1.77 >+++ compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 13 Jan 2011 22:58:25 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -89,6 +90,12 @@ > if (this.binding != null && this.binding.declaringClass == declaringElement) > this.bits &= ~ASTNode.CanBeStatic; > } >+ // leverage null-info from parameter annotations: >+ long argumentTagBits = this.arguments[i].binding.tagBits; >+ if ((argumentTagBits & TagBits.AnnotationNullable) != 0) >+ flowInfo.markPotentiallyNullBit(this.arguments[i].binding); >+ else if ((argumentTagBits & TagBits.AnnotationNonNull) != 0) >+ flowInfo.markAsDefinitelyNonNull(this.arguments[i].binding); > } > } > if (this.binding.declaringClass instanceof MemberTypeBinding && !this.binding.declaringClass.isStatic()) { >Index: compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java,v >retrieving revision 1.68 >diff -u -r1.68 ReturnStatement.java >--- compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 12 Aug 2010 16:58:28 -0000 1.68 >+++ compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 13 Jan 2011 22:58:26 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,7 +7,9 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE >+ * Stephan Herrmann - Contributions for >+ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -40,6 +42,18 @@ > if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { > this.expression.checkNPE(currentScope, flowContext, flowInfo); > } >+ if (this.expression.nullStatus(flowInfo) != FlowInfo.NON_NULL) { >+ // if we can't prove non-null check against declared null-ness of the enclosing method: >+ AbstractMethodDeclaration referenceMethod = currentScope.methodScope().referenceMethod(); >+ if (referenceMethod != null) { >+ MethodBinding method = referenceMethod.binding; >+ if ((method.tagBits & TagBits.AnnotationNonNull) != 0) { >+ char[][] annotationName = currentScope.environment().globalOptions.nonNullAnnotationName; >+ currentScope.problemReporter().possiblyNullFromNonNullMethod(this, this.expression.nullStatus(flowInfo), >+ annotationName[annotationName.length-1]); >+ } >+ } >+ } > } > this.initStateIndex = > currentScope.methodScope().recordInitializationStates(flowInfo); >Index: compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java,v >retrieving revision 1.238 >diff -u -r1.238 CompilerOptions.java >--- compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 11 Jan 2011 14:22:15 -0000 1.238 >+++ compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 13 Jan 2011 22:58:31 -0000 >@@ -8,8 +8,10 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Benjamin Muskalla - Contribution for bug 239066 >- * Stephan Herrmann - Contribution for bug 236385 >- * Stephan Herrmann - Contribution for bug 295551 >+ * Stephan Herrmann - Contributions for >+ * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used >+ * bug 295551 - Add option to automatically promote all warnings to errors >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.impl; > >@@ -106,6 +108,9 @@ > public static final String OPTION_ReportNullReference = "org.eclipse.jdt.core.compiler.problem.nullReference"; //$NON-NLS-1$ > public static final String OPTION_ReportPotentialNullReference = "org.eclipse.jdt.core.compiler.problem.potentialNullReference"; //$NON-NLS-1$ > public static final String OPTION_ReportRedundantNullCheck = "org.eclipse.jdt.core.compiler.problem.redundantNullCheck"; //$NON-NLS-1$ >+ public static final String OPTION_ReportNullContractViolation = "org.eclipse.jdt.core.compiler.problem.nullContractViolation"; //$NON-NLS-1$ >+ public static final String OPTION_ReportPotentialNullContractViolation = "org.eclipse.jdt.core.compiler.problem.potentialNullContractViolation"; //$NON-NLS-1$ >+ public static final String OPTION_ReportNullContractInsufficientInfo = "org.eclipse.jdt.core.compiler.problem.nullContractInsufficientInfo"; //$NON-NLS-1$ > public static final String OPTION_ReportAutoboxing = "org.eclipse.jdt.core.compiler.problem.autoboxing"; //$NON-NLS-1$ > public static final String OPTION_ReportAnnotationSuperInterface = "org.eclipse.jdt.core.compiler.problem.annotationSuperInterface"; //$NON-NLS-1$ > public static final String OPTION_ReportMissingOverrideAnnotation = "org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation"; //$NON-NLS-1$ >@@ -141,6 +146,11 @@ > public static final String OPTION_ReportMissingAnnotation = "org.eclipse.jdt.core.compiler.problem.missingAnnotation"; //$NON-NLS-1$ > public static final String OPTION_ReportMissingJavadoc = "org.eclipse.jdt.core.compiler.problem.missingJavadoc"; //$NON-NLS-1$ > >+ public static final String OPTION_NullableAnnotationName = "org.eclipse.jdt.core.compiler.annotation.nullable"; //$NON-NLS-1$ >+ public static final String OPTION_NonNullAnnotationName = "org.eclipse.jdt.core.compiler.annotation.nonnull"; //$NON-NLS-1$ >+ public static final String OPTION_EmulateNullAnnotationTypes = "org.eclipse.jdt.core.compiler.annotation.emulate"; //$NON-NLS-1$ >+ public static final String OPTION_DefaultImportNullAnnotationTypes = "org.eclipse.jdt.core.compiler.annotation.defaultImport"; //$NON-NLS-1$ >+ > /** > * Possible values for configurable options > */ >@@ -170,6 +180,9 @@ > public static final String NO_TAG = "no_tag"; //$NON-NLS-1$ > public static final String ALL_STANDARD_TAGS = "all_standard_tags"; //$NON-NLS-1$ > >+ private static final char[][] DEFAULT_NONNULL_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.NonNull".toCharArray()); //$NON-NLS-1$ >+ private static final char[][] DEFAULT_NULLABLE_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.Nullable".toCharArray()); //$NON-NLS-1$ >+ > /** > * Bit mask for configurable problems (error/warning threshold) > * Note: bitmask assumes 3 highest bits to denote irritant group (to allow storing 8 groups of 29 bits each >@@ -243,6 +256,9 @@ > public static final int UnusedObjectAllocation = IrritantSet.GROUP2 | ASTNode.Bit4; > public static final int MethodCanBeStatic = IrritantSet.GROUP2 | ASTNode.Bit5; > public static final int MethodCanBePotentiallyStatic = IrritantSet.GROUP2 | ASTNode.Bit6; >+ public static final int NullContractViolation = IrritantSet.GROUP2 | ASTNode.Bit7; >+ public static final int PotentialNullContractViolation = IrritantSet.GROUP2 | ASTNode.Bit8; >+ public static final int NullContractInsufficientInfo = IrritantSet.GROUP2 | ASTNode.Bit9; > > // Severity level for handlers > /** >@@ -364,6 +380,14 @@ > public boolean includeNullInfoFromAsserts; > /** Controls whether forced generic type problems get reported */ > public boolean reportUnavoidableGenericTypeProblems; >+ /** Fully qualified name of annotation to use as marker for nullable types. */ >+ public char[][] nullableAnnotationName; >+ /** Fully qualified name of annotation to use as marker for nonnull types. */ >+ public char[][] nonNullAnnotationName; >+ /** Should null annotation types be emulated by synthetic bindings? */ >+ public boolean emulateNullAnnotationTypes; >+ /** Should null annotation types be imported by default? */ >+ public boolean defaultImportNullAnnotationTypes; > > // keep in sync with warningTokenToIrritant and warningTokenFromIrritant > public final static String[] warningTokens = { >@@ -503,6 +527,12 @@ > return OPTION_ReportPotentialNullReference; > case RedundantNullCheck : > return OPTION_ReportRedundantNullCheck; >+ case NullContractViolation : >+ return OPTION_ReportNullContractViolation; >+ case PotentialNullContractViolation : >+ return OPTION_ReportPotentialNullContractViolation; >+ case NullContractInsufficientInfo : >+ return OPTION_ReportNullContractInsufficientInfo; > case AutoBoxing : > return OPTION_ReportAutoboxing; > case AnnotationSuperInterface : >@@ -748,6 +778,9 @@ > case NullReference : > case PotentialNullReference : > case RedundantNullCheck : >+ case NullContractViolation : >+ case PotentialNullContractViolation : >+ case NullContractInsufficientInfo : > return "null"; //$NON-NLS-1$ > case FallthroughCase : > return "fallthrough"; //$NON-NLS-1$ >@@ -923,6 +956,9 @@ > optionsMap.put(OPTION_ReportNullReference, getSeverityString(NullReference)); > optionsMap.put(OPTION_ReportPotentialNullReference, getSeverityString(PotentialNullReference)); > optionsMap.put(OPTION_ReportRedundantNullCheck, getSeverityString(RedundantNullCheck)); >+ optionsMap.put(OPTION_ReportNullContractViolation, getSeverityString(NullContractViolation)); >+ optionsMap.put(OPTION_ReportPotentialNullContractViolation, getSeverityString(PotentialNullContractViolation)); >+ optionsMap.put(OPTION_ReportNullContractInsufficientInfo, getSeverityString(NullContractInsufficientInfo)); > optionsMap.put(OPTION_SuppressWarnings, this.suppressWarnings ? ENABLED : DISABLED); > optionsMap.put(OPTION_SuppressOptionalErrors, this.suppressOptionalErrors ? ENABLED : DISABLED); > optionsMap.put(OPTION_ReportUnhandledWarningToken, getSeverityString(UnhandledWarningToken)); >@@ -943,6 +979,16 @@ > optionsMap.put(OPTION_IncludeNullInfoFromAsserts, this.includeNullInfoFromAsserts ? ENABLED : DISABLED); > optionsMap.put(OPTION_ReportMethodCanBeStatic, getSeverityString(MethodCanBeStatic)); > optionsMap.put(OPTION_ReportMethodCanBePotentiallyStatic, getSeverityString(MethodCanBePotentiallyStatic)); >+ if (this.nullableAnnotationName != null) { >+ char[] compoundName = CharOperation.concatWith(this.nullableAnnotationName, '.'); >+ optionsMap.put(OPTION_NullableAnnotationName, String.valueOf(compoundName)); >+ } >+ if (this.nonNullAnnotationName != null) { >+ char[] compoundName = CharOperation.concatWith(this.nonNullAnnotationName, '.'); >+ optionsMap.put(OPTION_NonNullAnnotationName, String.valueOf(compoundName)); >+ } >+ optionsMap.put(OPTION_EmulateNullAnnotationTypes, this.emulateNullAnnotationTypes ? ENABLED : DISABLED); >+ optionsMap.put(OPTION_DefaultImportNullAnnotationTypes, this.defaultImportNullAnnotationTypes ? ENABLED : DISABLED); > return optionsMap; > } > >@@ -1351,6 +1397,9 @@ > if ((optionValue = optionsMap.get(OPTION_ReportNullReference)) != null) updateSeverity(NullReference, optionValue); > if ((optionValue = optionsMap.get(OPTION_ReportPotentialNullReference)) != null) updateSeverity(PotentialNullReference, optionValue); > if ((optionValue = optionsMap.get(OPTION_ReportRedundantNullCheck)) != null) updateSeverity(RedundantNullCheck, optionValue); >+ if ((optionValue = optionsMap.get(OPTION_ReportNullContractViolation)) != null) updateSeverity(NullContractViolation, optionValue); >+ if ((optionValue = optionsMap.get(OPTION_ReportPotentialNullContractViolation)) != null) updateSeverity(PotentialNullContractViolation, optionValue); >+ if ((optionValue = optionsMap.get(OPTION_ReportNullContractInsufficientInfo)) != null) updateSeverity(NullContractInsufficientInfo, optionValue); > if ((optionValue = optionsMap.get(OPTION_ReportAutoboxing)) != null) updateSeverity(AutoBoxing, optionValue); > if ((optionValue = optionsMap.get(OPTION_ReportAnnotationSuperInterface)) != null) updateSeverity(AnnotationSuperInterface, optionValue); > if ((optionValue = optionsMap.get(OPTION_ReportMissingOverrideAnnotation)) != null) updateSeverity(MissingOverrideAnnotation, optionValue); >@@ -1485,6 +1534,36 @@ > this.storeAnnotations = false; > } > } >+ if ((optionValue = optionsMap.get(OPTION_NullableAnnotationName)) != null) { >+ this.nullableAnnotationName = CharOperation.splitAndTrimOn('.', ((String)optionValue).toCharArray()); >+ } >+ if ((optionValue = optionsMap.get(OPTION_NonNullAnnotationName)) != null) { >+ this.nonNullAnnotationName = CharOperation.splitAndTrimOn('.', ((String)optionValue).toCharArray()); >+ } >+ if ((optionValue = optionsMap.get(OPTION_EmulateNullAnnotationTypes)) != null) { >+ if (ENABLED.equals(optionValue)) { >+ this.emulateNullAnnotationTypes = true; >+ // ensure that we actually have annotation names to emulate: >+ if (this.nullableAnnotationName == null) >+ this.nullableAnnotationName = DEFAULT_NULLABLE_ANNOTATION_NAME; >+ if (this.nonNullAnnotationName == null) >+ this.nonNullAnnotationName = DEFAULT_NONNULL_ANNOTATION_NAME; >+ } else if (DISABLED.equals(optionValue)) { >+ this.emulateNullAnnotationTypes = false; >+ } >+ } >+ if ((optionValue = optionsMap.get(OPTION_DefaultImportNullAnnotationTypes)) != null) { >+ if (ENABLED.equals(optionValue)) { >+ this.defaultImportNullAnnotationTypes = true; >+ // ensure that we actually have annotation names to be used for default imports: >+ if (this.nullableAnnotationName == null) >+ this.nullableAnnotationName = DEFAULT_NULLABLE_ANNOTATION_NAME; >+ if (this.nonNullAnnotationName == null) >+ this.nonNullAnnotationName = DEFAULT_NONNULL_ANNOTATION_NAME; >+ } else if (DISABLED.equals(optionValue)) { >+ this.defaultImportNullAnnotationTypes = false; >+ } >+ } > } > public String toString() { > StringBuffer buf = new StringBuffer("CompilerOptions:"); //$NON-NLS-1$ >@@ -1560,6 +1639,9 @@ > buf.append("\n\t- null reference: ").append(getSeverityString(NullReference)); //$NON-NLS-1$ > buf.append("\n\t- potential null reference: ").append(getSeverityString(PotentialNullReference)); //$NON-NLS-1$ > buf.append("\n\t- redundant null check: ").append(getSeverityString(RedundantNullCheck)); //$NON-NLS-1$ >+ buf.append("\n\t- null contract violation: ").append(getSeverityString(NullContractViolation)); //$NON-NLS-1$ >+ buf.append("\n\t- potential null contract vialotation: ").append(getSeverityString(PotentialNullContractViolation)); //$NON-NLS-1$ >+ buf.append("\n\t- insufficient information for checking null contract: ").append(getSeverityString(NullContractInsufficientInfo)); //$NON-NLS-1$ > buf.append("\n\t- autoboxing: ").append(getSeverityString(AutoBoxing)); //$NON-NLS-1$ > buf.append("\n\t- annotation super interface: ").append(getSeverityString(AnnotationSuperInterface)); //$NON-NLS-1$ > buf.append("\n\t- missing @Override annotation: ").append(getSeverityString(MissingOverrideAnnotation)); //$NON-NLS-1$ >Index: compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java,v >retrieving revision 1.11 >diff -u -r1.11 IrritantSet.java >--- compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java 17 Dec 2010 09:38:53 -0000 1.11 >+++ compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java 13 Jan 2011 22:58:31 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > > package org.eclipse.jdt.internal.compiler.impl; >@@ -58,9 +59,12 @@ > public static final IrritantSet UNCHECKED = new IrritantSet(CompilerOptions.UncheckedTypeOperation); > public static final IrritantSet UNQUALIFIED_FIELD_ACCESS = new IrritantSet(CompilerOptions.UnqualifiedFieldAccess); > >- public static final IrritantSet COMPILER_DEFAULT_ERRORS = new IrritantSet(0); // no optional error by default >+ public static final IrritantSet COMPILER_DEFAULT_ERRORS = new IrritantSet(0); // see static initializer below > public static final IrritantSet COMPILER_DEFAULT_WARNINGS = new IrritantSet(0); // see static initializer below > static { >+ COMPILER_DEFAULT_ERRORS >+ .set(CompilerOptions.NullContractViolation >+ | CompilerOptions.PotentialNullContractViolation); > COMPILER_DEFAULT_WARNINGS > // group-0 warnings enabled by default > .set( >@@ -98,7 +102,8 @@ > // group-2 warnings enabled by default > .set( > CompilerOptions.DeadCode >- |CompilerOptions.Tasks); >+ | CompilerOptions.Tasks >+ | CompilerOptions.NullContractInsufficientInfo); > > ALL.setAll(); > HIDING >@@ -107,7 +112,10 @@ > .set(CompilerOptions.TypeHiding); > NULL > .set(CompilerOptions.PotentialNullReference) >- .set(CompilerOptions.RedundantNullCheck); >+ .set(CompilerOptions.RedundantNullCheck) >+ .set(CompilerOptions.NullContractViolation) >+ .set(CompilerOptions.PotentialNullContractViolation) >+ .set(CompilerOptions.NullContractInsufficientInfo); > RESTRICTION.set(CompilerOptions.DiscouragedReference); > STATIC_ACCESS.set(CompilerOptions.NonStaticAccessToStatic); > UNUSED >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java,v >retrieving revision 1.133 >diff -u -r1.133 BinaryTypeBinding.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java 6 Jan 2011 19:58:11 -0000 1.133 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java 13 Jan 2011 22:58:33 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -553,6 +554,8 @@ > isAnnotationType() ? convertMemberValue(method.getDefaultValue(), this.environment, missingTypeNames) : null, > this.environment); > >+ scanForNullAnnotation(method, result); >+ > if (use15specifics) > result.tagBits |= method.getTagBits(); > result.typeVariables = typeVars; >@@ -1092,6 +1095,53 @@ > AnnotationBinding[] retrieveAnnotations(Binding binding) { > return AnnotationBinding.addStandardAnnotations(super.retrieveAnnotations(binding), binding.getAnnotationTagBits(), this.environment); > } >+private void scanForNullAnnotation(IBinaryMethod method, MethodBinding result) { >+ char[][] nullableAnnotationName = this.environment.globalOptions.nullableAnnotationName; >+ char[][] nonNullAnnotationName = this.environment.globalOptions.nonNullAnnotationName; >+ if (nullableAnnotationName == null || nonNullAnnotationName == null) >+ return; // not configured to use null annotations >+ >+ IBinaryAnnotation[] annotations = method.getAnnotations(); >+ if (annotations != null) { >+ for (int i = 0; i < annotations.length; i++) { >+ char[] annotationTypeName = annotations[i].getTypeName(); >+ if (annotationTypeName[0] != 'L') >+ continue; >+ char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' >+ if (CharOperation.equals(typeName, nonNullAnnotationName)) { >+ result.tagBits |= TagBits.AnnotationNonNull; >+ return; >+ } >+ if (CharOperation.equals(typeName, nullableAnnotationName)) { >+ result.tagBits |= TagBits.AnnotationNullable; >+ return; >+ } >+ } >+ } >+ >+ for (int j = 0; j < result.parameters.length; j++) { >+ IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j); >+ if (paramAnnotations != null) { >+ for (int i = 0; i < paramAnnotations.length; i++) { >+ char[] annotationTypeName = paramAnnotations[i].getTypeName(); >+ if (annotationTypeName[0] != 'L') >+ continue; >+ char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';' >+ if (CharOperation.equals(typeName, nonNullAnnotationName)) { >+ if (result.parameterNonNullness == null) >+ result.parameterNonNullness = new Boolean[result.parameters.length]; >+ result.parameterNonNullness[j] = Boolean.TRUE; >+ break; >+ } else if (CharOperation.equals(typeName, nullableAnnotationName)) { >+ if (result.parameterNonNullness == null) >+ result.parameterNonNullness = new Boolean[result.parameters.length]; >+ result.parameterNonNullness[j] = Boolean.FALSE; >+ break; >+ } >+ } >+ } >+ } >+} > SimpleLookupTable storedAnnotations(boolean forceInitialize) { > if (forceInitialize && this.storedAnnotations == null) { > if (!this.environment.globalOptions.storeAnnotations) >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java,v >retrieving revision 1.128 >diff -u -r1.128 CompilationUnitScope.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java 12 Aug 2010 08:51:55 -0000 1.128 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java 13 Jan 2011 22:58:35 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,7 +7,8 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Erling Ellingsen - patch for bug 125570 >+ * Erling Ellingsen - patch for bug 125570 >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -160,7 +161,10 @@ > > // allocate the import array, add java.lang.* by default > int numberOfStatements = this.referenceContext.imports.length; >- int numberOfImports = numberOfStatements + 1; >+ int numberOfDefaultImports = 1; >+ if (this.environment.globalOptions.defaultImportNullAnnotationTypes) >+ numberOfDefaultImports += 2; >+ int numberOfImports = numberOfStatements + numberOfDefaultImports; > for (int i = 0; i < numberOfStatements; i++) { > ImportReference importReference = this.referenceContext.imports[i]; > if (((importReference.bits & ASTNode.OnDemand) != 0) && CharOperation.equals(TypeConstants.JAVA_LANG, importReference.tokens) && !importReference.isStatic()) { >@@ -169,8 +173,11 @@ > } > } > ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; >- resolvedImports[0] = getDefaultImports()[0]; >- int index = 1; >+ ImportBinding[] defaultImports = getDefaultImports(); // consistent number of default imports is ensured in LookupEnvironment.makeNullAnnotationTypeImports() >+ for (int i = 0; i < numberOfDefaultImports; i++) { >+ resolvedImports[i] = defaultImports[i]; >+ } >+ int index = numberOfDefaultImports; > > nextImport : for (int i = 0; i < numberOfStatements; i++) { > ImportReference importReference = this.referenceContext.imports[i]; >@@ -303,6 +310,13 @@ > return; // can be called when a field constant is resolved before static imports > if (this.referenceContext.imports == null) { > this.typeOrPackageCache = new HashtableOfObject(1); >+ for (int i = 0; i < this.imports.length; i++) { >+ // cache default-imported null annotation types: >+ if (!this.imports[i].onDemand) { >+ char[][] importName = this.imports[i].compoundName; >+ this.typeOrPackageCache.put(importName[importName.length-1], this.imports[i].resolvedImport); >+ } >+ } > return; > } > >@@ -327,9 +341,18 @@ > break; > } > } >+ int numberOfDefaultImports = 1; >+ if (this.environment.globalOptions.defaultImportNullAnnotationTypes) { >+ numberOfDefaultImports += 2; >+ numberOfImports += 2; >+ } > ImportBinding[] resolvedImports = new ImportBinding[numberOfImports]; >- resolvedImports[0] = getDefaultImports()[0]; >- int index = 1; >+ ImportBinding[] defaultImports = getDefaultImports(); // consistent number of default imports is ensured in LookupEnvironment.makeNullAnnotationTypeImports() >+ for (int i = 0; i < numberOfDefaultImports; i++) { >+ resolvedImports[i] = defaultImports[i]; >+ } >+ >+ int index = numberOfDefaultImports; > > // keep static imports with normal imports until there is a reason to split them up > // on demand imports continue to be packages & types. need to check on demand type imports for fields/methods >@@ -613,7 +636,19 @@ > importBinding = missingObject.fPackage; > } > >- return this.environment.defaultImports = new ImportBinding[] {new ImportBinding(TypeConstants.JAVA_LANG, true, importBinding, null)}; >+ ImportBinding javaLangImport = new ImportBinding(TypeConstants.JAVA_LANG, true, importBinding, null); >+ ImportBinding[] nullAnnotationImports = this.environment.makeNullAnnotationTypeImports(); // trigger regardless of option below >+ if (this.environment.globalOptions.defaultImportNullAnnotationTypes) { >+ ImportBinding[] allDefaultImports = new ImportBinding[nullAnnotationImports.length+1];// java.lang.* + null-annotations >+ allDefaultImports[0] = javaLangImport; >+ System.arraycopy(nullAnnotationImports, 0, >+ allDefaultImports, 1, >+ nullAnnotationImports.length); >+ this.environment.defaultImports = allDefaultImports; >+ } else { >+ this.environment.defaultImports = new ImportBinding[] {javaLangImport}; >+ } >+ return this.environment.defaultImports; > } > // NOT Public API > public final Binding getImport(char[][] compoundName, boolean onDemand, boolean isStaticImport) { >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java,v >retrieving revision 1.109 >diff -u -r1.109 LookupEnvironment.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java 1 Nov 2010 14:15:47 -0000 1.109 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java 13 Jan 2011 22:58:37 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -1314,6 +1315,72 @@ > return this.nameEnvironment.isPackage(null, name); > return this.nameEnvironment.isPackage(compoundName, name); > } >+ >+private ReferenceBinding makeNullAnnotationType(char[][] compoundName, int typeId) { >+ char[][] packageName = CharOperation.subarray(compoundName, 0, compoundName.length-1); >+ PackageBinding packageBinding = createPackage(packageName); >+ ReferenceBinding typeBinding = packageBinding.getType(compoundName[compoundName.length-1]); >+ if (typeBinding != null && typeBinding.isValidBinding()) >+ this.problemReporter.conflictingTypeEmulation(compoundName); // does not return >+ >+ BinaryTypeBinding emulatedType = new BinaryTypeBinding(); >+ emulatedType.compoundName = compoundName; >+ emulatedType.modifiers = ClassFileConstants.AccAnnotation | ClassFileConstants.AccPublic; >+ emulatedType.fields = Binding.NO_FIELDS; >+ emulatedType.methods = Binding.NO_METHODS; >+ emulatedType.memberTypes = Binding.NO_MEMBER_TYPES; >+ emulatedType.superclass = getType(TypeConstants.JAVA_LANG_OBJECT); >+ emulatedType.superInterfaces = Binding.NO_SUPERINTERFACES; >+ emulatedType.fPackage = packageBinding; >+ emulatedType.typeVariables = Binding.NO_TYPE_VARIABLES; >+ emulatedType.tagBits = TagBits.AreFieldsComplete | TagBits.AreFieldsSorted >+ | TagBits.AreMethodsComplete | TagBits.AreMethodsSorted >+ | TagBits.HasNoMemberTypes | TagBits.TypeVariablesAreConnected >+ | TagBits.AnnotationClassRetention >+ | TagBits.AnnotationForMethod | TagBits.AnnotationForParameter ; >+ emulatedType.id = typeId; >+ >+ packageBinding.addType(emulatedType); >+ >+ return emulatedType; >+} >+ >+protected ImportBinding[] makeNullAnnotationTypeImports() { >+ char[][] nullableAnnotationName = this.globalOptions.nullableAnnotationName; >+ char[][] nonNullAnnotationName = this.globalOptions.nonNullAnnotationName; >+ if (nullableAnnotationName == null || nonNullAnnotationName == null) { >+ if (this.globalOptions.emulateNullAnnotationTypes || this.globalOptions.defaultImportNullAnnotationTypes) >+ // shouldn't happen by construction of CompilerOptions.set(Map) >+ this.problemReporter.abortDueToInternalError("Inconsistent null annotation options"); //$NON-NLS-1$ >+ return new ImportBinding[0]; >+ } >+ // fetch annotation types for emulation and/or default import: >+ ReferenceBinding nullableAnnotationType = null; >+ ReferenceBinding nonNullAnnotationType = null; >+ if (this.globalOptions.emulateNullAnnotationTypes) { >+ nullableAnnotationType = makeNullAnnotationType(nullableAnnotationName, TypeIds.T_ConfiguredAnnotationNullable); >+ nonNullAnnotationType = makeNullAnnotationType(nonNullAnnotationName, TypeIds.T_ConfiguredAnnotationNonNull); >+ } else { // not emulated means those types should exist (and need to be marked): >+ nullableAnnotationType = getType(nullableAnnotationName); >+ if (nullableAnnotationType != null && nullableAnnotationType.isValidBinding()) >+ nullableAnnotationType.id = TypeIds.T_ConfiguredAnnotationNullable; >+ else if (this.globalOptions.defaultImportNullAnnotationTypes) >+ this.problemReporter.missingNullAnnotationType(nullableAnnotationName); >+ >+ nonNullAnnotationType = getType(nonNullAnnotationName); >+ if (nonNullAnnotationType != null && nonNullAnnotationType.isValidBinding()) >+ nonNullAnnotationType.id = TypeIds.T_ConfiguredAnnotationNonNull; >+ else if (this.globalOptions.defaultImportNullAnnotationTypes) >+ this.problemReporter.missingNullAnnotationType(nonNullAnnotationName); >+ } >+ if (this.globalOptions.defaultImportNullAnnotationTypes) >+ return new ImportBinding[] { >+ new ImportBinding(nullableAnnotationName, false, nullableAnnotationType, null), >+ new ImportBinding(nonNullAnnotationName, false, nonNullAnnotationType, null) >+ }; >+ return new ImportBinding[0]; >+} >+ > // The method verifier is lazily initialized to guarantee the receiver, the compiler & the oracle are ready. > public MethodVerifier methodVerifier() { > if (this.verifier == null) >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java,v >retrieving revision 1.127 >diff -u -r1.127 MethodBinding.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java 7 Sep 2010 13:39:18 -0000 1.127 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java 13 Jan 2011 22:58:39 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -28,6 +29,7 @@ > public char[] selector; > public TypeBinding returnType; > public TypeBinding[] parameters; >+ public Boolean[] parameterNonNullness; // TRUE means @NonNull declared, FALSE means @Nullable declared, null means nothing declared > public ReferenceBinding[] thrownExceptions; > public ReferenceBinding declaringClass; > public TypeVariableBinding[] typeVariables = Binding.NO_TYPE_VARIABLES; >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java,v >retrieving revision 1.114 >diff -u -r1.114 MethodVerifier.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java 17 Dec 2010 06:40:12 -0000 1.114 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java 13 Jan 2011 22:58:42 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -8,6 +8,7 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Benjamin Muskalla - Contribution for bug 239066 >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -152,6 +153,7 @@ > // interface I { @Override Object clone(); } does not override Object#clone() > currentMethod.modifiers |= ExtraCompilerModifiers.AccOverriding; > } >+ checkNullContractCompatibility(currentMethod, inheritedMethod); > > if (!areReturnTypesCompatible(currentMethod, inheritedMethod) > && (currentMethod.returnType.tagBits & TagBits.HasMissingType) == 0) { >@@ -184,7 +186,9 @@ > checkForBridgeMethod(currentMethod, inheritedMethod, allInheritedMethods); > } > } >- >+protected void checkNullContractCompatibility(MethodBinding currentMethod, MethodBinding inheritedMethod) { >+ // nothing to do here. Real action happens at 1.5+ >+} > public void reportRawReferences(MethodBinding currentMethod, MethodBinding inheritedMethod) { > // nothing to do here. Real action happens at 1.5+ > } >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java,v >retrieving revision 1.121 >diff -u -r1.121 MethodVerifier15.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 17 Dec 2010 06:40:13 -0000 1.121 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 13 Jan 2011 22:58:43 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -407,6 +408,62 @@ > return false; > } > >+protected void checkNullContractCompatibility(MethodBinding currentMethod, MethodBinding inheritedMethod) { >+ // return type: >+ if ((inheritedMethod.tagBits & TagBits.AnnotationNonNull) != 0) { >+ if ((currentMethod.tagBits & TagBits.AnnotationNullable) != 0) { >+ AbstractMethodDeclaration methodDecl = currentMethod.sourceMethod(); >+ this.type.scope.problemReporter().illegalRedefinitionToNullableReturn(methodDecl, inheritedMethod.declaringClass, >+ this.environment.globalOptions.nonNullAnnotationName); >+ } >+ } >+ if ((currentMethod.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0) >+ currentMethod.tagBits |= (inheritedMethod.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)); >+ >+ // parameters: >+ if (inheritedMethod.parameterNonNullness != null) { >+ // inherited method has null-annotations, check and possibly transfer: >+ >+ // prepare for transfering (contract inheritance): >+ if (currentMethod.parameterNonNullness == null) >+ currentMethod.parameterNonNullness = new Boolean[currentMethod.parameters.length]; >+ >+ for (int i = 0; i < inheritedMethod.parameterNonNullness.length; i++) { >+ >+ Boolean inheritedNonNullNess = inheritedMethod.parameterNonNullness[i]; >+ if (inheritedNonNullNess != Boolean.TRUE) { // super parameter is not restricted to @NonNull >+ if (currentMethod.parameterNonNullness[i] == Boolean.TRUE) { // current parameter is restricted to @NonNull >+ this.type.scope.problemReporter().illegalRedefinitionToNonNullParameter( >+ currentMethod.sourceMethod().arguments[i], >+ inheritedMethod.declaringClass, >+ inheritedNonNullNess == null >+ ? null >+ : this.environment.globalOptions.nullableAnnotationName); >+ continue; >+ } >+ } >+ >+ if (currentMethod.parameterNonNullness[i] == null && inheritedNonNullNess != null) { >+ // inherit this annotation as the current method has no annotation: >+ currentMethod.parameterNonNullness[i] = inheritedNonNullNess; >+ VariableBinding argumentBinding = currentMethod.sourceMethod().arguments[i].binding; >+ argumentBinding.tagBits |= inheritedNonNullNess.booleanValue() >+ ? TagBits.AnnotationNonNull : TagBits.AnnotationNullable; >+ } >+ } >+ } else if (currentMethod.parameterNonNullness != null) { >+ // super method has no annotations but current has >+ for (int i = 0; i < currentMethod.parameterNonNullness.length; i++) { >+ if (currentMethod.parameterNonNullness[i] == Boolean.TRUE) { // tightening from unconstrained to @NonNull >+ this.type.scope.problemReporter().illegalRedefinitionToNonNullParameter( >+ currentMethod.sourceMethod().arguments[i], >+ inheritedMethod.declaringClass, >+ null); >+ } >+ } >+ } >+} >+ > void reportRawReferences() { > CompilerOptions compilerOptions = this.type.scope.compilerOptions(); > if (compilerOptions.sourceLevel < ClassFileConstants.JDK1_5 // shouldn't whine at all >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java,v >retrieving revision 1.184 >diff -u -r1.184 SourceTypeBinding.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java 5 Jan 2011 19:57:26 -0000 1.184 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java 13 Jan 2011 22:58:46 -0000 >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -1420,9 +1421,12 @@ > } > } > // only assign parameters if no problems are found >- if (!foundArgProblem) { >+ if (foundArgProblem) { >+ methodDecl.binding = null; >+ } else { > method.parameters = newParameters; > } >+ methodDecl.bindArguments(); > } > > boolean foundReturnTypeProblem = false; >@@ -1465,7 +1469,6 @@ > } > } > if (foundArgProblem) { >- methodDecl.binding = null; > method.parameters = Binding.NO_PARAMETERS; // see 107004 > // nullify type parameter bindings as well as they have a backpointer to the method binding > // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81134) >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java,v >retrieving revision 1.45 >diff -u -r1.45 TagBits.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java 17 Dec 2010 06:40:13 -0000 1.45 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java 13 Jan 2011 22:58:47 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -119,10 +120,13 @@ > long AnnotationInherited = ASTNode.Bit49L; > long AnnotationOverride = ASTNode.Bit50L; > long AnnotationSuppressWarnings = ASTNode.Bit51L; >- long AllStandardAnnotationsMask = AnnotationTargetMASK | AnnotationRetentionMASK | AnnotationDeprecated | AnnotationDocumented | AnnotationInherited | AnnotationOverride | AnnotationSuppressWarnings; >+ long AnnotationNullable = ASTNode.Bit52L; >+ long AnnotationNonNull = ASTNode.Bit53L; >+ long AllStandardAnnotationsMask = AnnotationTargetMASK | AnnotationRetentionMASK | AnnotationDeprecated | AnnotationDocumented >+ | AnnotationInherited | AnnotationOverride | AnnotationSuppressWarnings | AnnotationNullable | AnnotationNonNull; > >- long DefaultValueResolved = ASTNode.Bit52L; >+ long DefaultValueResolved = ASTNode.Bit54L; > > // set when type contains non-private constructor(s) >- long HasNonPrivateConstructor = ASTNode.Bit53L; >+ long HasNonPrivateConstructor = ASTNode.Bit55L; > } >Index: compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java,v >retrieving revision 1.34 >diff -u -r1.34 TypeIds.java >--- compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java 7 Mar 2009 01:08:09 -0000 1.34 >+++ compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java 13 Jan 2011 22:58:47 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2009 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for Bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -89,6 +90,9 @@ > > final int T_JavaUtilCollection = 59; > >+ final int T_ConfiguredAnnotationNullable = 60; >+ final int T_ConfiguredAnnotationNonNull = 61; >+ > final int NoId = Integer.MAX_VALUE; > > public static final int IMPLICIT_CONVERSION_MASK = 0xFF; >Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v >retrieving revision 1.428 >diff -u -r1.428 ProblemReporter.java >--- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 17 Dec 2010 09:38:53 -0000 1.428 >+++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 13 Jan 2011 22:58:59 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -8,7 +8,9 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Benjamin Muskalla - Contribution for bug 239066 >- * Stephan Herrmann - Contribution for bug 236385 >+ * Stephan Herrmann - Contributions for >+ * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.problem; > >@@ -81,6 +83,7 @@ > import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; > import org.eclipse.jdt.internal.compiler.env.AccessRestriction; > import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; >+import org.eclipse.jdt.internal.compiler.flow.FlowInfo; > import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; > import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; > import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; >@@ -293,6 +296,19 @@ > case IProblem.NullLocalVariableInstanceofYieldsFalse: > return CompilerOptions.RedundantNullCheck; > >+ case IProblem.DefiniteNullFromNonNullMethod: >+ case IProblem.DefiniteNullToNonnullParameter: >+ case IProblem.IllegalRedefinitionToNullableReturn: >+ case IProblem.IllegalRedefinitionToNonNullParameter: >+ case IProblem.IllegalDefinitionToNonNullParameter: >+ return CompilerOptions.NullContractViolation; >+ case IProblem.PotentialNullFromNonNullMethod: >+ case IProblem.PotentialNullToNonnullParameter: >+ return CompilerOptions.PotentialNullContractViolation; >+ case IProblem.NonNullParameterInsufficientInfo: >+ case IProblem.NonNullReturnInsufficientInfo: >+ return CompilerOptions.NullContractInsufficientInfo; >+ > case IProblem.BoxingConversion : > case IProblem.UnboxingConversion : > return CompilerOptions.AutoBoxing; >@@ -469,6 +485,9 @@ > case CompilerOptions.NullReference : > case CompilerOptions.PotentialNullReference : > case CompilerOptions.RedundantNullCheck : >+ case CompilerOptions.NullContractViolation : >+ case CompilerOptions.PotentialNullContractViolation : >+ case CompilerOptions.NullContractInsufficientInfo : > case CompilerOptions.IncompleteEnumSwitch : > case CompilerOptions.FallthroughCase : > case CompilerOptions.OverridingMethodWithoutSuperInvocation : >@@ -530,6 +549,8 @@ > switch (problemID) { > case IProblem.IsClassPathCorrect : > case IProblem.CorruptedSignature : >+ case IProblem.ConflictingTypeEmulation : >+ case IProblem.MissingNullAnnotationType : > return CategorizedProblem.CAT_BUILDPATH; > > default : >@@ -1331,6 +1352,15 @@ > importRef.sourceStart, > importRef.sourceEnd); > } >+public void conflictingTypeEmulation(char[][] compoundName) { >+ String[] arguments = new String[] {CharOperation.toString(compoundName)}; >+ this.handle( >+ IProblem.ConflictingTypeEmulation, >+ arguments, >+ arguments, >+ ProblemSeverities.Error | ProblemSeverities.Abort | ProblemSeverities.Fatal, // not configurable >+ 0, 0); >+} > public void constantOutOfRange(Literal literal, TypeBinding literalType) { > String[] arguments = new String[] {new String(literalType.readableName()), new String(literal.source())}; > this.handle( >@@ -2437,6 +2467,32 @@ > qualifiedTypeReference.sourceStart, > qualifiedTypeReference.sourceEnd); > } >+public void illegalRedefinitionToNonNullParameter(Argument argument, ReferenceBinding declaringClass, char[][] inheritedAnnotationName) { >+ if (inheritedAnnotationName == null) { >+ this.handle( >+ IProblem.IllegalDefinitionToNonNullParameter, >+ new String[] { new String(argument.name), new String(declaringClass.readableName()) }, >+ new String[] { new String(argument.name), new String(declaringClass.shortReadableName()) }, >+ argument.sourceStart, >+ argument.sourceEnd); >+ >+ } else { >+ this.handle( >+ IProblem.IllegalRedefinitionToNonNullParameter, >+ new String[] { new String(argument.name), new String(declaringClass.readableName()), CharOperation.toString(inheritedAnnotationName)}, >+ new String[] { new String(argument.name), new String(declaringClass.shortReadableName()), new String(inheritedAnnotationName[inheritedAnnotationName.length-1])}, >+ argument.sourceStart, >+ argument.sourceEnd); >+ } >+} >+public void illegalRedefinitionToNullableReturn(AbstractMethodDeclaration methodDecl, ReferenceBinding declaringClass, char[][] nonNullAnnotationName) { >+ this.handle( >+ IProblem.IllegalRedefinitionToNullableReturn, >+ new String[] { new String(declaringClass.readableName()), CharOperation.toString(nonNullAnnotationName)}, >+ new String[] { new String(declaringClass.shortReadableName()), new String(nonNullAnnotationName[nonNullAnnotationName.length-1])}, >+ methodDecl.sourceStart, >+ methodDecl.sourceEnd); >+} > public void illegalStaticModifierForMemberType(SourceTypeBinding type) { > String[] arguments = new String[] {new String(type.sourceName())}; > this.handle( >@@ -5116,6 +5172,11 @@ > switchStatement.expression.sourceStart, > switchStatement.expression.sourceEnd); > } >+ >+public void missingNullAnnotationType(char[][] nullAnnotationName) { >+ String[] args = { new String(CharOperation.concatWith(nullAnnotationName, '.')) }; >+ this.handle(IProblem.MissingNullAnnotationType, args, args, 0, 0); >+} > public void missingOverrideAnnotation(AbstractMethodDeclaration method) { > int severity = computeSeverity(IProblem.MissingOverrideAnnotation); > if (severity == ProblemSeverities.Ignore) return; >@@ -6078,6 +6139,34 @@ > caseStatement.sourceStart, > caseStatement.sourceEnd); > } >+public void possiblyNullFromNonNullMethod(ReturnStatement returnStatement, int nullStatus, char[] annotationName) { >+ int problemId = IProblem.NonNullReturnInsufficientInfo; >+ if ((nullStatus & FlowInfo.NULL) != 0) >+ problemId = IProblem.DefiniteNullFromNonNullMethod; >+ if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) >+ problemId = IProblem.PotentialNullFromNonNullMethod; >+ String[] arguments = new String[] { String.valueOf(annotationName) }; >+ this.handle( >+ problemId, >+ arguments, >+ arguments, >+ returnStatement.sourceStart, >+ returnStatement.sourceEnd); >+} >+public void possiblyNullToNonNullParameter(Expression argument, int nullStatus, char[] annotationName) { >+ int problemId = IProblem.NonNullParameterInsufficientInfo; >+ if ((nullStatus & FlowInfo.NULL) != 0) >+ problemId = IProblem.DefiniteNullToNonnullParameter; >+ else if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) >+ problemId = IProblem.PotentialNullToNonnullParameter; >+ String[] arguments = new String[] { String.valueOf(annotationName) }; >+ this.handle( >+ problemId, >+ arguments, >+ arguments, >+ argument.sourceStart, >+ argument.sourceEnd); >+} > public void publicClassMustMatchFileName(CompilationUnitDeclaration compUnitDecl, TypeDeclaration typeDecl) { > this.referenceContext = typeDecl; // report the problem against the type not the entire compilation unit > String[] arguments = new String[] {new String(compUnitDecl.getFileName()), new String(typeDecl.name)}; >Index: compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties,v >retrieving revision 1.260 >diff -u -r1.260 messages.properties >--- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 17 Dec 2010 09:38:53 -0000 1.260 >+++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 13 Jan 2011 22:59:01 -0000 >@@ -1,5 +1,5 @@ > ############################################################################### >-# Copyright (c) 2000, 2010 IBM Corporation and others. >+# Copyright (c) 2000, 2011 IBM Corporation and others. > # All rights reserved. This program and the accompanying materials > # are made available under the terms of the Eclipse Public License v1.0 > # which accompanies this distribution, and is available at >@@ -8,7 +8,9 @@ > # Contributors: > # IBM Corporation - initial API and implementation > # Benjamin Muskalla - Contribution for bug 239066 >-# Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 185682 - Increment/decrement operators mark local variables as read >+# Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for >+# bug 185682 - Increment/decrement operators mark local variables as read >+# bug 186342 - [compiler][null]Using annotations for null checking > ############################################################################### > 0 = {0} > 1 = super cannot be used in java.lang.Object >@@ -619,6 +621,19 @@ > 858 = The parameterized constructor <{3}>{0}({1}) of type {2} is not applicable for the arguments ({4}) > 859 = The constructor {0}({1}) of raw type {2} is no longer generic; it cannot be parameterized with arguments <{3}> > >+### NULL ANNOTATIONS >+880 = Null contract violation: returning null from a method declared as @{0}. >+881 = Null contract violation: return value can be null but method is declared as @{0}. >+882 = Potential null contract violation: insufficient nullness information regarding return value while the method is declared as @{0}. >+883 = Null contract violation: passing null to a parameter declared as @{0}. >+884 = Null contract violation: potentially passing null to a parameter declared as @{0}. >+885 = Potential null contract violation: insufficient nullness information regarding a value that is passed to a parameter declared as @{0}. >+886 = Buildpath problem: emulation of type {0} is requested (for null annotations) but a type of this name exists on the build path. >+887 = Buildpath problem: the type {0} which is configured as a null annotation type cannot be resolved. >+888 = Cannot relax null contract for method return, inherited method from {0} is declared as @{1}. >+889 = Cannot tighten null contract for parameter {0}, inherited method from {1} declares this parameter as @{2}. >+890 = Cannot tighten null contract for parameter {0}, inherited method from {1} does not constrain this parameter. >+ > ### ELABORATIONS > ## Access restrictions > 78592 = The type {1} is not accessible due to restriction on classpath entry {0} >Index: model/org/eclipse/jdt/core/JavaCore.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java,v >retrieving revision 1.657 >diff -u -r1.657 JavaCore.java >--- model/org/eclipse/jdt/core/JavaCore.java 17 Dec 2010 09:38:57 -0000 1.657 >+++ model/org/eclipse/jdt/core/JavaCore.java 13 Jan 2011 22:59:11 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -81,8 +81,16 @@ > * COMPILER_PB_UNUSED_DECLARED_THROWN_EXCEPTION_EXEMPT_EXCEPTION_AND_THROWABLE > * IBM Corporation - added getOptionForConfigurableSeverity(int) > * Benjamin Muskalla - added COMPILER_PB_MISSING_SYNCHRONIZED_ON_INHERITED_METHOD >- * Stephan Herrmann - added COMPILER_PB_UNUSED_OBJECT_ALLOCATION >- * Stephan Herrmann - added COMPILER_PB_SUPPRESS_OPTIONAL_ERRORS >+ * Stephan Herrmann - added the following constants: >+ * COMPILER_PB_UNUSED_OBJECT_ALLOCATION >+ * COMPILER_PB_SUPPRESS_OPTIONAL_ERRORS >+ * COMPILER_NULLABLE_ANNOTATION_NAME >+ * COMPILER_NONNULL_ANNOTATION_NAME >+ * COMPILER_EMULATE_NULL_ANNOTATION_TYPES >+ * COMPILER_DEFAULT_IMPORT_NULL_ANNOTATION_TYPES >+ * COMPILER_PB_NULL_CONTRACT_VIOLATION >+ * COMPILER_PB_POTENTIAL_NULL_CONTRACT_VIOLATION >+ * COMPILER_PB_NULL_CONTRACT_INSUFFICIENT_INFO > *******************************************************************************/ > > package org.eclipse.jdt.core; >@@ -1576,6 +1584,172 @@ > */ > public static final String COMPILER_PB_POTENTIAL_NULL_REFERENCE = PLUGIN_ID + ".compiler.problem.potentialNullReference"; //$NON-NLS-1$ > /** >+ * Compiler option ID: Name of Annotation Type for Nullable Types. >+ * <p>This option defines a fully qualified Java type name that the compiler may use >+ * to perform special null analysis.</p> >+ * <p>If the annotation specified by this option is applied to a type in a method >+ * signature or variable declaration this will be interpreted as a contract that >+ * <code>null</code> is a legal value in that position. Currently supported >+ * positions are: method parameters and method return type.</p> >+ * <p>If a value whose type >+ * is annotated with this annotation is dereferenced without checking for null >+ * the compiler will trigger a diagnostic as further controlled by >+ * {@link #COMPILER_PB_POTENTIAL_NULL_REFERENCE}.</p> >+ * <p>The compiler may furthermore check adherence to the null contract as further >+ * controlled by {@link #COMPILER_PB_NULL_CONTRACT_VIOLATION}, >+ * {@link #COMPILER_PB_POTENTIAL_NULL_CONTRACT_VIOLATION} and >+ * {@link #COMPILER_PB_NULL_CONTRACT_INSUFFICIENT_INFO}. >+ * </p> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.nullable"</code></dd> >+ * <dt>Possible values:</dt><dd>any legal Java type name</dd> >+ * <dt>Default:</dt><dd><code>"org.eclipse.jdt.annotation.Nullable"</code></dd> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_NULLABLE_ANNOTATION_NAME = PLUGIN_ID + ".compiler.annotation.nullable"; //$NON-NLS-1$ >+ /** >+ * Compiler option ID: Name of Annotation Type for Non-Null Types. >+ * <p>This option defines a fully qualified Java type name that the compiler may use >+ * to perform special null analysis.</p> >+ * <p>If the annotation specified by this option is applied to a type in a method >+ * signature or variable declaration this will be interpreted as a contract that >+ * <code>null</code> is <b>not</b> a legal value in that position. Currently >+ * supported positions are: method parameters and method return type.</p> >+ * <p>For values declared with this annotation the compiler will never trigger a null >+ * reference diagnostic (as controlled by {@link #COMPILER_PB_POTENTIAL_NULL_REFERENCE} >+ * and {@link #COMPILER_PB_NULL_REFERENCE}), because the assumption is made that null >+ * will never occur at runtime in these positions.</p> >+ * <p>The compiler may furthermore check adherence to the null contract as further >+ * controlled by {@link #COMPILER_PB_NULL_CONTRACT_VIOLATION}, >+ * {@link #COMPILER_PB_POTENTIAL_NULL_CONTRACT_VIOLATION} and >+ * {@link #COMPILER_PB_NULL_CONTRACT_INSUFFICIENT_INFO}. >+ * </p> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.nonnull"</code></dd> >+ * <dt>Possible values:</dt><dd>any legal Java type name</dd> >+ * <dt>Default:</dt><dd><code>"org.eclipse.jdt.annotation.NonNull"</code></dd> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_NONNULL_ANNOTATION_NAME = PLUGIN_ID + ".compiler.annotation.nonnull"; //$NON-NLS-1$ >+ /** >+ * Compiler option ID: Emulate Null Annotation Types. >+ * <p>When enabled, the compiler will use the annotation types specified in >+ * {@link #COMPILER_NONNULL_ANNOTATION_NAME} and {@link #COMPILER_NULLABLE_ANNOTATION_NAME} >+ * without searching for a corresponding type definition, ie., these annotation >+ * types don't have to actually exist.</p> >+ * <p>This option is used to make null contract analysis independent of any additional >+ * classes that would otherwise need to be supplied at compile time.</p> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.emulate"</code></dd> >+ * <dt>Possible values:</dt><dd>{ "disabled", "enabled" }</dd> >+ * <dt>Default:</dt><dd><code>"disabled"</code></dd> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_EMULATE_NULL_ANNOTATION_TYPES = PLUGIN_ID + ".compiler.annotation.emulate"; //$NON-NLS-1$ >+ /** >+ * Compiler option ID: Default Import of Null Annotation Types. >+ * <p>When enabled, the compiler will be able to resolve the annotation types specified in >+ * {@link #COMPILER_NONNULL_ANNOTATION_NAME} and {@link #COMPILER_NULLABLE_ANNOTATION_NAME} >+ * by their simple names without an explicit import statement.</p> >+ * <p>This option is used to avoid mentioning the fully qualified annotation names >+ * in any source files, as to facility the migration from one set of annotations >+ * to another, e.g., when standard annotations for this purpose will be defined >+ * in the future. >+ * </p> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.defaultImport"</code></dd> >+ * <dt>Possible values:</dt><dd>{ "disabled", "enabled" }</dd> >+ * <dt>Default:</dt><dd><code>"disabled"</code></dd> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_DEFAULT_IMPORT_NULL_ANNOTATION_TYPES = PLUGIN_ID + ".compiler.annotation.defaultImport"; //$NON-NLS-1$ >+ /** >+ * Compiler option ID: Reporting Violations of Null Contracts. >+ * <p>When enabled, the compiler will issue an error or a warning whenever one of the >+ * following situations is detected: >+ * <ol> >+ * <li>A method declared with a nonnull annotation returns an expression that is >+ * statically known to evaluate to a null value.</li> >+ * <li>An expression that is statically known to evaluate to a null value is passed >+ * as an argument in a method call where the corresponding parameter of the called >+ * method is declared with a nonnull annotation.</li> >+ * <li>A method that overrides an inherited method declared with a nonnull annotation >+ * tries to relax that contract by specifying a nullable annotation >+ * (prohibition of contravariant return).</li> >+ * <li>A method that overrides an inherited method which has a nullable declaration >+ * for at least one of its parameters, tries to tighten that null contract by >+ * specifying a nonnull annotation for its corresponding parameter >+ * (prohibition of covariant parameters).</li> >+ * </ol> >+ * </p> >+ * <p>The compiler options {@link #COMPILER_NONNULL_ANNOTATION_NAME} and >+ * {@link #COMPILER_NULLABLE_ANNOTATION_NAME} control which annotations the compiler >+ * shall interpret as nonnull or nullable annotations, respectively. >+ * </p> >+ * <dl> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.nullContractViolation"</code></dd> >+ * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> >+ * <dt>Default:</dt><dd><code>"error"</code></dd> >+ * </dl> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_PB_NULL_CONTRACT_VIOLATION = PLUGIN_ID + ".compiler.problem.nullContractViolation"; //$NON-NLS-1$ >+ /** >+ * Compiler option ID: Reporting Violations of Null Contracts with Potential Null Value. >+ * <p>When enabled, the compiler will issue an error or a warning whenever one of the >+ * following situations is detected: >+ * <ol> >+ * <li>A method declared with a nonnull annotation returns an expression that is >+ * statically known to evaluate to a null value on some flow.</li> >+ * <li>An expression that is statically known to evaluate to a null value on some flow >+ * is passed as an argument in a method call where the corresponding parameter of >+ * the called method is declared with a nonnull annotation.</li> >+ * </ol> >+ * </p> >+ * <p>The compiler options {@link #COMPILER_NONNULL_ANNOTATION_NAME} and >+ * {@link #COMPILER_NULLABLE_ANNOTATION_NAME} control which annotations the compiler >+ * shall interpret as nonnull or nullable annotations, respectively. >+ * </p> >+ * <dl> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.potentialNullContractViolation"</code></dd> >+ * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> >+ * <dt>Default:</dt><dd><code>"error"</code></dd> >+ * </dl> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_PB_POTENTIAL_NULL_CONTRACT_VIOLATION = PLUGIN_ID + ".compiler.problem.potentialNullContractViolation"; //$NON-NLS-1$ >+ /** >+ * Compiler option ID: Reporting Insufficient Information for Analysing Adherence to Null Contracts. >+ * <p>When enabled, the compiler will issue an error or a warning whenever one of the >+ * following situations is detected: >+ * <ol> >+ * <li>A method declared with a nonnull annotation returns an expression for which >+ * insufficient nullness information is available for statically proving that no >+ * flow will pass a null value at runtime.</li> >+ * <li>An expression for which insufficient nullness information is available for >+ * statically proving that it will never evaluate to a null value at runtime >+ * is passed as an argument in a method call where the corresponding parameter of >+ * the called method is declared with a nonnull annotation.</li> >+ * </ol> >+ * Insufficient nullness information is usually a consequence of using other unannotated >+ * variables or methods. >+ * </p> >+ * <p>The compiler options {@link #COMPILER_NONNULL_ANNOTATION_NAME} and >+ * {@link #COMPILER_NULLABLE_ANNOTATION_NAME} control which annotations the compiler >+ * shall interpret as nonnull or nullable annotations, respectively. >+ * </p> >+ * <dl> >+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.nullContractInsufficientInfo"</code></dd> >+ * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> >+ * <dt>Default:</dt><dd><code>"warning"</code></dd> >+ * </dl> >+ * @since 3.7 >+ * @category CompilerOptionID >+ */ >+ public static final String COMPILER_PB_NULL_CONTRACT_INSUFFICIENT_INFO = PLUGIN_ID + ".compiler.problem.nullContractInsufficientInfo"; //$NON-NLS-1$ >+ /** > * Compiler option ID: Reporting Redundant Null Check. > * <p>When enabled, the compiler will issue an error or a warning whenever a > * variable that is statically known to hold a null or a non-null value >#P org.eclipse.jdt.core.tests.compiler >Index: src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java,v >retrieving revision 1.222 >diff -u -r1.222 BatchCompilerTest.java >--- src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 17 Dec 2010 09:39:05 -0000 1.222 >+++ src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 13 Jan 2011 22:59:40 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -10,7 +10,9 @@ > * Benjamin Muskalla - Contribution for bug 239066 > * Stephan Herrmann - Contribution for bug 236385 > * Stephan Herrmann - Contribution for bug 295551 >- * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 185682 - Increment/decrement operators mark local variables as read >+ * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for >+ * bug 185682 - Increment/decrement operators mark local variables as read >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.core.tests.compiler.regression; > >@@ -48,7 +50,7 @@ > private static final Main MAIN = new Main(null/*outWriter*/, null/*errWriter*/, false/*systemExit*/, null/*options*/, null/*progress*/); > > static { >-// TESTS_NAMES = new String[] { "test295_warn_options" }; >+// TESTS_NAMES = new String[] { "testNullAnnotations" }; > // TESTS_NUMBERS = new int[] { 306 }; > // TESTS_RANGE = new int[] { 298, -1 }; > } >@@ -1589,6 +1591,22 @@ > " -classNames <className1[,className2,...]>\n" + > " qualified names of binary classes to process\n" + > " \n" + >+ " Null annotation options:\n" + >+ " -nullAnnotations:<suboptions>\n" + >+ " enable use of annotations for specifying null contracts;\n" + >+ " <suboptions> is a non-empty, comma-separated list of:\n" + >+ " nullable=<typename>\n" + >+ " specifies the fully qualified name of an annotation type\n" + >+ " to be used for marking types whose values include null\n" + >+ " nonnull=<typename>\n" + >+ " specifies the fully qualified name of an annotation type\n" + >+ " to be used for marking types whose values cannot be null\n" + >+ " emulate tells the compiler to emulate the above annotation types\n" + >+ " although they do not exist on the classpath\n" + >+ " import tells the compiler to import the above annotation types\n" + >+ " without specific mention in the sources such that their\n" + >+ " simple names can be used without explicit imports\n" + >+ " \n" + > " Advanced options:\n" + > " @<file> read command line arguments from file\n" + > " -maxProblems <n> max number of problems per compilation unit (100 by\n" + >@@ -1793,6 +1811,8 @@ > " <argument value=\"---OUTPUT_DIR_PLACEHOLDER---\"/>\n" + > " </command_line>\n" + > " <options>\n" + >+ " <option key=\"org.eclipse.jdt.core.compiler.annotation.defaultImport\" value=\"disabled\"/>\n" + >+ " <option key=\"org.eclipse.jdt.core.compiler.annotation.emulate\" value=\"disabled\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"disabled\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.5\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.codegen.unusedLocal\" value=\"optimize out\"/>\n" + >@@ -1850,11 +1870,14 @@ > " <option key=\"org.eclipse.jdt.core.compiler.problem.noEffectAssignment\" value=\"warning\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion\" value=\"warning\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral\" value=\"ignore\"/>\n" + >+ " <option key=\"org.eclipse.jdt.core.compiler.problem.nullContractInsufficientInfo\" value=\"warning\"/>\n" + >+ " <option key=\"org.eclipse.jdt.core.compiler.problem.nullContractViolation\" value=\"error\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.nullReference\" value=\"warning\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.overridingMethodWithoutSuperInvocation\" value=\"ignore\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod\" value=\"warning\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.parameterAssignment\" value=\"ignore\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment\" value=\"ignore\"/>\n" + >+ " <option key=\"org.eclipse.jdt.core.compiler.problem.potentialNullContractViolation\" value=\"error\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.potentialNullReference\" value=\"ignore\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.rawTypeReference\" value=\"warning\"/>\n" + > " <option key=\"org.eclipse.jdt.core.compiler.problem.redundantNullCheck\" value=\"ignore\"/>\n" + >@@ -12264,4 +12287,68 @@ > "3 problems (1 error, 2 warnings)", > true); > } >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=186342 -- minimal options passed >+public void testNullAnnotations1() { >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @org.eclipse.jdt.annotation.NonNull Object foo(boolean b) {\n" + >+ " return null;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "\"" + OUTPUT_DIR + File.separator + "X.java\"" >+ + " -1.5 -nullAnnotations:emulate -d \"" + OUTPUT_DIR + "\"", >+ "", >+ "----------\n" + >+ "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + >+ " return null;\n" + >+ " ^^^^^^^^^^^^\n" + >+ "Null contract violation: returning null from a method declared as @NonNull.\n" + >+ "----------\n" + >+ "1 problem (1 error)", >+ true); >+} >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=186342 -- full options passed >+public void testNullAnnotations2() { >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @NichtNull Object foo(boolean b) {\n" + >+ " return null;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "\"" + OUTPUT_DIR + File.separator + "X.java\"" >+ + " -1.5 -nullAnnotations:nullable=org.foo.Nullish,emulate,import,nonnull=de.foo.NichtNull -d \"" + OUTPUT_DIR + "\"", >+ "", >+ "----------\n" + >+ "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + >+ " return null;\n" + >+ " ^^^^^^^^^^^^\n" + >+ "Null contract violation: returning null from a method declared as @NichtNull.\n" + >+ "----------\n" + >+ "1 problem (1 error)", >+ true); >+} >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=186342 -- unrecognized sub-option >+public void testNullAnnotations3() { >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @NichtNull Object foo(boolean b) {\n" + >+ " return null;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "\"" + OUTPUT_DIR + File.separator + "X.java\"" >+ + " -1.5 -nullAnnotations:wrong -d \"" + OUTPUT_DIR + "\"", >+ "", >+ "Unrecognized sub-option of -nullAnnotations: wrong,\n" + >+ "legal values are nullable=.., nonnull=.., emulate and import\n", >+ true); >+} > } >Index: src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java,v >retrieving revision 1.38 >diff -u -r1.38 CompilerInvocationTests.java >--- src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java 17 Dec 2010 09:39:05 -0000 1.38 >+++ src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java 13 Jan 2011 22:59:45 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2006, 2010 IBM Corporation and others. >+ * Copyright (c) 2006, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -8,7 +8,9 @@ > * Contributors: > * IBM Corporation - initial API and implementation > * Benjamin Muskalla - Contribution for bug 239066 >- * Stephan Herrmann - Contribution for bug 236385 >+ * Stephan Herrmann - Contributions for >+ * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used >+ * bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.core.tests.compiler.regression; > >@@ -386,9 +388,12 @@ > expectedProblemAttributes.put("CodeSnippetMissingMethod", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); > expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("ConflictingImport", new ProblemAttributes(CategorizedProblem.CAT_IMPORT)); >+ expectedProblemAttributes.put("ConflictingTypeEmulation", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH)); > expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("CorruptedSignature", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH)); > expectedProblemAttributes.put("DeadCode", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("DefiniteNullFromNonNullMethod", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("DefiniteNullToNonnullParameter", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("DirectInvocationOfAbstractMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); > expectedProblemAttributes.put("DisallowedTargetForAnnotation", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("DiscouragedReference", new ProblemAttributes(CategorizedProblem.CAT_RESTRICTION)); >@@ -491,6 +496,8 @@ > expectedProblemAttributes.put("IllegalPrimitiveOrArrayTypeForEnclosingInstance", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("IllegalQualifiedEnumConstantLabel", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); > expectedProblemAttributes.put("IllegalQualifiedParameterizedTypeAllocation", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); >+ expectedProblemAttributes.put("IllegalRedefinitionToNullableReturn", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("IllegalRedefinitionToNonNullParameter", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("IllegalStaticModifierForMemberType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("IllegalTypeVariableSuperReference", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); > expectedProblemAttributes.put("IllegalUsageOfQualifiedTypeReference", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); >@@ -669,6 +676,7 @@ > expectedProblemAttributes.put("MissingEnclosingInstance", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("MissingEnclosingInstanceForConstructorCall", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("MissingEnumConstantCase", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("MissingNullAnnotationType", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH)); > expectedProblemAttributes.put("MissingOverrideAnnotation", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); > expectedProblemAttributes.put("MissingOverrideAnnotationForInterfaceMethodImplementation", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); > expectedProblemAttributes.put("MissingReturnType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); >@@ -697,6 +705,8 @@ > expectedProblemAttributes.put("NonGenericMethod", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("NonGenericType", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("NonNullLocalVariableComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("NonNullReturnInsufficientInfo", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("NonNullParameterInsufficientInfo", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("NonStaticAccessToStaticField", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); > expectedProblemAttributes.put("NonStaticAccessToStaticMethod", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); > expectedProblemAttributes.put("NonStaticContextForEnumMemberType", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); >@@ -746,6 +756,8 @@ > expectedProblemAttributes.put("ParsingErrorUnexpectedEOF", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); > expectedProblemAttributes.put("PossibleAccidentalBooleanAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("PotentialNullLocalVariableReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("PotentialNullFromNonNullMethod", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); >+ expectedProblemAttributes.put("PotentialNullToNonnullParameter", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); > expectedProblemAttributes.put("PublicClassMustMatchFileName", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("RawMemberTypeCannotBeParameterized", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); > expectedProblemAttributes.put("RawTypeReference", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW)); >@@ -1023,9 +1035,12 @@ > expectedProblemAttributes.put("CodeSnippetMissingMethod", SKIP); > expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(JavaCore.COMPILER_PB_COMPARING_IDENTICAL)); > expectedProblemAttributes.put("ConflictingImport", SKIP); >+ expectedProblemAttributes.put("ConflictingTypeEmulation", SKIP); > expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(JavaCore.COMPILER_PB_VARARGS_ARGUMENT_NEED_CAST)); > expectedProblemAttributes.put("CorruptedSignature", SKIP); > expectedProblemAttributes.put("DeadCode", new ProblemAttributes(JavaCore.COMPILER_PB_DEAD_CODE)); >+ expectedProblemAttributes.put("DefiniteNullFromNonNullMethod", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_CONTRACT_VIOLATION)); >+ expectedProblemAttributes.put("DefiniteNullToNonnullParameter", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_CONTRACT_VIOLATION)); > expectedProblemAttributes.put("DirectInvocationOfAbstractMethod", SKIP); > expectedProblemAttributes.put("DisallowedTargetForAnnotation", SKIP); > expectedProblemAttributes.put("DiscouragedReference", new ProblemAttributes(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE)); >@@ -1128,6 +1143,8 @@ > expectedProblemAttributes.put("IllegalPrimitiveOrArrayTypeForEnclosingInstance", SKIP); > expectedProblemAttributes.put("IllegalQualifiedEnumConstantLabel", SKIP); > expectedProblemAttributes.put("IllegalQualifiedParameterizedTypeAllocation", SKIP); >+ expectedProblemAttributes.put("IllegalRedefinitionToNullableReturn", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_CONTRACT_VIOLATION)); >+ expectedProblemAttributes.put("IllegalRedefinitionToNonNullParameter", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_CONTRACT_VIOLATION)); > expectedProblemAttributes.put("IllegalStaticModifierForMemberType", SKIP); > expectedProblemAttributes.put("IllegalTypeVariableSuperReference", SKIP); > expectedProblemAttributes.put("IllegalUsageOfQualifiedTypeReference", SKIP); >@@ -1306,6 +1323,7 @@ > expectedProblemAttributes.put("MissingEnclosingInstance", SKIP); > expectedProblemAttributes.put("MissingEnclosingInstanceForConstructorCall", SKIP); > expectedProblemAttributes.put("MissingEnumConstantCase", new ProblemAttributes(JavaCore.COMPILER_PB_INCOMPLETE_ENUM_SWITCH)); >+ expectedProblemAttributes.put("MissingNullAnnotationType", SKIP); > expectedProblemAttributes.put("MissingOverrideAnnotation", new ProblemAttributes(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION)); > expectedProblemAttributes.put("MissingOverrideAnnotationForInterfaceMethodImplementation", SKIP); > expectedProblemAttributes.put("MissingReturnType", SKIP); >@@ -1334,6 +1352,8 @@ > expectedProblemAttributes.put("NonGenericMethod", SKIP); > expectedProblemAttributes.put("NonGenericType", SKIP); > expectedProblemAttributes.put("NonNullLocalVariableComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK)); >+ expectedProblemAttributes.put("NonNullReturnInsufficientInfo", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_CONTRACT_INSUFFICIENT_INFO)); >+ expectedProblemAttributes.put("NonNullParameterInsufficientInfo", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_CONTRACT_INSUFFICIENT_INFO)); > expectedProblemAttributes.put("NonStaticAccessToStaticField", new ProblemAttributes(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER)); > expectedProblemAttributes.put("NonStaticAccessToStaticMethod", new ProblemAttributes(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER)); > expectedProblemAttributes.put("NonStaticContextForEnumMemberType", SKIP); >@@ -1383,6 +1403,8 @@ > expectedProblemAttributes.put("ParsingErrorUnexpectedEOF", SKIP); > expectedProblemAttributes.put("PossibleAccidentalBooleanAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_POSSIBLE_ACCIDENTAL_BOOLEAN_ASSIGNMENT)); > expectedProblemAttributes.put("PotentialNullLocalVariableReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE)); >+ expectedProblemAttributes.put("PotentialNullFromNonNullMethod", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_CONTRACT_VIOLATION)); >+ expectedProblemAttributes.put("PotentialNullToNonnullParameter", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_CONTRACT_VIOLATION)); > expectedProblemAttributes.put("PublicClassMustMatchFileName", SKIP); > expectedProblemAttributes.put("RawMemberTypeCannotBeParameterized", SKIP); > expectedProblemAttributes.put("RawTypeReference", new ProblemAttributes(JavaCore.COMPILER_PB_RAW_TYPE_REFERENCE)); >Index: src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java >=================================================================== >RCS file: src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java >diff -N src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,842 @@ >+/******************************************************************************* >+ * Copyright (c) 2010, 2011 GK Software AG and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * Contributors: >+ * Stephan Herrmann - initial API and implementation >+ *******************************************************************************/ >+package org.eclipse.jdt.core.tests.compiler.regression; >+ >+import java.util.Map; >+ >+import junit.framework.Test; >+ >+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; >+ >+public class NullAnnotationTest extends AbstractComparableTest { >+ >+public NullAnnotationTest(String name) { >+ super(name); >+} >+ >+// Static initializer to specify tests subset using TESTS_* static variables >+// All specified tests which do not belong to the class are skipped... >+static { >+// TESTS_NAMES = new String[] { "test_parameter_contract_inheritance" }; >+// TESTS_NUMBERS = new int[] { 561 }; >+// TESTS_RANGE = new int[] { 1, 2049 }; >+} >+ >+public static Test suite() { >+ return buildComparableTestSuite(testClass()); >+} >+ >+public static Class testClass() { >+ return NullAnnotationTest.class; >+} >+ >+// Conditionally augment problem detection settings >+static boolean setNullRelatedOptions = true; >+protected Map getCompilerOptions() { >+ Map defaultOptions = super.getCompilerOptions(); >+ if (setNullRelatedOptions) { >+ defaultOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ defaultOptions.put(CompilerOptions.OPTION_ReportPotentialNullReference, CompilerOptions.ERROR); >+ defaultOptions.put(CompilerOptions.OPTION_ReportRedundantNullCheck, CompilerOptions.ERROR); >+ defaultOptions.put(CompilerOptions.OPTION_ReportRawTypeReference, CompilerOptions.IGNORE); >+ defaultOptions.put(CompilerOptions.OPTION_IncludeNullInfoFromAsserts, CompilerOptions.ENABLED); >+ >+ // leave new options at these defaults: >+// defaultOptions.put(CompilerOptions.OPTION_ReportNullContractViolation, CompilerOptions.ERROR); >+// defaultOptions.put(CompilerOptions.OPTION_ReportPotentialNullContractViolation, CompilerOptions.ERROR); >+// defaultOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.WARNING); >+ >+ defaultOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.eclipse.jdt.annotation.Nullable"); >+ defaultOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.eclipse.jdt.annotation.NonNull"); >+ defaultOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.ENABLED); >+ defaultOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ } >+ return defaultOptions; >+} >+// a nullable argument is dereferenced without a check >+public void test_nullable_paramter_001() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(@Nullable Object o) {\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ "}\n"}, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " System.out.print(o.toString());\n" + >+ " ^\n" + >+ "Potential null pointer access: The variable o may be null at this location\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+ >+// a null value is passed to a nullable argument >+public void test_nullable_paramter_002() { >+ runConformTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(@Nullable Object o) {\n" + >+ " // nop\n" + >+ " }\n" + >+ " void bar() {\n" + >+ " foo(null);\n" + >+ " }\n" + >+ "}\n"}, >+ ""); >+} >+ >+// a non-null argument is checked for null >+public void test_nonnull_parameter_001() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(@NonNull Object o) {\n" + >+ " if (o != null)\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ "}\n"}, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " if (o != null)\n" + >+ " ^\n" + >+ "Redundant null check: The variable o cannot be null at this location\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a non-null argument is dereferenced without a check >+public void test_nonnull_parameter_002() { >+ runConformTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(@NonNull Object o) {\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ " public static void main(String... args) {\n" + >+ " new X().foo(\"OK\");\n" + >+ " }\n" + >+ "}\n"}, >+ "OK"); >+} >+// passing null to nonnull parameter >+public void test_nonnull_parameter_003() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(@NonNull Object o) {\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ " void bar() {\n" + >+ " foo(null);\n" + >+ " }\n" + >+ "}\n"}, >+ "----------\n" + >+ "1. ERROR in X.java (at line 6)\n" + >+ " foo(null);\n" + >+ " ^^^^\n" + >+ "Null contract violation: passing null to a parameter declared as @NonNull.\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// passing potential null to nonnull parameter - target method is consumed from .class >+public void test_nonnull_parameter_004() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " void setObject(@NonNull Object o) { }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void bar(Lib l, boolean b) {\n" + >+ " Object o = null;\n" + >+ " if (b) o = new Object();\n" + >+ " l.setObject(o);\n" + >+ " }\n" + >+ "}\n"}, >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 5)\n" + >+ " l.setObject(o);\n" + >+ " ^\n" + >+ "Null contract violation: potentially passing null to a parameter declared as @NonNull.\n" + >+ "----------\n", >+ "",/* expected output */ >+ "",/* expected error */ >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// passing unknown value to nonnull parameter - target method is consumed from .class >+public void test_nonnull_parameter_005() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " void setObject(@NonNull Object o) { }\n" + >+ "}\n" >+ }); >+ runConformTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void bar(Lib l, Object o) {\n" + >+ " l.setObject(o);\n" + >+ " }\n" + >+ "}\n"}, >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. WARNING in X.java (at line 3)\n" + >+ " l.setObject(o);\n" + >+ " ^\n" + >+ "Potential null contract violation: insufficient nullness information regarding a value that is passed to a parameter declared as @NonNull.\n" + >+ "----------\n", >+ "",/* expected output */ >+ "",/* expected error */ >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a method tries to tighten the null contract, super declares parameter o as @Nullable >+// other parameters: s is redefined from not constrained to @Nullable which is OK >+// third is redefined from not constrained to @NonNull which is bad, too >+public void test_parameter_contract_inheritance_001() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " void foo(String s, @Nullable Object o, Object third) { }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " void foo(@Nullable String s, @NonNull Object o, @NonNull Object third) { System.out.print(o.toString()); }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " void foo(@Nullable String s, @NonNull Object o, @NonNull Object third) { System.out.print(o.toString()); }\n" + >+ " ^\n" + >+ "Cannot tighten null contract for parameter o, inherited method from Lib declares this parameter as @Nullable.\n" + >+ "----------\n" + >+ "2. ERROR in X.java (at line 3)\n" + >+ " void foo(@Nullable String s, @NonNull Object o, @NonNull Object third) { System.out.print(o.toString()); }\n" + >+ " ^^^^^\n" + >+ "Cannot tighten null contract for parameter third, inherited method from Lib does not constrain this parameter.\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a method body fails to handle the inherited null contract, super declares parameter as @Nullable >+public void test_parameter_contract_inheritance_002() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " void foo(@Nullable Object o) { }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " void foo(Object o) {\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 4)\n" + >+ " System.out.print(o.toString());\n" + >+ " ^\n" + >+ "Potential null pointer access: The variable o may be null at this location\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a method relaxes the parameter null contract, super declares parameter o as @NonNull >+// other (first) parameter just repeats the inherited @NonNull >+public void test_parameter_contract_inheritance_003() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " void foo(@NonNull String s, @NonNull Object o) { }\n" + >+ "}\n", >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " void foo(@NonNull String s, @Nullable Object o) { ; }\n" + >+ " void bar() { foo(\"OK\", null); }\n" + >+ "}\n" >+ }, >+ ""); >+} >+// a method adds a @NonNull annotation, super has no null annotation >+// changing other from unconstrained to @Nullable is OK >+public void test_parameter_contract_inheritance_004() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " void foo(Object o, Object other) { }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " void foo(@NonNull Object o, @Nullable Object other) { System.out.print(o.toString()); }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " void foo(@NonNull Object o, @Nullable Object other) { System.out.print(o.toString()); }\n" + >+ " ^\n" + >+ "Cannot tighten null contract for parameter o, inherited method from Lib does not constrain this parameter.\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a method tries to relax the null contract, super declares @NonNull return >+public void test_parameter_contract_inheritance_005() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " @NonNull Object getObject() { return new Object(); }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " @Nullable Object getObject() { return null; }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " @Nullable Object getObject() { return null; }\n" + >+ " ^^^^^^^^^^^\n" + >+ "Cannot relax null contract for method return, inherited method from Lib is declared as @NonNull.\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// super has no contraint for return, sub method confirms the null contract as @Nullable >+public void test_parameter_contract_inheritance_006() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " Object getObject() { return null; }\n" + >+ "}\n" >+ }); >+ runConformTest( >+ new String[] { >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " @Nullable Object getObject() { return null; }\n" + >+ "}\n" >+ }, >+ "", >+ null/*classLibs*/, >+ false /* flush output directory */, >+ null/*vmArguments*/, >+ null/*customOptions*/, >+ null/*compilerRequestor*/); >+} >+// a method body violates the inherited null contract, super declares @NonNull return >+public void test_parameter_contract_inheritance_007() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " @NonNull Object getObject() { return new Object(); }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X extends Lib {\n" + >+ " @Override\n" + >+ " Object getObject() { return null; }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " Object getObject() { return null; }\n" + >+ " ^^^^^^^^^^^^\n" + >+ "Null contract violation: returning null from a method declared as @NonNull.\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a nullable return value is dereferenced without a check >+public void test_nullable_return_001() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @Nullable Object getObject() { return null; }\n" + >+ " void foo() {\n" + >+ " Object o = getObject();\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 5)\n" + >+ " System.out.print(o.toString());\n" + >+ " ^\n" + >+ "Potential null pointer access: The variable o may be null at this location\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a nullable return value is dereferenced without a check, method is read from .class file >+public void test_nullable_return_002() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " @Nullable Object getObject() { return null; }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(Lib l) {\n" + >+ " Object o = l.getObject();\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 4)\n" + >+ " System.out.print(o.toString());\n" + >+ " ^\n" + >+ "Potential null pointer access: The variable o may be null at this location\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a non-null return value is checked for null, method is read from .class file >+public void test_nonnull_return_001() { >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " @NonNull Object getObject() { return new Object(); }\n" + >+ "}\n" >+ }); >+ runNegativeTest( >+ false /* flush output directory */, >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " void foo(Lib l) {\n" + >+ " Object o = l.getObject();\n" + >+ " if (o != null)\n" + >+ " System.out.print(o.toString());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ // compiler options >+ null /* no class libraries */, >+ null /* no custom options */, >+ "----------\n" + >+ "1. ERROR in X.java (at line 4)\n" + >+ " if (o != null)\n" + >+ " ^\n" + >+ "Redundant null check: The variable o cannot be null at this location\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a non-null method returns null >+public void test_nonnull_return_003() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @NonNull Object getObject(boolean b) {\n" + >+ " if (b)\n" + >+ " return null;\n" + // definite contract violation despite enclosing "if" >+ " return new Object();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 4)\n" + >+ " return null;\n" + >+ " ^^^^^^^^^^^^\n" + >+ "Null contract violation: returning null from a method declared as @NonNull.\n" + >+ "----------\n", >+ JavacTestOptions.Excuse.EclipseWarningConfiguredAsError); >+} >+// a non-null method potentially returns null >+public void test_nonnull_return_004() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @NonNull Object getObject(@Nullable Object o) {\n" + >+ " return o;\n" + // 'o' is only potentially null >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " return o;\n" + >+ " ^^^^^^^^^\n" + >+ "Null contract violation: return value can be null but method is declared as @NonNull.\n" + >+ "----------\n"); >+} >+// a non-null method returns its non-null argument >+public void test_nonnull_return_005() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ runConformTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @NonNull Object getObject(@NonNull Object o) {\n" + >+ " return o;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null/*classLibs*/, >+ true/*shouldFlushOutputDirectory*/, >+ null/*vmArguments*/, >+ customOptions, >+ null/*compilerRequestor*/); >+} >+//a non-null method has insufficient nullness info for its return value >+public void test_nonnull_return_006() { >+ runNegativeTest( >+ new String[] { >+ "X.java", >+ "public class X {\n" + >+ " @NonNull Object getObject(Object o) {\n" + >+ " return o;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. WARNING in X.java (at line 3)\n" + >+ " return o;\n" + >+ " ^^^^^^^^^\n" + >+ "Potential null contract violation: insufficient nullness information regarding return value while the method is declared as @NonNull.\n" + >+ "----------\n"); >+} >+// mixed use of fully qualified name / explicit import >+public void test_annotation_import_001() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.Nullable"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.NonNull"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.DISABLED); >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " @org.foo.NonNull Object getObject() { return new Object(); }\n" + // FQN >+ "}\n", >+ "X.java", >+ "import org.foo.NonNull;\n" + // explicit import >+ "public class X {\n" + >+ " @NonNull Object getObject(@NonNull Lib l) {\n" + >+ " return l.getObject();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null/*classLibs*/, >+ true/*shouldFlushOutputDirectory*/, >+ null/*vmArguments*/, >+ customOptions, >+ null/*compilerRequestor*/); >+} >+ >+// use of explicit imports throughout >+public void test_annotation_import_002() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.Nullable"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.NonNull"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.DISABLED); >+ runConformTest( >+ new String[] { >+ "Lib.java", >+ "import org.foo.NonNull;\n" + >+ "public class Lib {\n" + >+ " @NonNull Object getObject() { return new Object(); }\n" + >+ "}\n", >+ "X.java", >+ "import org.foo.NonNull;\n" + >+ "public class X {\n" + >+ " @NonNull Object getObject(@org.foo.Nullable String dummy, @NonNull Lib l) {\n" + >+ " Object o = l.getObject();" + >+ " return o;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null/*classLibs*/, >+ true/*shouldFlushOutputDirectory*/, >+ null/*vmArguments*/, >+ customOptions, >+ null/*compilerRequestor*/); >+} >+// default import plus explicit ones >+public void test_annotation_import_003() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.Nullable"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.NonNull"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ runConformTest( >+ new String[] { >+ "libpack/Lib.java", >+ "package libpack;\n" + >+ "public class Lib {\n" + >+ " public @NonNull Object getObject() { return new Object(); }\n" + >+ "}\n", >+ "X.java", >+ "import libpack.Lib;\n" + >+ "public class X {\n" + >+ " @NonNull Object getObject(@NonNull Lib l) {\n" + >+ " return l.getObject();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null/*classLibs*/, >+ true/*shouldFlushOutputDirectory*/, >+ null/*vmArguments*/, >+ customOptions, >+ null/*compilerRequestor*/); >+} >+// default import but unspecified annotation names >+public void test_annotation_import_004() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, null); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, null); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ runConformTest( >+ new String[] { >+ "libpack/Lib.java", >+ "package libpack;\n" + >+ "public class Lib {\n" + >+ " public @NonNull Object getObject() { return new Object(); }\n" + >+ "}\n", >+ "X.java", >+ "import libpack.Lib;\n" + >+ "public class X {\n" + >+ " @NonNull Object getObject(@NonNull Lib l) {\n" + >+ " return l.getObject();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null/*classLibs*/, >+ true/*shouldFlushOutputDirectory*/, >+ null/*vmArguments*/, >+ customOptions, >+ null/*compilerRequestor*/); >+} >+// default import of existing annotation types >+public void test_annotation_import_005() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.MayBeNull"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.MustNotBeNull"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ customOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.DISABLED); >+ runNegativeTest( >+ true/*shouldFlushOutputDirectory*/, >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " Object getObject() { return new Object(); }\n" + >+ "}\n", >+ "X.java", >+ "public class X {\n" + >+ " @MustNotBeNull Object getObject(@MustNotBeNull Lib l) {\n" + >+ " return l.getObject();\n" + >+ " }\n" + >+ "}\n", >+ >+ "org/foo/MayBeNull.java", >+ "package org.foo;\n" + >+ "import java.lang.annotation.*;\n" + >+ "@Retention(RetentionPolicy.CLASS)\n" + >+ "public @interface MayBeNull {}\n", >+ >+ "org/foo/MustNotBeNull.java", >+ "package org.foo;\n" + >+ "import java.lang.annotation.*;\n" + >+ "@Retention(RetentionPolicy.CLASS)\n" + >+ "public @interface MustNotBeNull {}\n", >+ }, >+ null/*classLibs*/, >+ customOptions, >+ "----------\n" + >+ "1. ERROR in X.java (at line 3)\n" + >+ " return l.getObject();\n" + >+ " ^^^^^^^^^^^^^^^^^^^^^\n" + >+ "Potential null contract violation: insufficient nullness information regarding return value while the method is declared as @MustNotBeNull.\n" + >+// "Potential null contract violation: insufficient nullness information for checking return value against declaration as @MustNotBeNull.\n" + >+ "----------\n", >+ JavacTestOptions.SKIP); >+} >+// a non-null method returns a value obtained from an unannotated method, default import of missing annotation types >+public void test_annotation_import_006() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_ReportNullContractInsufficientInfo, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.MayBeNull"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.MustNotBeNull"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ customOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.DISABLED); >+ runNegativeTest( >+ true/*shouldFlushOutputDirectory*/, >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " Object getObject() { return new Object(); }\n" + >+ "}\n", >+ "X.java", >+ "public class X {\n" + >+ " @MustNotBeNull Object getObject(@MustNotBeNull Lib l) {\n" + >+ " return l.getObject();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ null/*classLibs*/, >+ customOptions, >+ "----------\n" + >+ "1. ERROR in Lib.java (at line 0)\n" + >+ " public class Lib {\n" + >+ " ^\n" + >+ "Buildpath problem: the type org.foo.MayBeNull which is configured as a null annotation type cannot be resolved.\n" + >+ "----------\n", >+ JavacTestOptions.SKIP); >+} >+// emulation names conflict with existing types >+public void test_annotation_emulation_001() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "libpack.Lib"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "libpack.Lib"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.ENABLED); >+ runNegativeTest( >+ true/*shouldFlushOutputDirectory*/, >+ new String[] { >+ "libpack/Lib.java", >+ "package libpack;\n" + >+ "public class Lib {\n" + >+ "}\n", >+ }, >+ null/*classLibs*/, >+ customOptions, >+ "----------\n" + >+ "1. ERROR in libpack\\Lib.java (at line 0)\n" + >+ " package libpack;\n" + >+ " ^\n" + >+ "Buildpath problem: emulation of type libpack.Lib is requested (for null annotations) but a type of this name exists on the build path.\n" + >+ "----------\n", >+ JavacTestOptions.SKIP); >+} >+// regular use (explicit import/FQN) of existing annotation types (=no emulation) >+public void test_annotation_emulation_002() { >+ Map customOptions = getCompilerOptions(); >+ customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_ReportPotentialNullContractViolation, CompilerOptions.ERROR); >+ customOptions.put(CompilerOptions.OPTION_NullableAnnotationName, "org.foo.MayBeNull"); >+ customOptions.put(CompilerOptions.OPTION_NonNullAnnotationName, "org.foo.MustNotBeNull"); >+ customOptions.put(CompilerOptions.OPTION_DefaultImportNullAnnotationTypes, CompilerOptions.DISABLED); >+ customOptions.put(CompilerOptions.OPTION_EmulateNullAnnotationTypes, CompilerOptions.DISABLED); >+ runNegativeTest( >+ true/*shouldFlushOutputDirectory*/, >+ new String[] { >+ "Lib.java", >+ "public class Lib {\n" + >+ " @org.foo.MayBeNull Object getObject() { return new Object(); }\n" + // FQN >+ "}\n", >+ "X.java", >+ "import org.foo.MustNotBeNull;\n" + // explicit import >+ "public class X {\n" + >+ " @MustNotBeNull Object getObject(@MustNotBeNull Lib l) {\n" + >+ " return l.getObject();\n" + >+ " }\n" + >+ "}\n", >+ >+ "org/foo/MayBeNull.java", >+ "package org.foo;\n" + >+ "import java.lang.annotation.*;\n" + >+ "@Retention(RetentionPolicy.CLASS)\n" + >+ "public @interface MayBeNull {}\n", >+ >+ "org/foo/MustNotBeNull.java", >+ "package org.foo;\n" + >+ "import java.lang.annotation.*;\n" + >+ "@Retention(RetentionPolicy.CLASS)\n" + >+ "public @interface MustNotBeNull {}\n", >+ }, >+ null/*classLibs*/, >+ customOptions, >+ "----------\n" + >+ "1. ERROR in X.java (at line 4)\n" + >+ " return l.getObject();\n" + >+ " ^^^^^^^^^^^^^^^^^^^^^\n" + >+ "Null contract violation: return value can be null but method is declared as @MustNotBeNull.\n" + >+ "----------\n", >+ JavacTestOptions.SKIP); >+} >+ >+} >Index: src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java,v >retrieving revision 1.88 >diff -u -r1.88 TestAll.java >--- src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java 1 Oct 2010 21:09:57 -0000 1.88 >+++ src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java 13 Jan 2011 22:59:47 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2010 IBM Corporation and others. >+ * Copyright (c) 2000, 2011 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,6 +7,7 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * Stephan Herrmann - Contribution for bug 186342 - [compiler][null]Using annotations for null checking > *******************************************************************************/ > package org.eclipse.jdt.core.tests.compiler.regression; > >@@ -63,6 +64,7 @@ > if (UnconditionalFlowInfo.COVERAGE_TEST_FLAG) { > standardTests.add(NullReferenceImplTests.class); > } >+ standardTests.add(NullAnnotationTest.class); > standardTests.add(CompilerInvocationTests.class); > standardTests.add(InnerEmulationTest.class); > standardTests.add(SuperTypeTest.class);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 186342
:
74851
|
86246
|
86247
|
89354
|
184335
|
185507
|
186796
|
186798
|
186872
|
186876
|
186889
|
186890
|
206525
|
206557
|
207270
|
207308
|
207478
|
207565
|
207567
|
207573
|
207592
|
207604
|
207635
|
207637
|
207639
|
207657
|
207659
|
207672
|
207677
|
207685