Index: compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java,v retrieving revision 1.62 diff -u -r1.62 LocalDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 28 Oct 2006 04:11:27 -0000 1.62 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 28 Jul 2007 11:21:59 -0000 @@ -62,6 +62,8 @@ default: flowInfo.markAsDefinitelyUnknown(this.binding); } + if (isNonNullAnnotated(currentScope, binding.getAnnotations()) && nullStatus != FlowInfo.NON_NULL) + binding.declaringScope.problemReporter().localCannotBeAssignedWithPotentiallyNull(binding, initialization); // no need to inform enclosing try block since its locals won't get // known by the finally block } Index: compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java,v retrieving revision 1.69 diff -u -r1.69 EqualExpression.java --- compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java 19 Jul 2007 14:04:59 -0000 1.69 +++ compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java 28 Jul 2007 11:21:58 -0000 @@ -28,10 +28,33 @@ if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, right.nullStatus(flowInfo), this.left); } + // TODO: if allowed, simpler check would be for left and right nullStatus equality (for != UNKNOW) + Expression tmp = left; + while (tmp instanceof CastExpression) + tmp = ((CastExpression)tmp).expression; + if (tmp instanceof MessageSend) { + MessageSend ms = (MessageSend)tmp; + int rightNullStatus = right.nullStatus(flowInfo); + if ((rightNullStatus == FlowInfo.NULL + || rightNullStatus == FlowInfo.NON_NULL) + && isNonNullAnnotated(scope, ms.binding.getAnnotations())) + scope.problemReporter().cannotReturnPotentiallyNullExpression(left); + } local = this.right.localVariableBinding(); if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, left.nullStatus(flowInfo), this.right); } + tmp = right; + while (tmp instanceof CastExpression) + tmp = ((CastExpression)tmp).expression; + if (tmp instanceof MessageSend) { + MessageSend ms = (MessageSend)tmp; + int rightNullStatus = left.nullStatus(flowInfo); + if ((rightNullStatus == FlowInfo.NULL + || rightNullStatus == FlowInfo.NON_NULL) + && isNonNullAnnotated(scope, ms.binding.getAnnotations())) + scope.problemReporter().cannotReturnPotentiallyNullExpression(right); + } } private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) { switch (nullStatus) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java,v retrieving revision 1.84 diff -u -r1.84 ASTNode.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java 22 Jun 2007 15:50:14 -0000 1.84 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java 28 Jul 2007 11:21:56 -0000 @@ -15,7 +15,9 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; import org.eclipse.jdt.internal.compiler.ASTVisitor; public abstract class ASTNode implements TypeConstants, TypeIds { @@ -711,6 +713,30 @@ } } +/** + * Return true if ab contains + * a non-null annotation. + */ +public static boolean isNonNullAnnotated(Scope currentScope, AnnotationBinding[] ab) { + if (ab == null || ab.length == 0) + return false; + if (currentScope.compilerOptions().getSeverity(CompilerOptions.NullReference) != ProblemSeverities.Ignore) { + // TODO: use lazy creation + char[][] annotations = CharOperation.splitOn(';', currentScope.compilerOptions().nonNullAnnotations.toCharArray()); + for (int i = 0; i < ab.length; i++) { + if (ab[i] != null) { + for (int j = 0; j < annotations.length; j++) { + char[] annotation = ab[i].getAnnotationType().readableName(); + if (CharOperation.compareTo(annotation, annotations[j]) == 0) { + return true; + } + } + } + } + } + return false; +} + public int sourceStart() { return this.sourceStart; } 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.122 diff -u -r1.122 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 26 Apr 2007 21:03:26 -0000 1.122 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 28 Jul 2007 11:22:00 -0000 @@ -55,6 +55,8 @@ public TypeReference[] typeArguments; public TypeBinding[] genericTypeArguments; + private boolean isReturnValueNonNull = false; + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { boolean nonStatic = !this.binding.isStatic(); @@ -67,6 +69,11 @@ int length = this.arguments.length; for (int i = 0; i < length; i++) { flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); + + if (arguments[i].nullStatus(flowInfo) != FlowInfo.NON_NULL + && isNonNullAnnotated(currentScope, binding.getParameterAnnotations(i))) { + currentScope.problemReporter().cannotPassPotentiallyNullExpressionAsArgument(binding, arguments[i]); + } } } ReferenceBinding[] thrownExceptions; @@ -254,6 +261,8 @@ } } public int nullStatus(FlowInfo flowInfo) { + if (isReturnValueNonNull) + return FlowInfo.NON_NULL; return FlowInfo.UNKNOWN; } @@ -513,6 +522,10 @@ } } } + + if (isNonNullAnnotated(scope, binding.getAnnotations())) + isReturnValueNonNull = true; + return this.resolvedType; } 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.61 diff -u -r1.61 MethodDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 17 Jul 2007 15:48:43 -0000 1.61 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 28 Jul 2007 11:22:01 -0000 @@ -20,6 +20,8 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; @@ -67,6 +69,37 @@ if (binding.isAbstract() || binding.isNative()) return; + boolean[] argumentIsNonNull = null; + if (arguments != null) + argumentIsNonNull = new boolean[arguments.length]; + + ReferenceBinding declaringClassRef = binding.declaringClass; + + if ((returnType.bits & TagBits.IsBaseType) == 0) { + + ReferenceBinding type = isOverriddenMethodNonNullAnnotated(declaringClassRef, -1, classScope); + if (type != null && !isNonNullAnnotated(classScope, binding.getAnnotations())) + classScope.problemReporter().nonNullAnnotationIsMissingForOverridingMethod(type, binding, this); + } + + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + ReferenceBinding type = isOverriddenMethodNonNullAnnotated(declaringClassRef, i, classScope); + boolean argIsNonNull = isNonNullAnnotated(classScope, binding.getParameterAnnotations(i)); + if (type != null && !argIsNonNull) + classScope.problemReporter().nonNullAnnotationIsMissingForArgumentInOverridingMethod(type, binding, arguments[i]); + + argumentIsNonNull[i] = type != null || argIsNonNull; + } + } + + if (argumentIsNonNull != null) { + for (int i = 0; i < argumentIsNonNull.length; i++) { + if (!argumentIsNonNull[i] && isNonNullAnnotated(classScope, binding.getParameterAnnotations(i))) + argumentIsNonNull[i] = true; + } + } + ExceptionHandlingFlowContext methodContext = new ExceptionHandlingFlowContext( initializationContext, @@ -79,6 +112,8 @@ if (this.arguments != null) { for (int i = 0, count = this.arguments.length; i < count; i++) { flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding); + if (argumentIsNonNull[i]) + flowInfo.markAsDefinitelyNonNull(this.arguments[i].binding); } } // propagate to statements @@ -111,6 +146,77 @@ } } + + /** + * Check all the overridden methods (super classes and interfaces) + * searching for NonNull annotation. Return the first type which + * contains an annotated overridden method. + * + * @param declaringClassRef the base type + * @param argument if positive, search annotations on parameters, else + * search on method + * @param classScope + * @return the type containing the overridden and annotated method + * or null + */ + public ReferenceBinding isOverriddenMethodNonNullAnnotated(ReferenceBinding declaringClassRef, int argument, ClassScope classScope) { + if (declaringClassRef == null) + return null; + + if (binding.isPrivate() || binding.isConstructor()) + return null; + + ReferenceBinding superClassRef = declaringClassRef.superclass(); + if (superClassRef != null) { + MethodBinding mb = superClassRef.getExactMethod(selector, binding.parameters, classScope.compilationUnitScope()); + + if (mb != null) { + boolean nonNullAnnotated; + if (argument < 0) + nonNullAnnotated = isNonNullAnnotated(classScope, mb.getAnnotations()); + else + nonNullAnnotated = isNonNullAnnotated(classScope, mb.getParameterAnnotations(argument)); + + // if an annotation is found, returns + if (nonNullAnnotated) + return superClassRef; + } else { + ReferenceBinding type = isOverriddenMethodNonNullAnnotated(superClassRef, argument, classScope); + if (type != null) + return type; + } + } + + // if an overridden method have been found, but it was not annotated + // the check continues through the interfaces + + ReferenceBinding[] superInterfacesRef = declaringClassRef.superInterfaces(); + if (superInterfacesRef != null) { + for (int i = 0; i < superInterfacesRef.length; i++) { + if (superInterfacesRef[i] != null) { + MethodBinding mb = superInterfacesRef[i].getExactMethod(selector, binding.parameters, classScope.compilationUnitScope()); + + if (mb != null) { + boolean nonNullAnnotated; + if (argument < 0) + nonNullAnnotated = isNonNullAnnotated(classScope, mb.getAnnotations()); + else + nonNullAnnotated = isNonNullAnnotated(classScope, mb.getParameterAnnotations(argument)); + + if (nonNullAnnotated) + return superInterfacesRef[i]; + } else { + ReferenceBinding type = isOverriddenMethodNonNullAnnotated(superInterfacesRef[i], argument, classScope); + if (type != null) + return type; + } + } + } + } + + return null; + } + public boolean isMethod() { return true; 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.59 diff -u -r1.59 ReturnStatement.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 19 Jul 2007 14:05:58 -0000 1.59 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java 28 Jul 2007 11:22:02 -0000 @@ -37,6 +37,14 @@ if (this.expression != null) { flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); + + AbstractMethodDeclaration methodDecl = currentScope.methodScope().referenceMethod(); + MethodBinding methodBinding = methodDecl.binding; + + if ((methodBinding.returnType.tagBits & TagBits.IsBaseType) == 0 + && expression.nullStatus(flowInfo) != FlowInfo.NON_NULL + && isNonNullAnnotated(currentScope, methodBinding.getAnnotations())) + currentScope.problemReporter().cannotReturnPotentiallyNullExpression(expression); } this.initStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); Index: compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java,v retrieving revision 1.78 diff -u -r1.78 Assignment.java --- compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 6 Mar 2007 02:38:48 -0000 1.78 +++ compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java 28 Jul 2007 11:21:56 -0000 @@ -22,7 +22,8 @@ public Expression lhs; public Expression expression; - + private boolean isNonNull; + public Assignment(Expression lhs, Expression expression, int sourceEnd) { //lhs is always a reference by construction , //but is build as an expression ==> the checkcast cannot fail @@ -31,8 +32,10 @@ this.expression = expression; this.sourceStart = lhs.sourceStart; this.sourceEnd = sourceEnd; + this.isNonNull = false; } + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // record setting a variable: various scenarii are possible, setting an array reference, // a field reference, a blank final field reference, a field of an enclosing instance or @@ -44,6 +47,8 @@ flowContext.recordUsingNullReference(currentScope, local, this.lhs, FlowContext.CAN_ONLY_NULL | FlowContext.IN_ASSIGNMENT, flowInfo); } + if (isNonNull && nullStatus != FlowInfo.NON_NULL) + local.declaringScope.problemReporter().localCannotBeAssignedWithPotentiallyNull(local, expression); } flowInfo = ((Reference) lhs) .analyseAssignment(currentScope, flowContext, flowInfo, this, false) @@ -57,7 +62,10 @@ flowInfo.markAsDefinitelyNonNull(local); break; default: - flowInfo.markAsDefinitelyUnknown(local); + if (isNonNull) + flowInfo.markAsDefinitelyNonNull(local); + else + flowInfo.markAsDefinitelyUnknown(local); } if (flowContext.initsOnFinally != null) { switch(nullStatus) { @@ -68,7 +76,10 @@ flowContext.initsOnFinally.markAsDefinitelyNonNull(local); break; default: - flowContext.initsOnFinally.markAsDefinitelyUnknown(local); + if (isNonNull) + flowContext.initsOnFinally.markAsDefinitelyNonNull(local); + else + flowContext.initsOnFinally.markAsDefinitelyUnknown(local); } } } @@ -146,6 +157,8 @@ } public int nullStatus(FlowInfo flowInfo) { + if (isNonNull) + return FlowInfo.NON_NULL; return this.expression.nullStatus(flowInfo); } @@ -192,6 +205,13 @@ scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName()); } + // check for NonNull annotation + LocalVariableBinding local = this.lhs.localVariableBinding(); + if (local != null && local.kind() == Binding.LOCAL + && (local.type.tagBits & TagBits.IsBaseType) == 0) { + isNonNull = isNonNullAnnotated(scope, local.getAnnotations()); + } + // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character // may require to widen the rhs expression at runtime if (lhsType != rhsType) // must call before computeConversion() and typeMismatchError() 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.190 diff -u -r1.190 IProblem.java --- compiler/org/eclipse/jdt/core/compiler/IProblem.java 11 Jul 2007 13:47:21 -0000 1.190 +++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 28 Jul 2007 11:21:54 -0000 @@ -1275,4 +1275,11 @@ // associated with it /** @since 3.2 */ int ExternalProblemFixable = 901; + + int LocalCannotBeAssignedPotentiallyNull = Internal + 903; + int CannotPassPotentiallyNullExpressionAsArgument = Internal + 904; + int CannotReturnPotentiallyNullExpression = Internal + 905; + int NonNullAnnotationIsMissingForOverridingMethod = Internal + 906; + int NonNullAnnotationIsMissingForArgumentInOverridingMethod = Internal + 907; + } 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.221 diff -u -r1.221 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 11 Jul 2007 13:40:49 -0000 1.221 +++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 28 Jul 2007 11:22:25 -0000 @@ -587,3 +587,10 @@ 857 = Incorrect number of type arguments for generic constructor <{3}>{0}({1}) of type {2}; it cannot be parameterized with arguments <{4}> 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}> + +### @NonNull annotation +903 = Cannot assign null or potentially null expression to {0} because of @NonNull annotation +904 = Cannot pass null or potentially null expression as argument for method {0} because of @NonNull annotation +905 = Cannot return null or potentially null expression because of @NonNull annotation +906 = Method {1} isn't NonNull annotated while overridden method in {0} is +907 = Argument {2} in method {1} isn't NonNull annotated while overridden method in type {0} is 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.351 diff -u -r1.351 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 19 Jul 2007 14:07:25 -0000 1.351 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 28 Jul 2007 11:22:23 -0000 @@ -293,6 +293,13 @@ case IProblem.OverridingMethodWithoutSuperInvocation: return CompilerOptions.OverridingMethodWithoutSuperInvocation; + + case IProblem.LocalCannotBeAssignedPotentiallyNull: + case IProblem.CannotReturnPotentiallyNullExpression: + case IProblem.CannotPassPotentiallyNullExpressionAsArgument: + case IProblem.NonNullAnnotationIsMissingForOverridingMethod: + case IProblem.NonNullAnnotationIsMissingForArgumentInOverridingMethod: + return CompilerOptions.NullReference; } return 0; } @@ -4460,6 +4467,66 @@ nodeSourceStart(local, location), nodeSourceEnd(local, location)); } +public void localCannotBeAssignedWithPotentiallyNull(LocalVariableBinding local, ASTNode location) { + int severity = computeSeverity(IProblem.LocalCannotBeAssignedPotentiallyNull); + if (severity == ProblemSeverities.Ignore) return; + String[] arguments = new String[] { new String(local.name) }; + this.handle( + IProblem.LocalCannotBeAssignedPotentiallyNull, + arguments, + arguments, + severity, + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); +} +public void cannotReturnPotentiallyNullExpression(ASTNode location) { + int severity = computeSeverity(IProblem.CannotReturnPotentiallyNullExpression); + if (severity == ProblemSeverities.Ignore) return; + String[] arguments = new String[] { }; + this.handle( + IProblem.CannotReturnPotentiallyNullExpression, + arguments, + arguments, + severity, + location.sourceStart, + location.sourceEnd); +} +public void nonNullAnnotationIsMissingForOverridingMethod(ReferenceBinding type, MethodBinding method, ASTNode location) { + int severity = computeSeverity(IProblem.NonNullAnnotationIsMissingForOverridingMethod); + if (severity == ProblemSeverities.Ignore) return; + String[] arguments = new String[] { new String(type.readableName()), new String(method.readableName()) }; + this.handle( + IProblem.NonNullAnnotationIsMissingForOverridingMethod, + arguments, + arguments, + severity, + location.sourceStart, + location.sourceEnd); +} +public void nonNullAnnotationIsMissingForArgumentInOverridingMethod(ReferenceBinding type, MethodBinding method, Argument arg) { + int severity = computeSeverity(IProblem.NonNullAnnotationIsMissingForArgumentInOverridingMethod); + if (severity == ProblemSeverities.Ignore) return; + String[] arguments = new String[] { new String(type.readableName()), new String(method.readableName()), new String(arg.name) }; + this.handle( + IProblem.NonNullAnnotationIsMissingForArgumentInOverridingMethod, + arguments, + arguments, + severity, + arg.sourceStart, + arg.sourceEnd); +} +public void cannotPassPotentiallyNullExpressionAsArgument(MethodBinding method, ASTNode location) { + int severity = computeSeverity(IProblem.CannotPassPotentiallyNullExpressionAsArgument); + if (severity == ProblemSeverities.Ignore) return; + String[] arguments = new String[] { new String(method.readableName()) }; + this.handle( + IProblem.CannotPassPotentiallyNullExpressionAsArgument, + arguments, + arguments, + severity, + nodeSourceStart(method, location), + nodeSourceEnd(method, location)); +} public void localVariableNullComparedToNonNull(LocalVariableBinding local, ASTNode location) { int severity = computeSeverity(IProblem.NullLocalVariableComparisonYieldsFalse); if (severity == ProblemSeverities.Ignore) return; 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.184 diff -u -r1.184 CompilerOptions.java --- compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 7 May 2007 17:01:22 -0000 1.184 +++ compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 28 Jul 2007 11:22:07 -0000 @@ -113,6 +113,7 @@ public static final String OPTION_ReportOverridingMethodWithoutSuperInvocation = "org.eclipse.jdt.core.compiler.problem.overridingMethodWithoutSuperInvocation"; //$NON-NLS-1$ public static final String OPTION_GenerateClassFiles = "org.eclipse.jdt.core.compiler.generateClassFiles"; //$NON-NLS-1$ public static final String OPTION_Process_Annotations = "org.eclipse.jdt.core.compiler.processAnnotations"; //$NON-NLS-1$ + public static final String OPTION_NonNullAnnotations = "org.eclipse.jdt.core.compiler.nonNullAnnotations"; //$NON-NLS-1$ // Backward compatibility public static final String OPTION_ReportInvalidAnnotation = "org.eclipse.jdt.core.compiler.problem.invalidAnnotation"; //$NON-NLS-1$ @@ -199,7 +200,7 @@ public static final long OverridingMethodWithoutSuperInvocation = ASTNode.Bit50L; public static final long PotentialNullReference = ASTNode.Bit51L; public static final long RedundantNullCheck = ASTNode.Bit52L; - + // Map: String optionKey --> Long irritant> private static Map OptionToIrritants; @@ -320,6 +321,9 @@ // Enable annotation processing by default only in batch mode public boolean processAnnotations = false; + // annotations list for null checks (separator is ';') + public String nonNullAnnotations = "org.NonNull;edu.umd.cs.findbugs.annotations.NonNull"; //$NON-NLS-1$ + /** * Initializing the compiler options with defaults */ @@ -434,6 +438,7 @@ optionsMap.put(OPTION_ReportOverridingMethodWithoutSuperInvocation, getSeverityString(OverridingMethodWithoutSuperInvocation)); optionsMap.put(OPTION_GenerateClassFiles, this.generateClassFiles ? ENABLED : DISABLED); optionsMap.put(OPTION_Process_Annotations, this.processAnnotations ? ENABLED : DISABLED); + optionsMap.put(OPTION_NonNullAnnotations, this.nonNullAnnotations); return optionsMap; } @@ -926,6 +931,9 @@ this.storeAnnotations = false; } } + if ((optionValue = optionsMap.get(OPTION_NonNullAnnotations)) != null) { + this.nonNullAnnotations = (String)optionValue; + } } public String toString() { @@ -1010,6 +1018,7 @@ buf.append("\n\t- parameter assignment: ").append(getSeverityString(ParameterAssignment)); //$NON-NLS-1$ buf.append("\n\t- generate class files: ").append(this.generateClassFiles ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- process annotations: ").append(this.processAnnotations ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- non null annotations list (';'): ").append(this.nonNullAnnotations); //$NON-NLS-1$ return buf.toString(); }