Revert "Fixed bug 467776 [compiler][implementation] decouple method verification from bridge method generation"
This reverts commit 65386f283034d2adbed1c5efa5bf0164d0891bf0.
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index f022ecc..a2458df 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -33089,7 +33089,7 @@
"1. ERROR in X.java (at line 7)\n" +
" abstract class GLinkElementView<M,CM> extends AbstractLinkView<M> {}\n" +
" ^^^^^^^^^^^^^^^^\n" +
- "The return types are incompatible for the inherited methods EditPart.getViewer(), AbstractLinkView<M>.getViewer()\n" +
+ "The return types are incompatible for the inherited methods ILinkViewElement.getViewer(), EditPart.getViewer(), AbstractLinkView<M>.getViewer()\n" +
"----------\n" +
"2. ERROR in X.java (at line 11)\n" +
" public SheetViewer getViewer() { return null; } \n" +
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
index a4c90fe..edb77db 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
@@ -14207,68 +14207,4 @@
assertEquals("Wrong contents", expectedOutput, result);
}
}
-// https://bugs.eclipse.org/bugs/show_bug.cgi?id=438812, Missing bridge methods in indirect child classes with ECJ 3.10.0
-public void testBug438812a() throws Exception {
- this.runConformTest(
- new String[] {
- "A.java",
- "import java.util.Collection;\n" +
- "import java.util.List;\n" +
- "\n" +
- "public abstract class A {\n" +
- " abstract Iterable getIterable();\n" +
- "}\n" +
- "\n" +
- "class B extends A {\n" +
- " public Collection getIterable() { return null; }\n" +
- "}\n" +
- "\n" +
- "class C extends B {\n" +
- " public List getIterable() { return null; }\n" +
- "}",
- },
- "");
- String expectedOutput = " public bridge synthetic java.lang.Iterable getIterable();";
-
- File f = new File(OUTPUT_DIR + File.separator + "C.class");
- byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
- ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
- String result = disassembler.disassemble(classFileBytes, "\n", ClassFileBytesDisassembler.DETAILED);
- int index = result.indexOf(expectedOutput);
- if (index == -1 || expectedOutput.length() == 0) {
- System.out.println(Util.displayString(result, 3));
- }
- if (index == -1) {
- assertEquals("Wrong contents", expectedOutput, result);
- }
-}
-// https://bugs.eclipse.org/bugs/show_bug.cgi?id=461529, Abstract class extending interface with default impl won't compile, but does compile from cmd line
-public void testBug461529() throws Exception {
- if (this.complianceLevel < ClassFileConstants.JDK1_8) return;
- this.runConformTest(
- new String[] {
- "foo/IBarable.java",
- "package foo;\n" +
- "public interface IBarable<T extends IBarable<T>> {\n" +
- " default IBar<T> createBar() {\n" +
- " throw new UnsupportedOperationException();\n" +
- " }\n" +
- "}\n",
- "foo/IBar.java",
- "package foo;\n" +
- "public interface IBar<T extends IBarable<T>> {\n" +
- " T bar();\n" +
- "}\n",
- "foo/Foo.java",
- "package foo;\n" +
- "public abstract class Foo implements IBarable<Foo> {\n" +
- " public abstract static class Builder implements IBar<Foo> {}\n" +
- " @Override\n" +
- " public abstract Builder createBar();\n" +
- "}\n",
- "foo/ChildFoo.java",
- "package foo;\n" +
- "public abstract class ChildFoo extends Foo {}\n"
- });
-}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
index 936e738..58166ae 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java
@@ -40,11 +40,6 @@
SourceTypeBinding type;
HashtableOfObject inheritedMethods;
HashtableOfObject currentMethods;
- /**
- * Methods that are to be considered inherited even though they are overridden somewhere in the
- * hierarchy - notably for bridge method generation
- */
- HashtableOfObject inheritedOverriddenMethods;
/*
Binding creation is responsible for reporting all problems with types:
- all modifier problems (duplicates & multiple visibility modifiers + incompatible combinations - abstract/final)
@@ -67,7 +62,6 @@
this.type = null; // Initialized with the public method verify(SourceTypeBinding)
this.inheritedMethods = null;
this.currentMethods = null;
- this.inheritedOverriddenMethods = null;
}
boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
return areMethodsCompatible(one, two, this.environment);
@@ -197,25 +191,6 @@
if (!inheritedMethod.isStatic() && !inheritedMethod.isFinal())
checkForBridgeMethod(currentMethod, inheritedMethod, allInheritedMethods);
}
- MethodBinding[] overridden = (MethodBinding[])this.inheritedOverriddenMethods.get(currentMethod.selector);
- if (overridden != null) {
- for (int i = overridden.length; --i >= 0;) {
- MethodBinding inheritedMethod = overridden[i];
- if (!inheritedMethod.isStatic() && !inheritedMethod.isFinal())
- checkForBridgeMethod(currentMethod, inheritedMethod, allInheritedMethods);
- }
- }
-}
-void addBridgeMethodCandidate(MethodBinding overriddenMethod) {
- MethodBinding[] existing = (MethodBinding[])this.inheritedOverriddenMethods.get(overriddenMethod.selector);
- if (existing == null) {
- existing = new MethodBinding[]{overriddenMethod};
- } else {
- int length = existing.length;
- System.arraycopy(existing, 0, existing = new MethodBinding[length + 1], 0, length);
- existing[length] = overriddenMethod;
- }
- this.inheritedOverriddenMethods.put(overriddenMethod.selector, existing);
}
public void reportRawReferences(MethodBinding currentMethod, MethodBinding inheritedMethod) {
@@ -529,7 +504,6 @@
// see usage of canOverridingMethodDifferInErasure below.
this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
- this.inheritedOverriddenMethods = new HashtableOfObject(11);
ReferenceBinding superType = superclass;
HashtableOfObject nonVisibleDefaultMethods = new HashtableOfObject(3); // maps method selectors to an array of methods
@@ -555,10 +529,6 @@
continue existing; // may need to record incompatible return type
}
}
- if (TypeBinding.notEquals(inheritedMethod.returnType, existingMethod.returnType) &&
- areReturnTypesCompatible(existingMethod, inheritedMethod)) {
- addBridgeMethodCandidate(inheritedMethod);
- }
continue nextMethod;
}
}
@@ -642,17 +612,9 @@
// look to see if any of the existingMethods implement this inheritedMethod
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358, skip inherited method only if any overriding version
// in a subclass is guaranteed to have the same erasure as an existing method.
- for (int e = 0; e < length; e++) {
- if (isInterfaceMethodImplemented(inheritedMethod, existingMethods[e], superType)) {
- if (TypeBinding.notEquals(inheritedMethod.returnType, existingMethods[e].returnType)) {
- // overridden, but with different return type, need to check
- // for bridge method
- addBridgeMethodCandidate(inheritedMethod);
- }
- if (!canOverridingMethodDifferInErasure(existingMethods[e], inheritedMethod))
- continue nextMethod;
- }
- }
+ for (int e = 0; e < length; e++)
+ if (isInterfaceMethodImplemented(inheritedMethod, existingMethods[e], superType) && !canOverridingMethodDifferInErasure(existingMethods[e], inheritedMethod))
+ continue nextMethod; // skip interface method with the same signature if visible to its declaringClass
System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
existingMethods[length] = inheritedMethod;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
index b583e89..2fa02c9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -949,18 +949,21 @@
return true;
}
}
-// caveat: returns false if a method is implemented, but with a return type that is incompatible with that of the interface method
+// caveat: returns false if a method is implemented that needs a bridge method
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
return false; // must hold onto ParameterizedMethod to see if a bridge method is necessary
inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod);
- if (inheritedMethod == null || !doesMethodOverride(existingMethod, inheritedMethod))
+ if (inheritedMethod == null
+ || TypeBinding.notEquals(inheritedMethod.returnType, existingMethod.returnType)) // need to keep around to produce bridge methods? ...
return false;
- return TypeBinding.equalsEquals(inheritedMethod.returnType, existingMethod.returnType)
- || (TypeBinding.notEquals(this.type, existingMethod.declaringClass) // ... not if inheriting the bridge situation from a superclass
- && !existingMethod.declaringClass.isInterface()
- && areReturnTypesCompatible(existingMethod, inheritedMethod)); // may have to report incompatible return type
+
+ if (!doesMethodOverride(existingMethod, inheritedMethod))
+ return false;
+
+ return TypeBinding.notEquals(this.type, existingMethod.declaringClass) // ... not if inheriting the bridge situation from a superclass
+ && !existingMethod.declaringClass.isInterface();
}
public boolean isMethodSubsignature(MethodBinding method, MethodBinding inheritedMethod) {
if (!org.eclipse.jdt.core.compiler.CharOperation.equals(method.selector, inheritedMethod.selector))