8074803: Name clash

Javac incorrectly reports a name clash.

Reviewed-by: mcimadamore
This commit is contained in:
Srikanth Adayapalam 2015-10-22 16:18:28 +05:30
parent 200d75bd08
commit b84f19e870
4 changed files with 126 additions and 26 deletions
langtools
src/jdk.compiler/share/classes/com/sun/tools/javac
test/tools/javac/NameClash

@ -220,11 +220,7 @@ public class Flags {
*/
public static final long UNION = 1L<<39;
/**
* Flag that marks a special kind of bridge method (the ones that
* come from restricted supertype bounds).
*/
public static final long OVERRIDE_BRIDGE = 1L<<40;
// Flag bit (1L << 40) is available.
/**
* Flag that marks an 'effectively final' local variable.
@ -383,7 +379,6 @@ public class Flags {
HYPOTHETICAL(Flags.HYPOTHETICAL),
PROPRIETARY(Flags.PROPRIETARY),
UNION(Flags.UNION),
OVERRIDE_BRIDGE(Flags.OVERRIDE_BRIDGE),
EFFECTIVELY_FINAL(Flags.EFFECTIVELY_FINAL),
CLASH(Flags.CLASH),
AUXILIARY(Flags.AUXILIARY),

@ -1528,9 +1528,33 @@ public abstract class Symbol extends AnnoConstruct implements Element {
* It is assumed that both symbols have the same name. The static
* modifier is ignored for this test.
*
* A quirk in the works is that if the receiver is a method symbol for
* an inherited abstract method we answer false summarily all else being
* immaterial. Abstract "own" methods (i.e `this' is a direct member of
* origin) don't get rejected as summarily and are put to test against the
* suitable criteria.
*
* See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
*/
public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult) {
return overrides(_other, origin, types, checkResult, true);
}
/** Does this symbol override `other' symbol, when both are seen as
* members of class `origin'? It is assumed that _other is a member
* of origin.
*
* Caveat: If `this' is an abstract inherited member of origin, it is
* deemed to override `other' only when `requireConcreteIfInherited'
* is false.
*
* It is assumed that both symbols have the same name. The static
* modifier is ignored for this test.
*
* See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
*/
public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult,
boolean requireConcreteIfInherited) {
if (isConstructor() || _other.kind != MTH) return false;
if (this == _other) return true;
@ -1550,7 +1574,7 @@ public abstract class Symbol extends AnnoConstruct implements Element {
}
// check for an inherited implementation
if ((flags() & ABSTRACT) != 0 ||
if (((flags() & ABSTRACT) != 0 && requireConcreteIfInherited) ||
((other.flags() & ABSTRACT) == 0 && (other.flags() & DEFAULT) == 0) ||
!other.isOverridableIn(origin) ||
!this.isMemberOf(origin, types))

@ -86,7 +86,7 @@ public class TransTypes extends TreeTranslator {
log = Log.instance(context);
syms = Symtab.instance(context);
enter = Enter.instance(context);
overridden = new HashMap<>();
bridgeSpans = new HashMap<>();
types = Types.instance(context);
make = TreeMaker.instance(context);
resolve = Resolve.instance(context);
@ -96,10 +96,12 @@ public class TransTypes extends TreeTranslator {
annotate = Annotate.instance(context);
}
/** A hashtable mapping bridge methods to the methods they override after
* type erasure.
/** A hashtable mapping bridge methods to the pair of methods they bridge.
* The bridge overrides the first of the pair after type erasure and deflects
* to the second of the pair (which differs in type erasure from the one
* it overrides thereby necessitating the bridge)
*/
Map<MethodSymbol,MethodSymbol> overridden;
Map<MethodSymbol, Pair<MethodSymbol, MethodSymbol>> bridgeSpans;
/** Construct an attributed tree for a cast of expression to target type,
* unless it already has precisely that type.
@ -294,9 +296,9 @@ public class TransTypes extends TreeTranslator {
bridges.append(md);
}
// Add bridge to scope of enclosing class and `overridden' table.
// Add bridge to scope of enclosing class and keep track of the bridge span.
origin.members().enter(bridge);
overridden.put(bridge, meth);
bridgeSpans.put(bridge, new Pair<>(meth, impl));
}
private List<VarSymbol> createBridgeParams(MethodSymbol impl, MethodSymbol bridge,
@ -344,12 +346,12 @@ public class TransTypes extends TreeTranslator {
if (sym.kind == MTH &&
sym.name != names.init &&
(sym.flags() & (PRIVATE | STATIC)) == 0 &&
(sym.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC &&
(sym.flags() & SYNTHETIC) != SYNTHETIC &&
sym.isMemberOf(origin, types))
{
MethodSymbol meth = (MethodSymbol)sym;
MethodSymbol bridge = meth.binaryImplementation(origin, types);
MethodSymbol impl = meth.implementation(origin, types, true, overrideBridgeFilter);
MethodSymbol impl = meth.implementation(origin, types, true);
if (bridge == null ||
bridge == meth ||
(impl != null && !bridge.owner.isSubClass(impl.owner, types))) {
@ -365,14 +367,19 @@ public class TransTypes extends TreeTranslator {
// reflection design error.
addBridge(pos, meth, impl, origin, false, bridges);
}
} else if ((bridge.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) == SYNTHETIC) {
MethodSymbol other = overridden.get(bridge);
} else if ((bridge.flags() & SYNTHETIC) == SYNTHETIC) {
final Pair<MethodSymbol, MethodSymbol> bridgeSpan = bridgeSpans.get(bridge);
MethodSymbol other = bridgeSpan == null ? null : bridgeSpan.fst;
if (other != null && other != meth) {
if (impl == null || !impl.overrides(other, origin, types, true)) {
// Bridge for other symbol pair was added
log.error(pos, "name.clash.same.erasure.no.override",
other, other.location(origin.type, types),
meth, meth.location(origin.type, types));
// Is bridge effectively also the bridge for `meth', if so no clash.
MethodSymbol target = bridgeSpan == null ? null : bridgeSpan.snd;
if (target == null || !target.overrides(meth, origin, types, true, false)) {
// Bridge for other symbol pair was added
log.error(pos, "name.clash.same.erasure.no.override",
other, other.location(origin.type, types),
meth, meth.location(origin.type, types));
}
}
}
} else if (!bridge.overrides(meth, origin, types, true)) {
@ -388,11 +395,6 @@ public class TransTypes extends TreeTranslator {
}
}
// where
private Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
public boolean accepts(Symbol s) {
return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
}
};
/**
* @param method The symbol for which a bridge might have to be added

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8074803
* @summary Incorrect name clash error
*
* @compile NameClashTest.java
*/
public class NameClashTest {
String log = "";
interface A1 {
A1 m(String s);
}
abstract class A2 implements A1 {
public abstract A2 m(String s);
}
interface B1 {
A1 m(String s);
}
interface B2 extends B1 {
A2 m(String s);
}
abstract class C extends A2 implements B2 {}
class D extends C {
public A2 m(String s) {
log += s;
return null;
}
}
public static void main(String[] args) {
NameClashTest nct = new NameClashTest();
A1 a1 = nct.new D();
a1.m("A1.m ");
A2 a2 = nct.new D();
a2.m("A2.m ");
B1 b1 = nct.new D();
b1.m("B1.m ");
B2 b2 = nct.new D();
b2.m("B2.m ");
C c = nct.new D();
c.m("C.m ");
D d = nct.new D();
d.m("D.m ");
if (!nct.log.equals("A1.m A2.m B1.m B2.m C.m D.m "))
throw new AssertionError("unexpected output: " + nct.log);
}
}