diff --git a/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java index 4116c5e03b1c1458b8a4f28ea1691bea40d88385..0c83e4d6686f6b4445f747d187b8dbeb5880e06b 100644 --- a/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java +++ b/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; +import java.util.Set; public class ArrayTypeImpl extends ReferenceTypeImpl implements ArrayType @@ -61,7 +62,8 @@ public class ArrayTypeImpl extends ReferenceTypeImpl return findType(componentSignature()); } - void addVisibleMethods(Map map) { + @Override + void addVisibleMethods(Map map, Set seenInterfaces) { // arrays don't have methods } diff --git a/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java index 2b2c0eecb70f43b5c9c7b89b4bca8d330b62be90..16b46e6be4e72396965435ee0916947957166380 100644 --- a/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java +++ b/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java @@ -382,7 +382,8 @@ public class ClassTypeImpl extends ReferenceTypeImpl } } - void addVisibleMethods(Map methodMap) { + @Override + void addVisibleMethods(Map methodMap, Set seenInterfaces) { /* * Add methods from * parent types first, so that the methods in this class will @@ -392,12 +393,15 @@ public class ClassTypeImpl extends ReferenceTypeImpl Iterator iter = interfaces().iterator(); while (iter.hasNext()) { InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next(); - interfaze.addVisibleMethods(methodMap); + if (!seenInterfaces.contains(interfaze)) { + interfaze.addVisibleMethods(methodMap, seenInterfaces); + seenInterfaces.add(interfaze); + } } ClassTypeImpl clazz = (ClassTypeImpl)superclass(); if (clazz != null) { - clazz.addVisibleMethods(methodMap); + clazz.addVisibleMethods(methodMap, seenInterfaces); } addToMethodMap(methodMap, methods()); diff --git a/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java b/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java index 8fa7670127b79276312e50965ab7be7e42ba1149..8e81c56ed88d7d820c35ba96fa4416b40ef67e5c 100644 --- a/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java +++ b/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.Iterator; import java.util.Collections; +import java.util.Set; import java.lang.ref.SoftReference; public class InterfaceTypeImpl extends ReferenceTypeImpl @@ -80,7 +81,8 @@ public class InterfaceTypeImpl extends ReferenceTypeImpl return implementors; } - void addVisibleMethods(Map methodMap) { + @Override + void addVisibleMethods(Map methodMap, Set seenInterfaces) { /* * Add methods from * parent types first, so that the methods in this class will @@ -88,7 +90,10 @@ public class InterfaceTypeImpl extends ReferenceTypeImpl */ for (InterfaceType interfaze : superinterfaces()) { - ((InterfaceTypeImpl)interfaze).addVisibleMethods(methodMap); + if (!seenInterfaces.contains(interfaze)) { + ((InterfaceTypeImpl)interfaze).addVisibleMethods(methodMap, seenInterfaces); + seenInterfaces.add(interfaze); + } } addToMethodMap(methodMap, methods()); diff --git a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java index 29da75da50ddff6f36caf5b1ec9cb5014329ff68..be98d5e0f3e5f38c6b25541a227e2d685840e614 100644 --- a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java +++ b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java @@ -511,7 +511,7 @@ implements ReferenceType { methodMap.put(method.name().concat(method.signature()), method); } - abstract void addVisibleMethods(Map methodMap); + abstract void addVisibleMethods(Map methodMap, Set seenInterfaces); public List visibleMethods() { /* @@ -520,7 +520,7 @@ implements ReferenceType { * concatenation of name and signature. */ Map map = new HashMap(); - addVisibleMethods(map); + addVisibleMethods(map, new HashSet()); /* * ... but the hash map destroys order. Methods should be diff --git a/test/com/sun/jdi/VisibleMethods.java b/test/com/sun/jdi/VisibleMethods.java new file mode 100644 index 0000000000000000000000000000000000000000..70f7f5abe401d39331a118ff0fa62fcc7e8764ec --- /dev/null +++ b/test/com/sun/jdi/VisibleMethods.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2013, 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 + * @summary Test ReferenceType.visibleMethods + * @bug 8028430 + * + * @author Staffan Larsen + * + * @run build TestScaffold VMConnection TargetListener TargetAdapter + * @run compile -g VisibleMethods.java + * @run main VisibleMethods + */ +import com.sun.jdi.Method; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.StringReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.event.BreakpointEvent; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/********** target program **********/ + +interface Super { + public void m(Object o); // This method should not be visible in AC + public void m(String s); // This method should not be visible in AC +} + +interface One extends Super { + public void m(Object o); + public void m1(); // Either this method or Two.m1 should be visible in AC +} + +interface Two extends Super { + public void m(String s); + public void m1(); // Either this method or One.m1 should be visible in AC +} + +abstract class AC implements One, Two { +} + +class CC extends AC { + public void m(Object o) { + } + public void m(String s) { + } + public void m1() { + } + public static void main(String[] args) { + System.out.println("Goodbye from VisibleMethods!"); + } +} + +/********** test program **********/ + +public class VisibleMethods extends TestScaffold { + ReferenceType targetClass; + ThreadReference mainThread; + + VisibleMethods(String args[]) { + super(args); + } + + public static void main(String[] args) throws Exception { + new VisibleMethods(args).startTests(); + } + + /********** test core **********/ + + protected void runTests() + throws Exception + { + /* + * Run to String. + */ + startToMain("CC"); + + ReferenceType ac = findReferenceType("AC"); + List visible = ac.visibleMethods(). + stream(). + map(Method::toString). + collect(Collectors.toList()); + + System.out.println("visibleMethods(): " + visible); + + verifyContains(visible, 1, "Two.m(java.lang.String)"); + verifyContains(visible, 1, "One.m(java.lang.Object)"); + verifyContains(visible, 0, "Super.m(java.lang.Object)"); + verifyContains(visible, 0, "Super.m(java.lang.String)"); + verifyContains(visible, 1, "Two.m1()", "One.m1()"); + + /* + * resume the target listening for events + */ + listenUntilVMDisconnect(); + } + + private void verifyContains(List methods, int matches, + String... sigs) throws Exception { + if (countMatches(methods, sigs) != matches) { + throw new Exception("visibleMethods() should have contained " + + matches + " entry/entries from " + Arrays.toString(sigs)); + } + } + + private int countMatches(List list1, String[] list2) { + int count = 0; + for (String s1 : list1) { + for (String s2 : list2) { + if (s1.equals(s2)) { + count++; + } + } + } + return count; + } +}