diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 3bf1f593634fd..56b678f847224 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -2590,7 +2590,7 @@ public void visitApply(JCMethodInvocation tree) { //where Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List argtypes, Type restype) { if (msym != null && - msym.owner == syms.objectType.tsym && + (msym.owner == syms.objectType.tsym || msym.owner.isInterface()) && methodName == names.getClass && argtypes.isEmpty()) { // as a special case, x.getClass() has type Class diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index c18060a85a665..a9d47bf7ca7d8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -469,7 +469,7 @@ private boolean notOverriddenIn(Type site, Symbol sym) { return true; else { 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))); } } @@ -1854,7 +1854,8 @@ private Symbol findMethod(Env env, List[] itypes = (List[])new List[] { List.nil(), List.nil() }; 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, s.members(), bestSoFar, allowBoxing, useVarargs, true); if (name == names.init) return bestSoFar; @@ -1892,6 +1893,19 @@ private Symbol findMethod(Env env, } } } + 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; } diff --git a/test/langtools/tools/javac/api/TestGetElementReference.java b/test/langtools/tools/javac/api/TestGetElementReference.java index 7eb8cd0238188..9de0dc61c189a 100644 --- a/test/langtools/tools/javac/api/TestGetElementReference.java +++ b/test/langtools/tools/javac/api/TestGetElementReference.java @@ -23,7 +23,7 @@ /* * @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 * @modules jdk.compiler * @build TestGetElementReference diff --git a/test/langtools/tools/javac/api/TestGetElementReferenceData.java b/test/langtools/tools/javac/api/TestGetElementReferenceData.java index b86defa69f604..8e86092a364ba 100644 --- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java +++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.java @@ -37,6 +37,10 @@ private static void test() { target(TestGetElementReferenceData :: test/*getElement:METHOD:test.nested.TestGetElementReferenceData.test()*/); 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*/) ; + 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(); } public static class Base { @@ -50,4 +54,8 @@ public static class TypeParam { @Target(ElementType.TYPE_USE) @interface TypeAnnotation { } + interface I { + public String toString(); + } + interface J extends I {} } diff --git a/test/langtools/tools/javac/api/TestIsAccessible.java b/test/langtools/tools/javac/api/TestIsAccessible.java new file mode 100644 index 0000000000000..dd1f509a33afe --- /dev/null +++ b/test/langtools/tools/javac/api/TestIsAccessible.java @@ -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 { }"; + } + } +} diff --git a/test/langtools/tools/javac/resolve/NoObjectToString.java b/test/langtools/tools/javac/resolve/NoObjectToString.java new file mode 100644 index 0000000000000..c7275a8cd5e45 --- /dev/null +++ b/test/langtools/tools/javac/resolve/NoObjectToString.java @@ -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 {} + +}