diff --git a/org.eclipse.jdt.annotation/src/org/eclipse/jdt/annotation/NonNull.java b/org.eclipse.jdt.annotation/src/org/eclipse/jdt/annotation/NonNull.java index 78aa71c..9372739 100644 --- a/org.eclipse.jdt.annotation/src/org/eclipse/jdt/annotation/NonNull.java +++ b/org.eclipse.jdt.annotation/src/org/eclipse/jdt/annotation/NonNull.java @@ -35,8 +35,8 @@ *
  • Nullness of the value can be statically determined, the entity is definitely bound from either of: *
  • - *
  • Nullness can not definitely be determined, because different code branches yield different results.
  • - *
  • Nullness can not be determined, because other program elements are involved for which + *
  • Nullness cannot definitely be determined, because different code branches yield different results.
  • + *
  • Nullness cannot be determined, because other program elements are involved for which * null annotations are lacking.
  • * *

    diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java index 6c6bd01..025c21c 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java @@ -52,7 +52,7 @@ // 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_illegal_annotation_007" }; +// TESTS_NAMES = new String[] { "test_assignment_expression_1" }; // TESTS_NUMBERS = new int[] { 561 }; // TESTS_RANGE = new int[] { 1, 2049 }; } @@ -2474,6 +2474,36 @@ "Type mismatch: required \'@NonNull String\' but the provided value can be null\n" + "----------\n"); } +public void test_assignment_expression_1() { + Map customOptions = getCompilerOptions(); +// customOptions.put(CompilerOptions.OPTION_ReportPotentialNullSpecViolation, JavaCore.ERROR); + customOptions.put(JavaCore.COMPILER_NONNULL_IS_DEFAULT, JavaCore.ENABLED); + customOptions.put(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK, JavaCore.ERROR); + runConformTestWithLibs( + new String[] { + "X.java", + "import org.eclipse.jdt.annotation.*;\n" + + "public class X {\n" + + " @Nullable Object foo() {\n" + + " Object o = null;\n" + + " boolean keepLooking = true;\n" + + " while(keepLooking) {\n" + + " if ((o=getO()) != null) {\n" + + " return o;\n" + + " }\n" + + " }\n" + + " return null;\n" + + " }\n" + + "\n" + + " private @Nullable Object getO() {\n" + + " return new Object();\n" + + " }\n" + + "}\n", + + }, + customOptions, + ""); +} // a nonnull variable is dereferenced method of a nested type public void test_nesting_1() { Map customOptions = getCompilerOptions(); diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS4Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS4Test.java index 1e06c11..9c7b8e9 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS4Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15JLS4Test.java @@ -7476,7 +7476,6 @@ assertTrue("Not assignement compatible", typeBinding.isAssignmentCompatible(typeBinding2)); assertTrue("Not assignement compatible", typeBinding.isAssignmentCompatible(collectionTypeBinding)); } - /* * https://bugs.eclipse.org/bugs/show_bug.cgi?id=156352 */ @@ -7495,10 +7494,13 @@ buffer.append(typeBinding.getAnnotations().length); typeBinding= typeBinding.getSuperclass(); } - // initially, this test expected "000", but after https://bugs.eclipse.org/186342 - // annotations are resolved more eagerly, which makes the annotations on Test2 show up, - // which is actually the right outcome. - assertEquals("Wrong number of annotations", "020", String.valueOf(buffer)); + // the right outcome would be "020", but depending on the strategy when exactly + // annotations are resolved the annotations on Test2 are (not) present when + // traversing the super-class chain. + // The patch in https://bugs.eclipse.org/186342#c196 produced "020" but + // the previous behavior ("000") was restored in https://bugs.eclipse.org/365387 + // (see the change in SourceTypeBinding.resolveTypesFor(..)) + assertEquals("Wrong number of annotations", "000", String.valueOf(buffer)); } } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java index e89ba8f..fd388a6 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter15Test.java @@ -7498,10 +7498,13 @@ buffer.append(typeBinding.getAnnotations().length); typeBinding= typeBinding.getSuperclass(); } - // initially, this test expected "000", but after https://bugs.eclipse.org/186342 - // annotations are resolved more eagerly, which makes the annotations on Test2 show up, - // which is actually the right outcome. - assertEquals("Wrong number of annotations", "020", String.valueOf(buffer)); + // the right outcome would be "020", but depending on the strategy when exactly + // annotations are resolved the annotations on Test2 are (not) present when + // traversing the super-class chain. + // The patch in https://bugs.eclipse.org/186342#c196 produced "020" but + // the previous behavior ("000") was restored in https://bugs.eclipse.org/365387 + // (see the change in SourceTypeBinding.resolveTypesFor(..)) + assertEquals("Wrong number of annotations", "000", String.valueOf(buffer)); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index 59a7ecd..46d4540 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -119,7 +119,7 @@ } public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { super.checkNPE(scope, flowContext, flowInfo); - if (nullStatus(flowInfo) == FlowInfo.POTENTIALLY_NULL) + if ((nullStatus(flowInfo) & FlowInfo.POTENTIALLY_NULL) != 0) scope.problemReporter().messageSendPotentialNullReference(this.binding, this); } /** @@ -281,7 +281,7 @@ if ((tagBits & TagBits.AnnotationNonNull) != 0) return FlowInfo.NON_NULL; if ((tagBits & TagBits.AnnotationNullable) != 0) - return FlowInfo.POTENTIALLY_NULL; + return FlowInfo.POTENTIALLY_NULL | FlowInfo.POTENTIALLY_NON_NULL; } return FlowInfo.UNKNOWN; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java index 7df8a71..98caf30 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java @@ -564,9 +564,10 @@ while (size <= nullCount) size *= 2; this.expectedTypes = new TypeBinding[size]; } - else if (nullCount == this.expectedTypes.length) { + else if (nullCount >= this.expectedTypes.length) { + int oldLen = this.expectedTypes.length; System.arraycopy(this.expectedTypes, 0, - this.expectedTypes = new TypeBinding[nullCount * 2], 0, nullCount); + this.expectedTypes = new TypeBinding[nullCount * 2], 0, oldLen); } this.expectedTypes[nullCount] = expectedType; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java index 0ac09c9..c973fd3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -778,6 +778,7 @@ OPTION_NonNullIsDefault, OPTION_ReportNullSpecViolation, OPTION_ReportPotentialNullSpecViolation, + OPTION_ReportNullSpecInsufficientInfo, OPTION_ReportRedundantNullAnnotation }; return result; @@ -1225,6 +1226,7 @@ this.nullableAnnotationName = DEFAULT_NULLABLE_ANNOTATION_NAME; this.nonNullAnnotationName = DEFAULT_NONNULL_ANNOTATION_NAME; this.nonNullByDefaultAnnotationName = DEFAULT_NONNULLBYDEFAULT_ANNOTATION_NAME; + this.defaultNonNullness = 0; } public void set(Map optionsMap) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index 094c155..e8b277c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -1597,7 +1597,8 @@ typeParameters[i].binding = null; return null; } - createArgumentBindings(method); + if (this.scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) + createArgumentBindings(method); // need annotations resolved already at this point if (foundReturnTypeProblem) return method; // but its still unresolved with a null return type & is still connected to its method declaration diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java index ca6b9fa..b381b01 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java @@ -547,11 +547,11 @@ if (this.lineEnds == null || this.linePtr == -1) return -1; - if (lineNumber > this.linePtr + 2) + if (lineNumber > this.lineEnds.length+1) return -1; if (lineNumber <= 0) return -1; - if (lineNumber == this.linePtr + 2) + if (lineNumber == this.lineEnds.length + 1) return this.eofPosition; return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line }