Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2017-04-13 22:15:50 +0000
committerStephan Herrmann2017-04-13 22:15:50 +0000
commit4338868bca17d013740bdd5f87257ce2620da83a (patch)
tree22a1128ea641c7f13a330379fd10de7b76e7d221
parentcb0a7308a9e951a76867f8a7170d00b125238fe5 (diff)
downloadeclipse.jdt.core-4338868bca17d013740bdd5f87257ce2620da83a.tar.gz
eclipse.jdt.core-4338868bca17d013740bdd5f87257ce2620da83a.tar.xz
eclipse.jdt.core-4338868bca17d013740bdd5f87257ce2620da83a.zip
Bug 414761: [null] Annotation-based nullnes inference fails for fields
in 'while' loop Change-Id: I313719ad6739e1dbc745d8870c2a0955a4e320e3 Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java47
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java18
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java4
9 files changed, 75 insertions, 19 deletions
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 eee31ad799..96bbce47e1 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
@@ -5372,6 +5372,53 @@ public void test_nullable_field_15() {
potNPE_nullable("The field nullable") +
"----------\n");
}
+// access to a nullable field - dereference after check in while loop
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=414761
+public void test_nullable_field_16() {
+ // currently no flow analysis for fields is implemented,
+ // but the direct sequence of null-check + dereference is optionally supported as a special case
+ Map options = getCompilerOptions();
+ options.put(JavaCore.COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS, JavaCore.ENABLED);
+ runNegativeTestWithLibs(
+ new String[] {
+ "X.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "public class X {\n" +
+ " @Nullable Object prop;\n" +
+ " void testWhileAlone(){\n" +
+ " while(this.prop != null) {\n" +
+ " test(this.prop);\n" +
+ " }\n" +
+ " }\n" +
+ " @Nullable Object other;\n" +
+ " void testTwoFields() {\n" +
+ " boolean b = this.other != null;\n" + // we had funny interaction between analyses of other & prop
+ " while(this.prop != null) {\n" +
+ " test(this.prop);\n" +
+ " }\n" +
+ " }\n" +
+ " void testWhileInIf() {\n" +
+ " if (this.prop != null) {\n" +
+ " while(this.other != null) {\n" +
+ " test(this.prop);\n" + // no longer protected by outer if
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ " void test(@NonNull Object param){\n" +
+ " assert param != null;\n" +
+ " }" +
+ "}\n"
+ },
+ options /*customOptions*/,
+ "----------\n" +
+ "1. ERROR in X.java (at line 19)\n" +
+ " test(this.prop);\n" +
+ " ^^^^^^^^^\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8
+ ? "Null type mismatch: required '@NonNull Object' but the provided value is specified as @Nullable\n"
+ : "Null type mismatch (type annotations): required \'@NonNull Object\' but this expression has type \'@Nullable Object\'\n") +
+ "----------\n");
+}
// an enum is declared within the scope of a null-default
// https://bugs.eclipse.org/331649#c61
public void test_enum_field_01() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index bd51350fd0..48850affe5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -82,7 +82,7 @@ public class SwitchStatement extends Statement {
this.expression.checkNPE(currentScope, flowContext, flowInfo, 1);
}
SwitchFlowContext switchContext =
- new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true);
+ new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true, true);
// analyse the block by considering specially the case/default statements (need to bind them
// to the entry point)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
index a215dda1c1..e5eeaae730 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -103,6 +103,7 @@ public class WhileStatement extends Statement {
this.continueLabel,
currentScope,
true);
+ loopingContext.copyNullCheckedFieldsFrom(condLoopContext);
if (isConditionFalse) {
actionInfo = FlowInfo.DEAD_END;
} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
index c12c04406a..893df8a3f2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -97,7 +97,7 @@ ExceptionHandlingFlowContext(
BlockScope scope,
UnconditionalFlowInfo flowInfo) {
- super(parent, associatedNode);
+ super(parent, associatedNode, true);
this.isMethodContext = scope == scope.methodScope();
this.handledExceptions = handledExceptions;
this.catchArguments = catchArguments;
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 ce65992f2b..d225440473 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -61,7 +61,7 @@ import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
public class FlowContext implements TypeConstants {
// preempt marks looping contexts
- public final static FlowContext NotContinuableContext = new FlowContext(null, null);
+ public final static FlowContext NotContinuableContext = new FlowContext(null, null, true);
public ASTNode associatedNode;
public FlowContext parent;
public FlowInfo initsOnFinally;
@@ -121,7 +121,7 @@ public static final int IN_INSTANCEOF = 0x0400;
// check happened in an instanceof expression
public static final int CONTEXT_MASK = ~CHECK_MASK & ~HIDE_NULL_COMPARISON_WARNING_MASK;
-public FlowContext(FlowContext parent, ASTNode associatedNode) {
+public FlowContext(FlowContext parent, ASTNode associatedNode, boolean inheritNullFieldChecks) {
this.parent = parent;
this.associatedNode = associatedNode;
if (parent != null) {
@@ -130,8 +130,16 @@ public FlowContext(FlowContext parent, ASTNode associatedNode) {
}
this.initsOnFinally = parent.initsOnFinally;
this.conditionalLevel = parent.conditionalLevel;
- this.nullCheckedFieldReferences = parent.nullCheckedFieldReferences; // re-use list if there is one
- this.timesToLiveForNullCheckInfo = parent.timesToLiveForNullCheckInfo;
+ if (inheritNullFieldChecks)
+ copyNullCheckedFieldsFrom(parent); // re-use list if there is one
+ }
+}
+
+public void copyNullCheckedFieldsFrom(FlowContext other) {
+ Reference[] fieldReferences = other.nullCheckedFieldReferences;
+ if (fieldReferences != null && fieldReferences.length > 0 && fieldReferences[0] != null) {
+ this.nullCheckedFieldReferences = other.nullCheckedFieldReferences;
+ this.timesToLiveForNullCheckInfo = other.timesToLiveForNullCheckInfo;
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
index 309eefc3a1..b279d47d7d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -26,7 +26,7 @@ public class LabelFlowContext extends SwitchFlowContext {
public char[] labelName;
public LabelFlowContext(FlowContext parent, ASTNode associatedNode, char[] labelName, BranchLabel breakLabel, BlockScope scope) {
- super(parent, associatedNode, breakLabel, false);
+ super(parent, associatedNode, breakLabel, false, true);
this.labelName = labelName;
checkLabelValidity(scope);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
index ec758b4d75..1fd26137cb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -105,7 +105,7 @@ public class LoopingFlowContext extends SwitchFlowContext {
BranchLabel continueLabel,
Scope associatedScope,
boolean isPreTest) {
- super(parent, associatedNode, breakLabel, isPreTest);
+ super(parent, associatedNode, breakLabel, isPreTest, false);
this.tagBits |= FlowContext.PREEMPT_NULL_DIAGNOSTIC;
// children will defer to this, which may defer to its own parent
this.continueLabel = continueLabel;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
index 279fff0a36..ce2ed9b7bf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -24,8 +24,8 @@ public class SwitchFlowContext extends FlowContext {
public BranchLabel breakLabel;
public UnconditionalFlowInfo initsOnBreak = FlowInfo.DEAD_END;
-public SwitchFlowContext(FlowContext parent, ASTNode associatedNode, BranchLabel breakLabel, boolean isPreTest) {
- super(parent, associatedNode);
+public SwitchFlowContext(FlowContext parent, ASTNode associatedNode, BranchLabel breakLabel, boolean isPreTest, boolean inheritNullFieldChecks) {
+ super(parent, associatedNode, inheritNullFieldChecks);
this.breakLabel = breakLabel;
if (isPreTest && parent.conditionalLevel > -1) {
this.conditionalLevel++;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
index 1623e51260..98f4fecfbc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 GK Software AG and others.
+ * Copyright (c) 2013, 2017 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
@@ -25,7 +25,7 @@ public abstract class TryFlowContext extends FlowContext {
public FlowContext outerTryContext;
public TryFlowContext(FlowContext parent, ASTNode associatedNode) {
- super(parent, associatedNode);
+ super(parent, associatedNode, true);
}
public void markFinallyNullStatus(LocalVariableBinding local, int nullStatus) {

Back to the top