diff --git a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java index 5e2d064..16e5ad4 100644 --- a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java +++ b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java @@ -5,6 +5,7 @@ package org.jetbrains.java.decompiler.main.collectors; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; import org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute; import org.jetbrains.java.decompiler.util.TextBuffer; import org.jetbrains.java.decompiler.struct.StructClass; import org.jetbrains.java.decompiler.struct.StructContext; @@ -20,6 +21,7 @@ public class ImportCollector { private final Set setNotImportedNames = new HashSet<>(); // set of field names in this class and all its predecessors. private final Set setFieldNames = new HashSet<>(); + private final Set setInnerClassNames = new HashSet<>(); private final String currentPackageSlash; private final String currentPackagePoint; @@ -37,15 +39,37 @@ public class ImportCollector { } Map classes = DecompilerContext.getStructContext().getClasses(); + LinkedList queue = new LinkedList<>(); StructClass currentClass = root.classStruct; while (currentClass != null) { + if (currentClass.superClass != null) { + queue.add(currentClass.superClass.getString()); + } + + Collections.addAll(queue, currentClass.getInterfaceNames()); + // all field names for the current class .. for (StructField f : currentClass.getFields()) { setFieldNames.add(f.getName()); } + // .. all inner classes for the current class .. + if (currentClass.hasAttribute(StructInnerClassesAttribute.ATTRIBUTE_INNER_CLASSES)) { + StructInnerClassesAttribute attribute = + (StructInnerClassesAttribute)currentClass.getAttribute(StructInnerClassesAttribute.ATTRIBUTE_INNER_CLASSES); + + for (StructInnerClassesAttribute.Entry entry : attribute.getEntries()) { + if (entry.enclosingName != null && entry.enclosingName.equals(currentClass.qualifiedName)) { + setInnerClassNames.add(entry.simpleName); + } + } + } + // .. and traverse through parent. - currentClass = currentClass.superClass != null ? classes.get(currentClass.superClass.getString()) : null; + currentClass = !queue.isEmpty() ? classes.get(queue.removeFirst()) : null; + while (currentClass == null && !queue.isEmpty()) { + currentClass = classes.get(queue.removeFirst()); + } } } @@ -105,12 +129,14 @@ public class ImportCollector { StructContext context = DecompilerContext.getStructContext(); - // check for another class which could 'shadow' this one. Two cases: + // check for another class which could 'shadow' this one. Three cases: // 1) class with the same short name in the current package // 2) class with the same short name in the default package + // 3) inner class with the same short name in the current class, a super class, or an implemented interface boolean existsDefaultClass = (context.getClass(currentPackageSlash + shortName) != null && !packageName.equals(currentPackagePoint)) || // current package - (context.getClass(shortName) != null && !currentPackagePoint.isEmpty()); // default package + (context.getClass(shortName) != null && !currentPackagePoint.isEmpty()) || // default package + setInnerClassNames.contains(shortName); // inner class if (existsDefaultClass || (mapSimpleNames.containsKey(shortName) && !packageName.equals(mapSimpleNames.get(shortName)))) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index e08ab4b..896d2db 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -70,7 +70,8 @@ public class SingleClassesTest { @Test public void testAnonymousSignature() { doTest("pkg/TestAnonymousSignature"); } @Test public void testLocalsSignature() { doTest("pkg/TestLocalsSignature"); } @Test public void testParameterizedTypes() { doTest("pkg/TestParameterizedTypes"); } - @Test public void testShadowing() { doTest("pkg/TestShadowing", "pkg/Shadow", "ext/Shadow"); } + @Test public void testShadowing() { doTest("pkg/TestShadowing", "pkg/Shadow", "ext/Shadow", + "pkg/TestShadowingSuperClass"); } @Test public void testStringConcat() { doTest("pkg/TestStringConcat"); } @Test public void testJava9StringConcat() { doTest("java9/TestJava9StringConcat"); } @Test public void testMethodReferenceSameName() { doTest("pkg/TestMethodReferenceSameName"); } diff --git a/testData/classes/pkg/TestShadowing.class b/testData/classes/pkg/TestShadowing.class index 228fd8f..caca600 100644 Binary files a/testData/classes/pkg/TestShadowing.class and b/testData/classes/pkg/TestShadowing.class differ diff --git a/testData/classes/pkg/TestShadowingSuperClass$Builder.class b/testData/classes/pkg/TestShadowingSuperClass$Builder.class new file mode 100644 index 0000000..ec4d6ad Binary files /dev/null and b/testData/classes/pkg/TestShadowingSuperClass$Builder.class differ diff --git a/testData/classes/pkg/TestShadowingSuperClass.class b/testData/classes/pkg/TestShadowingSuperClass.class new file mode 100644 index 0000000..e489b60 Binary files /dev/null and b/testData/classes/pkg/TestShadowingSuperClass.class differ diff --git a/testData/results/TestShadowing.dec b/testData/results/TestShadowing.dec index 45adbea..b7c0cd7 100644 --- a/testData/results/TestShadowing.dec +++ b/testData/results/TestShadowing.dec @@ -1,6 +1,7 @@ package pkg; -class TestShadowing { +class TestShadowing extends TestShadowingSuperClass { ext.Shadow.B instanceOfB = new ext.Shadow.B(); + java.util.Calendar.Builder calBuilder = new java.util.Calendar.Builder(); } diff --git a/testData/src/pkg/TestShadowing.java b/testData/src/pkg/TestShadowing.java index c8792b2..8539778 100644 --- a/testData/src/pkg/TestShadowing.java +++ b/testData/src/pkg/TestShadowing.java @@ -1,5 +1,12 @@ package pkg; -class TestShadowing { +import java.util.Calendar; + +class TestShadowing extends TestShadowingSuperClass { ext.Shadow.B instanceOfB = new ext.Shadow.B(); + Calendar.Builder calBuilder = new Calendar.Builder(); +} + +class TestShadowingSuperClass { + static class Builder { } } \ No newline at end of file