Skip to content

Commit

Permalink
8272564: Incorrect attribution of method invocations of Object method…
Browse files Browse the repository at this point in the history
…s on interfaces

Reviewed-by: jlaskey, mcimadamore, vromero
  • Loading branch information
lahodaj committed Oct 5, 2021
1 parent a914ee7 commit a5080ef
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 4 deletions.
Expand Up @@ -2590,7 +2590,7 @@ public void visitApply(JCMethodInvocation tree) {
//where
Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List<Type> 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<? extends |X|>
Expand Down
Expand Up @@ -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)));
}
}
Expand Down Expand Up @@ -1854,7 +1854,8 @@ private Symbol findMethod(Env<AttrContext> env,
List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>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;
Expand Down Expand Up @@ -1892,6 +1893,19 @@ private Symbol findMethod(Env<AttrContext> 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;
}

Expand Down
Expand Up @@ -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
Expand Down
Expand Up @@ -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 {
Expand All @@ -50,4 +54,8 @@ public static class TypeParam<TT/*getElement:TYPE_PARAMETER:TT*/> {
@Target(ElementType.TYPE_USE)
@interface TypeAnnotation {
}
interface I {
public String toString();
}
interface J extends I {}
}
75 changes: 75 additions & 0 deletions 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 { }";
}
}
}
79 changes: 79 additions & 0 deletions 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 {}

}

1 comment on commit a5080ef

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.