From 16619db174221a8531e615ba95fb061e82fb2646 Mon Sep 17 00:00:00 2001 From: emmanue1 Date: Sun, 16 Jun 2019 12:12:48 +0200 Subject: [PATCH] Add string concatenation in Java 9 support --- .../org/jd/core/v1/api/printer/Printer.java | 30 ++--- .../core/v1/model/classfile/ConstantPool.java | 10 +- .../expression/StringConstantExpression.java | 2 + .../util/ByteCodeParser.java | 60 +++++---- .../util/ByteCodeWriter.java | 14 +- .../util/ControlFlowGraphMaker.java | 4 +- .../util/CreateConcatStringUtil.java | 58 --------- .../util/StringConcatenationUtil.java | 120 ++++++++++++++++++ .../visitor/InitInstanceFieldVisitor.java | 53 +++----- .../classfile/ClassFileDeserializer.java | 40 +++--- .../visitor/CompilationUnitVisitor.java | 14 +- 11 files changed, 240 insertions(+), 165 deletions(-) delete mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java create mode 100644 src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java diff --git a/src/main/java/org/jd/core/v1/api/printer/Printer.java b/src/main/java/org/jd/core/v1/api/printer/Printer.java index e71db4f1..4f30d48a 100644 --- a/src/main/java/org/jd/core/v1/api/printer/Printer.java +++ b/src/main/java/org/jd/core/v1/api/printer/Printer.java @@ -9,7 +9,13 @@ public interface Printer { - int UNKNOWN_LINE_NUMBER = 0; + void start(int maxLineNumber, int majorVersion, int minorVersion); + void end(); + + void printText(String text); + void printNumericConstant(String constant); + void printStringConstant(String constant, String ownerInternalName); + void printKeyword(String keyword); // Declaration & reference types int TYPE = 1; @@ -19,30 +25,24 @@ public interface Printer { int PACKAGE = 5; int MODULE = 6; - // Marker types - int COMMENT = 1; - int JAVADOC = 2; - int ERROR = 3; - int IMPORT_STATEMENTS = 4; - - void start(int maxLineNumber, int majorVersion, int minorVersion); - void end(); - - void printText(String text); - void printNumericConstant(String constant); - void printStringConstant(String constant, String ownerInternalName); - void printKeyword(String keyword); - void printDeclaration(int type, String internalTypeName, String name, String descriptor); void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName); void indent(); void unindent(); + int UNKNOWN_LINE_NUMBER = 0; + void startLine(int lineNumber); void endLine(); void extraLine(int count); + // Marker types + int COMMENT = 1; + int JAVADOC = 2; + int ERROR = 3; + int IMPORT_STATEMENTS = 4; + void startMarker(int type); void endMarker(int type); } diff --git a/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java b/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java index 330dbaf3..326bda79 100644 --- a/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java +++ b/src/main/java/org/jd/core/v1/model/classfile/ConstantPool.java @@ -22,13 +22,19 @@ public T getConstant(int index) { return (T)constants[index]; } - public String getConstantTypeName(int classIndex) { - ConstantClass cc = (ConstantClass)constants[classIndex]; + public String getConstantTypeName(int index) { + ConstantClass cc = (ConstantClass)constants[index]; ConstantUtf8 cutf8 = (ConstantUtf8)constants[cc.getNameIndex()]; return cutf8.getValue(); } public String getConstantString(int index) { + ConstantString cString = (ConstantString)constants[index]; + ConstantUtf8 cutf8 = (ConstantUtf8)constants[cString.getStringIndex()]; + return cutf8.getValue(); + } + + public String getConstantUtf8(int index) { ConstantUtf8 cutf8 = (ConstantUtf8)constants[index]; return cutf8.getValue(); } diff --git a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java index c8b6fead..93156fd3 100644 --- a/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java +++ b/src/main/java/org/jd/core/v1/model/javasyntax/expression/StringConstantExpression.java @@ -11,6 +11,8 @@ import org.jd.core.v1.model.javasyntax.type.Type; public class StringConstantExpression extends AbstractLineNumberExpression { + public static final StringConstantExpression EMPTY_STRING = new StringConstantExpression(""); + protected String string; public StringConstantExpression(String string) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java index 832e9e78..dd933e82 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeParser.java @@ -727,8 +727,8 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ot = objectTypeMaker.make(typeName); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - name = constants.getConstantString(constantNameAndType.getNameIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); BaseExpression parameters = getParameters(statements, stack, descriptor); Type returnedType = signatureParser.parseReturnedType(descriptor); @@ -777,7 +777,7 @@ public void parse(BasicBlock basicBlock, Statements statements, Defau "toString".equals(name) && "()Ljava/lang/String;".equals(descriptor)) { typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); if ("java/lang/StringBuilder".equals(typeName) || "java/lang/StringBuffer".equals(typeName)) { - stack.push(CreateConcatStringUtil.create(expression1, lineNumber, typeName)); + stack.push(StringConcatenationUtil.create(expression1, lineNumber, typeName)); break; } } @@ -1043,7 +1043,7 @@ private void parseLDC(DefaultStack stack, ConstantPool constants, in break; case Constant.CONSTANT_String: int stringIndex = ((ConstantString)constant).getStringIndex(); - stack.push(new StringConstantExpression(lineNumber, constants.getConstantString(stringIndex))); + stack.push(new StringConstantExpression(lineNumber, constants.getConstantUtf8(stringIndex))); break; } } @@ -1273,27 +1273,39 @@ private void parseInvokeDynamic(Statements statements, DefaultStack stack, ConstantPool constan ConstantMemberRef constantMemberRef = constants.getConstant(index); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); if (name.equals("TYPE") && typeName.startsWith("java/lang/")) { switch (typeName) { @@ -1653,7 +1665,7 @@ private void parseGetStatic(DefaultStack stack, ConstantPool constan } } - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); ObjectType ot = objectTypeMaker.make(typeName); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); @@ -1665,8 +1677,8 @@ private void parsePutStatic(Statements statements, DefaultStack stac String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ObjectType ot = objectTypeMaker.make(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); Expression valueRef = stack.pop(); Expression objectRef = new ObjectTypeReferenceExpression(lineNumber, ot, !internalTypeName.equals(typeName) || localVariableMaker.containsName(name)); @@ -1679,8 +1691,8 @@ private void parseGetField(DefaultStack stack, ConstantPool constant String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ObjectType ot = objectTypeMaker.make(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); Expression objectRef = stack.pop(); stack.push(new FieldReferenceExpression(lineNumber, type, getFieldInstanceReference(objectRef, ot, name), typeName, name, descriptor)); @@ -1691,8 +1703,8 @@ private void parsePutField(Statements statements, DefaultStack stack String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ObjectType ot = objectTypeMaker.make(typeName); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); Type type = signatureParser.parseTypeSignature(descriptor); Expression valueRef = stack.pop(); Expression objectRef = stack.pop(); @@ -1942,12 +1954,12 @@ public static boolean isAssertCondition(String internalTypeName, BasicBlock basi ConstantPool constants = method.getConstants(); ConstantMemberRef constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); if (! "$assertionsDisabled".equals(name)) return false; - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); if (! "Z".equals(descriptor)) return false; @@ -2309,7 +2321,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 182: case 183: // INVOKEVIRTUAL, INVOKESPECIAL constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= 1 + countMethodParameters(descriptor); if (descriptor.charAt(descriptor.length()-1) != 'V') { @@ -2319,7 +2331,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 184: // INVOKESTATIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= countMethodParameters(descriptor); if (descriptor.charAt(descriptor.length()-1) != 'V') { @@ -2329,7 +2341,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 185: // INVOKEINTERFACE constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= 1 + countMethodParameters(descriptor); offset += 2; // Skip 'count' and one byte @@ -2340,7 +2352,7 @@ public static int evalStackDepth(ConstantPool constants, byte[] code, BasicBlock case 186: // INVOKEDYNAMIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); depth -= countMethodParameters(descriptor); offset += 2; // Skip 2 bytes diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java index 7ca88b75..47531a14 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ByteCodeWriter.java @@ -204,24 +204,24 @@ protected static void writeByteCode(String linePrefix, StringBuilder sb, Constan ConstantMemberRef constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); String typeName = constants.getConstantTypeName(constantMemberRef.getClassIndex()); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String name = constants.getConstantString(constantNameAndType.getNameIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); sb.append(" ").append(typeName).append('.').append(name).append(" : ").append(descriptor); break; case 180: case 181: case 182: case 183: case 184: // GETFIELD, PUTFIELD, INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - name = constants.getConstantString(constantNameAndType.getNameIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); sb.append(" ").append(name).append(" : ").append(descriptor); break; case 185: case 186: // INVOKEINTERFACE, INVOKEDYNAMIC constantMemberRef = constants.getConstant(((code[++offset] & 255) << 8) | (code[++offset] & 255)); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - name = constants.getConstantString(constantNameAndType.getNameIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + name = constants.getConstantUtf8(constantNameAndType.getNameIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); sb.append(" ").append(name).append(" : ").append(descriptor); @@ -302,7 +302,7 @@ protected static void writeLDC(StringBuilder sb, ConstantPool constants, Constan case Constant.CONSTANT_String: sb.append(" '"); int stringIndex = ((ConstantString) constant).getStringIndex(); - String str = constants.getConstantString(stringIndex); + String str = constants.getConstantUtf8(stringIndex); for (char c : str.toCharArray()) { switch (c) { diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java index 0a2b9fec..b85f70d1 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/ControlFlowGraphMaker.java @@ -98,7 +98,7 @@ public static ControlFlowGraph make(Method method) { case 182: case 183: case 184: // INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC ConstantMemberRef constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); ConstantNameAndType constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - String descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + String descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); if (descriptor.charAt(descriptor.length()-1) == 'V') { lastStatementOffset = offset; } @@ -106,7 +106,7 @@ public static ControlFlowGraph make(Method method) { case 185: case 186: // INVOKEINTERFACE, INVOKEDYNAMIC constantMemberRef = constants.getConstant( ((code[++offset] & 255) << 8) | (code[++offset] & 255) ); constantNameAndType = constants.getConstant(constantMemberRef.getNameAndTypeIndex()); - descriptor = constants.getConstantString(constantNameAndType.getDescriptorIndex()); + descriptor = constants.getConstantUtf8(constantNameAndType.getDescriptorIndex()); offset += 2; // Skip 2 bytes if (descriptor.charAt(descriptor.length()-1) == 'V') { lastStatementOffset = offset; diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java deleted file mode 100644 index 3c753dc4..00000000 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/CreateConcatStringUtil.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2008-2019 Emmanuel Dupuy. - * This project is distributed under the GPLv3 license. - * This is a Copyleft license that gives the user the right to use, - * copy and modify the code freely for non-commercial purposes. - */ - -package org.jd.core.v1.service.converter.classfiletojavasyntax.util; - -import org.jd.core.v1.model.javasyntax.expression.BinaryOperatorExpression; -import org.jd.core.v1.model.javasyntax.expression.Expression; -import org.jd.core.v1.model.javasyntax.expression.MethodInvocationExpression; -import org.jd.core.v1.model.javasyntax.expression.NewExpression; -import org.jd.core.v1.model.javasyntax.type.ObjectType; - -public class CreateConcatStringUtil { - - public static Expression create(Expression expression, int lineNumber, String typeName) { - if (expression.getClass() == MethodInvocationExpression.class) { - MethodInvocationExpression mie = (MethodInvocationExpression)expression; - - if ("append".equals(mie.getName()) && (mie.getParameters() != null) && !mie.getParameters().isList()) { - Expression concatenatedStringExpression = mie.getParameters().getFirst(); - - Expression expr = mie.getExpression(); - - while (expr.getClass() == MethodInvocationExpression.class) { - mie = (MethodInvocationExpression)expr; - - if (("append".equals(mie.getName()) == false) || (mie.getParameters() == null) || mie.getParameters().isList()) - break; - - concatenatedStringExpression = new BinaryOperatorExpression(mie.getLineNumber(), ObjectType.TYPE_STRING, (Expression)mie.getParameters(), "+", concatenatedStringExpression, 4); - expr = mie.getExpression(); - } - - if (expr.getClass() == NewExpression.class) { - NewExpression ne = (NewExpression)expr; - String internalTypeName = ne.getType().getDescriptor(); - - if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { - if (ne.getParameters() == null) { - return concatenatedStringExpression; - } else if (!ne.getParameters().isList()) { - expression = ne.getParameters().getFirst(); - - if (expression.getType() == ObjectType.TYPE_STRING) { - return new BinaryOperatorExpression(ne.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", concatenatedStringExpression, 4); - } - } - } - } - } - } - - return new MethodInvocationExpression(lineNumber, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;"); - } -} diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java new file mode 100644 index 00000000..5a8f477a --- /dev/null +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/util/StringConcatenationUtil.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2008-2019 Emmanuel Dupuy. + * This project is distributed under the GPLv3 license. + * This is a Copyleft license that gives the user the right to use, + * copy and modify the code freely for non-commercial purposes. + */ + +package org.jd.core.v1.service.converter.classfiletojavasyntax.util; + +import org.jd.core.v1.model.javasyntax.expression.*; +import org.jd.core.v1.model.javasyntax.type.ObjectType; +import org.jd.core.v1.util.DefaultList; + +import java.util.StringTokenizer; + +public class StringConcatenationUtil { + + public static Expression create(Expression expression, int lineNumber, String typeName) { + if (expression.getClass() == MethodInvocationExpression.class) { + MethodInvocationExpression mie = (MethodInvocationExpression) expression; + + if ("append".equals(mie.getName()) && (mie.getParameters() != null) && !mie.getParameters().isList()) { + Expression concatenatedStringExpression = mie.getParameters().getFirst(); + Expression expr = mie.getExpression(); + + while (expr.getClass() == MethodInvocationExpression.class) { + mie = (MethodInvocationExpression) expr; + + if (("append".equals(mie.getName()) == false) || (mie.getParameters() == null) || mie.getParameters().isList()) { + break; + } + + concatenatedStringExpression = new BinaryOperatorExpression(mie.getLineNumber(), ObjectType.TYPE_STRING, (Expression) mie.getParameters(), "+", concatenatedStringExpression, 4); + expr = mie.getExpression(); + } + + if (expr.getClass() == NewExpression.class) { + NewExpression ne = (NewExpression) expr; + String internalTypeName = ne.getType().getDescriptor(); + + if ("Ljava/lang/StringBuilder;".equals(internalTypeName) || "Ljava/lang/StringBuffer;".equals(internalTypeName)) { + if (ne.getParameters() == null) { + return concatenatedStringExpression; + } + if (!ne.getParameters().isList()) { + expression = ne.getParameters().getFirst(); + + if (expression.getType() == ObjectType.TYPE_STRING) { + return new BinaryOperatorExpression(ne.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", concatenatedStringExpression, 4); + } + } + } + } + } + } + + return new MethodInvocationExpression(lineNumber, ObjectType.TYPE_STRING, expression, typeName, "toString", "()Ljava/lang/String;"); + } + + public static Expression create(String recipe, BaseExpression parameters) { + StringTokenizer st = new StringTokenizer(recipe, "\u0001", true); + + if (st.hasMoreTokens()) { + String token = st.nextToken(); + Expression expression = token.equals("\u0001") ? createFirstStringConcatenationItem(parameters.getFirst()) : new StringConstantExpression(token); + + if (parameters.isList()) { + DefaultList list = parameters.getList(); + int index = 0; + + while (st.hasMoreTokens()) { + token = st.nextToken(); + Expression e = token.equals("\u0001") ? list.get(index++) : new StringConstantExpression(token); + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", e, 6); + } + } else { + while (st.hasMoreTokens()) { + token = st.nextToken(); + Expression e = token.equals("\u0001") ? parameters.getFirst() : new StringConstantExpression(token); + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", e, 6); + } + } + + return expression; + } else { + return StringConstantExpression.EMPTY_STRING; + } + } + + public static Expression create(BaseExpression parameters) { + if (parameters.isList()) { + DefaultList list = parameters.getList(); + + switch (list.size()) { + case 0: + return StringConstantExpression.EMPTY_STRING; + case 1: + return createFirstStringConcatenationItem(parameters.getFirst()); + default: + Expression expression = createFirstStringConcatenationItem(parameters.getFirst()); + + for (int i = 1, len = list.size(); i < len; i++) { + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, expression, "+", list.get(i), 6); + } + + return expression; + } + } else { + return createFirstStringConcatenationItem(parameters.getFirst()); + } + } + + private static Expression createFirstStringConcatenationItem(Expression expression) { + if (!expression.getType().equals(ObjectType.TYPE_STRING)) { + expression = new BinaryOperatorExpression(expression.getLineNumber(), ObjectType.TYPE_STRING, StringConstantExpression.EMPTY_STRING, "+", expression, 6); + } + + return expression; + } +} \ No newline at end of file diff --git a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java index f403df69..1c1c3fb5 100644 --- a/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java +++ b/src/main/java/org/jd/core/v1/service/converter/classfiletojavasyntax/visitor/InitInstanceFieldVisitor.java @@ -24,10 +24,7 @@ import org.jd.core.v1.service.converter.classfiletojavasyntax.model.javasyntax.declaration.ClassFileFieldDeclaration; import org.jd.core.v1.util.DefaultList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.ListIterator; +import java.util.*; public class InitInstanceFieldVisitor extends AbstractJavaSyntaxVisitor { protected SearchFirstLineNumberVisitor searchFirstLineNumberVisitor = new SearchFirstLineNumberVisitor(); @@ -87,7 +84,7 @@ public void visit(ConstructorDeclaration declaration) { if (cfcd.getStatements().getClass() == Statements.class) { Statements statements = (Statements) cfcd.getStatements(); ListIterator iterator = statements.listIterator(); - Expression superConstructorCall = searchSuperConstructorCall(iterator); + SuperConstructorInvocationExpression superConstructorCall = searchSuperConstructorCall(iterator); if (superConstructorCall != null) { String internalTypeName = cfcd.getClassFile().getInternalTypeName(); @@ -95,7 +92,8 @@ public void visit(ConstructorDeclaration declaration) { datas.add(new Data(cfcd, statements, iterator.nextIndex())); if (datas.size() == 1) { - initPutFields(internalTypeName, cfcd, iterator); + int firstLineNumber = superConstructorCall.getDescriptor().equals("()V") ? Printer.UNKNOWN_LINE_NUMBER : superConstructorCall.getLineNumber(); + initPutFields(internalTypeName, firstLineNumber, iterator); } else { filterPutFields(internalTypeName, iterator); } @@ -124,7 +122,7 @@ public void visit(LocalVariableReferenceExpression expression) { containsLocalVariableReference = true; } - protected Expression searchSuperConstructorCall(ListIterator iterator) { + protected SuperConstructorInvocationExpression searchSuperConstructorCall(ListIterator iterator) { while (iterator.hasNext()) { Statement statement = iterator.next(); @@ -133,7 +131,7 @@ protected Expression searchSuperConstructorCall(ListIterator iterator Class clazz = expression.getClass(); if (clazz == SuperConstructorInvocationExpression.class) { - return expression; + return (SuperConstructorInvocationExpression)expression; } if (clazz == ConstructorInvocationExpression.class) { @@ -145,30 +143,9 @@ protected Expression searchSuperConstructorCall(ListIterator iterator return null; } - protected void initPutFields(String internalTypeName, ClassFileConstructorDeclaration cfcd, ListIterator iterator) { - Method method = cfcd.getMethod(); + protected void initPutFields(String internalTypeName, int firstLineNumber, ListIterator iterator) { HashSet fieldNames = new HashSet<>(); - int lineNumberBefore = 0; - int lineNumberAfter = 0; Expression expression = null; - AttributeCode attributeCode = method.getAttribute("Code"); - - if (attributeCode != null) { - AttributeLineNumberTable lineNumberTable = attributeCode.getAttribute("LineNumberTable"); - - if (lineNumberTable != null) { - LineNumber[] lineNumbers = lineNumberTable.getLineNumberTable(); - lineNumberBefore = lineNumbers[0].getLineNumber(); - lineNumberAfter = lineNumbers[lineNumbers.length - 1].getLineNumber(); - - for (ClassFileConstructorOrMethodDeclaration cfcomd : cfcd.getBodyDeclaration().getMethodDeclarations()) { - if ((cfcomd.getFirstLineNumber() > lineNumberBefore) && (cfcomd.getFirstLineNumber() < lineNumberAfter)) { - lineNumberAfter = Printer.UNKNOWN_LINE_NUMBER; - break; - } - } - } - } while (iterator.hasNext()) { Statement statement = iterator.next(); @@ -210,15 +187,27 @@ protected void initPutFields(String internalTypeName, ClassFileConstructorDeclar putFields.add(cfboe); fieldNames.add(fieldName); + expression = null; } - if ((lineNumberAfter != Printer.UNKNOWN_LINE_NUMBER) && (expression != null) && (expression.getLineNumber() != lineNumberAfter)) { + int lastLineNumber; + + if (expression == null) { + lastLineNumber = (firstLineNumber == Printer.UNKNOWN_LINE_NUMBER) ? Printer.UNKNOWN_LINE_NUMBER : firstLineNumber+1; + } else { + lastLineNumber = expression.getLineNumber(); + } + + if (firstLineNumber < lastLineNumber) { Iterator ite = putFields.iterator(); while (ite.hasNext()) { int lineNumber = ite.next().getLineNumber(); - if ((lineNumberBefore <= lineNumber) && (lineNumber <= lineNumberAfter)) { + if ((firstLineNumber <= lineNumber) && (lastLineNumber <= lastLineNumber)) { + if (lastLineNumber == lastLineNumber) { + lastLineNumber++; + } ite.remove(); } } diff --git a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java index 5b21ed14..7bf3fc6a 100644 --- a/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java +++ b/src/main/java/org/jd/core/v1/service/deserializer/classfile/ClassFileDeserializer.java @@ -191,8 +191,8 @@ protected Field[] loadFields(ClassFileReader reader, ConstantPool constants) { int signatureIndex = reader.readUnsignedShort(); HashMap attributes = loadAttributes(reader, constants); - String name = constants.getConstantString(nameIndex); - String signature = constants.getConstantString(signatureIndex); + String name = constants.getConstantUtf8(nameIndex); + String signature = constants.getConstantUtf8(signatureIndex); fields[i] = new Field(accessFlags, name, signature, attributes); } @@ -213,8 +213,8 @@ protected Method[] loadMethods(ClassFileReader reader, ConstantPool constants) { int signatureIndex = reader.readUnsignedShort(); HashMap attributes = loadAttributes(reader, constants); - String name = constants.getConstantString(nameIndex); - String signature = constants.getConstantString(signatureIndex); + String name = constants.getConstantUtf8(nameIndex); + String signature = constants.getConstantUtf8(signatureIndex); methods[i] = new Method(accessFlags, name, signature, attributes, constants); } @@ -284,7 +284,7 @@ protected HashMap loadAttributes(ClassFileReader reader, Cons attributes.put(name, new AttributeModule( constants.getConstantTypeName(reader.readUnsignedShort()), reader.readUnsignedShort(), - constants.getConstantString(reader.readUnsignedShort()), + constants.getConstantUtf8(reader.readUnsignedShort()), loadModuleInfos(reader, constants), loadPackageInfos(reader, constants), loadPackageInfos(reader, constants), @@ -310,12 +310,12 @@ protected HashMap loadAttributes(ClassFileReader reader, Cons case "Signature": if (attributeLength != 2) throw new ClassFileFormatException("Invalid attribute length"); - attributes.put(name, new AttributeSignature(constants.getConstantString(reader.readUnsignedShort()))); + attributes.put(name, new AttributeSignature(constants.getConstantUtf8(reader.readUnsignedShort()))); break; case "SourceFile": if (attributeLength != 2) throw new ClassFileFormatException("Invalid attribute length"); - attributes.put(name, new AttributeSourceFile(constants.getConstantString(reader.readUnsignedShort()))); + attributes.put(name, new AttributeSourceFile(constants.getConstantUtf8(reader.readUnsignedShort()))); break; case "Synthetic": if (attributeLength != 0) @@ -346,17 +346,17 @@ protected ElementValue loadElementValue(ClassFileReader reader, ConstantPool con return new ElementValuePrimitiveType(type, constValue); case 'e': int typeNameIndex = reader.readUnsignedShort(); - String typeName = constants.getConstantString(typeNameIndex); + String typeName = constants.getConstantUtf8(typeNameIndex); int constNameIndex = reader.readUnsignedShort(); - String constName = constants.getConstantString(constNameIndex); + String constName = constants.getConstantUtf8(constNameIndex); return new ElementValueEnumConstValue(typeName, constName); case 'c': int classInfoIndex = reader.readUnsignedShort(); - String classInfo = constants.getConstantString(classInfoIndex); + String classInfo = constants.getConstantUtf8(classInfoIndex); return new ElementValueClassInfo(classInfo); case '@': int typeIndex = reader.readUnsignedShort(); - typeName = constants.getConstantString(typeIndex); + typeName = constants.getConstantUtf8(typeIndex); return new ElementValueAnnotationValue(new Annotation(typeName, loadElementValuePairs(reader, constants))); case '[': return new ElementValueArrayValue(loadElementValues(reader, constants)); @@ -374,7 +374,7 @@ protected ElementValuePair[] loadElementValuePairs(ClassFileReader reader, Const for (int i=0; i < count; i++) { int elementNameIndex = reader.readUnsignedShort(); - String elementName = constants.getConstantString(elementNameIndex); + String elementName = constants.getConstantUtf8(elementNameIndex); pairs[i] = new ElementValuePair(elementName, loadElementValue(reader, constants)); } @@ -487,7 +487,7 @@ protected InnerClass[] loadInnerClasses(ClassFileReader reader, ConstantPool con String innerTypeName = constants.getConstantTypeName(innerTypeIndex); String outerTypeName = (outerTypeIndex == 0) ? null : constants.getConstantTypeName(outerTypeIndex); - String innerName = (innerNameIndex == 0) ? null : constants.getConstantString(innerNameIndex); + String innerName = (innerNameIndex == 0) ? null : constants.getConstantUtf8(innerNameIndex); innerClasses[i] = new InnerClass(innerTypeName, outerTypeName, innerName, innerAccessFlags); } @@ -509,8 +509,8 @@ protected LocalVariable[] loadLocalVariables(ClassFileReader reader, ConstantPoo int descriptorIndex = reader.readUnsignedShort(); int index = reader.readUnsignedShort(); - String name = constants.getConstantString(nameIndex); - String descriptor = constants.getConstantString(descriptorIndex); + String name = constants.getConstantUtf8(nameIndex); + String descriptor = constants.getConstantUtf8(descriptorIndex); localVariables[i] = new LocalVariable(startPc, length, name, descriptor, index); } @@ -532,8 +532,8 @@ protected LocalVariableType[] loadLocalVariableTypes(ClassFileReader reader, Con int descriptorIndex = reader.readUnsignedShort(); int index = reader.readUnsignedShort(); - String name = constants.getConstantString(nameIndex); - String descriptor = constants.getConstantString(descriptorIndex); + String name = constants.getConstantUtf8(nameIndex); + String descriptor = constants.getConstantUtf8(descriptorIndex); localVariables[i] = new LocalVariableType(startPc, length, name, descriptor, index); } @@ -565,7 +565,7 @@ protected MethodParameter[] loadParameters(ClassFileReader reader, ConstantPool for (int i=0; i iterator = packageInfo.getModuleInfoNames().iterator(); String moduleInfoName = iterator.next(); - tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, "module-info", moduleInfoName, null, null)); while (iterator.hasNext()) { tokens.add(TextToken.COMMA); tokens.add(NewLineToken.NEWLINE_1); moduleInfoName = iterator.next(); - tokens.add(new ReferenceToken(ReferenceToken.MODULE, moduleInfoName.replace('.', '/'), moduleInfoName, null, null)); + tokens.add(new ReferenceToken(ReferenceToken.MODULE, "module-info", moduleInfoName, null, null)); } tokens.add(EndBlockToken.END_DECLARATION_OR_STATEMENT_BLOCK); @@ -1282,6 +1282,10 @@ protected void buildTokensForAccessFlags(int flags) { tokens.add(PROTECTED); tokens.add(TextToken.SPACE); } + if ((flags & FLAG_DEFAULT) != 0) { + tokens.add(DEFAULT); + tokens.add(TextToken.SPACE); + } if ((flags & FLAG_STATIC) != 0) { tokens.add(STATIC); tokens.add(TextToken.SPACE);