mirror of
https://github.com/moparisthebest/fernflower
synced 2024-11-29 04:22:22 -05:00
decompiler: fixed bytecode mapping for anonymous classes
This commit is contained in:
parent
b3681fe952
commit
32e7765874
@ -43,10 +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;
|
||||
import java.util.*;
|
||||
|
||||
public class ClassWriter {
|
||||
|
||||
@ -160,11 +157,11 @@ public class ClassWriter {
|
||||
DecompilerContext.getLogger().endWriteClass();
|
||||
}
|
||||
|
||||
public void classToJava(ClassNode node, TextBuffer buffer, int indent) {
|
||||
public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
|
||||
ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
|
||||
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
|
||||
|
||||
int total_offset_lines = 0;
|
||||
final int startLine = tracer != null ? tracer.getCurrentSourceLine() : 0;
|
||||
BytecodeMappingTracer dummy_tracer = new BytecodeMappingTracer();
|
||||
|
||||
try {
|
||||
@ -176,14 +173,12 @@ public class ClassWriter {
|
||||
|
||||
DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
|
||||
|
||||
String lineSeparator = DecompilerContext.getNewLineSeparator();
|
||||
|
||||
// write class definition
|
||||
int start_class_def = buffer.length();
|
||||
writeClassDefinition(node, buffer, indent);
|
||||
|
||||
// // count lines in class definition the easiest way
|
||||
// total_offset_lines = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1;
|
||||
// startLine = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1;
|
||||
|
||||
boolean hasContent = false;
|
||||
|
||||
@ -199,14 +194,14 @@ public class ClassWriter {
|
||||
if (isEnum) {
|
||||
if (enumFields) {
|
||||
buffer.append(',');
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
enumFields = true;
|
||||
}
|
||||
else if (enumFields) {
|
||||
buffer.append(';');
|
||||
buffer.append(lineSeparator);
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
buffer.appendLineSeparator();
|
||||
enumFields = false;
|
||||
}
|
||||
|
||||
@ -217,11 +212,11 @@ public class ClassWriter {
|
||||
|
||||
if (enumFields) {
|
||||
buffer.append(';');
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
|
||||
// FIXME: fields don't matter at the moment
|
||||
total_offset_lines = buffer.count(lineSeparator, start_class_def);
|
||||
//startLine = buffer.countLines(start_class_def);
|
||||
|
||||
// methods
|
||||
for (StructMethod mt : cl.getMethods()) {
|
||||
@ -232,15 +227,15 @@ public class ClassWriter {
|
||||
|
||||
int position = buffer.length();
|
||||
if (hasContent) {
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
BytecodeMappingTracer method_tracer = new BytecodeMappingTracer(total_offset_lines);
|
||||
BytecodeMappingTracer method_tracer = new BytecodeMappingTracer(buffer.countLines() + startLine);
|
||||
boolean methodSkipped = !methodToJava(node, mt, buffer, indent + 1, method_tracer);
|
||||
if (!methodSkipped) {
|
||||
hasContent = true;
|
||||
DecompilerContext.getBytecodeSourceMapper().addTracer(cl.qualifiedName,
|
||||
InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()), method_tracer);
|
||||
total_offset_lines = (method_tracer.getCurrentSourceLine() + 1); // zero-based line index
|
||||
//startLine = (method_tracer.getCurrentSourceLine() + 1); // zero-based line index
|
||||
}
|
||||
else {
|
||||
buffer.setLength(position);
|
||||
@ -257,9 +252,9 @@ public class ClassWriter {
|
||||
if (hide) continue;
|
||||
|
||||
if (hasContent) {
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
classToJava(inner, buffer, indent + 1);
|
||||
classToJava(inner, buffer, indent + 1, tracer);
|
||||
|
||||
hasContent = true;
|
||||
}
|
||||
@ -268,7 +263,7 @@ public class ClassWriter {
|
||||
buffer.appendIndent(indent).append('}');
|
||||
|
||||
if (node.type != ClassNode.CLASS_ANONYMOUS) {
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@ -794,7 +789,7 @@ public class ClassWriter {
|
||||
}
|
||||
|
||||
buffer.append(';');
|
||||
buffer.append(lineSeparator);
|
||||
buffer.appendLineSeparator();
|
||||
}
|
||||
else {
|
||||
if (!clinit && !dinit) {
|
||||
@ -811,7 +806,7 @@ public class ClassWriter {
|
||||
|
||||
if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
|
||||
try {
|
||||
tracer.incrementCurrentSourceLine(buffer.count(lineSeparator, start_index_method));
|
||||
tracer.incrementCurrentSourceLine(buffer.countLines(start_index_method));
|
||||
int startLine = tracer.getCurrentSourceLine();
|
||||
|
||||
TextBuffer code = root.toJava(indent + 1, tracer);
|
||||
@ -845,31 +840,36 @@ public class ClassWriter {
|
||||
|
||||
// save total lines
|
||||
// TODO: optimize
|
||||
tracer.setCurrentSourceLine(buffer.count(lineSeparator, start_index_method));
|
||||
tracer.setCurrentSourceLine(buffer.countLines(start_index_method));
|
||||
|
||||
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>();
|
||||
HashMap<Integer, Set<Integer>> lineStartOffsets = new HashMap<Integer, Set<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());
|
||||
Set<Integer> curr = lineStartOffsets.get(lineNumber);
|
||||
if (curr == null) {
|
||||
curr = new TreeSet<Integer>(); // requires natural sorting!
|
||||
}
|
||||
curr.add(entry.getKey());
|
||||
lineStartOffsets.put(lineNumber, curr);
|
||||
}
|
||||
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);
|
||||
Set<Integer> startOffsets = lineStartOffsets.get(lineNumber);
|
||||
if (startOffsets != null) {
|
||||
for (Integer offset : startOffsets) {
|
||||
int number = table.findLineNumber(offset);
|
||||
if (number >= 0) {
|
||||
code.setLineMapping(number, pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = text.indexOf(lineSeparator, pos+1);
|
||||
|
@ -256,7 +256,7 @@ public class ClassesProcessor {
|
||||
new NestedMemberAccess().propagateMemberAccess(root);
|
||||
|
||||
TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
|
||||
new ClassWriter().classToJava(root, classBuffer, 0);
|
||||
new ClassWriter().classToJava(root, classBuffer, 0, null);
|
||||
|
||||
String lineSeparator = DecompilerContext.getNewLineSeparator();
|
||||
int total_offset_lines = 0;
|
||||
|
@ -115,7 +115,7 @@ public class TextBuffer {
|
||||
while (currentLine < srcLines.length) {
|
||||
String line = srcLines[currentLine];
|
||||
int lineEnd = currentLineStartOffset + line.length() + myLineSeparator.length();
|
||||
if (markOffset >= currentLineStartOffset && markOffset <= lineEnd) {
|
||||
if (markOffset <= lineEnd) {
|
||||
int requiredLine = markLine - 1;
|
||||
int linesToAdd = requiredLine - dumpedLines;
|
||||
dumpedLines = requiredLine;
|
||||
@ -223,6 +223,14 @@ public class TextBuffer {
|
||||
return this;
|
||||
}
|
||||
|
||||
public int countLines() {
|
||||
return countLines(0);
|
||||
}
|
||||
|
||||
public int countLines(int from) {
|
||||
return count(myLineSeparator, from);
|
||||
}
|
||||
|
||||
public int count(String substring, int from) {
|
||||
int count = 0, length = substring.length(), p = from;
|
||||
while ((p = myStringBuilder.indexOf(substring, p)) > 0) {
|
||||
|
@ -270,9 +270,11 @@ public class NewExprent extends Exprent {
|
||||
}
|
||||
Exprent methodObject = constructor == null ? null : constructor.getInstance();
|
||||
new ClassWriter().classLambdaToJava(child, buf, methodObject, indent);
|
||||
tracer.incrementCurrentSourceLine(buf.countLines());
|
||||
}
|
||||
else {
|
||||
new ClassWriter().classToJava(child, buf, indent);
|
||||
new ClassWriter().classToJava(child, buf, indent, tracer);
|
||||
tracer.incrementCurrentSourceLine(buf.countLines());
|
||||
}
|
||||
}
|
||||
else if (directArrayInit) {
|
||||
|
@ -17,7 +17,6 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
import org.jetbrains.java.decompiler.main.ClassWriter;
|
||||
@ -92,7 +91,7 @@ public class VarExprent extends Exprent {
|
||||
|
||||
if (classdef) {
|
||||
ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(vartype.value);
|
||||
new ClassWriter().classToJava(child, buffer, indent);
|
||||
new ClassWriter().classToJava(child, buffer, indent, tracer);
|
||||
}
|
||||
else {
|
||||
String name = null;
|
||||
|
BIN
testData/classes/pkg/TestClassSimpleBytecodeMapping$1.class
Normal file
BIN
testData/classes/pkg/TestClassSimpleBytecodeMapping$1.class
Normal file
Binary file not shown.
Binary file not shown.
@ -3,6 +3,11 @@ package pkg;
|
||||
public class TestClassSimpleBytecodeMapping {
|
||||
public int test() {
|
||||
System.out.println("before");
|
||||
this.run(new Runnable() {
|
||||
public void run() {
|
||||
System.out.println("Runnable");
|
||||
}
|
||||
});
|
||||
if(Math.random() > 0.0D) {
|
||||
System.out.println("0");
|
||||
return 0;
|
||||
@ -11,26 +16,42 @@ public class TestClassSimpleBytecodeMapping {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void run(Runnable var1) {
|
||||
var1.run();
|
||||
}
|
||||
}
|
||||
|
||||
class pkg/TestClassSimpleBytecodeMapping{
|
||||
method run (Ljava/lang/Runnable;)V{
|
||||
1 20
|
||||
}
|
||||
|
||||
method test ()I{
|
||||
0 4
|
||||
3 4
|
||||
5 4
|
||||
8 5
|
||||
b 5
|
||||
c 5
|
||||
d 5
|
||||
10 6
|
||||
13 6
|
||||
15 6
|
||||
18 7
|
||||
19 7
|
||||
1a 9
|
||||
1d 9
|
||||
1f 9
|
||||
22 10
|
||||
23 10
|
||||
11 5
|
||||
14 10
|
||||
17 10
|
||||
18 10
|
||||
19 10
|
||||
1c 11
|
||||
1f 11
|
||||
21 11
|
||||
24 12
|
||||
25 12
|
||||
26 14
|
||||
29 14
|
||||
2b 14
|
||||
2e 15
|
||||
2f 15
|
||||
}
|
||||
}
|
||||
class pkg/TestClassSimpleBytecodeMapping$1{
|
||||
method run ()V{
|
||||
0 7
|
||||
3 7
|
||||
5 7
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package pkg;
|
||||
|
||||
import java.lang.Override;
|
||||
import java.lang.Runnable;
|
||||
|
||||
public class TestClassSimpleBytecodeMapping {
|
||||
|
||||
public TestClassSimpleBytecodeMapping() {}
|
||||
@ -8,6 +11,13 @@ public class TestClassSimpleBytecodeMapping {
|
||||
|
||||
System.out.println("before");
|
||||
|
||||
run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Runnable");
|
||||
}
|
||||
});
|
||||
|
||||
if(Math.random() > 0) {
|
||||
System.out.println("0");
|
||||
return 0;
|
||||
@ -17,4 +27,7 @@ public class TestClassSimpleBytecodeMapping {
|
||||
}
|
||||
}
|
||||
|
||||
void run(Runnable r) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user