Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java128
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java52
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java69
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java7
4 files changed, 221 insertions, 35 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
index 3641963001..f3e1a1f498 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java
@@ -25,6 +25,7 @@
* Bug 431408 - Java 8 (1.8) generics bug
* Bug 432603 - [compile][1.7] ecj reports an Error while javac doesn't
* Bug 399527 - Type inference problem
+ * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -4952,5 +4953,132 @@ public void testBug399527_comment1() {
sourceString
});
}
+public void testBug434570() {
+ runConformTest(
+ new String[] {
+ "example/Example.java",
+ "package example;\n" +
+ "\n" +
+ "import example.Example.Config;\n" +
+ "import example.Example.CustomInitializer;\n" +
+ "\n" +
+ "@Config(initializers = CustomInitializer.class)\n" +
+ "public class Example {\n" +
+ "\n" +
+ " static interface Context {\n" +
+ " }\n" +
+ "\n" +
+ " static interface ConfigurableContext extends Context {\n" +
+ " }\n" +
+ "\n" +
+ " static abstract class AbstractContext implements ConfigurableContext {\n" +
+ " }\n" +
+ "\n" +
+ " static class GenericContext extends AbstractContext {\n" +
+ " }\n" +
+ "\n" +
+ " static interface Initializer<C extends ConfigurableContext> {\n" +
+ " }\n" +
+ "\n" +
+ " static @interface Config {\n" +
+ " Class<? extends Initializer<? extends ConfigurableContext>>[] initializers() default {};\n" +
+ " }\n" +
+ "\n" +
+ " static class CustomInitializer implements Initializer<GenericContext> {\n" +
+ " }\n" +
+ "\n" +
+ " @Config(initializers = CustomInitializer.class)\n" +
+ " static class CompilationSuccess {\n" +
+ " }\n" +
+ "\n" +
+ "}\n"
+ });
+}
+public void testBug434630() {
+ runConformTest(
+ new String[] {
+ "Foo.java",
+ "interface Provider<T> {}\n" +
+ "@interface ProvidedBy {\n" +
+ " Class<? extends Provider<?>> value();" +
+ "}\n" +
+ "\n" +
+ "@ProvidedBy(Foo.SomeProvider.class)\n" +
+ "public interface Foo {\n" +
+ " \n" +
+ " public static class SomeProvider implements Provider<Foo> {\n" +
+ "\n" +
+ " public Foo get() {\n" +
+ " return null;\n" +
+ " }\n" +
+ " \n" +
+ " }\n" +
+ "}\n"
+ });
+}
+public void _testBug434570_comment3() {
+ runConformTest(
+ new String[] {
+ "TestWontCompile.java",
+ "import org.bug.AnnotationWithClassParameter;\n" +
+ "import org.bug.CustomHandler;\n" +
+ "import org.bug.Handler;\n" +
+ "\n" +
+ "\n" +
+ "@AnnotationWithClassParameter(CustomHandler.class)\n" +
+ "public class TestWontCompile extends ATest<Object> {\n" +
+ " \n" +
+ " public static void main(String[] args) {\n" +
+ " Class<? extends Handler<?>> h = CustomHandler.class;\n" +
+ " }\n" +
+ "\n" +
+ "}\n",
+ "ATest.java",
+ "public abstract class ATest<T> {\n" +
+ "\n" +
+ "}\n",
+ "org/bug/Item.java",
+ "package org.bug;\n" +
+ "\n" +
+ "public interface Item {\n" +
+ "\n" +
+ "}\n",
+ "org/bug/CustomItem.java",
+ "package org.bug;\n" +
+ "\n" +
+ "public class CustomItem implements Item {\n" +
+ "\n" +
+ "}\n",
+ "org/bug/Handler.java",
+ "package org.bug;\n" +
+ "\n" +
+ "public abstract class Handler<T extends Item> {\n" +
+ "\n" +
+ "}\n",
+ "org/bug/CustomHandler.java",
+ "package org.bug;\n" +
+ "\n" +
+ "public class CustomHandler extends Handler<CustomItem> {\n" +
+ "\n" +
+ "}\n",
+ "org/bug/AnnotationWithClassParameter.java",
+ "package org.bug;\n" +
+ "\n" +
+ "import java.lang.annotation.Documented;\n" +
+ "import java.lang.annotation.ElementType;\n" +
+ "import java.lang.annotation.Retention;\n" +
+ "import java.lang.annotation.RetentionPolicy;\n" +
+ "import java.lang.annotation.Target;\n" +
+ "\n" +
+ "@Target(ElementType.TYPE)\n" +
+ "@Retention(RetentionPolicy.RUNTIME)\n" +
+ "@Documented\n" +
+ "public @interface AnnotationWithClassParameter {\n" +
+ " \n" +
+ " Class<? extends Handler<?>> value();\n" +
+ "\n" +
+ "}\n"
+ });
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
index 103812bf42..81ca5c886b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2014 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
@@ -10,6 +10,7 @@
* Stephan Herrmann - Contributions for
* bug 186342 - [compiler][null] Using annotations for null checking
* bug 365519 - editorial cleanup after bug 186342 and bug 365387
+ * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -58,7 +59,7 @@ public class MemberValuePair extends ASTNode {
return output;
}
- public void resolveTypeExpecting(BlockScope scope, TypeBinding requiredType) {
+ public void resolveTypeExpecting(final BlockScope scope, final TypeBinding requiredType) {
if (this.value == null) {
this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding);
@@ -76,7 +77,7 @@ public class MemberValuePair extends ASTNode {
}
this.value.setExpectedType(requiredType); // needed in case of generic method invocation - looks suspect, generic method invocation here ???
- TypeBinding valueType;
+ final TypeBinding valueType;
if (this.value instanceof ArrayInitializer) {
ArrayInitializer initializer = (ArrayInitializer) this.value;
valueType = initializer.resolveTypeExpecting(scope, this.binding.returnType);
@@ -101,25 +102,38 @@ public class MemberValuePair extends ASTNode {
if (valueType == null)
return;
- TypeBinding leafType = requiredType.leafComponentType();
- if (!(this.value.isConstantValueOfTypeAssignableToType(valueType, requiredType)
- || valueType.isCompatibleWith(requiredType))) {
-
- if (!(requiredType.isArrayType()
- && requiredType.dimensions() == 1
- && (this.value.isConstantValueOfTypeAssignableToType(valueType, leafType)
- || valueType.isCompatibleWith(leafType)))) {
-
- if (leafType.isAnnotationType() && !valueType.isAnnotationType()) {
- scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, this.value, leafType);
+ final TypeBinding leafType = requiredType.leafComponentType();
+ // the next check may need deferring:
+ final boolean[] shouldExit = new boolean[1];
+ Runnable check = new Runnable() {
+ @Override
+ public void run() {
+ if (!(MemberValuePair.this.value.isConstantValueOfTypeAssignableToType(valueType, requiredType)
+ || valueType.isCompatibleWith(requiredType))) {
+ if (!(requiredType.isArrayType()
+ && requiredType.dimensions() == 1
+ && (MemberValuePair.this.value.isConstantValueOfTypeAssignableToType(valueType, leafType)
+ || valueType.isCompatibleWith(leafType)))) {
+
+ if (leafType.isAnnotationType() && !valueType.isAnnotationType()) {
+ scope.problemReporter().annotationValueMustBeAnnotation(MemberValuePair.this.binding.declaringClass,
+ MemberValuePair.this.name, MemberValuePair.this.value, leafType);
+ } else {
+ scope.problemReporter().typeMismatchError(valueType, requiredType, MemberValuePair.this.value, null);
+ }
+ shouldExit[0] = true; // TODO may allow to proceed to find more errors at once
+ }
} else {
- scope.problemReporter().typeMismatchError(valueType, requiredType, this.value, null);
+ scope.compilationUnitScope().recordTypeConversion(requiredType.leafComponentType(), valueType.leafComponentType());
+ MemberValuePair.this.value.computeConversion(scope, requiredType, valueType);
}
- return; // may allow to proceed to find more errors at once
}
- } else {
- scope.compilationUnitScope().recordTypeConversion(requiredType.leafComponentType(), valueType.leafComponentType());
- this.value.computeConversion(scope, requiredType, valueType);
+ };
+ // ... now or later?
+ if (!scope.deferCheck(check)) {
+ check.run();
+ if (shouldExit[0])
+ return;
}
// annotation methods can only return base types, String, Class, enum type, annotation types and arrays of these
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index 7e4176aed4..5d45063a4d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2014 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
@@ -18,11 +18,13 @@
* Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables
* Bug 427199 - [1.8][resource] avoid resource leak warnings on Streams that have no resource
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
+ * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 415821 - [1.8][compiler] CLASS_EXTENDS target type annotation missing for anonymous classes
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -47,7 +49,8 @@ public class ClassScope extends Scope {
public TypeDeclaration referenceContext;
public TypeReference superTypeReference;
- java.util.ArrayList deferredBoundChecks;
+ java.util.ArrayList<Object> deferredBoundChecks; // contains TypeReference or Runnable. TODO consider making this a List<Runnable>
+ boolean connectingHierarchy;
public ClassScope(Scope parent, TypeDeclaration context) {
super(Scope.CLASS_SCOPE, parent);
@@ -881,8 +884,11 @@ public class ClassScope extends Scope {
// Perform deferred bound checks for parameterized type references (only done after hierarchy is connected)
public void checkParameterizedTypeBounds() {
- for (int i = 0, l = this.deferredBoundChecks == null ? 0 : this.deferredBoundChecks.size(); i < l; i++)
- ((TypeReference) this.deferredBoundChecks.get(i)).checkBounds(this);
+ for (int i = 0, l = this.deferredBoundChecks == null ? 0 : this.deferredBoundChecks.size(); i < l; i++) {
+ Object toCheck = this.deferredBoundChecks.get(i);
+ if (toCheck instanceof TypeReference)
+ ((TypeReference) toCheck).checkBounds(this);
+ }
this.deferredBoundChecks = null;
ReferenceBinding[] memberTypes = this.referenceContext.binding.memberTypes;
@@ -1082,19 +1088,25 @@ public class ClassScope extends Scope {
void connectTypeHierarchy() {
SourceTypeBinding sourceType = this.referenceContext.binding;
- if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) == 0) {
- sourceType.tagBits |= TagBits.BeginHierarchyCheck;
- environment().typesBeingConnected.add(sourceType);
- boolean noProblems = connectSuperclass();
- noProblems &= connectSuperInterfaces();
- environment().typesBeingConnected.remove(sourceType);
- sourceType.tagBits |= TagBits.EndHierarchyCheck;
- noProblems &= connectTypeVariables(this.referenceContext.typeParameters, false);
- sourceType.tagBits |= TagBits.TypeVariablesAreConnected;
- if (noProblems && sourceType.isHierarchyInconsistent())
- problemReporter().hierarchyHasProblems(sourceType);
+ try {
+ if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) == 0) {
+ this.connectingHierarchy = true;
+ sourceType.tagBits |= TagBits.BeginHierarchyCheck;
+ environment().typesBeingConnected.add(sourceType);
+ boolean noProblems = connectSuperclass();
+ noProblems &= connectSuperInterfaces();
+ environment().typesBeingConnected.remove(sourceType);
+ sourceType.tagBits |= TagBits.EndHierarchyCheck;
+ noProblems &= connectTypeVariables(this.referenceContext.typeParameters, false);
+ sourceType.tagBits |= TagBits.TypeVariablesAreConnected;
+ if (noProblems && sourceType.isHierarchyInconsistent())
+ problemReporter().hierarchyHasProblems(sourceType);
+ }
+ connectMemberTypes();
+ } finally {
+ this.connectingHierarchy = false;
+ deferredMemberValueCheck();
}
- connectMemberTypes();
LookupEnvironment env = environment();
try {
env.missingClassFileLocation = this.referenceContext;
@@ -1107,6 +1119,31 @@ public class ClassScope extends Scope {
}
}
+ @Override
+ public boolean deferCheck(Runnable check) {
+ if (this.connectingHierarchy) {
+ if (this.deferredBoundChecks == null)
+ this.deferredBoundChecks = new ArrayList<Object>();
+ this.deferredBoundChecks.add(check);
+ return true;
+ } else {
+ return super.deferCheck(check);
+ }
+ }
+
+ private void deferredMemberValueCheck() {
+ if (this.deferredBoundChecks != null) {
+ Iterator iterator = this.deferredBoundChecks.iterator();
+ while (iterator.hasNext()) {
+ Object check = iterator.next();
+ if (check instanceof Runnable) {
+ ((Runnable)check).run();
+ iterator.remove();
+ }
+ }
+ }
+ }
+
private void connectTypeHierarchyWithoutMembers() {
// must ensure the imports are resolved
if (this.parent instanceof CompilationUnitScope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 1e519e37d1..01b9022145 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -42,6 +42,7 @@
* Bug 428811 - [1.8][compiler] Type witness unnecessarily required
* Bug 429424 - [1.8][inference] Problem inferring type of method's parameter
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
+ * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class
* Jesper S Moller - Contributions for
* Bug 378674 - "The method can be declared as static" is wrong
* Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
@@ -4889,6 +4890,12 @@ public abstract class Scope {
return null;
}
+ public boolean deferCheck(Runnable check) {
+ if (this.parent != null)
+ return this.parent.deferCheck(check); // only ClassScope potentially records this
+ return false;
+ }
+
public void deferBoundCheck(TypeReference typeRef) {
if (this.kind == CLASS_SCOPE) {
ClassScope classScope = (ClassScope) this;

Back to the top