From bc4d142688682c6e11b2e8550c169386439ccfb3 Mon Sep 17 00:00:00 2001 From: JDLogic Date: Tue, 11 Sep 2018 19:48:32 +0300 Subject: [PATCH] Fix short name imports shadowed by super inner classes --- .../main/collectors/ImportCollector.java | 32 ++++++++++++++++-- .../java/decompiler/SingleClassesTest.java | 3 +- testData/classes/pkg/TestShadowing.class | Bin 342 -> 509 bytes .../pkg/TestShadowingSuperClass$Builder.class | Bin 0 -> 296 bytes .../classes/pkg/TestShadowingSuperClass.class | Bin 0 -> 296 bytes testData/results/TestShadowing.dec | 3 +- testData/src/pkg/TestShadowing.java | 9 ++++- 7 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 testData/classes/pkg/TestShadowingSuperClass$Builder.class create mode 100644 testData/classes/pkg/TestShadowingSuperClass.class 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 228fd8f7571f13eb43fd7fd3d86211b334142ec8..caca6001028523399a47d6a7737f665a8f393213 100644 GIT binary patch literal 509 zcmZ`$$xZ@65Pdx??F=IbE-0X);h-Fxi#Lo1NK8zK9v~(j8>Yq9v4_l}{+0(qqKO~i zM;VJHE+HPO>Q!}By_f2b&)0VV$Jn=EqR6pj!9dZ(5=tBu3#nPM&9TF=%aBnzjD+sX z%bO+xBeT!7mO;xCVJJg}Y+F7@PUlv*{!^{lV6ghaYsSiRWx&9{QKfw+9)%M}%5z%6 zliC$QZT?DA=@X?@bjpx8IJ{y=wtQDIO9e7iyh&IKKjk`k^9Giv+0B zeNDQ%K}JHzW5PwAk&$AGtArXzOe^L37_9yV<9dw52uXq|g6R?X%XDase3qI)AC^QK aIdEFOPPu^%*c1zd3~VAp#3_`i!~6pFe{Nv_ delta 229 zcmey%e2q!z)W2Q(7#J8#7$mqD*cb%a8HBkQm>2{(8CV%a*cn9G8N?>)n@pVPRnN`9 z!_FYi$iS0YQKBE5k(iQSuHwYQz|O$M$RJpdovt5}T3iAV&&*3_WDv+oEKAhSNz6;v z_fN`7O)g<%;6i9+PykxM2DF$Fh=FE6SwKsGBD_GJ4g)h-PC#or1Ebb%26Lv!?F`IY o8CW)gmGS{ekV6@O%2Pq|~C2#H1Xc2v=}^X;E^jTPBDj6p~t85}c8kl3$*gm#&wUSeD4cz{0@F&LF_Z zpj?ohu8*Q1xU?X($T=smxLC!hG&3h9wTO{{9nRwM%*%sHrxr6Z2!Kq}&q>Tn*Y{7# zN=+_dWRS*VB7*`06VN{(zzD=ZM*wLyAWIfVgG5-hwlgqp1WU66Nj9(`H&7D?kjKQp S$-oDsxqzZf4BQO73>*N(azX?E literal 0 HcmV?d00001 diff --git a/testData/classes/pkg/TestShadowingSuperClass.class b/testData/classes/pkg/TestShadowingSuperClass.class new file mode 100644 index 0000000000000000000000000000000000000000..e489b608e218f71e7aabae983287bd2fcf85b22f GIT binary patch literal 296 zcmaKnJx>Bb5Qg93YjHUQZH3O zIYL9@Bs;V3^Uh>;e}2Ed0ZeeEQAbzdQlY2NC#a{=CJ|=@Z{Zwgv&7^%=Y-ayb+(ui z>Vx4Mp)pG%CiI@IL8poKO>HPQY9n)pHq literal 0 HcmV?d00001 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