diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index feb8093..9fcf4bb 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -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 lineStartOffsets = new HashMap(); + HashMap> lineStartOffsets = new HashMap>(); for (Map.Entry 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 curr = lineStartOffsets.get(lineNumber); + if (curr == null) { + curr = new TreeSet(); // 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); - if (number >= 0) { - code.setLineMapping(number, pos); + Set 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); diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index 262b825..3fe0e01 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -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; diff --git a/src/org/jetbrains/java/decompiler/main/TextBuffer.java b/src/org/jetbrains/java/decompiler/main/TextBuffer.java index e631a51..b952811 100644 --- a/src/org/jetbrains/java/decompiler/main/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/main/TextBuffer.java @@ -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) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java index 6178ee4..a810a21 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -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) { diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java index 60a4efa..1910464 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java @@ -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; diff --git a/testData/classes/pkg/TestClassSimpleBytecodeMapping$1.class b/testData/classes/pkg/TestClassSimpleBytecodeMapping$1.class new file mode 100644 index 0000000..93a9cb2 Binary files /dev/null and b/testData/classes/pkg/TestClassSimpleBytecodeMapping$1.class differ diff --git a/testData/classes/pkg/TestClassSimpleBytecodeMapping.class b/testData/classes/pkg/TestClassSimpleBytecodeMapping.class index 1313994..4e4f8fb 100644 Binary files a/testData/classes/pkg/TestClassSimpleBytecodeMapping.class and b/testData/classes/pkg/TestClassSimpleBytecodeMapping.class differ diff --git a/testData/results/TestClassSimpleBytecodeMapping.dec b/testData/results/TestClassSimpleBytecodeMapping.dec index 51adb53..8b3c3df 100644 --- a/testData/results/TestClassSimpleBytecodeMapping.dec +++ b/testData/results/TestClassSimpleBytecodeMapping.dec @@ -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 } } diff --git a/testData/src/pkg/TestClassSimpleBytecodeMapping.java b/testData/src/pkg/TestClassSimpleBytecodeMapping.java index 8233fa9..0e9ecc2 100644 --- a/testData/src/pkg/TestClassSimpleBytecodeMapping.java +++ b/testData/src/pkg/TestClassSimpleBytecodeMapping.java @@ -1,5 +1,8 @@ package pkg; +import java.lang.Override; +import java.lang.Runnable; + public class TestClassSimpleBytecodeMapping { public TestClassSimpleBytecodeMapping() {} @@ -7,7 +10,14 @@ public class TestClassSimpleBytecodeMapping { public int test() { 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(); + } }