decompiler: map all lines according to bytecode information

This commit is contained in:
Egor.Ushakov 2014-10-15 20:20:44 +04:00
parent 6d03229b91
commit a182de6271
3 changed files with 53 additions and 12 deletions

View File

@ -43,6 +43,7 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.gen.generics.*;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -581,13 +582,9 @@ public class ClassWriter {
boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
boolean clinit = false, init = false, dinit = false;
int startLine = -1;
StructLineNumberTableAttribute lineNumberTable = null;
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) {
StructLineNumberTableAttribute lineNumberTable =
(StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
if (lineNumberTable != null) {
startLine = lineNumberTable.getFirstLine();
}
lineNumberTable = (StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
}
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
@ -804,8 +801,10 @@ public class ClassWriter {
buffer.append(' ');
}
//TODO: for now only start line set
buffer.setCurrentLine(startLine-1);
// We do not have line information for method start, lets have it here for now
if (lineNumberTable != null) {
buffer.setCurrentLine(lineNumberTable.getFirstLine() - 1);
}
buffer.append('{').appendLineSeparator();
RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
@ -813,11 +812,16 @@ public class ClassWriter {
if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
try {
tracer.incrementCurrentSourceLine(buffer.count(lineSeparator, start_index_method));
int startLine = tracer.getCurrentSourceLine();
TextBuffer code = root.toJava(indent + 1, tracer);
hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0;
if (!hideMethod && lineNumberTable != null) {
mapLines(code, lineNumberTable, tracer, startLine);
}
buffer.append(code);
}
catch (Throwable ex) {
@ -846,6 +850,33 @@ public class ClassWriter {
return !hideMethod;
}
private void mapLines(TextBuffer code, StructLineNumberTableAttribute table, BytecodeMappingTracer tracer, int startLine) {
// build line start offsets map
HashMap<Integer, Integer> lineStartOffsets = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
Integer lineNumber = entry.getValue() - startLine;
Integer curr = lineStartOffsets.get(lineNumber);
if (curr == null || curr > entry.getKey()) {
lineStartOffsets.put(lineNumber, entry.getKey());
}
}
String lineSeparator = DecompilerContext.getNewLineSeparator();
StringBuilder text = code.getOriginalText();
int pos = text.indexOf(lineSeparator);
int lineNumber = 0;
while (pos != -1) {
Integer startOffset = lineStartOffsets.get(lineNumber);
if (startOffset != null) {
int number = table.findLineNumber(startOffset);
if (number >= 0) {
code.setLineMapping(number, pos);
}
}
pos = text.indexOf(lineSeparator, pos+1);
lineNumber++;
}
}
private static boolean hideConstructor(ClassWrapper wrapper, boolean init, boolean throwsExceptions, int paramCount) {
if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
return false;

View File

@ -43,9 +43,13 @@ public class TextBuffer {
}
public void setCurrentLine(int line) {
setLineMapping(line, myStringBuilder.length()+1);
}
public void setLineMapping(int line, int offset) {
if (line >= 0) {
checkMapCreated();
myLineToOffsetMapping.put(line, myStringBuilder.length()+1);
myLineToOffsetMapping.put(line, offset);
}
}
@ -257,4 +261,8 @@ public class TextBuffer {
}
return res;
}
public StringBuilder getOriginalText() {
return myStringBuilder;
}
}

View File

@ -54,9 +54,11 @@ public class StructLineNumberTableAttribute extends StructGeneralAttribute {
}
public int findLineNumber(int pc) {
for (int i = 0; i < myLineInfo.length; i += 2) {
if (pc >= myLineInfo[i]) {
return myLineInfo[i + 1];
if (myLineInfo.length >= 2) {
for (int i = myLineInfo.length - 2; i >= 0; i -= 2) {
if (pc >= myLineInfo[i]) {
return myLineInfo[i + 1];
}
}
}
return -1;