fix: resolve char literal incorrect print as string (#856)
This commit is contained in:
@@ -4,6 +4,7 @@ public class Consts {
|
||||
public static final boolean DEBUG = false;
|
||||
public static final boolean DEBUG_USAGE = false;
|
||||
public static final boolean DEBUG_TYPE_INFERENCE = false;
|
||||
public static final boolean DEBUG_OVERLOADED_CASTS = false;
|
||||
|
||||
public static final String CLASS_OBJECT = "java.lang.Object";
|
||||
public static final String CLASS_STRING = "java.lang.String";
|
||||
|
||||
@@ -3,7 +3,6 @@ package jadx.core.codegen;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
@@ -71,11 +70,7 @@ public class TypeGen {
|
||||
case BOOLEAN:
|
||||
return lit == 0 ? "false" : "true";
|
||||
case CHAR:
|
||||
char ch = (char) lit;
|
||||
if (!NameMapper.isPrintableChar(ch)) {
|
||||
return Integer.toString(ch);
|
||||
}
|
||||
return stringUtils.unescapeChar(ch);
|
||||
return stringUtils.unescapeChar((char) lit, cast);
|
||||
case BYTE:
|
||||
return formatByte(lit, cast);
|
||||
case SHORT:
|
||||
|
||||
@@ -278,13 +278,14 @@ public class MethodInvokeVisitor extends AbstractVisitor {
|
||||
if (argsCount == 1) {
|
||||
return mthDetails.getArgTypes();
|
||||
}
|
||||
// TODO: try to minimize casts count
|
||||
parentMth.addComment("JADX DEBUG: Failed to find minimal casts for resolve overloaded methods, cast all args instead"
|
||||
+ NL + " method: " + mthDetails
|
||||
+ NL + " arg types: " + compilerVarTypes
|
||||
+ NL + " candidates:"
|
||||
+ NL + " " + Utils.listToString(overloadedMethods, NL + " "));
|
||||
|
||||
if (Consts.DEBUG_OVERLOADED_CASTS) {
|
||||
// TODO: try to minimize casts count
|
||||
parentMth.addComment("JADX DEBUG: Failed to find minimal casts for resolve overloaded methods, cast all args instead"
|
||||
+ NL + " method: " + mthDetails
|
||||
+ NL + " arg types: " + compilerVarTypes
|
||||
+ NL + " candidates:"
|
||||
+ NL + " " + Utils.listToString(overloadedMethods, NL + " "));
|
||||
}
|
||||
// not resolved -> cast all args
|
||||
return mthDetails.getArgTypes();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package jadx.core.utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
|
||||
public class StringUtils {
|
||||
private static final StringUtils DEFAULT_INSTANCE = new StringUtils(new JadxArgs());
|
||||
@@ -24,57 +27,74 @@ public class StringUtils {
|
||||
res.append('"');
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = str.charAt(i) & 0xFFFF;
|
||||
processChar(c, res);
|
||||
processCharInsideString(c, res);
|
||||
}
|
||||
res.append('"');
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public String unescapeChar(char ch) {
|
||||
if (ch == '\'') {
|
||||
return "'\\\''";
|
||||
private void processCharInsideString(int c, StringBuilder res) {
|
||||
String str = getSpecialStringForChar(c);
|
||||
if (str != null) {
|
||||
res.append(str);
|
||||
return;
|
||||
}
|
||||
if (c < 32 || c >= 127 && escapeUnicode) {
|
||||
res.append("\\u").append(String.format("%04x", c));
|
||||
} else {
|
||||
res.append((char) c);
|
||||
}
|
||||
StringBuilder res = new StringBuilder();
|
||||
res.append('\'');
|
||||
processChar(ch, res);
|
||||
res.append('\'');
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
private void processChar(int c, StringBuilder res) {
|
||||
/**
|
||||
* Represent single char best way possible
|
||||
*/
|
||||
public String unescapeChar(int c, boolean explicitCast) {
|
||||
if (c == '\'') {
|
||||
return "'\\''";
|
||||
}
|
||||
String str = getSpecialStringForChar(c);
|
||||
if (str != null) {
|
||||
return '\'' + str + '\'';
|
||||
}
|
||||
if (c >= 127 && escapeUnicode) {
|
||||
return String.format("'\\u%04x'", c);
|
||||
}
|
||||
if (NameMapper.isPrintableChar(c)) {
|
||||
return "'" + (char) c + '\'';
|
||||
}
|
||||
if (explicitCast) {
|
||||
return "(char) " + c;
|
||||
}
|
||||
return String.valueOf(c);
|
||||
}
|
||||
|
||||
public String unescapeChar(char ch) {
|
||||
return unescapeChar(ch, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getSpecialStringForChar(int c) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
res.append("\\n");
|
||||
break;
|
||||
return "\\n";
|
||||
case '\r':
|
||||
res.append("\\r");
|
||||
break;
|
||||
return "\\r";
|
||||
case '\t':
|
||||
res.append("\\t");
|
||||
break;
|
||||
return "\\t";
|
||||
case '\b':
|
||||
res.append("\\b");
|
||||
break;
|
||||
return "\\b";
|
||||
case '\f':
|
||||
res.append("\\f");
|
||||
break;
|
||||
return "\\f";
|
||||
case '\'':
|
||||
res.append('\'');
|
||||
break;
|
||||
return "'";
|
||||
case '"':
|
||||
res.append("\\\"");
|
||||
break;
|
||||
return "\\\"";
|
||||
case '\\':
|
||||
res.append("\\\\");
|
||||
break;
|
||||
return "\\\\";
|
||||
|
||||
default:
|
||||
if (c < 32 || c >= 127 && escapeUnicode) {
|
||||
res.append("\\u").append(String.format("%04x", c));
|
||||
} else {
|
||||
res.append((char) c);
|
||||
}
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,9 @@ class StringUtilsTest {
|
||||
checkCharUnescape('a', "a");
|
||||
checkCharUnescape(' ', " ");
|
||||
checkCharUnescape('\n', "\\n");
|
||||
checkCharUnescape('\'', "\\\'");
|
||||
checkCharUnescape('\0', "\\u0000");
|
||||
checkCharUnescape('\'', "\\'");
|
||||
|
||||
assertThat(stringUtils.unescapeChar('\0'), is("0"));
|
||||
}
|
||||
|
||||
private void checkCharUnescape(char input, String result) {
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package jadx.tests.integration.invoke;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestCastInOverloadedInvoke4 extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
public String test(String str) {
|
||||
return str.replace('\n', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("return str.replace('\\n', ' ');");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user