diff --git a/jadx-core/src/main/java/jadx/core/clsp/ClsSet.java b/jadx-core/src/main/java/jadx/core/clsp/ClsSet.java index 9bf4a3accf3f96d1b31690f6cea5c0399fc0248e..426b8a8a73e5eaa21e751f90be8e932dd31730ea 100644 --- a/jadx-core/src/main/java/jadx/core/clsp/ClsSet.java +++ b/jadx-core/src/main/java/jadx/core/clsp/ClsSet.java @@ -274,9 +274,9 @@ public class ClsSet { private static void writeArgType(DataOutputStream out, ArgType argType, Map names) throws IOException { if (argType.getWildcardType() != null) { out.writeByte(TypeEnum.WILDCARD.ordinal()); - int bounds = argType.getWildcardBounds(); - out.writeByte(bounds); - if (bounds != 0) { + ArgType.WildcardBound bound = argType.getWildcardBound(); + out.writeByte(bound.getNum()); + if (bound != ArgType.WildcardBound.UNBOUND) { writeArgType(out, argType.getWildcardType(), names); } } else if (argType.isGeneric()) { @@ -415,7 +415,7 @@ public class ClsSet { int bounds = in.readByte(); return bounds == 0 ? ArgType.wildcard() - : ArgType.wildcard(readArgType(in), bounds); + : ArgType.wildcard(readArgType(in), ArgType.WildcardBound.getByNum(bounds)); case GENERIC: String obj = classes[in.readInt()].getName(); diff --git a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java index fc21edf6346d5de33116d2ec5efbb25722b82711..01942264a5d77f8e148803f2e5fcaef94b31ba54 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java @@ -470,10 +470,9 @@ public class ClassGen { ArgType gt = generics[i]; ArgType wt = gt.getWildcardType(); if (wt != null) { - code.add('?'); - int bounds = gt.getWildcardBounds(); - if (bounds != 0) { - code.add(bounds == -1 ? " super " : " extends "); + ArgType.WildcardBound bound = gt.getWildcardBound(); + code.add(bound.getStr()); + if (bound != ArgType.WildcardBound.UNBOUND) { useType(code, wt); } } else { diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java index fc4f8704dc8749e50cbc2b69db994900e7dd8263..7f8a3cb3259cb1a3cc8ab5adaa5d5db853daa53a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java @@ -74,14 +74,14 @@ public abstract class ArgType { } public static ArgType wildcard() { - return new WildcardType(OBJECT, 0); + return new WildcardType(OBJECT, WildcardBound.UNBOUND); } - public static ArgType wildcard(ArgType obj, int bounds) { - return new WildcardType(obj, bounds); + public static ArgType wildcard(ArgType obj, WildcardBound bound) { + return new WildcardType(obj, bound); } - public static ArgType generic(String sign) { + public static ArgType parseGenericSignature(String sign) { return new SignatureParser(sign).consumeType(); } @@ -212,14 +212,40 @@ public abstract class ArgType { } } + public enum WildcardBound { + EXTENDS(1, "? extends "), // upper bound (? extends A) + UNBOUND(0, "?"), // no bounds (?) + SUPER(-1, "? super "); // lower bound (? super A) + + private final int num; + private final String str; + + WildcardBound(int val, String str) { + this.num = val; + this.str = str; + } + + public int getNum() { + return num; + } + + public String getStr() { + return str; + } + + public static WildcardBound getByNum(int num) { + return num == 0 ? UNBOUND : (num == 1 ? EXTENDS : SUPER); + } + } + private static final class WildcardType extends ObjectType { private final ArgType type; - private final int bounds; + private final WildcardBound bound; - public WildcardType(ArgType obj, int bounds) { + public WildcardType(ArgType obj, WildcardBound bound) { super(OBJECT.getObject()); this.type = obj; - this.bounds = bounds; + this.bound = bound; } @Override @@ -232,32 +258,24 @@ public abstract class ArgType { return type; } - /** - * Return wildcard bounds: - * - */ @Override - public int getWildcardBounds() { - return bounds; + public WildcardBound getWildcardBound() { + return bound; } @Override boolean internalEquals(Object obj) { return super.internalEquals(obj) - && bounds == ((WildcardType) obj).bounds + && bound == ((WildcardType) obj).bound && type.equals(((WildcardType) obj).type); } @Override public String toString() { - if (bounds == 0) { - return "?"; + if (bound == WildcardBound.UNBOUND) { + return bound.getStr(); } - return "? " + (bounds == -1 ? "super" : "extends") + ' ' + type; + return bound.getStr() + type; } } @@ -468,11 +486,8 @@ public abstract class ArgType { return null; } - /** - * @see WildcardType#getWildcardBounds() - */ - public int getWildcardBounds() { - return 0; + public WildcardBound getWildcardBound() { + return null; } public ArgType getOuterType() { @@ -629,6 +644,10 @@ public abstract class ArgType { if (isGenericType()) { return true; } + ArgType wildcardType = getWildcardType(); + if (wildcardType != null) { + return wildcardType.containsGenericType(); + } if (isGeneric()) { ArgType[] genericTypes = getGenericTypes(); if (genericTypes != null) { @@ -662,7 +681,7 @@ public abstract class ArgType { return new GenericObject(aliasFullName, type.getGenericTypes()); } if (type instanceof WildcardType) { - return new WildcardType(ArgType.object(aliasFullName), type.getWildcardBounds()); + return new WildcardType(ArgType.object(aliasFullName), type.getWildcardBound()); } } return ArgType.object(aliasFullName); diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java index dfcc71e38168a89553ab40a56042296067eb8e3f..d9de3d247ebf649e91715e7feda4215808377fdf 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java @@ -38,7 +38,8 @@ public class SignatureParser { if (a == null) { return null; } - return new SignatureParser(mergeSignature((List) a.getDefaultValue())); + String signature = mergeSignature((List) a.getDefaultValue()); + return new SignatureParser(signature); } private char next() { @@ -200,10 +201,10 @@ public class SignatureParser { type = ArgType.wildcard(); } else if (lookAhead('+')) { next(); - type = ArgType.wildcard(consumeType(), 1); + type = ArgType.wildcard(consumeType(), ArgType.WildcardBound.EXTENDS); } else if (lookAhead('-')) { next(); - type = ArgType.wildcard(consumeType(), -1); + type = ArgType.wildcard(consumeType(), ArgType.WildcardBound.SUPER); } else { type = consumeType(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/LocalVar.java b/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/LocalVar.java index f20044a60adffe2afbd1a266cc8901ce5d57a81f..f25ca9b640c1dbb11561c077dced5402cfc0f7bb 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/LocalVar.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/LocalVar.java @@ -31,7 +31,7 @@ public final class LocalVar { this.name = name; if (sign != null) { try { - ArgType gType = ArgType.generic(sign); + ArgType gType = ArgType.parseGenericSignature(sign); if (checkSignature(type, gType)) { type = gType; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/LoopRegionVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/LoopRegionVisitor.java index 5c3ac51afc295fcf86a4ce2855d3e3eb604dbd3c..8e2b1e338944c4cac8644072b26535d544db92ab 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/LoopRegionVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/LoopRegionVisitor.java @@ -327,7 +327,7 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor } ArgType wildcardType = gType.getWildcardType(); if (wildcardType != null - && gType.getWildcardBounds() == 1 + && gType.getWildcardBound() == ArgType.WildcardBound.EXTENDS && ArgType.isInstanceOf(mth.root(), wildcardType, varType)) { return true; } diff --git a/jadx-core/src/test/java/jadx/core/dex/instructions/args/ArgTypeTest.java b/jadx-core/src/test/java/jadx/core/dex/instructions/args/ArgTypeTest.java index f56f5b7a390222c2531b5d1c8ce3ab779c6e16cd..fbc5d9f010f6a54502e34722950483cd6a8bbd76 100644 --- a/jadx-core/src/test/java/jadx/core/dex/instructions/args/ArgTypeTest.java +++ b/jadx-core/src/test/java/jadx/core/dex/instructions/args/ArgTypeTest.java @@ -3,6 +3,7 @@ package jadx.core.dex.instructions.args; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class ArgTypeTest { @@ -13,4 +14,14 @@ class ArgTypeTest { assertEquals(first, second); } + + @Test + void testContainsGenericType() { + ArgType wildcard = ArgType.wildcard(ArgType.genericType("T"), ArgType.WildcardBound.SUPER); + assertTrue(wildcard.containsGenericType()); + + ArgType type = ArgType.generic("java.lang.List", wildcard); + assertTrue(type.containsGenericType()); + + } } diff --git a/jadx-core/src/test/java/jadx/tests/functional/SignatureParserTest.java b/jadx-core/src/test/java/jadx/tests/functional/SignatureParserTest.java index b0a881746ef59deaecf6c928f990adb81cc1d4d2..5c59c1e76c5ab46799474ece2f623c019aa6471f 100644 --- a/jadx-core/src/test/java/jadx/tests/functional/SignatureParserTest.java +++ b/jadx-core/src/test/java/jadx/tests/functional/SignatureParserTest.java @@ -6,6 +6,7 @@ import java.util.List; import org.junit.jupiter.api.Test; import jadx.core.dex.instructions.args.ArgType; +import jadx.core.dex.instructions.args.ArgType.WildcardBound; import jadx.core.dex.nodes.GenericInfo; import jadx.core.dex.nodes.parser.SignatureParser; @@ -60,10 +61,10 @@ class SignatureParserTest { @Test public void testWildcards() { checkWildcards("*", wildcard()); - checkWildcards("+Lb;", wildcard(object("b"), 1)); - checkWildcards("-Lb;", wildcard(object("b"), -1)); - checkWildcards("+TV;", wildcard(genericType("V"), 1)); - checkWildcards("-TV;", wildcard(genericType("V"), -1)); + checkWildcards("+Lb;", wildcard(object("b"), WildcardBound.EXTENDS)); + checkWildcards("-Lb;", wildcard(object("b"), WildcardBound.SUPER)); + checkWildcards("+TV;", wildcard(genericType("V"), WildcardBound.EXTENDS)); + checkWildcards("-TV;", wildcard(genericType("V"), WildcardBound.SUPER)); checkWildcards("**", wildcard(), wildcard()); checkWildcards("*Lb;", wildcard(), object("b")); @@ -116,7 +117,7 @@ class SignatureParserTest { assertThat(argTypes, hasSize(1)); ArgType argType = argTypes.get(0); assertThat(argType.getObject().indexOf('/'), is(-1)); - assertThat(argType, is(genericInner(generic("La/b/C;", genericType("T")), "d.E", (ArgType[]) null))); + assertThat(argType, is(genericInner(generic("La/b/C;", genericType("T")), "d.E", null))); } @Test