Fix short name imports shadowed by super inner classes

master
JDLogic 6 years ago committed by Egor Ushakov
parent 0a29a0a8df
commit bc4d142688
  1. 32
      src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
  2. 3
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  3. BIN
      testData/classes/pkg/TestShadowing.class
  4. BIN
      testData/classes/pkg/TestShadowingSuperClass$Builder.class
  5. BIN
      testData/classes/pkg/TestShadowingSuperClass.class
  6. 3
      testData/results/TestShadowing.dec
  7. 9
      testData/src/pkg/TestShadowing.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.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext; 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.util.TextBuffer;
import org.jetbrains.java.decompiler.struct.StructClass; import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructContext; import org.jetbrains.java.decompiler.struct.StructContext;
@ -20,6 +21,7 @@ public class ImportCollector {
private final Set<String> setNotImportedNames = new HashSet<>(); private final Set<String> setNotImportedNames = new HashSet<>();
// set of field names in this class and all its predecessors. // set of field names in this class and all its predecessors.
private final Set<String> setFieldNames = new HashSet<>(); private final Set<String> setFieldNames = new HashSet<>();
private final Set<String> setInnerClassNames = new HashSet<>();
private final String currentPackageSlash; private final String currentPackageSlash;
private final String currentPackagePoint; private final String currentPackagePoint;
@ -37,15 +39,37 @@ public class ImportCollector {
} }
Map<String, StructClass> classes = DecompilerContext.getStructContext().getClasses(); Map<String, StructClass> classes = DecompilerContext.getStructContext().getClasses();
LinkedList<String> queue = new LinkedList<>();
StructClass currentClass = root.classStruct; StructClass currentClass = root.classStruct;
while (currentClass != null) { while (currentClass != null) {
if (currentClass.superClass != null) {
queue.add(currentClass.superClass.getString());
}
Collections.addAll(queue, currentClass.getInterfaceNames());
// all field names for the current class .. // all field names for the current class ..
for (StructField f : currentClass.getFields()) { for (StructField f : currentClass.getFields()) {
setFieldNames.add(f.getName()); 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. // .. 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(); 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 // 1) class with the same short name in the current package
// 2) class with the same short name in the default 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 = boolean existsDefaultClass =
(context.getClass(currentPackageSlash + shortName) != null && !packageName.equals(currentPackagePoint)) || // current package (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 || if (existsDefaultClass ||
(mapSimpleNames.containsKey(shortName) && !packageName.equals(mapSimpleNames.get(shortName)))) { (mapSimpleNames.containsKey(shortName) && !packageName.equals(mapSimpleNames.get(shortName)))) {

@ -70,7 +70,8 @@ public class SingleClassesTest {
@Test public void testAnonymousSignature() { doTest("pkg/TestAnonymousSignature"); } @Test public void testAnonymousSignature() { doTest("pkg/TestAnonymousSignature"); }
@Test public void testLocalsSignature() { doTest("pkg/TestLocalsSignature"); } @Test public void testLocalsSignature() { doTest("pkg/TestLocalsSignature"); }
@Test public void testParameterizedTypes() { doTest("pkg/TestParameterizedTypes"); } @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 testStringConcat() { doTest("pkg/TestStringConcat"); }
@Test public void testJava9StringConcat() { doTest("java9/TestJava9StringConcat"); } @Test public void testJava9StringConcat() { doTest("java9/TestJava9StringConcat"); }
@Test public void testMethodReferenceSameName() { doTest("pkg/TestMethodReferenceSameName"); } @Test public void testMethodReferenceSameName() { doTest("pkg/TestMethodReferenceSameName"); }

@ -1,6 +1,7 @@
package pkg; package pkg;
class TestShadowing { class TestShadowing extends TestShadowingSuperClass {
ext.Shadow.B instanceOfB = new ext.Shadow.B(); ext.Shadow.B instanceOfB = new ext.Shadow.B();
java.util.Calendar.Builder calBuilder = new java.util.Calendar.Builder();
} }

@ -1,5 +1,12 @@
package pkg; package pkg;
class TestShadowing { import java.util.Calendar;
class TestShadowing extends TestShadowingSuperClass {
ext.Shadow.B instanceOfB = new ext.Shadow.B(); ext.Shadow.B instanceOfB = new ext.Shadow.B();
Calendar.Builder calBuilder = new Calendar.Builder();
}
class TestShadowingSuperClass {
static class Builder { }
} }
Loading…
Cancel
Save