Merge pull request #1 from UniquePassive/issue-151

Replace char primitives with integer values
This commit is contained in:
Adam
2017-10-17 18:47:23 -04:00
committed by GitHub
11 changed files with 591 additions and 27 deletions

View File

@@ -26,7 +26,7 @@
<target name="compile" depends="init,clean">
<mkdir dir="${out}"/>
<javac srcdir="${src}" destdir="${out}" source="1.6" target="1.6" encoding="UTF-8" debug="true" includeantruntime="false"/>
<javac srcdir="${src}" destdir="${out}" source="1.7" target="1.7" encoding="UTF-8" debug="true" includeantruntime="false"/>
</target>
<target name="dist" depends="init,compile">
@@ -39,7 +39,7 @@
<target name="test-compile" depends="init,compile">
<mkdir dir="${test-out}"/>
<javac srcdir="${test-src}" destdir="${test-out}" source="1.6" target="1.6" encoding="UTF-8" debug="true" includeantruntime="false">
<javac srcdir="${test-src}" destdir="${test-out}" source="1.7" target="1.7" encoding="UTF-8" debug="true" includeantruntime="false">
<classpath path="${out}"/>
<classpath refid="junit"/>
</javac>

View File

@@ -459,6 +459,11 @@ public class ClassWriter {
}
else {
buffer.append(" = ");
if (initializer.type == Exprent.EXPRENT_CONST) {
((ConstExprent) initializer).adjustConstType(fieldType);
}
// FIXME: special case field initializer. Can map to more than one method (constructor) and bytecode intruction.
buffer.append(initializer.toJava(indent, tracer));
}

View File

@@ -896,23 +896,25 @@ public class ExprProcessor implements CodeConstants {
VarType rightType = exprent.getExprType();
TextBuffer res = exprent.toJava(indent, tracer);
boolean cast =
castAlways ||
(!leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) ||
(castNull && rightType.type == CodeConstants.TYPE_NULL && !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType))) ||
(isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType));
if (cast) {
if (exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
res.enclose("(", ")");
}
boolean quote = cast && exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST);
res.prepend("(" + getCastTypeName(leftType) + ")");
if (cast) buffer.append('(').append(getCastTypeName(leftType)).append(')');
if (quote) buffer.append('(');
if (exprent.type == Exprent.EXPRENT_CONST) {
((ConstExprent) exprent).adjustConstType(leftType);
}
buffer.append(res);
buffer.append(exprent.toJava(indent, tracer));
if (quote) buffer.append(')');
return cast;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -138,6 +138,10 @@ public class AssignmentExprent extends Exprent {
buffer.append(left.toJava(indent, tracer));
}
if (right.type == EXPRENT_CONST) {
((ConstExprent) right).adjustConstType(leftType);
}
TextBuffer res = right.toJava(indent, tracer);
if (condType == CONDITION_NONE &&

View File

@@ -28,12 +28,13 @@ import org.jetbrains.java.decompiler.struct.match.MatchNode;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.TextUtil;
import java.util.*;
import java.util.Map.Entry;
public class ConstExprent extends Exprent {
private static final Map<Integer, String> ESCAPES = new HashMap<Integer, String>() {{
private static final Map<Integer, String> CHAR_ESCAPES = new HashMap<Integer, String>() {{
put(new Integer(0x8), "\\b"); /* \u0008: backspace BS */
put(new Integer(0x9), "\\t"); /* \u0009: horizontal tab HT */
put(new Integer(0xA), "\\n"); /* \u000a: linefeed LF */
@@ -127,17 +128,17 @@ public class ConstExprent extends Exprent {
return new TextBuffer(Boolean.toString(((Integer)value).intValue() != 0));
case CodeConstants.TYPE_CHAR:
Integer val = (Integer)value;
String ret = ESCAPES.get(val);
String ret = CHAR_ESCAPES.get(val);
if (ret == null) {
char c = (char)val.intValue();
if (c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
if (isPrintableAscii(c) || !ascii && TextUtil.isPrintableUnicode(c)) {
ret = String.valueOf(c);
}
else {
ret = InterpreterUtil.charToUnicodeLiteral(c);
ret = TextUtil.charToUnicodeLiteral(c);
}
}
return new TextBuffer(ret).enclose("\'", "\'");
return new TextBuffer(ret).enclose("'", "'");
case CodeConstants.TYPE_BYTE:
case CodeConstants.TYPE_BYTECHAR:
case CodeConstants.TYPE_SHORT:
@@ -306,7 +307,7 @@ public class ConstExprent extends Exprent {
buffer.append("\\\'");
break;
default:
if (c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
if (c >= 32 && c < 127 || !ascii && TextUtil.isPrintableUnicode(c)) {
buffer.append(c);
}
else {
@@ -389,6 +390,27 @@ public class ConstExprent extends Exprent {
this.constType = constType;
}
public void adjustConstType(VarType expectedType) {
// BYTECHAR and SHORTCHAR => CHAR in the CHAR context
if (expectedType.equals(VarType.VARTYPE_CHAR) &&
(constType.equals(VarType.VARTYPE_BYTECHAR) || constType.equals(VarType.VARTYPE_SHORTCHAR))) {
int intValue = getIntValue();
if (isPrintableAscii(intValue) || CHAR_ESCAPES.containsKey(intValue)) {
setConstType(VarType.VARTYPE_CHAR);
}
}
// CHAR => INT in the INT context
else if (expectedType.equals(VarType.VARTYPE_INT) &&
constType.equals(VarType.VARTYPE_CHAR)) {
setConstType(VarType.VARTYPE_INT);
}
}
private static boolean isPrintableAscii(int c) {
return c >= 32 && c < 127;
}
public Object getValue() {
return value;
}

View File

@@ -454,12 +454,35 @@ public class FunctionExprent extends Exprent {
tracer.addMapping(bytecode);
if (funcType <= FUNCTION_USHR) {
return wrapOperandString(lstOperands.get(0), false, indent, tracer)
Exprent left = lstOperands.get(0);
Exprent right = lstOperands.get(1);
if (right.type == EXPRENT_CONST) {
((ConstExprent) right).adjustConstType(left.getExprType());
}
else if (left.type == EXPRENT_CONST) {
((ConstExprent) left).adjustConstType(right.getExprType());
}
return wrapOperandString(left, false, indent, tracer)
.append(OPERATORS[funcType])
.append(wrapOperandString(lstOperands.get(1), true, indent, tracer));
.append(wrapOperandString(right, true, indent, tracer));
}
// try to determine more accurate type for 'char' literals
if (funcType >= FUNCTION_EQ) {
if (funcType <= FUNCTION_LE) {
Exprent left = lstOperands.get(0);
Exprent right = lstOperands.get(1);
if (right.type == EXPRENT_CONST) {
((ConstExprent) right).adjustConstType(left.getExprType());
}
else if (left.type == EXPRENT_CONST) {
((ConstExprent) left).adjustConstType(right.getExprType());
}
}
return wrapOperandString(lstOperands.get(0), false, indent, tracer)
.append(OPERATORS[funcType - FUNCTION_EQ + 11])
.append(wrapOperandString(lstOperands.get(1), true, indent, tracer));
@@ -484,11 +507,21 @@ public class FunctionExprent extends Exprent {
}
return res.append(".length");
case FUNCTION_IIF:
Exprent left = lstOperands.get(1);
Exprent right = lstOperands.get(2);
if (right.type == EXPRENT_CONST) {
((ConstExprent) right).adjustConstType(left.getExprType());
}
else if (left.type == EXPRENT_CONST) {
((ConstExprent) left).adjustConstType(right.getExprType());
}
return wrapOperandString(lstOperands.get(0), true, indent, tracer)
.append("?")
.append(wrapOperandString(lstOperands.get(1), true, indent, tracer))
.append(":")
.append(wrapOperandString(lstOperands.get(2), true, indent, tracer));
.append("?")
.append(wrapOperandString(left, true, indent, tracer))
.append(":")
.append(wrapOperandString(right, true, indent, tracer));
case FUNCTION_IPP:
return wrapOperandString(lstOperands.get(0), true, indent, tracer).append("++");
case FUNCTION_PPI:

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,12 +15,23 @@
*/
package org.jetbrains.java.decompiler.util;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.TextBuffer;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import java.util.Arrays;
import java.util.HashSet;
public class TextUtil {
private static final HashSet<String> KEYWORDS = new HashSet<>(Arrays.asList(
"abstract", "default", "if", "private", "this", "boolean", "do", "implements", "protected", "throw", "break", "double", "import",
"public", "throws", "byte", "else", "instanceof", "return", "transient", "case", "extends", "int", "short", "try", "catch", "final",
"interface", "static", "void", "char", "finally", "long", "strictfp", "volatile", "class", "float", "native", "super", "while",
"const", "for", "new", "switch", "continue", "goto", "package", "synchronized", "true", "false", "null", "assert"));
public static void writeQualifiedSuper(TextBuffer buf, String qualifier) {
ClassesProcessor.ClassNode classNode = (ClassesProcessor.ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
if (!qualifier.equals(classNode.classStruct.qualifiedName)) {
@@ -28,4 +39,48 @@ public class TextUtil {
}
buf.append("super");
}
public static String getIndentString(int length) {
if (length == 0) return "";
StringBuilder buf = new StringBuilder();
String indent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
while (length-- > 0) {
buf.append(indent);
}
return buf.toString();
}
public static boolean isPrintableUnicode(char c) {
int t = Character.getType(c);
return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR &&
t != Character.CONTROL && t != Character.FORMAT && t != Character.PRIVATE_USE && t != Character.SURROGATE;
}
public static String charToUnicodeLiteral(int value) {
String sTemp = Integer.toHexString(value);
sTemp = ("0000" + sTemp).substring(sTemp.length());
return "\\u" + sTemp;
}
public static boolean isValidIdentifier(String id, int version) {
return isJavaIdentifier(id) && !isKeyword(id, version);
}
private static boolean isJavaIdentifier(String id) {
if (id.isEmpty() || !Character.isJavaIdentifierStart(id.charAt(0))) {
return false;
}
for (int i = 1; i < id.length(); i++) {
if (!Character.isJavaIdentifierPart(id.charAt(i))) {
return false;
}
}
return true;
}
private static boolean isKeyword(String id, int version) {
return KEYWORDS.contains(id) || version > CodeConstants.BYTECODE_JAVA_5 && "enum".equals(id);
}
}

Binary file not shown.

View File

@@ -51,10 +51,10 @@ public class TestClassLoop {
for(boolean var8 = false; var2 < var1; ++var2) {// 70 73 90
char var6 = var0.charAt(var2);// 74
if(var6 == 48) {// 75
if (var6 == '0') {// 75
++var7;// 76
} else {
if(var6 != 46) {// 77
if (var6 != '.') {// 77
break;
}

View File

@@ -0,0 +1,337 @@
package pkg;
public class TestConstType {
private char lineBreak = '\n';
private char zero = 0;
public void setLineBreak(char os) {
switch(os) {// 8
case 'u':
this.lineBreak = '\r';// 10
break;// 11
case 'w':
this.lineBreak = '\n';// 14
}
}// 17
public void init() {
this.setLineBreak('w');// 20
}// 21
public String convertIndentation(String text) {
if (text.charAt(0) == '\t') {// 24
text = text.replace('\t', ' ');// 25
}
return text;// 27
}
public void printalot() {
System.out.println('a');// 31
System.out.println('\t');// 32
System.out.println(0);// 34
System.out.println(65);// 35
System.out.println(120);// 36
System.out.println(32760);// 37
System.out.println(32761);// 38
System.out.println(35000);// 39
System.out.println(50000);// 40
System.out.println(128000);// 41
System.out.println(60793);// 42
System.out.println(60737);// 43
System.out.println(60777);// 44
System.out.println(60785);// 45
System.out.println(60835);// 46
System.out.println(60843);// 47
System.out.println(60851);// 48
System.out.println(60859);// 49
System.out.println(1048576);// 50
System.out.println(49152);// 51
System.out.println(44100);// 52
System.out.println(44101);// 53
System.out.println(44102);// 54
System.out.println(44103);// 55
System.out.println(60000);// 56
System.out.println(64000);// 57
System.out.println(65000);// 58
System.out.println(45000);// 59
}// 60
public char guessType(int val) {
if (0 <= val && val <= 127) {// 63
return 'X';// 64
} else if (-128 <= val && val <= 127) {// 66
return 'B';// 67
} else if (128 <= val && val <= 32767) {// 69
return 'Y';// 70
} else if (-32768 <= val && val <= 32767) {// 72
return 'S';// 73
} else {
return (char)(32768 <= val && val <= 65535 ? 'C' : 'I');// 75 76 79
}
}
public int getTypeMaxValue(char type) {
int maxValue;
switch(type) {// 85
case 'B':
maxValue = 127;// 90
break;// 91
case 'C':
maxValue = 65535;// 99
break;// 100
case 'S':
maxValue = 32767;// 96
break;// 97
case 'X':
maxValue = 128;// 87
break;// 88
case 'Y':
maxValue = 32768;// 93
break;// 94
default:
maxValue = 2147483647;// 102
}
return maxValue;// 104
}
}
class 'pkg/TestConstType' {
method 'setLineBreak (C)V' {
1 7
1d 9
1f 9
22 10
26 12
28 12
2b 15
}
method 'init ()V' {
1 18
3 18
6 19
}
method 'convertIndentation (Ljava/lang/String;)Ljava/lang/String;' {
1 22
2 22
5 22
7 22
b 23
d 23
f 23
12 23
14 26
}
method 'printalot ()V' {
0 30
3 30
5 30
8 31
b 31
d 31
10 32
13 32
14 32
17 33
1a 33
1c 33
1f 34
22 34
24 34
27 35
2a 35
2d 35
30 36
33 36
36 36
39 37
3c 37
3e 37
41 38
44 38
46 38
49 39
4c 39
4e 39
51 40
54 40
56 40
59 41
5c 41
5e 41
61 42
64 42
66 42
69 43
6c 43
6e 43
71 44
74 44
76 44
79 45
7c 45
7e 45
81 46
84 46
86 46
89 47
8c 47
8e 47
91 48
94 48
96 48
99 49
9c 49
9e 49
a1 50
a4 50
a6 50
a9 51
ac 51
ae 51
b1 52
b4 52
b6 52
b9 53
bc 53
be 53
c1 54
c4 54
c6 54
c9 55
cc 55
ce 55
d1 56
d4 56
d6 56
d9 57
dc 57
de 57
e1 58
}
method 'guessType (I)C' {
0 61
2 61
6 61
8 61
b 62
d 62
e 63
11 63
15 63
17 63
1a 64
1c 64
1d 65
21 65
25 65
28 65
2b 66
2d 66
2e 67
32 67
36 67
39 67
3c 68
3e 68
3f 70
42 70
46 70
48 70
4b 70
4e 70
}
method 'getTypeMaxValue (C)I' {
1 76
34 87
37 87
38 88
3b 78
3d 78
3e 79
41 90
43 90
44 91
47 84
4a 84
4b 85
4e 81
50 81
51 82
54 93
56 93
58 96
}
}
Lines mapping:
8 <-> 8
10 <-> 10
11 <-> 11
14 <-> 13
17 <-> 16
20 <-> 19
21 <-> 20
24 <-> 23
25 <-> 24
27 <-> 27
31 <-> 31
32 <-> 32
34 <-> 33
35 <-> 34
36 <-> 35
37 <-> 36
38 <-> 37
39 <-> 38
40 <-> 39
41 <-> 40
42 <-> 41
43 <-> 42
44 <-> 43
45 <-> 44
46 <-> 45
47 <-> 46
48 <-> 47
49 <-> 48
50 <-> 49
51 <-> 50
52 <-> 51
53 <-> 52
54 <-> 53
55 <-> 54
56 <-> 55
57 <-> 56
58 <-> 57
59 <-> 58
60 <-> 59
63 <-> 62
64 <-> 63
66 <-> 64
67 <-> 65
69 <-> 66
70 <-> 67
72 <-> 68
73 <-> 69
75 <-> 71
76 <-> 71
79 <-> 71
85 <-> 77
87 <-> 88
88 <-> 89
90 <-> 79
91 <-> 80
93 <-> 91
94 <-> 92
96 <-> 85
97 <-> 86
99 <-> 82
100 <-> 83
102 <-> 94
104 <-> 97

View File

@@ -0,0 +1,106 @@
package pkg;
public class TestConstType {
private char lineBreak = '\n';
private char zero = 0;
public void setLineBreak(char os) {
switch (os) {
case 'u':
lineBreak = '\r';
break;
case 'w':
lineBreak = '\n';
break;
}
}
public void init() {
setLineBreak('w');
}
public String convertIndentation(String text) {
if (text.charAt(0) == '\t') {
text = text.replace('\t', ' ');
}
return text;
}
public void printalot() {
System.out.println('a');
System.out.println('\t');
System.out.println(0);
System.out.println(65);
System.out.println(120);
System.out.println(32760);
System.out.println(32761);
System.out.println(35000);
System.out.println(50000);
System.out.println(128000);
System.out.println(60793);
System.out.println(60737);
System.out.println(60777);
System.out.println(60785);
System.out.println(60835);
System.out.println(60843);
System.out.println(60851);
System.out.println(60859);
System.out.println(1048576);
System.out.println(49152);
System.out.println(44100);
System.out.println(44101);
System.out.println(44102);
System.out.println(44103);
System.out.println(60000);
System.out.println(64000);
System.out.println(65000);
System.out.println(45000);
}
public char guessType(int val) {
if (0 <= val && val <= 127) {
return 'X';
}
else if (-128 <= val && val <= 127) {
return 'B';
}
else if (128 <= val && val <= 32767) {
return 'Y';
}
else if (-32768 <= val && val <= 32767) {
return 'S';
}
else if (32768 <= val && val <= 0xFFFF) {
return 'C';
}
else {
return 'I';
}
}
public int getTypeMaxValue(char type) {
int maxValue;
switch (type) {
case 'X':
maxValue = 128;
break;
case 'B':
maxValue = 127;
break;
case 'Y':
maxValue = 32768;
break;
case 'S':
maxValue = 32767;
break;
case 'C':
maxValue = 0xFFFF;
break;
default:
maxValue = Integer.MAX_VALUE;
}
return maxValue;
}
}