IDEA-166363 Support LocalVariableTypeTable attribute

master
Egor.Ushakov 8 years ago
parent 1d331ddd6d
commit cb133af01e
  1. 33
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
  2. 8
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
  3. 8
      src/org/jetbrains/java/decompiler/struct/StructMember.java
  4. 6
      src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
  5. 65
      src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTypeTableAttribute.java
  6. 1
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  7. BIN
      testData/classes/pkg/TestLocalsSignature.class
  8. 25
      testData/results/TestLocalsSignature.dec
  9. 27
      testData/src/pkg/TestLocalsSignature.java

@ -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"); * 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.
@ -21,14 +21,19 @@ import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.TextBuffer; import org.jetbrains.java.decompiler.main.TextBuffer;
import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor; 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.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.GenericMain;
import org.jetbrains.java.decompiler.struct.match.MatchEngine; 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.IMatchable.MatchProperties;
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;
@ -101,7 +106,29 @@ public class VarExprent extends Exprent {
if (processor != null && processor.getVarFinal(new VarVersionPair(index, version)) == VarTypeProcessor.VAR_EXPLICIT_FINAL) { if (processor != null && processor.getVarFinal(new VarVersionPair(index, version)) == VarTypeProcessor.VAR_EXPLICIT_FINAL) {
buffer.append("final "); buffer.append("final ");
} }
buffer.append(ExprProcessor.getCastTypeName(getVarType())).append(" "); boolean generic = false;
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
MethodWrapper method = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
StructLocalVariableTypeTableAttribute attr = (StructLocalVariableTypeTableAttribute)method.methodStruct.getAttributes()
.getWithKey(StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE);
if (attr != null && processor != null) {
Integer index = processor.getVarOriginalIndex(new VarVersionPair(this.index, version));
if (index != null) {
String signature = attr.getMapVarSignatures().get(index);
if (signature != null) {
GenericFieldDescriptor descriptor = GenericMain.parseFieldSignature(signature);
if (descriptor != null) {
buffer.append(GenericMain.getGenericCastTypeName(descriptor.type));
generic = true;
}
}
}
}
}
if (!generic) {
buffer.append(ExprProcessor.getCastTypeName(getVarType()));
}
buffer.append(" ");
} }
buffer.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name); buffer.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name);
} }

@ -83,6 +83,14 @@ public class VarProcessor {
} }
} }
public Integer getVarOriginalIndex(VarVersionPair pair) {
if (varVersions == null) {
return null;
}
return varVersions.getMapOriginalVarIndices().get(pair.var);
}
public void refreshVarNames(VarNamesCollector vc) { public void refreshVarNames(VarNamesCollector vc) {
Map<VarVersionPair, String> tempVarNames = new HashMap<>(mapVarNames); Map<VarVersionPair, String> tempVarNames = new HashMap<>(mapVarNames);
for (Entry<VarVersionPair, String> ent : tempVarNames.entrySet()) { for (Entry<VarVersionPair, String> ent : tempVarNames.entrySet()) {

@ -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.
@ -18,6 +18,7 @@ package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.CodeConstants;
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.StructLocalVariableTableAttribute;
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTypeTableAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.DataInputFullStream; import org.jetbrains.java.decompiler.util.DataInputFullStream;
import org.jetbrains.java.decompiler.util.VBStyleCollection; import org.jetbrains.java.decompiler.util.VBStyleCollection;
@ -62,6 +63,11 @@ public class StructMember {
StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name); StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name);
table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute); table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
} }
else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name) && attributes.containsKey(name)) {
// merge all variable tables
StructLocalVariableTypeTableAttribute table = (StructLocalVariableTypeTableAttribute)attributes.getWithKey(name);
table.add((StructLocalVariableTypeTableAttribute)attribute);
}
else { else {
attributes.addWithKey(attribute, attribute.getName()); attributes.addWithKey(attribute, attribute.getName());
} }

@ -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.
@ -41,6 +41,7 @@ public class StructGeneralAttribute {
public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue";
public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods"; public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods";
public static final String ATTRIBUTE_SYNTHETIC = "Synthetic"; public static final String ATTRIBUTE_SYNTHETIC = "Synthetic";
@ -84,6 +85,9 @@ public class StructGeneralAttribute {
else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) { else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) {
attr = new StructLocalVariableTableAttribute(); attr = new StructLocalVariableTableAttribute();
} }
else if (ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.equals(name)) {
attr = new StructLocalVariableTypeTableAttribute();
}
else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) { else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) {
attr = new StructBootstrapMethodsAttribute(); attr = new StructBootstrapMethodsAttribute();
} }

@ -0,0 +1,65 @@
/*
* 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.
* 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 org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/*
u2 local_variable_type_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 signature_index;
u2 index;
} local_variable_type_table[local_variable_type_table_length];
*/
public class StructLocalVariableTypeTableAttribute extends StructGeneralAttribute {
private Map<Integer, String> mapVarSignatures = Collections.emptyMap();
@Override
public void initContent(ConstantPool pool) throws IOException {
DataInputFullStream data = stream();
int len = data.readUnsignedShort();
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) {
mapVarSignatures.putAll(attr.getMapVarSignatures());
}
public Map<Integer, String> getMapVarSignatures() {
return mapVarSignatures;
}
}

@ -77,6 +77,7 @@ public class SingleClassesTest {
@Test public void testInnerLocalPkg() { doTest("pkg/TestInnerLocalPkg"); } @Test public void testInnerLocalPkg() { doTest("pkg/TestInnerLocalPkg"); }
@Test public void testInnerSignature() { doTest("pkg/TestInnerSignature"); } @Test public void testInnerSignature() { doTest("pkg/TestInnerSignature"); }
@Test public void testAnonymousSignature() { doTest("pkg/TestAnonymousSignature"); } @Test public void testAnonymousSignature() { doTest("pkg/TestAnonymousSignature"); }
@Test public void testLocalsSignature() { doTest("pkg/TestLocalsSignature"); }
@Test public void testParameterizedTypes() { doTest("pkg/TestParameterizedTypes"); } @Test public void testParameterizedTypes() { doTest("pkg/TestParameterizedTypes"); }
@Test public void testShadowing() { doTest("pkg/TestShadowing", "pkg/Shadow", "ext/Shadow"); } @Test public void testShadowing() { doTest("pkg/TestShadowing", "pkg/Shadow", "ext/Shadow"); }
@Test public void testStringConcat() { doTest("pkg/TestStringConcat"); } @Test public void testStringConcat() { doTest("pkg/TestStringConcat"); }

@ -0,0 +1,25 @@
package pkg;
import java.util.ArrayList;
import java.util.List;
public class TestLocalsSignature {
public static void main(String[] args) {
List<String> s = new ArrayList();// 24
s.add("xxx");// 25
}// 26
}
class 'pkg/TestLocalsSignature' {
method 'main ([Ljava/lang/String;)V' {
7 7
9 8
b 8
11 9
}
}
Lines mapping:
24 <-> 8
25 <-> 9
26 <-> 10

@ -0,0 +1,27 @@
/*
* 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;
import java.util.ArrayList;
import java.util.List;
public class TestLocalsSignature {
public static void main(String[] args) {
List<String> s = new ArrayList<String>();
s.add("xxx");
}
}
Loading…
Cancel
Save