fix: improve boolean type handling in type inference
This commit is contained in:
@@ -29,22 +29,6 @@ public enum PrimitiveType {
|
||||
return longName;
|
||||
}
|
||||
|
||||
public static PrimitiveType getWidest(PrimitiveType a, PrimitiveType b) {
|
||||
if (a.ordinal() > b.ordinal()) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
public static PrimitiveType getSmaller(PrimitiveType a, PrimitiveType b) {
|
||||
if (a.ordinal() < b.ordinal()) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return longName;
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public class RegisterArg extends InsnArg implements Named {
|
||||
@@ -127,15 +128,17 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
|
||||
@Override
|
||||
public RegisterArg duplicate() {
|
||||
return duplicate(getRegNum(), sVar);
|
||||
return duplicate(getRegNum(), getInitType(), sVar);
|
||||
}
|
||||
|
||||
public RegisterArg duplicate(ArgType initType) {
|
||||
return duplicate(getRegNum(), initType, sVar);
|
||||
}
|
||||
|
||||
public RegisterArg duplicate(@Nullable SSAVar ssaVar) {
|
||||
return duplicate(getRegNum(), ssaVar);
|
||||
public RegisterArg duplicateWithNewSSAVar(MethodNode mth) {
|
||||
RegisterArg duplicate = duplicate(regNum, getInitType(), null);
|
||||
mth.makeNewSVar(duplicate);
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
public RegisterArg duplicate(int regNum, @Nullable SSAVar sVar) {
|
||||
|
||||
@@ -201,23 +201,27 @@ public class ModVisitor extends AbstractVisitor {
|
||||
if (castArg.getType() == ArgType.BOOLEAN) {
|
||||
ArgType type = insn.getResult().getType();
|
||||
if (type.isPrimitive()) {
|
||||
InsnArg zero = new LiteralArg(0, type);
|
||||
long litVal = 1;
|
||||
if (type == ArgType.DOUBLE) {
|
||||
litVal = DOUBLE_TO_BITS;
|
||||
} else if (type == ArgType.FLOAT) {
|
||||
litVal = FLOAT_TO_BITS;
|
||||
}
|
||||
InsnArg one = new LiteralArg(litVal, type);
|
||||
|
||||
IfNode ifNode = new IfNode(IfOp.EQ, -1, castArg, LiteralArg.TRUE);
|
||||
IfCondition condition = IfCondition.fromIfNode(ifNode);
|
||||
TernaryInsn ternary = new TernaryInsn(condition, insn.getResult(), one, zero);
|
||||
TernaryInsn ternary = makeBooleanConvertInsn(insn.getResult(), castArg, type);
|
||||
replaceInsn(mth, block, i, ternary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TernaryInsn makeBooleanConvertInsn(RegisterArg result, InsnArg castArg, ArgType type) {
|
||||
InsnArg zero = new LiteralArg(0, type);
|
||||
long litVal = 1;
|
||||
if (type == ArgType.DOUBLE) {
|
||||
litVal = DOUBLE_TO_BITS;
|
||||
} else if (type == ArgType.FLOAT) {
|
||||
litVal = FLOAT_TO_BITS;
|
||||
}
|
||||
InsnArg one = new LiteralArg(litVal, type);
|
||||
|
||||
IfNode ifNode = new IfNode(IfOp.EQ, -1, castArg, LiteralArg.TRUE);
|
||||
IfCondition condition = IfCondition.fromIfNode(ifNode);
|
||||
return new TernaryInsn(condition, result, one, zero);
|
||||
}
|
||||
|
||||
private void replaceConstInAnnotations(ClassNode cls) {
|
||||
if (cls.root().getArgs().isReplaceConsts()) {
|
||||
replaceConstsInAnnotationForAttrNode(cls, cls);
|
||||
|
||||
@@ -84,8 +84,13 @@ public class TypeCompare {
|
||||
}
|
||||
}
|
||||
if (firstPrimitive && secondPrimitive) {
|
||||
int comparePrimitives = first.getPrimitiveType().compareTo(second.getPrimitiveType());
|
||||
return comparePrimitives > 0 ? WIDER : NARROW;
|
||||
PrimitiveType firstPrimitiveType = first.getPrimitiveType();
|
||||
PrimitiveType secondPrimitiveType = second.getPrimitiveType();
|
||||
if (firstPrimitiveType == PrimitiveType.BOOLEAN
|
||||
|| secondPrimitiveType == PrimitiveType.BOOLEAN) {
|
||||
return CONFLICT;
|
||||
}
|
||||
return firstPrimitiveType.compareTo(secondPrimitiveType) > 0 ? WIDER : NARROW;
|
||||
}
|
||||
|
||||
LOG.warn("Type compare function not complete, can't compare {} and {}", first, second);
|
||||
|
||||
+146
-85
@@ -1,11 +1,13 @@
|
||||
package jadx.core.dex.visitors.typeinference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -23,12 +25,12 @@ import jadx.core.dex.instructions.InvokeNode;
|
||||
import jadx.core.dex.instructions.InvokeType;
|
||||
import jadx.core.dex.instructions.PhiInsn;
|
||||
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.LiteralArg;
|
||||
import jadx.core.dex.instructions.args.PrimitiveType;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.instructions.mods.TernaryInsn;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IMethodDetails;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
@@ -40,9 +42,11 @@ import jadx.core.dex.visitors.AttachMethodDetails;
|
||||
import jadx.core.dex.visitors.ConstInlineVisitor;
|
||||
import jadx.core.dex.visitors.InitCodeVariables;
|
||||
import jadx.core.dex.visitors.JadxVisitor;
|
||||
import jadx.core.dex.visitors.ModVisitor;
|
||||
import jadx.core.dex.visitors.blocksmaker.BlockSplitter;
|
||||
import jadx.core.dex.visitors.ssa.SSATransform;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.InsnList;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
@@ -60,11 +64,20 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
|
||||
private RootNode root;
|
||||
private TypeUpdate typeUpdate;
|
||||
private List<Function<MethodNode, Boolean>> resolvers;
|
||||
|
||||
@Override
|
||||
public void init(RootNode root) {
|
||||
this.root = root;
|
||||
this.typeUpdate = root.getTypeUpdate();
|
||||
this.resolvers = Arrays.asList(
|
||||
this::runTypePropagation,
|
||||
this::tryDeduceTypes,
|
||||
this::trySplitConstInsns,
|
||||
this::tryToFixIncompatiblePrimitives,
|
||||
this::tryInsertAdditionalMove,
|
||||
this::runMultiVariableSearch,
|
||||
this::tryRemoveGenerics);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,30 +88,24 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
if (Consts.DEBUG_TYPE_INFERENCE) {
|
||||
LOG.info("Start type inference in method: {}", mth);
|
||||
}
|
||||
if (resolveTypes(mth)) {
|
||||
for (SSAVar var : new ArrayList<>(mth.getSVars())) {
|
||||
processIncompatiblePrimitives(mth, var);
|
||||
for (Function<MethodNode, Boolean> resolver : resolvers) {
|
||||
if (resolver.apply(mth) && checkTypes(mth)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean resolveTypes(MethodNode mth) {
|
||||
if (runTypePropagation(mth)) {
|
||||
return true;
|
||||
/**
|
||||
* Check if all types resolved
|
||||
*/
|
||||
private boolean checkTypes(MethodNode mth) {
|
||||
for (SSAVar var : mth.getSVars()) {
|
||||
ArgType type = var.getTypeInfo().getType();
|
||||
if (!type.isTypeKnown()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (trySplitConstInsns(mth)) {
|
||||
return true;
|
||||
}
|
||||
if (tryInsertAdditionalMove(mth)) {
|
||||
return true;
|
||||
}
|
||||
if (runMultiVariableSearch(mth)) {
|
||||
return true;
|
||||
}
|
||||
if (tryRemoveGenerics(mth)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,23 +121,12 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
// start initial type propagation
|
||||
ssaVars.forEach(var -> setImmutableType(mth, var));
|
||||
ssaVars.forEach(var -> setBestType(mth, var));
|
||||
|
||||
// try other types if type is still unknown
|
||||
boolean resolved = true;
|
||||
for (SSAVar var : ssaVars) {
|
||||
ArgType type = var.getTypeInfo().getType();
|
||||
if (!type.isTypeKnown()
|
||||
&& !var.isTypeImmutable()
|
||||
&& !tryDeduceType(mth, var, type)) {
|
||||
resolved = false;
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean runMultiVariableSearch(MethodNode mth) {
|
||||
TypeSearch typeSearch = new TypeSearch(mth);
|
||||
try {
|
||||
TypeSearch typeSearch = new TypeSearch(mth);
|
||||
if (!typeSearch.run()) {
|
||||
mth.addWarnComment("Multi-variable type inference failed");
|
||||
}
|
||||
@@ -359,13 +355,30 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean tryDeduceType(MethodNode mth, SSAVar var, @Nullable ArgType type) {
|
||||
private boolean tryDeduceTypes(MethodNode mth) {
|
||||
boolean fixed = false;
|
||||
for (SSAVar ssaVar : mth.getSVars()) {
|
||||
if (deduceType(mth, ssaVar)) {
|
||||
fixed = true;
|
||||
}
|
||||
}
|
||||
return fixed;
|
||||
}
|
||||
|
||||
private boolean deduceType(MethodNode mth, SSAVar var) {
|
||||
if (var.isTypeImmutable()) {
|
||||
return false;
|
||||
}
|
||||
ArgType type = var.getTypeInfo().getType();
|
||||
if (type.isTypeKnown()) {
|
||||
return false;
|
||||
}
|
||||
// try best type from bounds again
|
||||
if (setBestType(mth, var)) {
|
||||
return true;
|
||||
}
|
||||
// try all possible types (useful for primitives)
|
||||
if (type != null && tryPossibleTypes(mth, var, type)) {
|
||||
if (tryPossibleTypes(mth, var, type)) {
|
||||
return true;
|
||||
}
|
||||
// for objects try super types
|
||||
@@ -379,7 +392,8 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
boolean resolved = true;
|
||||
for (SSAVar var : mth.getSVars()) {
|
||||
ArgType type = var.getTypeInfo().getType();
|
||||
if (!type.isTypeKnown() && !var.isTypeImmutable()
|
||||
if (!type.isTypeKnown()
|
||||
&& !var.isTypeImmutable()
|
||||
&& !tryRawType(mth, var)) {
|
||||
resolved = false;
|
||||
}
|
||||
@@ -462,44 +476,47 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private boolean tryInsertAdditionalMove(MethodNode mth) {
|
||||
boolean moveAdded = false;
|
||||
int insnsAdded = 0;
|
||||
for (SSAVar var : new ArrayList<>(mth.getSVars())) {
|
||||
if (tryInsertAdditionalInsn(mth, var)) {
|
||||
moveAdded = true;
|
||||
}
|
||||
insnsAdded += tryInsertAdditionalInsn(mth, var);
|
||||
}
|
||||
if (!moveAdded) {
|
||||
if (insnsAdded == 0) {
|
||||
return false;
|
||||
}
|
||||
mth.addDebugComment("Additional " + insnsAdded + " move instruction added to help type inference");
|
||||
|
||||
InitCodeVariables.rerun(mth);
|
||||
return runTypePropagation(mth);
|
||||
if (runTypePropagation(mth) && checkTypes(mth)) {
|
||||
return true;
|
||||
}
|
||||
return tryDeduceTypes(mth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add MOVE instruction before PHI in bound blocks to make 'soft' type link.
|
||||
* This allows to use different types in blocks merged by PHI.
|
||||
*/
|
||||
private boolean tryInsertAdditionalInsn(MethodNode mth, SSAVar var) {
|
||||
private int tryInsertAdditionalInsn(MethodNode mth, SSAVar var) {
|
||||
if (var.getTypeInfo().getType().isTypeKnown()) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
List<PhiInsn> usedInPhiList = var.getUsedInPhi();
|
||||
if (usedInPhiList.isEmpty()) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
InsnNode assignInsn = var.getAssign().getAssignInsn();
|
||||
if (assignInsn != null) {
|
||||
InsnType assignType = assignInsn.getType();
|
||||
if (assignType == InsnType.CONST) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
if (assignType == InsnType.MOVE && var.getUseCount() == 1) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (PhiInsn phiInsn : usedInPhiList) {
|
||||
if (!insertMoveForPhi(mth, phiInsn, var, false)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,8 +524,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
for (PhiInsn phiInsn : usedInPhiList) {
|
||||
insertMoveForPhi(mth, phiInsn, var, true);
|
||||
}
|
||||
mth.addComment("JADX INFO: additional move instructions added (" + usedInPhiList.size() + ") to help type inference");
|
||||
return true;
|
||||
return usedInPhiList.size();
|
||||
}
|
||||
|
||||
private boolean insertMoveForPhi(MethodNode mth, PhiInsn phiInsn, SSAVar var, boolean apply) {
|
||||
@@ -583,42 +599,87 @@ public final class TypeInferenceVisitor extends AbstractVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processIncompatiblePrimitives(MethodNode mth, SSAVar var) {
|
||||
if (var.getTypeInfo().getType() == ArgType.BOOLEAN) {
|
||||
for (ITypeBound bound : var.getTypeInfo().getBounds()) {
|
||||
if (bound.getBound() == BoundEnum.USE
|
||||
&& bound.getType().isPrimitive()
|
||||
&& bound.getType() != ArgType.BOOLEAN
|
||||
&& bound.getArg() != null) {
|
||||
InsnNode insn = bound.getArg().getParentInsn();
|
||||
if (insn == null || insn.getType() == InsnType.CAST) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IndexInsnNode castNode = new IndexInsnNode(InsnType.CAST, bound.getType(), 1);
|
||||
castNode.addArg(bound.getArg());
|
||||
castNode.setResult(InsnArg.reg(bound.getArg().getRegNum(), bound.getType()));
|
||||
|
||||
SSAVar newVar = mth.makeNewSVar(castNode.getResult());
|
||||
CodeVar codeVar = new CodeVar();
|
||||
codeVar.setType(bound.getType());
|
||||
newVar.setCodeVar(codeVar);
|
||||
newVar.getTypeInfo().setType(bound.getType());
|
||||
|
||||
for (int i = insn.getArgsCount() - 1; i >= 0; i--) {
|
||||
if (insn.getArg(i) == bound.getArg()) {
|
||||
insn.setArg(i, castNode.getResult().duplicate());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BlockNode blockNode = BlockUtils.getBlockByInsn(mth, insn);
|
||||
if (blockNode != null) {
|
||||
List<InsnNode> insnList = blockNode.getInstructions();
|
||||
insnList.add(insnList.indexOf(insn), castNode);
|
||||
}
|
||||
}
|
||||
private boolean tryToFixIncompatiblePrimitives(MethodNode mth) {
|
||||
boolean fixed = false;
|
||||
for (SSAVar var : new ArrayList<>(mth.getSVars())) {
|
||||
if (processIncompatiblePrimitives(mth, var)) {
|
||||
fixed = true;
|
||||
}
|
||||
}
|
||||
if (!fixed) {
|
||||
return false;
|
||||
}
|
||||
InitCodeVariables.rerun(mth);
|
||||
return runTypePropagation(mth);
|
||||
}
|
||||
|
||||
private boolean processIncompatiblePrimitives(MethodNode mth, SSAVar var) {
|
||||
TypeInfo typeInfo = var.getTypeInfo();
|
||||
if (typeInfo.getType().isTypeKnown()) {
|
||||
return false;
|
||||
}
|
||||
boolean boolAssign = false;
|
||||
for (ITypeBound bound : typeInfo.getBounds()) {
|
||||
if (bound.getBound() == BoundEnum.ASSIGN && bound.getType().equals(ArgType.BOOLEAN)) {
|
||||
boolAssign = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!boolAssign) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean fixed = false;
|
||||
for (ITypeBound bound : typeInfo.getBounds()) {
|
||||
if (bound.getBound() == BoundEnum.USE
|
||||
&& fixBooleanUsage(mth, bound)) {
|
||||
fixed = true;
|
||||
}
|
||||
}
|
||||
return fixed;
|
||||
}
|
||||
|
||||
private boolean fixBooleanUsage(MethodNode mth, ITypeBound bound) {
|
||||
ArgType boundType = bound.getType();
|
||||
if (!boundType.isPrimitive() || boundType == ArgType.BOOLEAN) {
|
||||
return false;
|
||||
}
|
||||
RegisterArg boundArg = bound.getArg();
|
||||
if (boundArg == null) {
|
||||
return false;
|
||||
}
|
||||
InsnNode insn = boundArg.getParentInsn();
|
||||
if (insn == null) {
|
||||
return false;
|
||||
}
|
||||
BlockNode blockNode = BlockUtils.getBlockByInsn(mth, insn);
|
||||
if (blockNode == null) {
|
||||
return false;
|
||||
}
|
||||
List<InsnNode> insnList = blockNode.getInstructions();
|
||||
int insnIndex = InsnList.getIndex(insnList, insn);
|
||||
if (insnIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
if (insn.getType() == InsnType.CAST) {
|
||||
// replace cast
|
||||
ArgType type = (ArgType) ((IndexInsnNode) insn).getIndex();
|
||||
TernaryInsn convertInsn = prepareBooleanConvertInsn(insn.getResult(), boundArg, type);
|
||||
BlockUtils.replaceInsn(mth, blockNode, insnIndex, convertInsn);
|
||||
} else {
|
||||
// insert before insn
|
||||
RegisterArg resultArg = boundArg.duplicateWithNewSSAVar(mth);
|
||||
TernaryInsn convertInsn = prepareBooleanConvertInsn(resultArg, boundArg, boundType);
|
||||
insnList.add(insnIndex, convertInsn);
|
||||
insn.replaceArg(bound.getArg(), convertInsn.getResult().duplicate());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private TernaryInsn prepareBooleanConvertInsn(RegisterArg resultArg, RegisterArg boundArg, ArgType useType) {
|
||||
RegisterArg useArg = boundArg.getSVar().getAssign().duplicate();
|
||||
TernaryInsn convertInsn = ModVisitor.makeBooleanConvertInsn(resultArg, useArg, useType);
|
||||
convertInsn.add(AFlag.SYNTHETIC);
|
||||
return convertInsn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static jadx.core.dex.instructions.args.ArgType.INT;
|
||||
import static jadx.core.dex.instructions.args.ArgType.NARROW;
|
||||
import static jadx.core.dex.instructions.args.ArgType.NARROW_INTEGRAL;
|
||||
import static jadx.core.dex.instructions.args.ArgType.OBJECT;
|
||||
import static jadx.core.dex.instructions.args.ArgType.SHORT;
|
||||
import static jadx.core.dex.instructions.args.ArgType.STRING;
|
||||
import static jadx.core.dex.instructions.args.ArgType.UNKNOWN;
|
||||
import static jadx.core.dex.instructions.args.ArgType.UNKNOWN_ARRAY;
|
||||
@@ -52,8 +53,6 @@ public class TypeCompareTest {
|
||||
public void compareTypes() {
|
||||
firstIsNarrow(INT, UNKNOWN);
|
||||
|
||||
firstIsNarrow(BOOLEAN, INT);
|
||||
|
||||
firstIsNarrow(array(UNKNOWN), UNKNOWN);
|
||||
firstIsNarrow(array(UNKNOWN), NARROW);
|
||||
}
|
||||
@@ -62,7 +61,9 @@ public class TypeCompareTest {
|
||||
public void comparePrimitives() {
|
||||
check(INT, UNKNOWN_OBJECT, TypeCompareEnum.CONFLICT);
|
||||
check(INT, OBJECT, TypeCompareEnum.CONFLICT);
|
||||
check(INT, BOOLEAN, TypeCompareEnum.CONFLICT);
|
||||
check(INT, CHAR, TypeCompareEnum.WIDER);
|
||||
check(INT, SHORT, TypeCompareEnum.WIDER);
|
||||
|
||||
firstIsNarrow(CHAR, NARROW_INTEGRAL);
|
||||
firstIsNarrow(array(CHAR), UNKNOWN_OBJECT);
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToByte extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(byte b) {
|
||||
@@ -24,9 +22,8 @@ public class TestBooleanToByte extends SmaliTest {
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToByte");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? (byte) 1 : 0);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? (byte) 1 : 0);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToChar extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(char b) {
|
||||
@@ -20,13 +18,12 @@ public class TestBooleanToChar extends SmaliTest {
|
||||
public void writeToParcel(TestBooleanToChar testBooleanToChar) {
|
||||
testBooleanToChar.write(this.showConsent ? (char) 1 : 0);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToChar");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? (char) 1 : 0);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? (char) 1 : 0);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToDouble extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(double d) {
|
||||
@@ -24,9 +22,8 @@ public class TestBooleanToDouble extends SmaliTest {
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToDouble");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? 1.0d : 0.0d);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? 1.0d : 0.0d);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToFloat extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(float f) {
|
||||
@@ -24,9 +22,8 @@ public class TestBooleanToFloat extends SmaliTest {
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToFloat");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? 1.0f : 0.0f);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? 1.0f : 0.0f);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToInt extends SmaliTest {
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
// @formatter:off
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(int b) {
|
||||
@@ -21,12 +19,11 @@ public class TestBooleanToInt extends SmaliTest {
|
||||
testBooleanToInt.write(this.showConsent ? 1 : 0);
|
||||
}
|
||||
*/
|
||||
//@formatter:on
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToInt");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? 1 : 0);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? 1 : 0);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToLong extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(long j) {
|
||||
@@ -24,9 +22,8 @@ public class TestBooleanToLong extends SmaliTest {
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToLong");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? 1 : 0);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? 1 : 0);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,14 @@ package jadx.tests.integration.conditions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestBooleanToShort extends SmaliTest {
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
/*
|
||||
private boolean showConsent;
|
||||
|
||||
public void write(short b) {
|
||||
@@ -24,9 +22,8 @@ public class TestBooleanToShort extends SmaliTest {
|
||||
// @formatter:on
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToShort");
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, containsString("write(this.showConsent ? (short) 1 : 0);"));
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOne("write(this.showConsent ? (short) 1 : 0);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class TestIssue13a extends IntegrationTest {
|
||||
private static final String TAG = "Parcel";
|
||||
private static final Map<ClassLoader, Map<String, Parcelable.Creator<?>>> M_CREATORS = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "ConstantConditions", "Java8MapApi", "rawtypes" })
|
||||
public final <T extends Parcelable> T test(ClassLoader loader) {
|
||||
String name = readString();
|
||||
if (name == null) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import static org.hamcrest.Matchers.not;
|
||||
|
||||
public class TestTypeResolver10 extends SmaliTest {
|
||||
|
||||
/**
|
||||
/*
|
||||
* Method argument assigned with different types in separate branches
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.class public LTestBooleanToByte;
|
||||
.class public Lconditions/TestBooleanToByte;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToByte;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToByte;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToByte;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToByte;->showConsent:Z
|
||||
|
||||
int-to-byte p1, p1
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToByte;->write(B)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToByte;->write(B)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.class public LTestBooleanToChar;
|
||||
.class public Lconditions/TestBooleanToChar;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToChar;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToChar;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToChar;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToChar;->showConsent:Z
|
||||
|
||||
int-to-char p1, p1
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToChar;->write(C)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToChar;->write(C)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.class public LTestBooleanToDouble;
|
||||
.class public Lconditions/TestBooleanToDouble;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToDouble;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToDouble;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToDouble;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToDouble;->showConsent:Z
|
||||
|
||||
int-to-double p1, p1
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToDouble;->write(D)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToDouble;->write(D)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.class public LTestBooleanToFloat;
|
||||
.class public Lconditions/TestBooleanToFloat;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToFloat;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToFloat;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToFloat;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToFloat;->showConsent:Z
|
||||
|
||||
int-to-float p1, p1
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToFloat;->write(F)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToFloat;->write(F)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
.class public LTestBooleanToInt;
|
||||
.class public Lconditions/TestBooleanToInt;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToInt;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToInt;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToInt;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToInt;->showConsent:Z
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToInt;->write(I)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToInt;->write(I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.class public LTestBooleanToLong;
|
||||
.class public Lconditions/TestBooleanToLong;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToLong;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToLong;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToLong;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToLong;->showConsent:Z
|
||||
|
||||
int-to-long p1, p1
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToLong;->write(J)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToLong;->write(J)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.class public LTestBooleanToShort;
|
||||
.class public Lconditions/TestBooleanToShort;
|
||||
.super Ljava/lang/Object;
|
||||
|
||||
.field private showConsent:Z
|
||||
|
||||
.method public writeToParcel(LTestBooleanToShort;)V
|
||||
.method public writeToParcel(Lconditions/TestBooleanToShort;)V
|
||||
.locals 0
|
||||
|
||||
iget-boolean p1, p0, LTestBooleanToShort;->showConsent:Z
|
||||
iget-boolean p1, p0, Lconditions/TestBooleanToShort;->showConsent:Z
|
||||
|
||||
int-to-short p1, p1
|
||||
|
||||
invoke-virtual {p0, p1}, LTestBooleanToShort;->write(S)V
|
||||
invoke-virtual {p0, p1}, Lconditions/TestBooleanToShort;->write(S)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
Reference in New Issue
Block a user