8272564: Incorrect attribution of method invocations of Object methods on interfaces
Reviewed-by: jlaskey, mcimadamore, vromero
This commit is contained in:
parent
a914ee7216
commit
a5080effc7
@ -2590,7 +2590,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
//where
|
//where
|
||||||
Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List<Type> argtypes, Type restype) {
|
Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List<Type> argtypes, Type restype) {
|
||||||
if (msym != null &&
|
if (msym != null &&
|
||||||
msym.owner == syms.objectType.tsym &&
|
(msym.owner == syms.objectType.tsym || msym.owner.isInterface()) &&
|
||||||
methodName == names.getClass &&
|
methodName == names.getClass &&
|
||||||
argtypes.isEmpty()) {
|
argtypes.isEmpty()) {
|
||||||
// as a special case, x.getClass() has type Class<? extends |X|>
|
// as a special case, x.getClass() has type Class<? extends |X|>
|
||||||
|
@ -469,7 +469,7 @@ public class Resolve {
|
|||||||
return true;
|
return true;
|
||||||
else {
|
else {
|
||||||
Symbol s2 = ((MethodSymbol)sym).implementation(site.tsym, types, true);
|
Symbol s2 = ((MethodSymbol)sym).implementation(site.tsym, types, true);
|
||||||
return (s2 == null || s2 == sym || sym.owner == s2.owner ||
|
return (s2 == null || s2 == sym || sym.owner == s2.owner || (sym.owner.isInterface() && s2.owner == syms.objectType.tsym) ||
|
||||||
!types.isSubSignature(types.memberType(site, s2), types.memberType(site, sym)));
|
!types.isSubSignature(types.memberType(site, s2), types.memberType(site, sym)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1854,7 +1854,8 @@ public class Resolve {
|
|||||||
List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>nil() };
|
List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>nil() };
|
||||||
|
|
||||||
InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK;
|
InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK;
|
||||||
for (TypeSymbol s : superclasses(intype)) {
|
boolean isInterface = site.tsym.isInterface();
|
||||||
|
for (TypeSymbol s : isInterface ? List.of(intype.tsym) : superclasses(intype)) {
|
||||||
bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
|
bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
|
||||||
s.members(), bestSoFar, allowBoxing, useVarargs, true);
|
s.members(), bestSoFar, allowBoxing, useVarargs, true);
|
||||||
if (name == names.init) return bestSoFar;
|
if (name == names.init) return bestSoFar;
|
||||||
@ -1892,6 +1893,19 @@ public class Resolve {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isInterface && bestSoFar.kind.isResolutionError()) {
|
||||||
|
bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes,
|
||||||
|
syms.objectType.tsym.members(), bestSoFar, allowBoxing, useVarargs, true);
|
||||||
|
if (bestSoFar.kind.isValid()) {
|
||||||
|
Symbol baseSymbol = bestSoFar;
|
||||||
|
bestSoFar = new MethodSymbol(bestSoFar.flags_field, bestSoFar.name, bestSoFar.type, intype.tsym) {
|
||||||
|
@Override
|
||||||
|
public Symbol baseSymbol() {
|
||||||
|
return baseSymbol;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
return bestSoFar;
|
return bestSoFar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8012929 8243074 8266281
|
* @bug 8012929 8243074 8266281 8272564
|
||||||
* @summary Trees.getElement should work not only for declaration trees, but also for use-trees
|
* @summary Trees.getElement should work not only for declaration trees, but also for use-trees
|
||||||
* @modules jdk.compiler
|
* @modules jdk.compiler
|
||||||
* @build TestGetElementReference
|
* @build TestGetElementReference
|
||||||
|
@ -37,6 +37,10 @@ public class TestGetElementReferenceData {
|
|||||||
target(TestGetElementReferenceData :: test/*getElement:METHOD:test.nested.TestGetElementReferenceData.test()*/);
|
target(TestGetElementReferenceData :: test/*getElement:METHOD:test.nested.TestGetElementReferenceData.test()*/);
|
||||||
Object/*getElement:CLASS:java.lang.Object*/ o = null;
|
Object/*getElement:CLASS:java.lang.Object*/ o = null;
|
||||||
if (o/*getElement:LOCAL_VARIABLE:o*/ instanceof String/*getElement:CLASS:java.lang.String*/ str/*getElement:BINDING_VARIABLE:str*/) ;
|
if (o/*getElement:LOCAL_VARIABLE:o*/ instanceof String/*getElement:CLASS:java.lang.String*/ str/*getElement:BINDING_VARIABLE:str*/) ;
|
||||||
|
I i = null;
|
||||||
|
i.toString/*getElement:METHOD:test.nested.TestGetElementReferenceData.I.toString()*/();
|
||||||
|
J j = null;
|
||||||
|
j.toString/*getElement:METHOD:test.nested.TestGetElementReferenceData.I.toString()*/();
|
||||||
}
|
}
|
||||||
private static void target(Runnable r) { r.run(); }
|
private static void target(Runnable r) { r.run(); }
|
||||||
public static class Base {
|
public static class Base {
|
||||||
@ -50,4 +54,8 @@ public class TestGetElementReferenceData {
|
|||||||
@Target(ElementType.TYPE_USE)
|
@Target(ElementType.TYPE_USE)
|
||||||
@interface TypeAnnotation {
|
@interface TypeAnnotation {
|
||||||
}
|
}
|
||||||
|
interface I {
|
||||||
|
public String toString();
|
||||||
|
}
|
||||||
|
interface J extends I {}
|
||||||
}
|
}
|
||||||
|
75
test/langtools/tools/javac/api/TestIsAccessible.java
Normal file
75
test/langtools/tools/javac/api/TestIsAccessible.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 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 8272564
|
||||||
|
* @summary Verify accessibility of Object-based methods inherited from super interfaces.
|
||||||
|
* @modules jdk.compiler
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.source.tree.CompilationUnitTree;
|
||||||
|
import com.sun.source.tree.Scope;
|
||||||
|
import com.sun.source.util.JavacTask;
|
||||||
|
import com.sun.source.util.TreePath;
|
||||||
|
import com.sun.source.util.Trees;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.type.DeclaredType;
|
||||||
|
import javax.tools.JavaCompiler;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.SimpleJavaFileObject;
|
||||||
|
import javax.tools.ToolProvider;
|
||||||
|
|
||||||
|
public class TestIsAccessible {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
||||||
|
assert tool != null;
|
||||||
|
final JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, Arrays.asList(new MyFileObject()));
|
||||||
|
|
||||||
|
CompilationUnitTree cut = ct.parse().iterator().next();
|
||||||
|
TreePath tp = new TreePath(new TreePath(cut), cut.getTypeDecls().get(0));
|
||||||
|
Scope s = Trees.instance(ct).getScope(tp);
|
||||||
|
TypeElement name = ct.getElements().getTypeElement("javax.lang.model.element.Name");
|
||||||
|
Trees trees = Trees.instance(ct);
|
||||||
|
|
||||||
|
if (trees.isAccessible(s, name)) {
|
||||||
|
for (Element member : ct.getElements().getAllMembers(name)) {
|
||||||
|
if (!trees.isAccessible(s, member, (DeclaredType) name.asType())) {
|
||||||
|
throw new IllegalStateException("Inaccessible Name member: " + member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MyFileObject extends SimpleJavaFileObject {
|
||||||
|
public MyFileObject() {
|
||||||
|
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
|
||||||
|
}
|
||||||
|
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||||
|
return "public class Test { }";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
test/langtools/tools/javac/resolve/NoObjectToString.java
Normal file
79
test/langtools/tools/javac/resolve/NoObjectToString.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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 8272564
|
||||||
|
* @summary Correct resolution of toString() (and other similar calls) on interfaces
|
||||||
|
* @modules jdk.jdeps/com.sun.tools.classfile
|
||||||
|
* @compile NoObjectToString.java
|
||||||
|
* @run main NoObjectToString
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import com.sun.tools.classfile.*;
|
||||||
|
import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info;
|
||||||
|
|
||||||
|
public class NoObjectToString {
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
NoObjectToString c = new NoObjectToString();
|
||||||
|
c.run(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(String... args) throws Exception {
|
||||||
|
//Verify there are no references to Object.toString() in a Test:
|
||||||
|
InputStream in = NoObjectToString.class.getResourceAsStream("NoObjectToString$Test.class");
|
||||||
|
try {
|
||||||
|
ClassFile cf = ClassFile.read(in);
|
||||||
|
for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) {
|
||||||
|
if (cpinfo.getTag() == ConstantPool.CONSTANT_Methodref) {
|
||||||
|
CONSTANT_Methodref_info ref = (CONSTANT_Methodref_info) cpinfo;
|
||||||
|
String methodDesc = ref.getClassInfo().getName() + "." + ref.getNameAndTypeInfo().getName() + ":" + ref.getNameAndTypeInfo().getType();
|
||||||
|
|
||||||
|
if ("java/lang/Object.toString:()Ljava/lang/String;".equals(methodDesc)) {
|
||||||
|
throw new AssertionError("Found call to j.l.Object.toString");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ConstantPoolException ignore) {
|
||||||
|
throw new AssertionError(ignore);
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
void test(I i, J j, K k) {
|
||||||
|
i.toString();
|
||||||
|
j.toString();
|
||||||
|
k.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
public String toString();
|
||||||
|
}
|
||||||
|
interface J extends I {}
|
||||||
|
interface K {}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user