Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2014-02-25 17:21:23 +0000
committerStephan Herrmann2014-02-25 17:21:23 +0000
commitb16af955ad096598d372b7b23da79db705ddee11 (patch)
tree2353982f07478b8ac05b2794352ae7d181093bf8
parent745840be480d4e43f22d0c4f40c198cdee6926a4 (diff)
downloadeclipse.jdt.core-b16af955ad096598d372b7b23da79db705ddee11.tar.gz
eclipse.jdt.core-b16af955ad096598d372b7b23da79db705ddee11.tar.xz
eclipse.jdt.core-b16af955ad096598d372b7b23da79db705ddee11.zip
Bug 428985 - [1.8][null] help the type inference to find a
nullness-annotated type if possible - more tests and fix
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java59
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java2
4 files changed, 73 insertions, 10 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
index 8132e223dd..8e87c5ea9a 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
@@ -2560,6 +2560,65 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest {
"----------\n");
}
+ // demonstrate that null annotations from the functional interface win, resulting in successful inference but null-safety issues
+ public void testNullTypeInference2e() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "PolyNull.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "\n" +
+ "interface Func<T> {\n" +
+ " T a(T i);\n" +
+ "}\n" +
+ "public class PolyNull {\n" +
+ " String extract(Func<@Nullable String> f, @Nullable String s) { return f.a(s); }\n" +
+ " @NonNull String testWARN() {\n" +
+ " return extract(i -> null, \"hallo\"); // OK to pass null\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in PolyNull.java (at line 9)\n" +
+ " return extract(i -> null, \"hallo\"); // OK to pass null\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'@NonNull String\'\n" +
+ "----------\n");
+ }
+
+ // demonstrate that null annotations from the functional interface win, resulting in successful inference but null-safety issues
+ public void testNullTypeInference2f() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "PolyNull.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "\n" +
+ "interface Func<T> {\n" +
+ " T a(T i);\n" +
+ "}\n" +
+ "public class PolyNull {\n" +
+ " <X> X extract(Func<@Nullable X> f, @Nullable X s) { return f.a(s); }\n" +
+ " @NonNull String testERR() {\n" +
+ " return extract(i -> needNN(i), \"ola\");\n" +
+ " }\n" +
+ " @NonNull String needNN(@NonNull String s) { return \"\"; }\n" +
+ "" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "----------\n" +
+ "1. WARNING in PolyNull.java (at line 9)\n" +
+ " return extract(i -> needNN(i), \"ola\");\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'@NonNull String\'\n" +
+ "----------\n" +
+ "2. ERROR in PolyNull.java (at line 9)\n" +
+ " return extract(i -> needNN(i), \"ola\");\n" +
+ " ^\n" +
+ "Null type mismatch (type annotations): required \'@NonNull String\' but this expression has type \'@Nullable String\'\n" +
+ "----------\n");
+ }
+
// missing return type should not cause NPE
public void testBug415850_01() {
runNegativeTestWithLibs(
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index 242027709a..dfa9258457 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -69,10 +69,10 @@ class BoundSet {
}
}
// pre: this.superBounds != null
- public TypeBinding[] lowerBounds(boolean onlyProper, LookupEnvironment environment) {
+ public TypeBinding[] lowerBounds(boolean onlyProper, InferenceVariable variable) {
TypeBinding[] boundTypes = new TypeBinding[this.superBounds.size()];
Iterator<TypeBound> it = this.superBounds.iterator();
- long nullHints = 0;
+ long nullHints = variable.nullHints;
int i = 0;
while(it.hasNext()) {
TypeBound current = it.next();
@@ -86,16 +86,16 @@ class BoundSet {
return Binding.NO_TYPES;
if (i < boundTypes.length)
System.arraycopy(boundTypes, 0, boundTypes=new TypeBinding[i], 0, i);
- useNullHints(nullHints, boundTypes, environment);
+ useNullHints(nullHints, boundTypes, variable.environment);
InferenceContext18.sortTypes(boundTypes);
return boundTypes;
}
// pre: this.subBounds != null
- public TypeBinding[] upperBounds(boolean onlyProper, LookupEnvironment environment) {
+ public TypeBinding[] upperBounds(boolean onlyProper, InferenceVariable variable) {
ReferenceBinding[] rights = new ReferenceBinding[this.subBounds.size()];
TypeBinding simpleUpper = null;
Iterator<TypeBound> it = this.subBounds.iterator();
- long nullHints = 0;
+ long nullHints = variable.nullHints;
int i = 0;
while(it.hasNext()) {
TypeBinding right=it.next().right;
@@ -116,7 +116,7 @@ class BoundSet {
return new TypeBinding[] { simpleUpper }; // no nullHints since not a reference type
if (i < rights.length)
System.arraycopy(rights, 0, rights=new ReferenceBinding[i], 0, i);
- useNullHints(nullHints, rights, environment);
+ useNullHints(nullHints, rights, variable.environment);
InferenceContext18.sortTypes(rights);
return rights;
}
@@ -782,7 +782,7 @@ class BoundSet {
ThreeSets three = this.boundsPerVariable.get(variable);
if (three == null || three.subBounds == null)
return Binding.NO_TYPES;
- return three.upperBounds(onlyProper, variable.environment);
+ return three.upperBounds(onlyProper, variable);
// TODO: if !onlyProper: should we also consider ThreeSets.inverseBounds,
// or is it safe to rely on incorporation to produce the required bounds?
}
@@ -795,7 +795,7 @@ class BoundSet {
ThreeSets three = this.boundsPerVariable.get(variable);
if (three == null || three.superBounds == null)
return Binding.NO_TYPES;
- return three.lowerBounds(onlyProper, variable.environment);
+ return three.lowerBounds(onlyProper, variable);
// bounds where 'variable' appears at the RHS are not relevant because
// we're only interested in bounds with a proper type, but if 'variable'
// appears as RHS the bound is by construction an inference variable,too.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
index 0f345bdc75..babb0322d5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013 GK Software AG.
+ * Copyright (c) 2013, 2014 GK Software AG.
* 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
@@ -34,8 +34,10 @@ public class InferenceSubstitution extends Scope.Substitutor implements Substitu
public TypeBinding substitute(Substitution substitution, TypeBinding originalType) {
for (int i = 0; i < this.variables.length; i++) {
InferenceVariable variable = this.variables[i];
- if (TypeBinding.equalsEquals(variable.typeParameter, originalType))
+ if (TypeBinding.equalsEquals(variable.typeParameter, originalType)) {
+ variable.nullHints |= originalType.tagBits & TagBits.AnnotationNullMASK;
return variable;
+ }
}
return super.substitute(substitution, originalType);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
index 9d0ca68f7c..8c454434eb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
@@ -25,12 +25,14 @@ public class InferenceVariable extends TypeVariableBinding {
InvocationSite site;
TypeBinding typeParameter;
+ long nullHints;
public InferenceVariable(TypeBinding typeParameter, int variableRank, InvocationSite site, LookupEnvironment environment, ReferenceBinding object) {
super(CharOperation.concat(typeParameter.shortReadableName(), Integer.toString(variableRank).toCharArray(), '#'),
null/*declaringElement*/, variableRank, environment);
this.site = site;
this.typeParameter = typeParameter;
+ this.nullHints |= typeParameter.tagBits & TagBits.AnnotationNullMASK;
this.superclass = object;
}

Back to the top