diff options
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java')
-rw-r--r-- | org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java | 188 |
1 files changed, 177 insertions, 11 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 5765e0bcf..9afa1200f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -22,6 +22,10 @@ * bug 374605 - Unreasonable warning for enum-based switch statements * bug 388281 - [compiler][null] inheritance of null annotations as an option * bug 376053 - [compiler][resource] Strange potential resource leak problems + * bug 381443 - [compiler][null] Allow parameter widening from @NonNull to unannotated + * bug 393719 - [compiler] inconsistent warnings on iteration variables + * bug 331649 - [compiler][null] consider null annotations for fields + * bug 382789 - [compiler][null] warn when syntactically-nonnull expression is compared against null *******************************************************************************/ package org.eclipse.jdt.internal.compiler.problem; @@ -50,6 +54,7 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ArrayReference; import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; @@ -81,6 +86,7 @@ import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NameReference; +import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; @@ -318,6 +324,7 @@ public static int getIrritant(int problemID) { case IProblem.UnsafeRawConstructorInvocation: case IProblem.UnsafeRawMethodInvocation: case IProblem.UnsafeTypeConversion: + case IProblem.UnsafeElementTypeConversion: case IProblem.UnsafeRawFieldAssignment: case IProblem.UnsafeGenericCast: case IProblem.UnsafeReturnTypeOverride: @@ -356,6 +363,7 @@ public static int getIrritant(int problemID) { return CompilerOptions.VarargsArgumentNeedCast; case IProblem.NullLocalVariableReference: + case IProblem.NullableFieldReference: return CompilerOptions.NullReference; case IProblem.PotentialNullLocalVariableReference: @@ -368,9 +376,14 @@ public static int getIrritant(int problemID) { case IProblem.NonNullLocalVariableComparisonYieldsFalse: case IProblem.NullLocalVariableComparisonYieldsFalse: case IProblem.NullLocalVariableInstanceofYieldsFalse: + case IProblem.RedundantNullCheckOnNonNullExpression: + case IProblem.NonNullExpressionComparisonYieldsFalse: case IProblem.RedundantNullCheckOnNonNullMessageSend: case IProblem.RedundantNullCheckOnSpecdNonNullLocalVariable: case IProblem.SpecdNonNullLocalVariableComparisonYieldsFalse: + case IProblem.NonNullMessageSendComparisonYieldsFalse: + case IProblem.RedundantNullCheckOnNonNullSpecdField: + case IProblem.NonNullSpecdFieldComparisonYieldsFalse: return CompilerOptions.RedundantNullCheck; case IProblem.RequiredNonNullButProvidedNull: @@ -378,13 +391,17 @@ public static int getIrritant(int problemID) { case IProblem.IllegalReturnNullityRedefinition: case IProblem.IllegalRedefinitionToNonNullParameter: case IProblem.IllegalDefinitionToNonNullParameter: - case IProblem.ParameterLackingNonNullAnnotation: case IProblem.ParameterLackingNullableAnnotation: case IProblem.CannotImplementIncompatibleNullness: + case IProblem.UninitializedNonNullField: + case IProblem.UninitializedNonNullFieldHintMissingDefault: case IProblem.ConflictingNullAnnotations: case IProblem.ConflictingInheritedNullAnnotations: return CompilerOptions.NullSpecViolation; + case IProblem.ParameterLackingNonNullAnnotation: + return CompilerOptions.NonnullParameterAnnotationDropped; + case IProblem.RequiredNonNullButProvidedPotentialNull: return CompilerOptions.NullAnnotationInferenceConflict; case IProblem.RequiredNonNullButProvidedUnknown: @@ -787,6 +804,7 @@ public static int getProblemCategory(int severity, int problemID) { case CompilerOptions.NullAnnotationInferenceConflict : case CompilerOptions.NullUncheckedConversion : case CompilerOptions.MissingNonNullByDefaultAnnotation: + case CompilerOptions.NonnullParameterAnnotationDropped: return CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM; case CompilerOptions.RedundantNullAnnotation : return CategorizedProblem.CAT_UNNECESSARY_CODE; @@ -5744,6 +5762,92 @@ public void localVariableNullComparedToNonNull(LocalVariableBinding local, ASTNo nodeSourceEnd(local, location)); } +/** + * @param expr expression being compared for null or nonnull + * @param checkForNull true if checking for null, false if checking for nonnull + */ +public boolean expressionNonNullComparison(Expression expr, boolean checkForNull) { + int problemId = 0; + Binding binding = null; + String[] arguments = null; + int start = 0, end = 0; + + Expression location = expr; + // unwrap uninteresting nodes: + while (true) { + if (expr instanceof Assignment) + return false; // don't report against the assignment, but the variable + else if (expr instanceof CastExpression) + expr = ((CastExpression) expr).expression; + else + break; + } + // check all those kinds of expressions that can possible answer NON_NULL from nullStatus(): + if (expr instanceof MessageSend) { + problemId = checkForNull + ? IProblem.NonNullMessageSendComparisonYieldsFalse + : IProblem.RedundantNullCheckOnNonNullMessageSend; + MethodBinding method = ((MessageSend)expr).binding; + binding = method; + arguments = new String[] { new String(method.shortReadableName()) }; + start = location.sourceStart; + end = location.sourceEnd; + } else if (expr instanceof Reference && !(expr instanceof ThisReference) && !(expr instanceof ArrayReference)) { + FieldBinding field = ((Reference)expr).lastFieldBinding(); + if (field == null) { + return false; + } + if (field.isNonNull()) { + problemId = checkForNull + ? IProblem.NonNullSpecdFieldComparisonYieldsFalse + : IProblem.RedundantNullCheckOnNonNullSpecdField; + char[][] nonNullName = this.options.nonNullAnnotationName; + arguments = new String[] { new String(field.name), + new String(nonNullName[nonNullName.length-1]) }; + } + binding = field; + start = nodeSourceStart(binding, location); + end = nodeSourceEnd(binding, location); + } else if (expr instanceof AllocationExpression + || expr instanceof ArrayAllocationExpression + || expr instanceof ArrayInitializer + || expr instanceof ClassLiteralAccess + || expr instanceof ThisReference) { + // fall through to bottom + } else if (expr instanceof Literal + || expr instanceof ConditionalExpression) { + if (expr instanceof NullLiteral) { + needImplementation(location); // reported as nonnull?? + return false; + } + if (expr.resolvedType != null && expr.resolvedType.isBaseType()) { + // false alarm, auto(un)boxing is involved + return false; + } + // fall through to bottom + } else if (expr instanceof BinaryExpression) { + if ((expr.bits & ASTNode.ReturnTypeIDMASK) != TypeIds.T_JavaLangString) { + // false alarm, primitive types involved, must be auto(un)boxing? + return false; + } + // fall through to bottom + } else { + needImplementation(expr); // want to see if we get here + return false; + } + if (problemId == 0) { + // standard case, fill in details now + problemId = checkForNull + ? IProblem.NonNullExpressionComparisonYieldsFalse + : IProblem.RedundantNullCheckOnNonNullExpression; + start = location.sourceStart; + end = location.sourceEnd; + arguments = NoArgument; + } + this.handle(problemId, arguments, arguments, start, end); + return true; +} + public void localVariableNullInstanceof(LocalVariableBinding local, ASTNode location) { int severity = computeSeverity(IProblem.NullLocalVariableInstanceofYieldsFalse); if (severity == ProblemSeverities.Ignore) return; @@ -5799,6 +5903,18 @@ public void localVariablePotentialNullReference(LocalVariableBinding local, ASTN nodeSourceEnd(local, location)); } +public void nullableFieldDereference(VariableBinding variable, long position) { + String[] arguments = new String[] {new String(variable.name)}; + char[][] nullableName = this.options.nullableAnnotationName; + arguments = new String[] {new String(variable.name), new String(nullableName[nullableName.length-1])}; + this.handle( + IProblem.NullableFieldReference, + arguments, + arguments, + (int)(position >>> 32), + (int)(position)); +} + public void localVariableRedundantCheckOnNonNull(LocalVariableBinding local, ASTNode location) { int severity = computeSeverity(IProblem.RedundantNullCheckOnNonNullLocalVariable); if (severity == ProblemSeverities.Ignore) return; @@ -7947,6 +8063,19 @@ public void uninitializedBlankFinalField(FieldBinding field, ASTNode location) { nodeSourceStart(field, location), nodeSourceEnd(field, location)); } +public void uninitializedNonNullField(FieldBinding field, ASTNode location) { + char[][] nonNullAnnotationName = this.options.nonNullAnnotationName; + String[] arguments = new String[] { + new String(nonNullAnnotationName[nonNullAnnotationName.length-1]), + new String(field.readableName()) + }; + this.handle( + methodHasMissingSwitchDefault() ? IProblem.UninitializedNonNullFieldHintMissingDefault : IProblem.UninitializedNonNullField, + arguments, + arguments, + nodeSourceStart(field, location), + nodeSourceEnd(field, location)); +} public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location) { binding.tagBits |= TagBits.NotInitialized; String[] arguments = new String[] {new String(binding.readableName())}; @@ -8334,6 +8463,21 @@ public void unsafeTypeConversion(Expression expression, TypeBinding expressionTy expression.sourceStart, expression.sourceEnd); } +public void unsafeElementTypeConversion(Expression expression, TypeBinding expressionType, TypeBinding expectedType) { + if (this.options.sourceLevel < ClassFileConstants.JDK1_5) return; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=305259 + int severity = computeSeverity(IProblem.UnsafeElementTypeConversion); + if (severity == ProblemSeverities.Ignore) return; + if (!this.options.reportUnavoidableGenericTypeProblems && expression.forcedToBeRaw(this.referenceContext)) { + return; + } + this.handle( + IProblem.UnsafeElementTypeConversion, + new String[] { new String(expressionType.readableName()), new String(expectedType.readableName()), new String(expectedType.erasure().readableName()) }, + new String[] { new String(expressionType.shortReadableName()), new String(expectedType.shortReadableName()), new String(expectedType.erasure().shortReadableName()) }, + severity, + expression.sourceStart, + expression.sourceEnd); +} public void unusedArgument(LocalDeclaration localDecl) { int severity = computeSeverity(IProblem.ArgumentIsNeverUsed); if (severity == ProblemSeverities.Ignore) return; @@ -8970,14 +9114,13 @@ public void nullityMismatch(Expression expression, TypeBinding providedType, Typ return; } if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) { - if (expression instanceof SingleNameReference) { - SingleNameReference snr = (SingleNameReference) expression; - if (snr.binding instanceof LocalVariableBinding) { - if (((LocalVariableBinding)snr.binding).isNullable()) { - nullityMismatchSpecdNullable(expression, requiredType, annotationName); - return; - } - } + VariableBinding var = expression.localVariableBinding(); + if (var == null && expression instanceof Reference) { + var = ((Reference)expression).lastFieldBinding(); + } + if (var != null && var.isNullable()) { + nullityMismatchSpecdNullable(expression, requiredType, annotationName); + return; } nullityMismatchPotentiallyNull(expression, requiredType, annotationName); return; @@ -12666,14 +12809,30 @@ public void illegalRedefinitionToNonNullParameter(Argument argument, ReferenceBi argument.type.sourceEnd); } } -public void parameterLackingNullAnnotation(Argument argument, ReferenceBinding declaringClass, boolean needNonNull, char[][] inheritedAnnotationName) { +public void parameterLackingNullableAnnotation(Argument argument, ReferenceBinding declaringClass, char[][] inheritedAnnotationName) { this.handle( - needNonNull ? IProblem.ParameterLackingNonNullAnnotation : IProblem.ParameterLackingNullableAnnotation, + IProblem.ParameterLackingNullableAnnotation, 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.type.sourceStart, argument.type.sourceEnd); } +public void parameterLackingNonnullAnnotation(Argument argument, ReferenceBinding declaringClass, char[][] inheritedAnnotationName) { + int sourceStart = 0, sourceEnd = 0; + if (argument != null) { + sourceStart = argument.type.sourceStart; + sourceEnd = argument.type.sourceEnd; + } else if (this.referenceContext instanceof TypeDeclaration) { + sourceStart = ((TypeDeclaration) this.referenceContext).sourceStart; + sourceEnd = ((TypeDeclaration) this.referenceContext).sourceEnd; + } + this.handle( + IProblem.ParameterLackingNonNullAnnotation, + new String[] { new String(declaringClass.readableName()), CharOperation.toString(inheritedAnnotationName)}, + new String[] { new String(declaringClass.shortReadableName()), new String(inheritedAnnotationName[inheritedAnnotationName.length-1])}, + sourceStart, + sourceEnd); +} public void illegalReturnRedefinition(AbstractMethodDeclaration abstractMethodDecl, MethodBinding inheritedMethod, char[][] nonNullAnnotationName) { MethodDeclaration methodDecl = (MethodDeclaration) abstractMethodDecl; StringBuffer methodSignature = new StringBuffer(); @@ -12758,6 +12917,13 @@ public void nullAnnotationIsRedundant(AbstractMethodDeclaration sourceMethod, in this.handle(IProblem.RedundantNullAnnotation, ProblemHandler.NoArgument, ProblemHandler.NoArgument, sourceStart, sourceEnd); } +public void nullAnnotationIsRedundant(FieldDeclaration sourceField) { + Annotation annotation = findAnnotation(sourceField.annotations, TypeIds.T_ConfiguredAnnotationNonNull); + int sourceStart = annotation != null ? annotation.sourceStart : sourceField.type.sourceStart; + int sourceEnd = sourceField.type.sourceEnd; + this.handle(IProblem.RedundantNullAnnotation, ProblemHandler.NoArgument, ProblemHandler.NoArgument, sourceStart, sourceEnd); +} + public void nullDefaultAnnotationIsRedundant(ASTNode location, Annotation[] annotations, Binding outer) { Annotation annotation = findAnnotation(annotations, TypeIds.T_ConfiguredAnnotationNonNullByDefault); int start = annotation != null ? annotation.sourceStart : location.sourceStart; |