IDEA-130708 Incorrect locals names
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2016 JetBrains s.r.o.
|
* Copyright 2000-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -163,7 +163,8 @@ public class ClassWrapper {
|
|||||||
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
||||||
StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr();
|
StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr();
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
varProc.setDebugVarNames(attr.getMapVarNames());
|
// only param names here
|
||||||
|
varProc.setDebugVarNames(attr.getMapParamNames());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2016 JetBrains s.r.o.
|
* Copyright 2000-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -341,7 +341,7 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_fload:
|
case opc_fload:
|
||||||
case opc_dload:
|
case opc_dload:
|
||||||
case opc_aload:
|
case opc_aload:
|
||||||
pushEx(stack, exprlist, new VarExprent(instr.getOperand(0), varTypes[instr.opcode - opc_iload], varProcessor));
|
pushEx(stack, exprlist, new VarExprent(instr.getOperand(0), varTypes[instr.opcode - opc_iload], varProcessor, bytecode_offset));
|
||||||
break;
|
break;
|
||||||
case opc_iaload:
|
case opc_iaload:
|
||||||
case opc_laload:
|
case opc_laload:
|
||||||
@@ -371,8 +371,8 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
case opc_astore:
|
case opc_astore:
|
||||||
Exprent top = stack.pop();
|
Exprent top = stack.pop();
|
||||||
int varindex = instr.getOperand(0);
|
int varindex = instr.getOperand(0);
|
||||||
AssignmentExprent assign =
|
AssignmentExprent assign = new AssignmentExprent(
|
||||||
new AssignmentExprent(new VarExprent(varindex, varTypes[instr.opcode - opc_istore], varProcessor), top, bytecode_offsets);
|
new VarExprent(varindex, varTypes[instr.opcode - opc_istore], varProcessor, nextMeaningfulOffset(block, i)), top, bytecode_offsets);
|
||||||
exprlist.add(assign);
|
exprlist.add(assign);
|
||||||
break;
|
break;
|
||||||
case opc_iastore:
|
case opc_iastore:
|
||||||
@@ -624,6 +624,23 @@ public class ExprProcessor implements CodeConstants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int nextMeaningfulOffset(BasicBlock block, int index) {
|
||||||
|
InstructionSequence seq = block.getSeq();
|
||||||
|
while (++index < seq.length()) {
|
||||||
|
switch (seq.getInstr(index).opcode) {
|
||||||
|
case opc_nop:
|
||||||
|
case opc_istore:
|
||||||
|
case opc_lstore:
|
||||||
|
case opc_fstore:
|
||||||
|
case opc_dstore:
|
||||||
|
case opc_astore:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return block.getOldOffset(index);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
|
private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
|
||||||
pushEx(stack, exprlist, exprent, null);
|
pushEx(stack, exprlist, exprent, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2016 JetBrains s.r.o.
|
* Copyright 2000-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -88,7 +88,7 @@ public class FieldExprent extends Exprent {
|
|||||||
if (method != null) {
|
if (method != null) {
|
||||||
StructLocalVariableTableAttribute attr = method.methodStruct.getLocalVariableAttr();
|
StructLocalVariableTableAttribute attr = method.methodStruct.getLocalVariableAttr();
|
||||||
if (attr != null) {
|
if (attr != null) {
|
||||||
return attr.getMapVarNames().containsValue(name);
|
return attr.containsName(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
|
|||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
|
||||||
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
|
||||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||||
|
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
|
||||||
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTypeTableAttribute;
|
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTypeTableAttribute;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
import org.jetbrains.java.decompiler.struct.gen.VarType;
|
||||||
import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor;
|
import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor;
|
||||||
@@ -36,6 +37,7 @@ import org.jetbrains.java.decompiler.struct.match.MatchEngine;
|
|||||||
import org.jetbrains.java.decompiler.struct.match.MatchNode;
|
import org.jetbrains.java.decompiler.struct.match.MatchNode;
|
||||||
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
|
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
import org.jetbrains.java.decompiler.util.TextUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -49,15 +51,21 @@ public class VarExprent extends Exprent {
|
|||||||
private VarType varType;
|
private VarType varType;
|
||||||
private boolean definition = false;
|
private boolean definition = false;
|
||||||
private VarProcessor processor;
|
private VarProcessor processor;
|
||||||
|
private final int visibleOffset;
|
||||||
private int version = 0;
|
private int version = 0;
|
||||||
private boolean classDef = false;
|
private boolean classDef = false;
|
||||||
private boolean stack = false;
|
private boolean stack = false;
|
||||||
|
|
||||||
public VarExprent(int index, VarType varType, VarProcessor processor) {
|
public VarExprent(int index, VarType varType, VarProcessor processor) {
|
||||||
|
this(index, varType, processor, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VarExprent(int index, VarType varType, VarProcessor processor, int visibleOffset) {
|
||||||
super(EXPRENT_VAR);
|
super(EXPRENT_VAR);
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.varType = varType;
|
this.varType = varType;
|
||||||
this.processor = processor;
|
this.processor = processor;
|
||||||
|
this.visibleOffset = visibleOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -77,7 +85,7 @@ public class VarExprent extends Exprent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Exprent copy() {
|
public Exprent copy() {
|
||||||
VarExprent var = new VarExprent(index, getVarType(), processor);
|
VarExprent var = new VarExprent(index, getVarType(), processor, visibleOffset);
|
||||||
var.setDefinition(definition);
|
var.setDefinition(definition);
|
||||||
var.setVersion(version);
|
var.setVersion(version);
|
||||||
var.setClassDef(classDef);
|
var.setClassDef(classDef);
|
||||||
@@ -97,43 +105,85 @@ public class VarExprent extends Exprent {
|
|||||||
tracer.incrementCurrentSourceLine(buffer.countLines());
|
tracer.incrementCurrentSourceLine(buffer.countLines());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String name = null;
|
VarVersionPair varVersion = new VarVersionPair(index, version);
|
||||||
if (processor != null) {
|
String name = getName(varVersion);
|
||||||
name = processor.getVarName(new VarVersionPair(index, version));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (definition) {
|
if (definition) {
|
||||||
if (processor != null && processor.getVarFinal(new VarVersionPair(index, version)) == VarTypeProcessor.VAR_EXPLICIT_FINAL) {
|
if (processor != null && processor.getVarFinal(varVersion) == VarTypeProcessor.VAR_EXPLICIT_FINAL) {
|
||||||
buffer.append("final ");
|
buffer.append("final ");
|
||||||
}
|
}
|
||||||
boolean generic = false;
|
appendDefinitionType(buffer, varVersion);
|
||||||
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
|
buffer.append(" ");
|
||||||
MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
|
}
|
||||||
StructLocalVariableTypeTableAttribute attr = (StructLocalVariableTypeTableAttribute)method.methodStruct.getAttributes()
|
|
||||||
.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE);
|
buffer.append(name == null ? ("var" + index + (this.version == 0 ? "" : "_" + this.version)) : name);
|
||||||
if (attr != null && processor != null) {
|
}
|
||||||
Integer index = processor.getVarOriginalIndex(new VarVersionPair(this.index, version));
|
|
||||||
if (index != null) {
|
return buffer;
|
||||||
String signature = attr.getMapVarSignatures().get(index);
|
}
|
||||||
|
|
||||||
|
private String getName(VarVersionPair varVersion) {
|
||||||
|
String name = null;
|
||||||
|
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
||||||
|
MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
|
||||||
|
if (method != null) {
|
||||||
|
StructLocalVariableTableAttribute attr = method.methodStruct.getLocalVariableAttr();
|
||||||
|
if (attr != null && processor != null) {
|
||||||
|
Integer index = processor.getVarOriginalIndex(varVersion);
|
||||||
|
if (index != null) {
|
||||||
|
name = attr.getName(index, visibleOffset);
|
||||||
|
if (name != null && TextUtil.isValidIdentifier(name, method.methodStruct.getClassStruct().getBytecodeVersion())) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (processor != null) {
|
||||||
|
name = processor.getVarName(varVersion);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendDefinitionType(TextBuffer buffer, VarVersionPair varVersion) {
|
||||||
|
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
|
||||||
|
MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
|
||||||
|
if (method != null) {
|
||||||
|
Integer originalIndex = null;
|
||||||
|
if (processor != null) {
|
||||||
|
originalIndex = processor.getVarOriginalIndex(varVersion);
|
||||||
|
}
|
||||||
|
if (originalIndex != null) {
|
||||||
|
// first try from signature
|
||||||
|
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
|
||||||
|
StructLocalVariableTypeTableAttribute attr = (StructLocalVariableTypeTableAttribute)method.methodStruct.getAttributes()
|
||||||
|
.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE);
|
||||||
|
if (attr != null) {
|
||||||
|
String signature = attr.getSignature(originalIndex, visibleOffset);
|
||||||
if (signature != null) {
|
if (signature != null) {
|
||||||
GenericFieldDescriptor descriptor = GenericMain.parseFieldSignature(signature);
|
GenericFieldDescriptor descriptor = GenericMain.parseFieldSignature(signature);
|
||||||
if (descriptor != null) {
|
if (descriptor != null) {
|
||||||
buffer.append(GenericMain.getGenericCastTypeName(descriptor.type));
|
buffer.append(GenericMain.getGenericCastTypeName(descriptor.type));
|
||||||
generic = true;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// then try from descriptor
|
||||||
|
StructLocalVariableTableAttribute attr = method.methodStruct.getLocalVariableAttr();
|
||||||
|
if (attr != null) {
|
||||||
|
String descriptor = attr.getDescriptor(originalIndex, visibleOffset);
|
||||||
|
if (descriptor != null) {
|
||||||
|
buffer.append(ExprProcessor.getCastTypeName(new VarType(descriptor)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!generic) {
|
|
||||||
buffer.append(ExprProcessor.getCastTypeName(getVarType()));
|
|
||||||
}
|
|
||||||
buffer.append(" ");
|
|
||||||
}
|
}
|
||||||
buffer.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
buffer.append(ExprProcessor.getCastTypeName(getVarType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ public class VarProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setVarVersions(RootStatement root) {
|
public void setVarVersions(RootStatement root) {
|
||||||
|
VarVersionsProcessor oldProcessor = varVersions;
|
||||||
varVersions = new VarVersionsProcessor(method, methodDescriptor);
|
varVersions = new VarVersionsProcessor(method, methodDescriptor);
|
||||||
varVersions.setVarVersions(root);
|
varVersions.setVarVersions(root, oldProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVarDefinitions(Statement root) {
|
public void setVarDefinitions(Statement root) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2016 JetBrains s.r.o.
|
* Copyright 2000-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -35,7 +35,7 @@ import java.util.Map.Entry;
|
|||||||
|
|
||||||
public class VarVersionsProcessor {
|
public class VarVersionsProcessor {
|
||||||
private final StructMethod method;
|
private final StructMethod method;
|
||||||
private Map<Integer, Integer> mapOriginalVarIndices = new HashMap<>();
|
private Map<Integer, Integer> mapOriginalVarIndices = Collections.emptyMap();
|
||||||
private VarTypeProcessor typeProcessor;
|
private VarTypeProcessor typeProcessor;
|
||||||
|
|
||||||
public VarVersionsProcessor(StructMethod mt, MethodDescriptor md) {
|
public VarVersionsProcessor(StructMethod mt, MethodDescriptor md) {
|
||||||
@@ -43,7 +43,7 @@ public class VarVersionsProcessor {
|
|||||||
typeProcessor = new VarTypeProcessor(mt, md);
|
typeProcessor = new VarTypeProcessor(mt, md);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVarVersions(RootStatement root) {
|
public void setVarVersions(RootStatement root, VarVersionsProcessor previousVersionsProcessor) {
|
||||||
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
|
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
|
||||||
ssa.splitVariables(root, method);
|
ssa.splitVariables(root, method);
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ public class VarVersionsProcessor {
|
|||||||
|
|
||||||
eliminateNonJavaTypes(typeProcessor);
|
eliminateNonJavaTypes(typeProcessor);
|
||||||
|
|
||||||
setNewVarIndices(typeProcessor, graph);
|
setNewVarIndices(typeProcessor, graph, previousVersionsProcessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void mergePhiVersions(SSAConstructorSparseEx ssa, DirectGraph graph) {
|
private static void mergePhiVersions(SSAConstructorSparseEx ssa, DirectGraph graph) {
|
||||||
@@ -227,7 +227,7 @@ public class VarVersionsProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNewVarIndices(VarTypeProcessor typeProcessor, DirectGraph graph) {
|
private void setNewVarIndices(VarTypeProcessor typeProcessor, DirectGraph graph, VarVersionsProcessor previousVersionsProcessor) {
|
||||||
final Map<VarVersionPair, VarType> mapExprentMaxTypes = typeProcessor.getMapExprentMaxTypes();
|
final Map<VarVersionPair, VarType> mapExprentMaxTypes = typeProcessor.getMapExprentMaxTypes();
|
||||||
Map<VarVersionPair, VarType> mapExprentMinTypes = typeProcessor.getMapExprentMinTypes();
|
Map<VarVersionPair, VarType> mapExprentMinTypes = typeProcessor.getMapExprentMinTypes();
|
||||||
Map<VarVersionPair, Integer> mapFinalVars = typeProcessor.getMapFinalVars();
|
Map<VarVersionPair, Integer> mapFinalVars = typeProcessor.getMapFinalVars();
|
||||||
@@ -286,7 +286,19 @@ public class VarVersionsProcessor {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mapOriginalVarIndices = mapOriginalVarIndices;
|
if (previousVersionsProcessor != null) {
|
||||||
|
Map<Integer, Integer> oldIndices = previousVersionsProcessor.getMapOriginalVarIndices();
|
||||||
|
this.mapOriginalVarIndices = new HashMap<>(mapOriginalVarIndices.size());
|
||||||
|
for (Entry<Integer, Integer> entry : mapOriginalVarIndices.entrySet()) {
|
||||||
|
Integer value = entry.getValue();
|
||||||
|
Integer oldValue = oldIndices.get(value);
|
||||||
|
value = oldValue != null ? oldValue : value;
|
||||||
|
this.mapOriginalVarIndices.put(entry.getKey(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.mapOriginalVarIndices = mapOriginalVarIndices;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public VarType getVarType(VarVersionPair pair) {
|
public VarType getVarType(VarVersionPair pair) {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class StructMember {
|
|||||||
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) {
|
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) {
|
||||||
// merge all variable tables
|
// merge all variable tables
|
||||||
StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name);
|
StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name);
|
||||||
table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
|
table.add((StructLocalVariableTableAttribute)attribute);
|
||||||
}
|
}
|
||||||
else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name) && attributes.containsKey(name)) {
|
else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name) && attributes.containsKey(name)) {
|
||||||
// merge all variable tables
|
// merge all variable tables
|
||||||
|
|||||||
@@ -19,9 +19,12 @@ import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
|||||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
u2 local_variable_table_length;
|
u2 local_variable_table_length;
|
||||||
@@ -34,32 +37,70 @@ import java.util.Map;
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
public class StructLocalVariableTableAttribute extends StructGeneralAttribute {
|
public class StructLocalVariableTableAttribute extends StructGeneralAttribute {
|
||||||
|
private List<LocalVariable> localVariables = Collections.emptyList();
|
||||||
private Map<Integer, String> mapVarNames = Collections.emptyMap();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
|
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
|
||||||
int len = data.readUnsignedShort();
|
int len = data.readUnsignedShort();
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
mapVarNames = new HashMap<>(len);
|
localVariables = new ArrayList<>(len);
|
||||||
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
data.discard(4);
|
int start_pc = data.readUnsignedShort();
|
||||||
|
int length = data.readUnsignedShort();
|
||||||
int nameIndex = data.readUnsignedShort();
|
int nameIndex = data.readUnsignedShort();
|
||||||
data.discard(2);
|
int descriptorIndex = data.readUnsignedShort();
|
||||||
int varIndex = data.readUnsignedShort();
|
int varIndex = data.readUnsignedShort();
|
||||||
mapVarNames.put(varIndex, pool.getPrimitiveConstant(nameIndex).getString());
|
localVariables.add(new LocalVariable(start_pc,
|
||||||
|
length,
|
||||||
|
pool.getPrimitiveConstant(nameIndex).getString(),
|
||||||
|
pool.getPrimitiveConstant(descriptorIndex).getString(),
|
||||||
|
varIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mapVarNames = Collections.emptyMap();
|
localVariables = Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLocalVariableTable(StructLocalVariableTableAttribute attr) {
|
public void add(StructLocalVariableTableAttribute attr) {
|
||||||
mapVarNames.putAll(attr.getMapVarNames());
|
localVariables.addAll(attr.localVariables);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, String> getMapVarNames() {
|
public String getName(int index, int visibleOffset) {
|
||||||
return mapVarNames;
|
return matchingVars(index, visibleOffset).map(v -> v.name).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescriptor(int index, int visibleOffset) {
|
||||||
|
return matchingVars(index, visibleOffset).map(v -> v.descriptor).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<LocalVariable> matchingVars(int index, int visibleOffset) {
|
||||||
|
return localVariables.stream()
|
||||||
|
.filter(v -> v.index == index && (visibleOffset >= v.start_pc && visibleOffset < v.start_pc + v.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsName(String name) {
|
||||||
|
return localVariables.stream().anyMatch(v -> v.name == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, String> getMapParamNames() {
|
||||||
|
return localVariables.stream().filter(v -> v.start_pc == 0).collect(Collectors.toMap(v -> v.index, v -> v.name, (n1, n2) -> n2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LocalVariable {
|
||||||
|
final int start_pc;
|
||||||
|
final int length;
|
||||||
|
final String name;
|
||||||
|
final String descriptor;
|
||||||
|
final int index;
|
||||||
|
|
||||||
|
private LocalVariable(int start_pc, int length, String name, String descriptor, int index) {
|
||||||
|
this.start_pc = start_pc;
|
||||||
|
this.length = length;
|
||||||
|
this.name = name;
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
|||||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Set;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
u2 local_variable_type_table_length;
|
u2 local_variable_type_table_length;
|
||||||
@@ -33,31 +31,19 @@ import java.util.Map;
|
|||||||
} local_variable_type_table[local_variable_type_table_length];
|
} local_variable_type_table[local_variable_type_table_length];
|
||||||
*/
|
*/
|
||||||
public class StructLocalVariableTypeTableAttribute extends StructGeneralAttribute {
|
public class StructLocalVariableTypeTableAttribute extends StructGeneralAttribute {
|
||||||
|
// store signature instead of descriptor
|
||||||
private Map<Integer, String> mapVarSignatures = Collections.emptyMap();
|
private final StructLocalVariableTableAttribute backingAttribute = new StructLocalVariableTableAttribute();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
|
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
|
||||||
int len = data.readUnsignedShort();
|
backingAttribute.initContent(data, pool);
|
||||||
if (len > 0) {
|
|
||||||
mapVarSignatures = new HashMap<>(len);
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
data.discard(6);
|
|
||||||
int signatureIndex = data.readUnsignedShort();
|
|
||||||
int varIndex = data.readUnsignedShort();
|
|
||||||
mapVarSignatures.put(varIndex, pool.getPrimitiveConstant(signatureIndex).getString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mapVarSignatures = Collections.emptyMap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(StructLocalVariableTypeTableAttribute attr) {
|
public void add(StructLocalVariableTypeTableAttribute attr) {
|
||||||
mapVarSignatures.putAll(attr.getMapVarSignatures());
|
backingAttribute.add(attr.backingAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, String> getMapVarSignatures() {
|
public String getSignature(int index, int visibleOffset) {
|
||||||
return mapVarSignatures;
|
return backingAttribute.getDescriptor(index, visibleOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ public class SingleClassesTest {
|
|||||||
@Test public void testIllegalVarName() { doTest("pkg/TestIllegalVarName"); }
|
@Test public void testIllegalVarName() { doTest("pkg/TestIllegalVarName"); }
|
||||||
@Test public void testKotlinConstructor() { doTest("pkg/TestKotlinConstructorKt"); }
|
@Test public void testKotlinConstructor() { doTest("pkg/TestKotlinConstructorKt"); }
|
||||||
@Test public void testAsserts() { doTest("pkg/TestAsserts"); }
|
@Test public void testAsserts() { doTest("pkg/TestAsserts"); }
|
||||||
|
@Test public void testLocalsNames() { doTest("pkg/TestLocalsNames"); }
|
||||||
|
|
||||||
private void doTest(String testFile, String... companionFiles) {
|
private void doTest(String testFile, String... companionFiles) {
|
||||||
ConsoleDecompiler decompiler = fixture.getDecompiler();
|
ConsoleDecompiler decompiler = fixture.getDecompiler();
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ public class Loader {
|
|||||||
throw new RuntimeException("Resource missing");
|
throw new RuntimeException("Resource missing");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
File e = new File(resource.toURI());
|
File file = new File(resource.toURI());
|
||||||
byte[] bytes = new byte[(int)e.length()];
|
byte[] bytes = new byte[(int)file.length()];
|
||||||
FileInputStream stream = new FileInputStream(e);
|
FileInputStream stream = new FileInputStream(file);
|
||||||
stream.read(bytes);
|
stream.read(bytes);
|
||||||
stream.close();
|
stream.close();
|
||||||
return new String(bytes, "UTF-8");
|
return new String(bytes, "UTF-8");
|
||||||
|
|||||||
BIN
testData/classes/pkg/TestLocalsNames.class
Normal file
BIN
testData/classes/pkg/TestLocalsNames.class
Normal file
Binary file not shown.
@@ -11,7 +11,7 @@ class TestAmbiguousCall {
|
|||||||
IllegalArgumentException iae = new IllegalArgumentException();// 8
|
IllegalArgumentException iae = new IllegalArgumentException();// 8
|
||||||
this.m1((RuntimeException)iae, "RE");// 9
|
this.m1((RuntimeException)iae, "RE");// 9
|
||||||
this.m1(iae, "IAE");// 10
|
this.m1(iae, "IAE");// 10
|
||||||
IllegalArgumentException re = new IllegalArgumentException();// 12
|
RuntimeException re = new IllegalArgumentException();// 12
|
||||||
this.m1((RuntimeException)re, "RE");// 13
|
this.m1((RuntimeException)re, "RE");// 13
|
||||||
this.m1((IllegalArgumentException)re, "IAE");// 14
|
this.m1((IllegalArgumentException)re, "IAE");// 14
|
||||||
}// 15
|
}// 15
|
||||||
|
|||||||
77
testData/results/TestLocalsNames.dec
Normal file
77
testData/results/TestLocalsNames.dec
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package pkg;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class TestLocalsNames {
|
||||||
|
private static void rename(File file, boolean recursively) {
|
||||||
|
if(file.isDirectory()) {// 22
|
||||||
|
long start = System.currentTimeMillis();// 23
|
||||||
|
File[] files = file.listFiles();// 25
|
||||||
|
File[] var5 = files;
|
||||||
|
int var6 = files.length;
|
||||||
|
|
||||||
|
for(int var7 = 0; var7 < var6; ++var7) {// 26
|
||||||
|
File s = var5[var7];
|
||||||
|
File dest = new File(s.getAbsolutePath() + ".tmp");// 27
|
||||||
|
|
||||||
|
assert s.renameTo(dest) : "unable to rename " + s + " to " + dest;// 28
|
||||||
|
}
|
||||||
|
|
||||||
|
long elapsed = System.currentTimeMillis() - start;// 31
|
||||||
|
System.out.println("took " + elapsed + "ms (" + elapsed / (long)files.length + "ms per dir)");// 32
|
||||||
|
}
|
||||||
|
|
||||||
|
}// 34
|
||||||
|
}
|
||||||
|
|
||||||
|
class 'pkg/TestLocalsNames' {
|
||||||
|
method 'rename (Ljava/io/File;Z)V' {
|
||||||
|
1 6
|
||||||
|
4 6
|
||||||
|
7 7
|
||||||
|
a 7
|
||||||
|
c 8
|
||||||
|
f 8
|
||||||
|
13 9
|
||||||
|
17 10
|
||||||
|
18 10
|
||||||
|
1a 12
|
||||||
|
1b 12
|
||||||
|
21 12
|
||||||
|
28 13
|
||||||
|
29 13
|
||||||
|
38 14
|
||||||
|
3e 14
|
||||||
|
43 14
|
||||||
|
49 14
|
||||||
|
55 16
|
||||||
|
66 16
|
||||||
|
70 16
|
||||||
|
7a 16
|
||||||
|
81 12
|
||||||
|
87 19
|
||||||
|
8b 19
|
||||||
|
8c 19
|
||||||
|
8e 20
|
||||||
|
98 20
|
||||||
|
a2 20
|
||||||
|
ab 20
|
||||||
|
ac 20
|
||||||
|
ad 20
|
||||||
|
b1 20
|
||||||
|
b6 20
|
||||||
|
b9 20
|
||||||
|
bc 23
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lines mapping:
|
||||||
|
22 <-> 7
|
||||||
|
23 <-> 8
|
||||||
|
25 <-> 9
|
||||||
|
26 <-> 13
|
||||||
|
27 <-> 15
|
||||||
|
28 <-> 17
|
||||||
|
31 <-> 20
|
||||||
|
32 <-> 21
|
||||||
|
34 <-> 24
|
||||||
35
testData/src/pkg/TestLocalsNames.java
Normal file
35
testData/src/pkg/TestLocalsNames.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class TestLocalsNames {
|
||||||
|
private static void rename(File file, boolean recursively) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
for (File s : files) {
|
||||||
|
File dest = new File(s.getAbsolutePath() + ".tmp");
|
||||||
|
assert s.renameTo(dest) : "unable to rename " + s + " to " + dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
long elapsed = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("took " + elapsed + "ms (" + elapsed / files.length + "ms per dir)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user