diff --git a/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java b/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java index 8b5c3d768c58..11382bce5701 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java +++ b/java/debugger/openapi/src/com/intellij/debugger/PositionManager.java @@ -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 LINE_NUMBERS_MAPPING_KEY = Key.create("line.numbers.mapping.key"); + /** * Returns the source position corresponding to the specified bytecode location. * diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 57502412093f..85b24fda7513 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -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 diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java index a486d9f83ee1..08ec6835a878 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java @@ -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"); diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java index 1e6a7d4262a5..269f1c57d4ca 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java @@ -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); diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java index 819ae6446d07..850c3d84888d 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java @@ -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); } } } diff --git a/plugins/java-decompiler/plugin/java-decompiler-plugin.iml b/plugins/java-decompiler/plugin/java-decompiler-plugin.iml index 6b5b607979f4..352da6d54947 100644 --- a/plugins/java-decompiler/plugin/java-decompiler-plugin.iml +++ b/plugins/java-decompiler/plugin/java-decompiler-plugin.iml @@ -14,6 +14,7 @@ + \ No newline at end of file diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java index d08ea993f012..58bdcb832fe2 100644 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java +++ b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java @@ -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; } } diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java index c8e275cdfb22..c7e25f4faae4 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java @@ -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); + } + } } diff --git a/plugins/java-decompiler/plugin/testData/LineNumbers.class b/plugins/java-decompiler/plugin/testData/LineNumbers.class new file mode 100644 index 000000000000..b83654ddacff Binary files /dev/null and b/plugins/java-decompiler/plugin/testData/LineNumbers.class differ diff --git a/plugins/java-decompiler/plugin/testData/LineNumbers.java b/plugins/java-decompiler/plugin/testData/LineNumbers.java new file mode 100644 index 000000000000..c2143bc99edc --- /dev/null +++ b/plugins/java-decompiler/plugin/testData/LineNumbers.java @@ -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); + } + } +}