feat: move variable name apply from codegen to new pass (#2422)
This commit is contained in:
@@ -16,6 +16,7 @@ import jadx.core.deobf.DeobfuscatorVisitor;
|
||||
import jadx.core.deobf.SaveDeobfMapping;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.visitors.AnonymousClassVisitor;
|
||||
import jadx.core.dex.visitors.ApplyVariableNames;
|
||||
import jadx.core.dex.visitors.AttachCommentsVisitor;
|
||||
import jadx.core.dex.visitors.AttachMethodDetails;
|
||||
import jadx.core.dex.visitors.AttachTryCatchVisitor;
|
||||
@@ -200,6 +201,7 @@ public class Jadx {
|
||||
passes.add(new MarkMethodsForInline());
|
||||
}
|
||||
passes.add(new ProcessVariables());
|
||||
passes.add(new ApplyVariableNames());
|
||||
passes.add(new PrepareForCodeGen());
|
||||
if (args.isCfgOutput()) {
|
||||
passes.add(DotGraphVisitor.dumpRegions());
|
||||
|
||||
@@ -2,57 +2,22 @@ package jadx.core.codegen;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.nodes.LoopLabelAttr;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.InvokeNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.instructions.args.NamedArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.instructions.mods.ConstructorInsn;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public class NameGen {
|
||||
|
||||
private static final Map<String, String> OBJ_ALIAS;
|
||||
|
||||
private final Set<String> varNames = new HashSet<>();
|
||||
private final MethodNode mth;
|
||||
private final boolean fallback;
|
||||
|
||||
static {
|
||||
OBJ_ALIAS = Utils.newConstStringMap(
|
||||
Consts.CLASS_STRING, "str",
|
||||
Consts.CLASS_CLASS, "cls",
|
||||
Consts.CLASS_THROWABLE, "th",
|
||||
Consts.CLASS_OBJECT, "obj",
|
||||
"java.util.Iterator", "it",
|
||||
"java.lang.Boolean", "bool",
|
||||
"java.lang.Short", "sh",
|
||||
"java.lang.Integer", "num",
|
||||
"java.lang.Character", "ch",
|
||||
"java.lang.Byte", "b",
|
||||
"java.lang.Float", "f",
|
||||
"java.lang.Long", "l",
|
||||
"java.lang.Double", "d",
|
||||
"java.lang.StringBuilder", "sb",
|
||||
"java.lang.Exception", "exc");
|
||||
}
|
||||
private final Set<String> varNames = new HashSet<>();
|
||||
|
||||
public NameGen(MethodNode mth, ClassGen classGen) {
|
||||
this.mth = mth;
|
||||
@@ -99,9 +64,9 @@ public class NameGen {
|
||||
if (fallback) {
|
||||
return name;
|
||||
}
|
||||
name = getUniqueVarName(name);
|
||||
arg.setName(name);
|
||||
return name;
|
||||
String uniqName = getUniqueVarName(name);
|
||||
arg.setName(uniqName);
|
||||
return uniqName;
|
||||
}
|
||||
|
||||
public String useArg(RegisterArg arg) {
|
||||
@@ -132,13 +97,10 @@ public class NameGen {
|
||||
|
||||
private String makeArgName(CodeVar var) {
|
||||
String name = var.getName();
|
||||
if (name == null) {
|
||||
name = guessName(var);
|
||||
if (NameMapper.isValidAndPrintable(name)) {
|
||||
return name;
|
||||
}
|
||||
if (!NameMapper.isValidAndPrintable(name)) {
|
||||
name = getFallbackName(var);
|
||||
}
|
||||
return name;
|
||||
return getFallbackName(var);
|
||||
}
|
||||
|
||||
private String getFallbackName(CodeVar var) {
|
||||
@@ -152,153 +114,4 @@ public class NameGen {
|
||||
private String getFallbackName(RegisterArg arg) {
|
||||
return "r" + arg.getRegNum();
|
||||
}
|
||||
|
||||
private String guessName(CodeVar var) {
|
||||
List<SSAVar> ssaVars = var.getSsaVars();
|
||||
if (ssaVars != null && !ssaVars.isEmpty()) {
|
||||
// TODO: use all vars for better name generation
|
||||
SSAVar ssaVar = ssaVars.get(0);
|
||||
if (ssaVar != null && ssaVar.getName() == null) {
|
||||
RegisterArg assignArg = ssaVar.getAssign();
|
||||
InsnNode assignInsn = assignArg.getParentInsn();
|
||||
if (assignInsn != null) {
|
||||
String name = makeNameFromInsn(assignInsn);
|
||||
if (name != null && NameMapper.isValidAndPrintable(name)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return makeNameForType(var.getType());
|
||||
}
|
||||
|
||||
private String makeNameForType(ArgType type) {
|
||||
if (type.isPrimitive()) {
|
||||
return type.getPrimitiveType().getShortName().toLowerCase();
|
||||
}
|
||||
if (type.isArray()) {
|
||||
return makeNameForType(type.getArrayRootElement()) + "Arr";
|
||||
}
|
||||
return makeNameForObject(type);
|
||||
}
|
||||
|
||||
private String makeNameForObject(ArgType type) {
|
||||
if (type.isGenericType()) {
|
||||
return StringUtils.escape(type.getObject().toLowerCase());
|
||||
}
|
||||
if (type.isObject()) {
|
||||
String alias = getAliasForObject(type.getObject());
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
return makeNameForCheckedClass(ClassInfo.fromType(mth.root(), type));
|
||||
}
|
||||
return StringUtils.escape(type.toString());
|
||||
}
|
||||
|
||||
private String makeNameForCheckedClass(ClassInfo classInfo) {
|
||||
String shortName = classInfo.getAliasShortName();
|
||||
String vName = fromName(shortName);
|
||||
if (vName != null) {
|
||||
return vName;
|
||||
}
|
||||
String lower = StringUtils.escape(shortName.toLowerCase());
|
||||
if (shortName.equals(lower)) {
|
||||
return lower + "Var";
|
||||
}
|
||||
return lower;
|
||||
}
|
||||
|
||||
private String makeNameForClass(ClassInfo classInfo) {
|
||||
String alias = getAliasForObject(classInfo.getFullName());
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
return makeNameForCheckedClass(classInfo);
|
||||
}
|
||||
|
||||
private static String fromName(String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (name.toUpperCase().equals(name)) {
|
||||
// all characters are upper case
|
||||
return name.toLowerCase();
|
||||
}
|
||||
String v1 = Character.toLowerCase(name.charAt(0)) + name.substring(1);
|
||||
if (!v1.equals(name)) {
|
||||
return v1;
|
||||
}
|
||||
if (name.length() < 3) {
|
||||
return name + "Var";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getAliasForObject(String name) {
|
||||
return OBJ_ALIAS.get(name);
|
||||
}
|
||||
|
||||
private String makeNameFromInsn(InsnNode insn) {
|
||||
switch (insn.getType()) {
|
||||
case INVOKE:
|
||||
InvokeNode inv = (InvokeNode) insn;
|
||||
return makeNameFromInvoke(inv.getCallMth());
|
||||
|
||||
case CONSTRUCTOR:
|
||||
ConstructorInsn co = (ConstructorInsn) insn;
|
||||
MethodNode callMth = mth.root().getMethodUtils().resolveMethod(co);
|
||||
if (callMth != null && callMth.contains(AFlag.ANONYMOUS_CONSTRUCTOR)) {
|
||||
// don't use name of anonymous class
|
||||
return null;
|
||||
}
|
||||
return makeNameForClass(co.getClassType());
|
||||
|
||||
case ARRAY_LENGTH:
|
||||
return "length";
|
||||
|
||||
case ARITH:
|
||||
case TERNARY:
|
||||
case CAST:
|
||||
for (InsnArg arg : insn.getArguments()) {
|
||||
if (arg.isInsnWrap()) {
|
||||
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
|
||||
String wName = makeNameFromInsn(wrapInsn);
|
||||
if (wName != null) {
|
||||
return wName;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String makeNameFromInvoke(MethodInfo callMth) {
|
||||
String name = callMth.getAlias();
|
||||
ClassInfo declClass = callMth.getDeclClass();
|
||||
if ("getInstance".equals(name)) {
|
||||
// e.g. Cipher.getInstance
|
||||
return makeNameForClass(declClass);
|
||||
}
|
||||
if (name.startsWith("get") || name.startsWith("set")) {
|
||||
return fromName(name.substring(3));
|
||||
}
|
||||
if ("iterator".equals(name)) {
|
||||
return "it";
|
||||
}
|
||||
if ("toString".equals(name)) {
|
||||
return makeNameForClass(declClass);
|
||||
}
|
||||
if ("forName".equals(name) && declClass.getType().equals(ArgType.CLASS)) {
|
||||
return OBJ_ALIAS.get(Consts.CLASS_CLASS);
|
||||
}
|
||||
if (name.startsWith("to")) {
|
||||
return fromName(name.substring(2));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,13 +59,11 @@ public class SSAVar implements Comparable<SSAVar> {
|
||||
return version;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RegisterArg getAssign() {
|
||||
public @NotNull RegisterArg getAssign() {
|
||||
return assign;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InsnNode getAssignInsn() {
|
||||
public @Nullable InsnNode getAssignInsn() {
|
||||
return assign.getParentInsn();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
package jadx.core.dex.visitors;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.InvokeNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.instructions.mods.ConstructorInsn;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.visitors.regions.variables.ProcessVariables;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
@JadxVisitor(
|
||||
name = "ApplyVariableNames",
|
||||
desc = "Try to guess variable name from usage",
|
||||
runAfter = {
|
||||
ProcessVariables.class
|
||||
}
|
||||
)
|
||||
public class ApplyVariableNames extends AbstractVisitor {
|
||||
|
||||
private static final Map<String, String> OBJ_ALIAS = Utils.newConstStringMap(
|
||||
Consts.CLASS_STRING, "str",
|
||||
Consts.CLASS_CLASS, "cls",
|
||||
Consts.CLASS_THROWABLE, "th",
|
||||
Consts.CLASS_OBJECT, "obj",
|
||||
"java.util.Iterator", "it",
|
||||
"java.util.HashMap", "map",
|
||||
"java.lang.Boolean", "bool",
|
||||
"java.lang.Short", "sh",
|
||||
"java.lang.Integer", "num",
|
||||
"java.lang.Character", "ch",
|
||||
"java.lang.Byte", "b",
|
||||
"java.lang.Float", "f",
|
||||
"java.lang.Long", "l",
|
||||
"java.lang.Double", "d",
|
||||
"java.lang.StringBuilder", "sb",
|
||||
"java.lang.Exception", "exc");
|
||||
|
||||
private static final Set<String> GOOD_VAR_NAMES = Set.of(
|
||||
"size", "length", "list", "map", "next");
|
||||
private static final List<String> INVOKE_PREFIXES = List.of(
|
||||
"get", "set", "to", "parse", "read", "format");
|
||||
|
||||
private RootNode root;
|
||||
|
||||
@Override
|
||||
public void init(RootNode root) throws JadxException {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
for (SSAVar ssaVar : mth.getSVars()) {
|
||||
CodeVar codeVar = ssaVar.getCodeVar();
|
||||
String newName = guessName(codeVar);
|
||||
if (newName != null) {
|
||||
codeVar.setName(newName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable String guessName(CodeVar var) {
|
||||
if (var.isThis()) {
|
||||
return RegisterArg.THIS_ARG_NAME;
|
||||
}
|
||||
if (!var.isDeclared()) {
|
||||
// name is not used in code
|
||||
return null;
|
||||
}
|
||||
if (NameMapper.isValidAndPrintable(var.getName())) {
|
||||
// the current name is valid, keep it
|
||||
return null;
|
||||
}
|
||||
List<SSAVar> ssaVars = var.getSsaVars();
|
||||
if (Utils.notEmpty(ssaVars)) {
|
||||
boolean mthArg = ssaVars.stream().anyMatch(ssaVar -> ssaVar.getAssign().contains(AFlag.METHOD_ARGUMENT));
|
||||
if (mthArg) {
|
||||
// for method args use defined type and ignore usage
|
||||
return makeNameForType(var.getType());
|
||||
}
|
||||
for (SSAVar ssaVar : ssaVars) {
|
||||
String name = makeNameForSSAVar(ssaVar);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return makeNameForType(var.getType());
|
||||
}
|
||||
|
||||
private @Nullable String makeNameForSSAVar(SSAVar ssaVar) {
|
||||
String ssaVarName = ssaVar.getName();
|
||||
if (ssaVarName != null) {
|
||||
return ssaVarName;
|
||||
}
|
||||
InsnNode assignInsn = ssaVar.getAssignInsn();
|
||||
if (assignInsn != null) {
|
||||
String name = makeNameFromInsn(ssaVar, assignInsn);
|
||||
if (NameMapper.isValidAndPrintable(name)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String makeNameFromInsn(SSAVar ssaVar, InsnNode insn) {
|
||||
switch (insn.getType()) {
|
||||
case INVOKE:
|
||||
return makeNameFromInvoke(ssaVar, (InvokeNode) insn);
|
||||
|
||||
case CONSTRUCTOR:
|
||||
ConstructorInsn co = (ConstructorInsn) insn;
|
||||
MethodNode callMth = root.getMethodUtils().resolveMethod(co);
|
||||
if (callMth != null && callMth.contains(AFlag.ANONYMOUS_CONSTRUCTOR)) {
|
||||
// don't use name of anonymous class
|
||||
return null;
|
||||
}
|
||||
return makeNameForClass(co.getClassType());
|
||||
|
||||
case ARRAY_LENGTH:
|
||||
return "length";
|
||||
|
||||
case ARITH:
|
||||
case TERNARY:
|
||||
case CAST:
|
||||
for (InsnArg arg : insn.getArguments()) {
|
||||
if (arg.isInsnWrap()) {
|
||||
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
|
||||
String wName = makeNameFromInsn(ssaVar, wrapInsn);
|
||||
if (wName != null) {
|
||||
return wName;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String makeNameForType(ArgType type) {
|
||||
if (type.isPrimitive()) {
|
||||
return type.getPrimitiveType().getShortName().toLowerCase();
|
||||
}
|
||||
if (type.isArray()) {
|
||||
return makeNameForType(type.getArrayRootElement()) + "Arr";
|
||||
}
|
||||
return makeNameForObject(type);
|
||||
}
|
||||
|
||||
private String makeNameForObject(ArgType type) {
|
||||
if (type.isGenericType()) {
|
||||
return StringUtils.escape(type.getObject().toLowerCase());
|
||||
}
|
||||
if (type.isObject()) {
|
||||
String alias = getAliasForObject(type.getObject());
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
return makeNameForCheckedClass(ClassInfo.fromType(root, type));
|
||||
}
|
||||
return StringUtils.escape(type.toString());
|
||||
}
|
||||
|
||||
private String makeNameForCheckedClass(ClassInfo classInfo) {
|
||||
String shortName = classInfo.getAliasShortName();
|
||||
String vName = fromName(shortName);
|
||||
if (vName != null) {
|
||||
return vName;
|
||||
}
|
||||
String lower = StringUtils.escape(shortName.toLowerCase());
|
||||
if (shortName.equals(lower)) {
|
||||
return lower + "Var";
|
||||
}
|
||||
return lower;
|
||||
}
|
||||
|
||||
private String makeNameForClass(ClassInfo classInfo) {
|
||||
String alias = getAliasForObject(classInfo.getFullName());
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
return makeNameForCheckedClass(classInfo);
|
||||
}
|
||||
|
||||
private static String fromName(String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (name.toUpperCase().equals(name)) {
|
||||
// all characters are upper case
|
||||
return name.toLowerCase();
|
||||
}
|
||||
String v1 = Character.toLowerCase(name.charAt(0)) + name.substring(1);
|
||||
if (!v1.equals(name)) {
|
||||
return v1;
|
||||
}
|
||||
if (name.length() < 3) {
|
||||
return name + "Var";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getAliasForObject(String name) {
|
||||
return OBJ_ALIAS.get(name);
|
||||
}
|
||||
|
||||
private String makeNameFromInvoke(SSAVar ssaVar, InvokeNode inv) {
|
||||
MethodInfo callMth = inv.getCallMth();
|
||||
String name = callMth.getAlias();
|
||||
ClassInfo declClass = callMth.getDeclClass();
|
||||
if ("getInstance".equals(name)) {
|
||||
// e.g. Cipher.getInstance
|
||||
return makeNameForClass(declClass);
|
||||
}
|
||||
String shortName = cutPrefix(name);
|
||||
if (shortName != null) {
|
||||
return fromName(shortName);
|
||||
}
|
||||
if ("iterator".equals(name)) {
|
||||
return "it";
|
||||
}
|
||||
if ("toString".equals(name)) {
|
||||
return makeNameForClass(declClass);
|
||||
}
|
||||
if ("forName".equals(name) && declClass.getType().equals(ArgType.CLASS)) {
|
||||
return OBJ_ALIAS.get(Consts.CLASS_CLASS);
|
||||
}
|
||||
// use method name as a variable name not the best idea in most cases
|
||||
if (!GOOD_VAR_NAMES.contains(name)) {
|
||||
String typeName = makeNameForType(ssaVar.getCodeVar().getType());
|
||||
if (!typeName.equalsIgnoreCase(name)) {
|
||||
return typeName + StringUtils.capitalizeFirstChar(name);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private @Nullable String cutPrefix(String name) {
|
||||
for (String prefix : INVOKE_PREFIXES) {
|
||||
if (name.startsWith(prefix)) {
|
||||
return name.substring(prefix.length());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ApplyVariableNames";
|
||||
}
|
||||
}
|
||||
@@ -331,6 +331,7 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
return false;
|
||||
}
|
||||
parentInsn.add(AFlag.DECLARE_VAR);
|
||||
var.getCodeVar().setDeclared(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -483,4 +483,11 @@ public class StringUtils {
|
||||
}
|
||||
return Float.toString(f) + 'f';
|
||||
}
|
||||
|
||||
public static String capitalizeFirstChar(String str) {
|
||||
if (isEmpty(str)) {
|
||||
return str;
|
||||
}
|
||||
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,11 +133,11 @@ public class TestIfCodeStyle extends SmaliTest {
|
||||
.oneOf(c -> c.doesNotContain("else").countString(8, "return;"),
|
||||
c -> c.countString(1, "else").countString(7, "return;"))
|
||||
.containsLines(2,
|
||||
"if (readInt < 0) {",
|
||||
indent() + "if (dataPosition > Integer.MAX_VALUE - readInt) {",
|
||||
"if (i < 0) {",
|
||||
indent() + "if (iDataPosition > Integer.MAX_VALUE - i) {",
|
||||
indent(2) + "throw new RuntimeException(\"Overflow in the size of parcelable\");",
|
||||
indent() + "}",
|
||||
indent() + "parcel.setDataPosition(dataPosition + readInt);",
|
||||
indent() + "parcel.setDataPosition(iDataPosition + i);",
|
||||
indent() + "return;",
|
||||
"}");
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TestInnerAssign3 extends SmaliTest {
|
||||
disableCompilation();
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("(testMethod = (testClass1 = null).testMethod()) == null")
|
||||
.containsOne("(testClass2TestMethod = (testClass1 = null).testMethod()) == null")
|
||||
.containsOne("testClass1.testField != null");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ public class TestLambdaInstance3 extends RaungTest {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.doesNotContain("this::get")
|
||||
.containsOne("return (TestCls) of::get;");
|
||||
// TODO: type inference set type for 'of' to Memoized and cast incorrectly removed
|
||||
.containsOne("return (TestCls) lazyOf::get;");
|
||||
// TODO: type inference set type for 'lazyOf' to Memoized and cast incorrectly removed
|
||||
// .containsOne("Memoized)");
|
||||
}
|
||||
|
||||
@@ -49,6 +49,6 @@ public class TestLambdaInstance3 extends RaungTest {
|
||||
assertThat(getClassNodeFromRaung())
|
||||
.code()
|
||||
.doesNotContain("this::get")
|
||||
.containsOne(" of::get");
|
||||
.containsOne(" lazyOf::get");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@ public class TestLoopRestore extends SmaliTest {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("try {")
|
||||
.containsOne("for (byte b : digest) {");
|
||||
.containsOne("for (byte b : bArrDigest) {");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,6 @@ public class TestTryCatchFinally15 extends SmaliTest {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.doesNotContain("parcel = Parcel.obtain();")
|
||||
.containsOne("this.zza.transact(i, parcel, obtain, 0);");
|
||||
.containsOne("this.zza.transact(i, parcel, parcelObtain, 0);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class TestPrimitiveConversion2 extends SmaliTest {
|
||||
.doesNotContain("z2 == 0")
|
||||
.doesNotContain("z2 | 2")
|
||||
.containsOne("(z2 ? 1 : 0) | 2")
|
||||
.containsOne("if (z2 && formatCurrency != null) {")
|
||||
.containsOne("if (z2 && currency != null) {")
|
||||
.containsOne("i = 1;");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ public class TestPrimitivesInIf extends IntegrationTest {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("short parseShort = Short.parseShort(str);");
|
||||
.containsOne("short s = Short.parseShort(str);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +44,13 @@ public class TestTypeResolver16 extends SmaliTest {
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("(List<T>) list");
|
||||
.containsOne("(List<T>) listUnion");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmali() {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("(List<T>) list");
|
||||
.containsOne("(List<T>) listUnion");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class TestTypeResolver17 extends SmaliTest {
|
||||
disableCompilation();
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("Cursor cursor = null;")
|
||||
.containsOne("Cursor cursorQuery = null;")
|
||||
.doesNotContain("(AutoCloseable autoCloseable = ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ public class TestVariablesInLoop extends SmaliTest {
|
||||
public void test() {
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("int i;")
|
||||
.countString(2, "i = 0;")
|
||||
.doesNotContain("i3");
|
||||
.containsOne("int iMth;")
|
||||
.countString(2, "iMth = 0;")
|
||||
.doesNotContain("i2");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user