Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSasikanth Bharadwaj2016-10-13 12:35:35 +0000
committerSasikanth Bharadwaj2016-10-15 07:37:52 +0000
commit8f0eb26398d5c8dde9ae3b5affe939426eea53ca (patch)
tree366df3a5275c178e873f98a39e9347fab9755cc2
parent626cae73ca62549fe78e25b477953af148a31148 (diff)
downloadeclipse.jdt.core-8f0eb26398d5c8dde9ae3b5affe939426eea53ca.tar.gz
eclipse.jdt.core-8f0eb26398d5c8dde9ae3b5affe939426eea53ca.tar.xz
eclipse.jdt.core-8f0eb26398d5c8dde9ae3b5affe939426eea53ca.zip
Bug 488663: [1.9] Allow diamond with anonymous classes
Change-Id: I9308db75bac88ea34a6c1e3ffbfc3a1c18038e92 Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=488663
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java2
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_9.java461
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java14
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java183
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties1
9 files changed, 610 insertions, 86 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 1b05ea7483..a40a484a0e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -849,6 +849,7 @@ public void test011_problem_categories() {
expectedProblemAttributes.put("NoSuperInInterfaceContext", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
expectedProblemAttributes.put("NonBlankFinalLocalAssignment", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
expectedProblemAttributes.put("NonConstantExpression", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
+ expectedProblemAttributes.put("NonDenotableTypeArgumentForAnonymousDiamond", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("NonExternalizedStringLiteral", new ProblemAttributes(CategorizedProblem.CAT_NLS));
expectedProblemAttributes.put("NonGenericConstructor", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("NonGenericMethod", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
@@ -1702,6 +1703,7 @@ public void test012_compiler_problems_tuning() {
expectedProblemAttributes.put("NoSuperInInterfaceContext", SKIP);
expectedProblemAttributes.put("NonBlankFinalLocalAssignment", SKIP);
expectedProblemAttributes.put("NonConstantExpression", SKIP);
+ expectedProblemAttributes.put("NonDenotableTypeArgumentForAnonymousDiamond", SKIP);
expectedProblemAttributes.put("NonExternalizedStringLiteral", new ProblemAttributes(JavaCore.COMPILER_PB_NON_NLS_STRING_LITERAL));
expectedProblemAttributes.put("NonGenericConstructor", SKIP);
expectedProblemAttributes.put("NonGenericMethod", SKIP);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_9.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_9.java
new file mode 100644
index 0000000000..d3cdb89c5c
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_9.java
@@ -0,0 +1,461 @@
+/*******************************************************************************
+ * Copyright (c) 2016 IBM Corporation.
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.compiler.regression;
+
+import java.util.Map;
+
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+
+import junit.framework.Test;
+
+@SuppressWarnings({ "rawtypes" })
+public class GenericsRegressionTest_9 extends AbstractRegressionTest {
+
+static {
+// TESTS_NAMES = new String[] { "testBug488663_006" };
+// TESTS_NUMBERS = new int[] { 40, 41, 43, 45, 63, 64 };
+// TESTS_RANGE = new int[] { 11, -1 };
+}
+public GenericsRegressionTest_9(String name) {
+ super(name);
+}
+public static Test suite() {
+ return buildMinimalComplianceTestSuite(testClass(), F_9);
+}
+
+// vanilla test case
+public void testBug488663_001() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public Y<String> bar() {\n" +
+ " Y<String> y = new Y<>() {\n" +
+ " @Override\n" +
+ " public void foo(String s) {\n" +
+ " this.s = s;\n" +
+ " }\n" +
+ " };\n" +
+ " return y;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<String> y = new X().bar();\n" +
+ " y.foo(\"Done\");\n" +
+ " y.print();\n" +
+ " }\n" +
+ "}\n" +
+ "abstract class Y<T> {\n" +
+ " String s;\n" +
+ " public abstract void foo(String s);\n" +
+ " public void print() {\n" +
+ " System.out.println(this.s);\n" +
+ " }\n" +
+ "}\n",
+ },
+ "Done");
+}
+
+// negative test case for diamond operator instantiation of denotable anonymous type but with parameterized method
+public void testBug488663_002() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public Y<String> bar() {\n" +
+ " Y<String> y = new Y<>() {\n" +
+ " @Override\n" +
+ " public void foo(T t) {\n" +
+ " this.s = t;\n" +
+ " }\n" +
+ " };\n" +
+ " return y;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<String> y = new X().bar();\n" +
+ " y.foo(\"Done\");\n" +
+ " y.print();\n" +
+ " }\n" +
+ "}\n" +
+ "abstract class Y<T> {\n" +
+ " T s;\n" +
+ " public abstract void foo(T t);\n" +
+ " public void print() {\n" +
+ " System.out.println(this.s);\n" +
+ " }\n" +
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 3)\n" +
+ " Y<String> y = new Y<>() {\n" +
+ " ^^^^^\n" +
+ "The type new Y<String>(){} must implement the inherited abstract method Y<String>.foo(String)\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 5)\n" +
+ " public void foo(T t) {\n" +
+ " ^\n" +
+ "T cannot be resolved to a type\n" +
+ "----------\n");
+}
+
+// diamond operator instantiation of denotable anonymous types with different type params
+public void testBug488663_003() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X { \n" +
+ "@SuppressWarnings(\"unused\") \n" +
+ " public static void main(String[] args) {\n" +
+ " Y<?> y1 = new Y<>(){};\n" +
+ " Y<String> y2 = new Y<>(){};\n" +
+ " Y<? extends String> y3 = new Y<>() {};\n" +
+ " Y<? super String> y4 = new Y<>() {};\n" +
+ " }\n" +
+ "}\n" +
+ "class Y<T> {}\n",
+ },
+ "");
+}
+
+// inner classes with diamond operator and anonymous classes
+public void testBug488663_004() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X { \n" +
+ "@SuppressWarnings(\"unused\") \n" +
+ " public static void main(String[] args) {\n" +
+ " Y<?> y1 = new X().new Y<>(){};\n" +
+ " Y<String> y2 = new X().new Y<>(){};\n" +
+ " Y<? extends String> y3 = new X().new Y<>() {};\n" +
+ " Y<? super String> y4 = new X().new Y<>() {};\n" +
+ " }\n" +
+ "\n" +
+ " class Y<T> {}\n" +
+ "}\n",
+ },
+ "");
+}
+
+// compiler error for non-denotable anonymous type with diamond operator - negative test
+public void testBug488663_005() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "interface I {}\n" +
+ "interface J{}\n" +
+ "class Y<T extends I & J> {}\n" +
+ "\n" +
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<?> y = new Y<>() {};\n" +
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 7)\n" +
+ " Y<?> y = new Y<>() {};\n" +
+ " ^\n" +
+ "Type Y<I & J> inferred for Y<>, is not valid for an anonymous class with '<>'\n" +
+ "----------\n");
+
+}
+
+//compiler error for non-denotable anonymous type with diamond operator - negative test
+public void testBug488663_006() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "class Y<T> {\n" +
+ " Y(T x) {}\n" +
+ "}\n" +
+ "\n" +
+ "class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<? extends Integer> fi = null;\n" +
+ " Y<?> f = new Y<>(fi){};\n" +
+ " }\n" +
+ "}\n",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 8)\n" +
+ " Y<?> f = new Y<>(fi){};\n" +
+ " ^\n" +
+ "Type Y<Y<capture#1-of ? extends Integer>> inferred for Y<>, is not valid for an anonymous class with '<>'\n" +
+ "----------\n");
+
+}
+// instantiate an interface using the anonymous diamond
+public void testBug488663_007() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " String name() {\n" +
+ " return this.name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " X x = new X(\"Success\");\n" +
+ " I<X> i = new I<>() {\n" +
+ " public String toString(X x1) {\n" +
+ " return x1.name();\n" +
+ " }\n" +
+ " };\n" +
+ " System.out.println(i.toString(x));\n" +
+ " }\n" +
+ "}\n" +
+ "interface I<T> {\n" +
+ " String toString(T t);\n" +
+ "}"
+ },
+ "Success");
+}
+// anonymous diamond instantiating interface as argument to an invocation
+public void testBug488663_008() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " <T> void print(T o, I<T> converter) {\n" +
+ " System.out.println(converter.toString(o));\n" +
+ " }\n" +
+ " String name() {\n" +
+ " return this.name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " X x = new X(\"Success\");\n" +
+ " x.print(x, new I<>() {\n" +
+ " public String toString(X x1) {\n" +
+ " return x1.name();\n" +
+ " }\n" +
+ " });\n" +
+ " }\n" +
+ "}\n" +
+ "interface I<T> {\n" +
+ " String toString(T t);\n" +
+ "}"
+ },
+ "Success");
+}
+// anonymous diamond instantiating an abstract class as argument to an invocation
+public void testBug488663_009() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " <T> void print(T o, I<T> converter) {\n" +
+ " System.out.println(converter.toString(o));\n" +
+ " }\n" +
+ " String name() {\n" +
+ " return this.name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " X x = new X(\"Success\");\n" +
+ " x.print(x, new Z<>() {\n" +
+ " public String toString(X x1) {\n" +
+ " return x1.name();\n" +
+ " }\n" +
+ " });\n" +
+ " }\n" +
+ "}\n" +
+ "interface I<T> {\n" +
+ " String toString(T t);\n" +
+ "}\n" +
+ "abstract class Z<T> implements I<T> {}\n"
+ },
+ "Success");
+}
+// anonymous diamond with polytype argument
+public void testBug488663_010() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<String> y = new Y<>(() -> System.out.println(\"Done\")) {\n" +
+ " };\n" +
+ " }\n" +
+ "}\n" +
+ "interface J {\n" +
+ " void doSomething();\n" +
+ "}\n" +
+ "class Y<T> {\n" +
+ " public Y(J j) {\n" +
+ " j.doSomething();\n" +
+ " }\n" +
+ "}",
+ },
+ "Done");
+}
+// anonymous diamond with polytype argument
+public void testBug488663_011() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<String> y = new Y<>(Y::foo) {\n" +
+ " };\n" +
+ " }\n" +
+ "}\n" +
+ "interface J {\n" +
+ " void doSomething();\n" +
+ "}\n" +
+ "class Y<T> {\n" +
+ " public Y(J j) {\n" +
+ " j.doSomething();\n" +
+ " }\n" +
+ " static void foo() {\n" +
+ " System.out.println(\"Done\");\n" +
+ " }\n" +
+ "}",
+ },
+ "Done");
+}
+// Nested anonymous diamonds - TODO - confirm that this is indeed correct as per spec
+public void testBug488663_012() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " String name() {\n" +
+ " return this.name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " Y<String> y = new Y<>(\"Done\", new I<>() {\n" +
+ " public void doSomething(String s) {\n" +
+ " System.out.println(s);\n" +
+ " }\n" +
+ " }){\n" +
+ " };\n" +
+ " }\n" +
+ "}\n" +
+ "interface I<T> {\n" +
+ " void doSomething(T t);\n" +
+ "}\n" +
+ "class Y<T> {\n" +
+ " public Y(T t, I<T> i) {\n" +
+ " i.doSomething(t);\n" +
+ " }\n" +
+ "}",
+ },
+ "Done");
+}
+// Redundant type argument specification - TODO - confirm that this is correct
+public void testBug488663_013() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, CompilerOptions.ERROR);
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " String name() {\n" +
+ " return this.name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " X x = new X(\"Success\");\n" +
+ " I<X> i = new I<X>() {\n" +
+ " public String toString(X x1) {\n" +
+ " return x1.name();\n" +
+ " }\n" +
+ " };\n" +
+ " System.out.println(i.toString(x));\n" +
+ " }\n" +
+ "}\n" +
+ "interface I<T> {\n" +
+ " String toString(T t);\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 11)\n" +
+ " I<X> i = new I<X>() {\n" +
+ " ^\n" +
+ "Redundant specification of type arguments <X>\n" +
+ "----------\n",
+ null, true, options);
+}
+// All non-private methods of an anonymous class instantiated with '<>' must be treated as being annotated with @override
+public void testBug488663_014() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "public class X {\n" +
+ " String name;\n" +
+ " public X(String name) {\n" +
+ " this.name = name;\n" +
+ " }\n" +
+ " <T> void print(T o, I<T> converter) {\n" +
+ " System.out.println(converter.toString(o));\n" +
+ " }\n" +
+ " String name() {\n" +
+ " return this.name;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " X x = new X(\"asdasfd\");\n" +
+ " x.print(x, new Z<>() {\n" +
+ " public String toString(String s) {\n" +
+ " return s;\n" +
+ " }\n" +
+ " });\n" +
+ " }\n" +
+ "}\n" +
+ "interface I<T> {\n" +
+ " String toString(T t);\n" +
+ "}\n" +
+ "class Z<T> implements I<T> {\n" +
+ " public String toString(T t) {\n" +
+ " return \"\";\n" +
+ " }\n" +
+ "}",
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 15)\n" +
+ " public String toString(String s) {\n" +
+ " ^^^^^^^^^^^^^^^^^^\n" +
+ "The method toString(String) of type new Z<X>(){} must override or implement a supertype method\n" +
+ "----------\n");
+}
+public static Class testClass() {
+ return GenericsRegressionTest_9.class;
+}
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index 54a34af1e2..86f65b61eb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1904,6 +1904,8 @@ void setSourceStart(int sourceStart);
int ServiceImplNotDefinedByModule = TypeRelated + 1210;
/** @since 3.13 BETA_JAVA9 */
int ExportedPackageDoesNotExistOrIsEmpty = TypeRelated + 1211;
+ /** @since 3.13 BETA_JAVA9 */
+ int NonDenotableTypeArgumentForAnonymousDiamond = TypeRelated + 1212;
/** @since 3.13 BETA_JAVA9 */
int DuplicateResource = Internal + 1251;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index ca43ccf73e..8915ff88d0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -594,15 +594,21 @@ public static MethodBinding inferDiamondConstructor(Scope scope, InvocationSite
if (constructorTypeArguments.length > 0)
System.arraycopy(((ParameterizedGenericMethodBinding)factory).typeArguments, sfmb.typeVariables().length - constructorTypeArguments.length ,
constructorTypeArguments, 0, constructorTypeArguments.length);
+ if (allocationType.isInterface()) {
+ ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) factory.returnType;
+ return new ParameterizedMethodBinding(parameterizedType, sfmb.getConstructor());
+ }
return sfmb.applyTypeArgumentsOnConstructor(((ParameterizedTypeBinding)factory.returnType).arguments, constructorTypeArguments, genericFactory.inferredWithUncheckedConversion);
}
return null;
}
-
public TypeBinding[] inferElidedTypes(final Scope scope) {
+ return inferElidedTypes((ParameterizedTypeBinding) this.resolvedType, scope);
+}
+public TypeBinding[] inferElidedTypes(ParameterizedTypeBinding parameterizedType, final Scope scope) {
- ReferenceBinding genericType = ((ParameterizedTypeBinding) this.resolvedType).genericType();
- ReferenceBinding enclosingType = this.resolvedType.enclosingType();
+ ReferenceBinding genericType = parameterizedType.genericType();
+ ReferenceBinding enclosingType = parameterizedType.enclosingType();
ParameterizedTypeBinding allocationType = scope.environment().createParameterizedType(genericType, genericType.typeVariables(), enclosingType);
/* Given the allocation type and the arguments to the constructor, see if we can synthesize a generic static factory
@@ -646,7 +652,7 @@ public void checkTypeArgumentRedundancy(ParameterizedTypeBinding allocationType,
// checking for redundant type parameters must fake a diamond,
// so we infer the same results as we would get with a diamond in source code:
this.type.bits |= IsDiamond;
- inferredTypes = inferElidedTypes(scope);
+ inferredTypes = inferElidedTypes(allocationType, scope);
} finally {
// reset effects of inference
this.type.bits = previousBits;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
index 9afc96ed3c..e2cdfd35dc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -36,6 +36,8 @@ package org.eclipse.jdt.internal.compiler.ast;
import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT;
+import java.util.Arrays;
+
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
@@ -48,6 +50,7 @@ import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier;
+import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
@@ -58,8 +61,10 @@ import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
@@ -482,8 +487,10 @@ public class QualifiedAllocationExpression extends AllocationExpression {
}
} else {
if (isDiamond) {
- scope.problemReporter().diamondNotWithAnoymousClasses(this.type);
- return null;
+ if (sourceLevel < ClassFileConstants.JDK9) {
+ scope.problemReporter().diamondNotWithAnoymousClasses(this.type);
+ return null;
+ }
}
ReferenceBinding superType = (ReferenceBinding) receiverType;
if (superType.isTypeVariable()) {
@@ -494,56 +501,7 @@ public class QualifiedAllocationExpression extends AllocationExpression {
scope.problemReporter().cannotInstantiate(this.type, superType);
return this.resolvedType = superType;
}
- // anonymous type scenario
- // an anonymous class inherits from java.lang.Object when declared "after" an interface
- ReferenceBinding anonymousSuperclass = superType.isInterface() ? scope.getJavaLangObject() : superType;
- // insert anonymous type in scope
- scope.addAnonymousType(this.anonymousType, superType);
- this.anonymousType.resolve(scope);
-
- // find anonymous super constructor
- this.resolvedType = this.anonymousType.binding; // 1.2 change
- if ((this.resolvedType.tagBits & TagBits.HierarchyHasProblems) != 0) {
- return null; // stop secondary errors
- }
- MethodBinding inheritedBinding = findConstructorBinding(scope, this, anonymousSuperclass, this.argumentTypes);
-
- if (!inheritedBinding.isValidBinding()) {
- if (inheritedBinding.declaringClass == null) {
- inheritedBinding.declaringClass = anonymousSuperclass;
- }
- if (this.type != null && !this.type.resolvedType.isValidBinding()) {
- // problem already got signaled on type reference, do not report secondary problem
- return null;
- }
- scope.problemReporter().invalidConstructor(this, inheritedBinding);
- return this.resolvedType;
- }
- if ((inheritedBinding.tagBits & TagBits.HasMissingType) != 0) {
- scope.problemReporter().missingTypeInConstructor(this, inheritedBinding);
- }
- if (this.enclosingInstance != null) {
- ReferenceBinding targetEnclosing = inheritedBinding.declaringClass.enclosingType();
- if (targetEnclosing == null) {
- scope.problemReporter().unnecessaryEnclosingInstanceSpecification(this.enclosingInstance, superType);
- return this.resolvedType;
- } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing) && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) {
- scope.problemReporter().typeMismatchError(enclosingInstanceType, targetEnclosing, this.enclosingInstance, null);
- return this.resolvedType;
- }
- this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType);
- }
- if (this.arguments != null) {
- if (checkInvocationArguments(scope, null, anonymousSuperclass, inheritedBinding, this.arguments, this.argumentTypes, this.argsContainCast, this)) {
- this.bits |= ASTNode.Unchecked;
- }
- }
- if (this.typeArguments != null && inheritedBinding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
- scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(inheritedBinding, this.genericTypeArguments, this.typeArguments);
- }
- // Update the anonymous inner class : superclass, interface
- this.binding = this.anonymousType.createDefaultConstructorWithBinding(inheritedBinding, (this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null);
- return this.resolvedType;
+ this.resolvedType = receiverType;
}
} else {
if (this.enclosingInstance != null) {
@@ -551,8 +509,9 @@ public class QualifiedAllocationExpression extends AllocationExpression {
this.resolvedType = receiverType = this.type.resolvedType;
}
}
+ MethodBinding constructorBinding = null;
if (isDiamond) {
- this.binding = inferConstructorOfElidedParameterizedType(scope);
+ this.binding = constructorBinding = inferConstructorOfElidedParameterizedType(scope);
if (this.binding == null || !this.binding.isValidBinding()) {
scope.problemReporter().cannotInferElidedTypes(this);
return this.resolvedType = null;
@@ -561,50 +520,122 @@ public class QualifiedAllocationExpression extends AllocationExpression {
return new PolyTypeBinding(this);
}
this.resolvedType = this.type.resolvedType = receiverType = this.binding.declaringClass;
+ if (this.anonymousType != null) {
+ constructorBinding = getAnonymousConstructorBinding((ReferenceBinding) receiverType, scope);
+ if (constructorBinding == null)
+ return null;
+ this.resolvedType = this.anonymousType.binding;
+ // Check that inferred type is denotable
+ if (!checkTypeArgumentValidity((ParameterizedTypeBinding) receiverType, scope)) {
+ scope.problemReporter().anonymousDiamondWithNonDenotableTypeArguments(this.type, receiverType);
+ return this.resolvedType;
+ }
+ }
resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope);
} else {
- this.binding = findConstructorBinding(scope, this, (ReferenceBinding) receiverType, this.argumentTypes);
+ if (this.anonymousType != null) {
+ constructorBinding = getAnonymousConstructorBinding((ReferenceBinding) receiverType, scope);
+ if (constructorBinding == null)
+ return null;
+ this.resolvedType = this.anonymousType.binding;
+ } else {
+ this.binding = constructorBinding = findConstructorBinding(scope, this, (ReferenceBinding) receiverType, this.argumentTypes);
+ }
}
-
- if (this.binding.isValidBinding()) {
- if (isMethodUseDeprecated(this.binding, scope, true)) {
- scope.problemReporter().deprecatedMethod(this.binding, this);
+ ReferenceBinding receiver = (ReferenceBinding) receiverType;
+ ReferenceBinding superType = receiver.isInterface() ? scope.getJavaLangObject() : receiver;
+ if (constructorBinding.isValidBinding()) {
+ if (isMethodUseDeprecated(constructorBinding, scope, true)) {
+ scope.problemReporter().deprecatedMethod(constructorBinding, this);
}
- if (checkInvocationArguments(scope, null, receiverType, this.binding, this.arguments, this.argumentTypes, this.argsContainCast, this)) {
+ if (checkInvocationArguments(scope, null, superType, constructorBinding, this.arguments,
+ this.argumentTypes, this.argsContainCast, this)) {
this.bits |= ASTNode.Unchecked;
}
- if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
- scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.genericTypeArguments, this.typeArguments);
+ if (this.typeArguments != null && constructorBinding.original().typeVariables == Binding.NO_TYPE_VARIABLES) {
+ scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(constructorBinding,
+ this.genericTypeArguments, this.typeArguments);
}
} else {
- if (this.binding.declaringClass == null) {
- this.binding.declaringClass = (ReferenceBinding) receiverType;
+ if (constructorBinding.declaringClass == null) {
+ constructorBinding.declaringClass = superType;
}
if (this.type != null && !this.type.resolvedType.isValidBinding()) {
// problem already got signaled on type reference, do not report secondary problem
return null;
}
- scope.problemReporter().invalidConstructor(this, this.binding);
- return this.resolvedType = receiverType;
+ scope.problemReporter().invalidConstructor(this, constructorBinding);
+ return this.resolvedType;
+ }
+ if ((constructorBinding.tagBits & TagBits.HasMissingType) != 0) {
+ scope.problemReporter().missingTypeInConstructor(this, constructorBinding);
}
- if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
- scope.problemReporter().missingTypeInConstructor(this, this.binding);
+ if (this.enclosingInstance != null) {
+ ReferenceBinding targetEnclosing = constructorBinding.declaringClass.enclosingType();
+ if (targetEnclosing == null) {
+ scope.problemReporter().unnecessaryEnclosingInstanceSpecification(this.enclosingInstance, receiver);
+ return this.resolvedType;
+ } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing) && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) {
+ scope.problemReporter().typeMismatchError(enclosingInstanceType, targetEnclosing, this.enclosingInstance, null);
+ return this.resolvedType;
+ }
+ this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType);
}
if (!isDiamond && receiverType.isParameterizedTypeWithActualArguments()) {
- checkTypeArgumentRedundancy((ParameterizedTypeBinding)receiverType, scope);
+ checkTypeArgumentRedundancy((ParameterizedTypeBinding) receiverType, scope);
}
- // The enclosing instance must be compatible with the innermost enclosing type
- ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
- if (TypeBinding.notEquals(expectedType, enclosingInstanceType)) // must call before computeConversion() and typeMismatchError()
- scope.compilationUnitScope().recordTypeConversion(expectedType, enclosingInstanceType);
- if (enclosingInstanceType.isCompatibleWith(expectedType) || scope.isBoxingCompatibleWith(enclosingInstanceType, expectedType)) {
- this.enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType);
+ if (this.anonymousType != null) {
+ // anonymous type scenario
+ // Update the anonymous inner class : superclass, interface
+
+ this.binding = this.anonymousType.createDefaultConstructorWithBinding(constructorBinding, (this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null);
+ return this.resolvedType;
+ } else {
return this.resolvedType = receiverType;
}
- scope.problemReporter().typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance, null);
- return this.resolvedType = receiverType;
}
+ private boolean checkTypeArgumentValidity(final ParameterizedTypeBinding allocationType, final Scope scope) {
+ class ValidityInspector extends TypeBindingVisitor {
+ private boolean noErrors;
+
+ public ValidityInspector() {
+ this.noErrors = true;
+ }
+
+ public boolean visit(IntersectionTypeBinding18 intersectionTypeBinding18) {
+ Arrays.sort(intersectionTypeBinding18.intersectingTypes, (t1, t2) -> t1.id - t2.id);
+ return this.noErrors = false; // stop traversal
+ }
+ public boolean visit(TypeVariableBinding typeVariable) {
+ if (typeVariable.isCapture()) {
+ return this.noErrors = false; // stop traversal
+ }
+ return true; // continue traversal
+ }
+ public boolean isValid() {
+ TypeBindingVisitor.visit(this, allocationType);
+ return this.noErrors;
+ }
+ }
+
+ return new ValidityInspector().isValid();
+ }
+ private MethodBinding getAnonymousConstructorBinding(ReferenceBinding receiverType, BlockScope scope) {
+ ReferenceBinding superType = receiverType;
+ // an anonymous class inherits from java.lang.Object when declared "after" an interface
+ ReferenceBinding anonymousSuperclass = superType.isInterface() ? scope.getJavaLangObject() : superType;
+ // insert anonymous type in scope
+ scope.addAnonymousType(this.anonymousType, superType);
+ this.anonymousType.resolve(scope);
+
+ // find anonymous super constructor
+ this.resolvedType = this.anonymousType.binding; // 1.2 change
+ if ((this.resolvedType.tagBits & TagBits.HierarchyHasProblems) != 0) {
+ return null; // stop secondary errors
+ }
+ return findConstructorBinding(scope, this, anonymousSuperclass, this.argumentTypes);
+ }
public void traverse(ASTVisitor visitor, BlockScope scope) {
if (visitor.visit(this, scope)) {
if (this.enclosingInstance != null)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
index 8ea7a19e58..6d5e816a54 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
@@ -179,12 +179,11 @@ private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
// after this point, tests on the 16 bits reserved.
int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag;
-
+ long sourceLevel = compilerOptions().sourceLevel;
// set the requested modifiers for a method in an interface/annotation
if (declaringClass.isInterface()) {
int expectedModifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract;
boolean isDefaultMethod = (modifiers & ExtraCompilerModifiers.AccDefaultMethod) != 0; // no need to check validity, is done by the parser
- long sourceLevel = compilerOptions().sourceLevel;
if (sourceLevel >= ClassFileConstants.JDK1_8 && !declaringClass.isAnnotationType()) {
expectedModifiers |= ClassFileConstants.AccStrictfp
| ExtraCompilerModifiers.AccDefaultMethod | ClassFileConstants.AccStatic;
@@ -219,6 +218,18 @@ private void checkAndSetModifiersForMethod(MethodBinding methodBinding) {
methodBinding.modifiers &= (expectedModifiers | ~ExtraCompilerModifiers.AccJustFlag);
}
return;
+ } else if (declaringClass.isAnonymousType() && sourceLevel >= ClassFileConstants.JDK9) {
+ // If the class instance creation expression elides the supertype's type arguments using '<>',
+ // then for all non-private methods declared in the class body, it is as if the method declaration
+ // is annotated with @Override - https://bugs.openjdk.java.net/browse/JDK-8073593
+ LocalTypeBinding local = (LocalTypeBinding) declaringClass;
+ TypeReference ref = local.scope.referenceContext.allocation.type;
+ if (ref != null && (ref.bits & ASTNode.IsDiamond) != 0) {
+ //
+ if ((realModifiers & (ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic )) == 0) {
+ methodBinding.tagBits |= TagBits.AnnotationOverride;
+ }
+ }
}
// check for abnormal modifiers
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 49afea1ae1..c006650371 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
@@ -4910,8 +4910,10 @@ public abstract class Scope {
break;
currentType = currentType.enclosingType();
}
+ boolean isInterface = allocationType.isInterface();
+ ReferenceBinding typeToSearch = isInterface ? getJavaLangObject() : allocationType;
- MethodBinding[] methods = allocationType.getMethods(TypeConstants.INIT, argumentTypes.length);
+ MethodBinding[] methods = typeToSearch.getMethods(TypeConstants.INIT, argumentTypes.length);
MethodBinding [] staticFactories = new MethodBinding[methods.length];
int sfi = 0;
for (int i = 0, length = methods.length; i < length; i++) {
@@ -4929,8 +4931,8 @@ public abstract class Scope {
int methodTypeVariablesArity = methodTypeVariables.length;
final int factoryArity = classTypeVariablesArity + methodTypeVariablesArity;
final LookupEnvironment environment = environment();
-
- MethodBinding staticFactory = new SyntheticFactoryMethodBinding(method.original(), environment, originalEnclosingType);
+ MethodBinding targetMethod = isInterface ? new MethodBinding(method.original(), genericType) : method.original();
+ MethodBinding staticFactory = new SyntheticFactoryMethodBinding(targetMethod, environment, originalEnclosingType);
staticFactory.typeVariables = new TypeVariableBinding[factoryArity];
final SimpleLookupTable map = new SimpleLookupTable(factoryArity);
@@ -5007,7 +5009,7 @@ public abstract class Scope {
if (staticFactory.thrownExceptions == null) {
staticFactory.thrownExceptions = Binding.NO_EXCEPTIONS;
}
- staticFactories[sfi++] = new ParameterizedMethodBinding((ParameterizedTypeBinding) environment.convertToParameterizedType(staticFactory.declaringClass),
+ staticFactories[sfi++] = new ParameterizedMethodBinding((ParameterizedTypeBinding) environment.convertToParameterizedType(isInterface ? allocationType : staticFactory.declaringClass),
staticFactory);
}
if (sfi == 0)
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 e0c72e4ed2..3502321aa2 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
@@ -9283,6 +9283,14 @@ public void diamondNotWithAnoymousClasses(TypeReference type) {
type.sourceStart,
type.sourceEnd);
}
+public void anonymousDiamondWithNonDenotableTypeArguments(TypeReference type, TypeBinding tb) {
+ this.handle(
+ IProblem.NonDenotableTypeArgumentForAnonymousDiamond,
+ new String[]{new String(tb.leafComponentType().shortReadableName()), type.toString()},
+ new String[]{new String(tb.leafComponentType().shortReadableName()), type.toString()},
+ type.sourceStart,
+ type.sourceEnd);
+}
public void redundantSpecificationOfTypeArguments(ASTNode location, TypeBinding[] argumentTypes) {
int severity = computeSeverity(IProblem.RedundantSpecificationOfTypeArguments);
if (severity != ProblemSeverities.Ignore) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 5dcd376fa6..da9d141861 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -884,6 +884,7 @@
1209 = Invalid service implementation, the type {0} is an inner class
1210 = Service implementation {0} is not defined in the module with the provides directive
1211 = The exported package {0} does not exist or is empty
+1212 = Type {0} inferred for {1}, is not valid for an anonymous class with '<>'
### Autoclosable try
1251 = Duplicate resource reference {0}

Back to the top