IDEA-127182 (passing line number map to debugger)

This commit is contained in:
Roman Shevchenko
2014-10-17 21:35:16 +02:00
parent cd2d76587a
commit 686974137a
10 changed files with 81 additions and 7 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -16,6 +16,7 @@
package com.intellij.debugger;
import com.intellij.debugger.requests.ClassPrepareRequestor;
import com.intellij.openapi.util.Key;
import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.request.ClassPrepareRequest;
@@ -31,6 +32,12 @@ import java.util.List;
* @see com.intellij.debugger.engine.JSR45PositionManager
*/
public interface PositionManager {
/**
* A mapping between lines contained in a byte code and actual source lines
* (placed into a user data of a VirtualFile for a .class file).
*/
Key<int[]> LINE_NUMBERS_MAPPING_KEY = Key.create("line.numbers.mapping.key");
/**
* Returns the source position corresponding to the specified bytecode location.
*
@@ -453,7 +453,11 @@ new.css.schema.enabled=true
editor.disable.rtl=false
editor.disable.rtl.description=Disables RTL support in editor (which is broken now anyway)
decompiler.use.line.mapping=false
decompiler.use.line.mapping.description=Maps original to decompiled line numbers when stepping in debugger.
decompiler.use.line.table=false
decompiler.use.line.table.description=Rearranges decompiled text to match original line numbers
ide.transparency.mode.for.windows=false
ide.transparency.mode.for.windows.description=Allow to add transparency to floating windows
ide.new.welcome.screen=false
@@ -181,7 +181,7 @@ public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
}
@Override
public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) {
File file = new File(getAbsolutePath(path), entryName);
try {
Writer out = new OutputStreamWriter(new FileOutputStream(file), "UTF8");
@@ -22,7 +22,7 @@ public interface IResultSaver {
void copyFile(String source, String path, String entryName);
void saveClassFile(String path, String qualifiedName, String entryName, String content);
void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping);
void createArchive(String path, String archiveName, Manifest manifest);
@@ -15,6 +15,8 @@
*/
package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link;
@@ -112,7 +114,11 @@ public class ContextUnit {
if (entryName != null) {
String content = decompiledData.getClassContent(cl);
if (content != null) {
resultSaver.saveClassFile(filename, cl.qualifiedName, entryName, content);
int[] mapping = null;
if (DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {
mapping = DecompilerContext.getBytecodeSourceMapper().getOriginalLinesMapping();
}
resultSaver.saveClassFile(filename, cl.qualifiedName, entryName, content, mapping);
}
}
}
@@ -14,6 +14,7 @@
<orderEntry type="module" module-name="java-psi-impl" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="platform-impl" />
<orderEntry type="module" module-name="debugger-openapi" />
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
</component>
</module>
@@ -15,6 +15,7 @@
*/
package org.jetbrains.java.decompiler;
import com.intellij.debugger.PositionManager;
import com.intellij.icons.AllIcons;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.ide.plugins.PluginManagerCore;
@@ -146,13 +147,27 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
MyBytecodeProvider provider = new MyBytecodeProvider(files);
MyResultSaver saver = new MyResultSaver();
myOptions.put(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS, Registry.is("decompiler.use.line.table") ? "1" : "0");
if (Registry.is("decompiler.use.line.mapping")) {
myOptions.put(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1");
myOptions.put(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS, "0");
}
else if (Registry.is("decompiler.use.line.table")) {
myOptions.put(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "0");
myOptions.put(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS, "1");
}
else {
myOptions.put(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "0");
myOptions.put(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS, "0");
}
BaseDecompiler decompiler = new BaseDecompiler(provider, saver, myOptions, myLogger);
for (String path : files.keySet()) {
decompiler.addSpace(new File(path), true);
}
decompiler.decompileContext();
file.putUserData(PositionManager.LINE_NUMBERS_MAPPING_KEY, saver.myMapping);
return saver.myResult;
}
catch (Exception e) {
@@ -190,11 +205,13 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
private static class MyResultSaver implements IResultSaver {
private String myResult = "";
private int[] myMapping = null;
@Override
public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) {
if (myResult.isEmpty()) {
myResult = content;
myMapping = mapping;
}
}
@@ -17,9 +17,12 @@ package org.jetbrains.java.decompiler;
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
import com.intellij.debugger.PositionManager;
import com.intellij.openapi.application.PluginPathManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -119,7 +122,7 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase {
private static VirtualFile getTestFile(String name) {
String path = PluginPathManager.getPluginHomePath("java-decompiler") + "/plugin/testData/" + name;
VirtualFile file = StandardFileSystems.local().findFileByPath(path);
VirtualFile file = StandardFileSystems.local().refreshAndFindFileByPath(path);
assertNotNull(path, file);
return file;
}
@@ -135,4 +138,24 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase {
private int offset(int line, int column) {
return myFixture.getEditor().getDocument().getLineStartOffset(line - 1) + column - 1;
}
public void testLineNumberMapping() {
RegistryValue value = Registry.get("decompiler.use.line.mapping");
boolean old = value.asBoolean();
try {
value.setValue(true);
VirtualFile file = getTestFile("LineNumbers.class");
assertNull(file.getUserData(PositionManager.LINE_NUMBERS_MAPPING_KEY));
new IdeaDecompiler().getText(file);
int[] mapping = file.getUserData(PositionManager.LINE_NUMBERS_MAPPING_KEY);
assertNotNull(mapping);
assertEquals(20, mapping.length);
}
finally {
value.setValue(old);
}
}
}
@@ -0,0 +1,16 @@
class LineNumbers {
void m(double a, double b, double c) {
double d = b*b - 4*a*c;
if (d < 0) {
System.out.println("No roots.");
} else if (d == 0) {
double x = -b / 2*a;
System.out.println("x=" + x);
} else {
d = Math.sqrt(d);
double x1 = -b - d / 2*a;
double x2 = -b + d / 2*a;
System.out.println("x1=" + x1 + " x2=" + x2);
}
}
}