/*
- * 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.
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Set;
public class ConcatenationHelper {
exprTmp = iex.getInstance();
}
}
+ else if ("makeConcatWithConstants".equals(iex.getName())) { // java 9 style
+ List<Exprent> parameters = extractParameters(iex.getBootstrapArguments(), iex);
+ if (parameters.size() >= 2) {
+ return createConcatExprent(parameters, expr.bytecode);
+ }
+ }
}
if (exprTmp == null) {
lstOperands.set(i, rep);
}
}
+ return createConcatExprent(lstOperands, expr.bytecode);
+ }
+ private static Exprent createConcatExprent(List<Exprent> lstOperands, Set<Integer> bytecode) {
// build exprent to return
Exprent func = lstOperands.get(0);
for (int i = 1; i < lstOperands.size(); i++) {
- List<Exprent> lstTmp = new ArrayList<Exprent>();
- lstTmp.add(func);
- lstTmp.add(lstOperands.get(i));
- func = new FunctionExprent(FunctionExprent.FUNCTION_STR_CONCAT, lstTmp, expr.bytecode);
+ func = new FunctionExprent(FunctionExprent.FUNCTION_STR_CONCAT, Arrays.asList(func, lstOperands.get(i)), bytecode);
}
return func;
}
+ // See StringConcatFactory in jdk sources
+ private static final char TAG_ARG = '\u0001';
+ private static final char TAG_CONST = '\u0002';
+
+ private static List<Exprent> extractParameters(List<PooledConstant> bootstrapArguments, InvocationExprent expr) {
+ List<Exprent> parameters = expr.getLstParameters();
+ if (bootstrapArguments != null) {
+ PooledConstant constant = bootstrapArguments.get(0);
+ if (constant.type == CodeConstants.CONSTANT_String) {
+ String recipe = ((PrimitiveConstant)constant).getString();
+
+ List<Exprent> res = new ArrayList<>();
+ StringBuilder acc = new StringBuilder();
+ int parameterId = 0;
+ for (int i = 0; i < recipe.length(); i++) {
+ char c = recipe.charAt(i);
+
+ if (c == TAG_CONST || c == TAG_ARG) {
+ // Detected a special tag, flush all accumulated characters
+ // as a constant first:
+ if (acc.length() > 0) {
+ res.add(new ConstExprent(VarType.VARTYPE_STRING, acc.toString(), expr.bytecode));
+ acc.setLength(0);
+ }
+ if (c == TAG_CONST) {
+ // skip for now
+ }
+ if (c == TAG_ARG) {
+ res.add(parameters.get(parameterId++));
+ }
+ }
+ else {
+ // Not a special characters, this is a constant embedded into
+ // the recipe itself.
+ acc.append(c);
+ }
+ }
+
+ // Flush the remaining characters as constant:
+ if (acc.length() > 0) {
+ res.add(new ConstExprent(VarType.VARTYPE_STRING, acc.toString(), expr.bytecode));
+ }
+
+ return res;
+ }
+ }
+ return new ArrayList<>(parameters);
+ }
+
private static boolean isAppendConcat(InvocationExprent expr, VarType cltype) {
if ("append".equals(expr.getName())) {
case opc_invokeinterface:
case opc_invokedynamic:
if (instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
-
LinkConstant invoke_constant = pool.getLinkConstant(instr.getOperand(0));
- int dynamic_invokation_type = -1;
+ List<PooledConstant> bootstrap_arguments = null;
if (instr.opcode == opc_invokedynamic && bootstrap != null) {
- List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
- if (bootstrap_arguments.size() > 1) { // INVOKEDYNAMIC is used not only for lambdas
- PooledConstant link = bootstrap_arguments.get(1);
- if (link instanceof LinkConstant) {
- dynamic_invokation_type = ((LinkConstant)link).index1;
- }
- }
+ bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
}
- InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, stack, dynamic_invokation_type, bytecode_offsets);
+ InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, bootstrap_arguments, stack, bytecode_offsets);
if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
exprlist.add(exprinv);
}
/*
- * Copyright 2000-2015 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.
*/
package org.jetbrains.java.decompiler.modules.decompiler.exps;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.MatchEngine;
import org.jetbrains.java.decompiler.util.ListStack;
import org.jetbrains.java.decompiler.util.TextUtil;
+import java.util.*;
+import java.util.Map.Entry;
+
public class InvocationExprent extends Exprent {
public static final int INVOKE_SPECIAL = 1;
private String invokeDynamicClassSuffix;
private int invocationTyp = INVOKE_VIRTUAL;
private List<Exprent> lstParameters = new ArrayList<Exprent>();
+ private List<PooledConstant> bootstrapArguments;
public InvocationExprent() {
super(EXPRENT_INVOCATION);
}
- public InvocationExprent(int opcode, LinkConstant cn, ListStack<Exprent> stack, int dynamicInvocationType, Set<Integer> bytecodeOffsets) {
+ public InvocationExprent(int opcode,
+ LinkConstant cn,
+ List<PooledConstant> bootstrapArguments,
+ ListStack<Exprent> stack,
+ Set<Integer> bytecodeOffsets) {
this();
name = cn.elementname;
classname = cn.classname;
+ this.bootstrapArguments = bootstrapArguments;
switch (opcode) {
case CodeConstants.opc_invokestatic:
}
if (opcode == CodeConstants.opc_invokedynamic) {
+ int dynamicInvocationType = -1;
+ if (bootstrapArguments != null) {
+ if (bootstrapArguments.size() > 1) { // INVOKEDYNAMIC is used not only for lambdas
+ PooledConstant link = bootstrapArguments.get(1);
+ if (link instanceof LinkConstant) {
+ dynamicInvocationType = ((LinkConstant)link).index1;
+ }
+ }
+ }
if (dynamicInvocationType == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic) {
isStatic = true;
}
ExprProcessor.copyEntries(lstParameters);
addBytecodeOffsets(expr.bytecode);
+ bootstrapArguments = expr.getBootstrapArguments();
}
@Override
return invokeDynamicClassSuffix;
}
+ public List<PooledConstant> getBootstrapArguments() {
+ return bootstrapArguments;
+ }
+
// *****************************************************************************
// IMatchable implementation
// *****************************************************************************
/*
- * Copyright 2000-2015 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.
@Test public void testInnerSignature() { doTest("pkg/TestInnerSignature"); }
@Test public void testParameterizedTypes() { doTest("pkg/TestParameterizedTypes"); }
@Test public void testShadowing() { doTest("pkg/TestShadowing", "pkg/Shadow", "ext/Shadow"); }
+ @Test public void testStringConcat() { doTest("pkg/TestStringConcat"); }
+ @Test public void testJava9StringConcat() { doTest("java9/TestJava9StringConcat"); }
protected void doTest(String testFile, String... companionFiles) {
ConsoleDecompiler decompiler = fixture.getDecompiler();
--- /dev/null
+package java9;
+
+public class TestJava9StringConcat {
+ public String test1(String var1, int var2) {
+ return var1 + var2;// 20
+ }
+
+ public String test2(String var1, int var2, Object var3) {
+ return "(" + var1 + "-" + var2 + "---" + var3 + ")";// 24
+ }
+}
+
+class 'java9/TestJava9StringConcat' {
+ method 'test1 (Ljava/lang/String;I)Ljava/lang/String;' {
+ 2 4
+ 7 4
+ }
+
+ method 'test2 (Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;' {
+ 3 8
+ 8 8
+ }
+}
+
+Lines mapping:
+20 <-> 5
+24 <-> 9
--- /dev/null
+package pkg;
+
+public class TestStringConcat {
+ public String test1(String var1, int var2) {
+ return var1 + var2;// 20
+ }
+
+ public String test2(String var1, int var2, Object var3) {
+ return "(" + var1 + "-" + var2 + "---" + var3 + ")";// 24
+ }
+}
+
+class 'pkg/TestStringConcat' {
+ method 'test1 (Ljava/lang/String;I)Ljava/lang/String;' {
+ f 4
+ 12 4
+ }
+
+ method 'test2 (Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String;' {
+ 7 8
+ 10 8
+ 19 8
+ 22 8
+ 27 8
+ 2a 8
+ }
+}
+
+Lines mapping:
+20 <-> 5
+24 <-> 9
--- /dev/null
+/*
+ * Copyright 2000-2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package java9;
+
+public class TestJava9StringConcat {
+ public String test1(String prefix, int a) {
+ return prefix + a;
+ }
+
+ public String test2(String var, int b, Object c) {
+ return "(" + var + "-" + b + "---" + c + ")";
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2000-2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestStringConcat {
+ public String test1(String prefix, int a) {
+ return prefix + a;
+ }
+
+ public String test2(String var, int b, Object c) {
+ return "(" + var + "-" + b + "---" + c + ")";
+ }
+}
\ No newline at end of file