diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java index c09fb1e5fe6c..bfc70d1af0a0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/LiveVariablesAnalyzer.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Pair; import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; @@ -26,6 +27,7 @@ import com.intellij.util.containers.FilteringIterator; import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -35,11 +37,13 @@ import java.util.*; public class LiveVariablesAnalyzer { private final DfaValueFactory myFactory; private final Instruction[] myInstructions; + private final MultiMap myForwardMap; private final MultiMap myBackwardMap; public LiveVariablesAnalyzer(ControlFlow flow, DfaValueFactory factory) { myFactory = factory; myInstructions = flow.getInstructions(); + myForwardMap = calcForwardMap(); myBackwardMap = calcBackwardMap(); } @@ -64,17 +68,49 @@ public class LiveVariablesAnalyzer { private MultiMap calcBackwardMap() { MultiMap result = MultiMap.create(); for (Instruction instruction : myInstructions) { - for (Instruction next : getSuccessors(instruction)) { + for (Instruction next : myForwardMap.get(instruction)) { result.putValue(next, instruction); } } return result; } + private MultiMap calcForwardMap() { + MultiMap result = MultiMap.create(); + for (Instruction instruction : myInstructions) { + if (isInterestingInstruction(instruction)) { + for (Instruction next : getSuccessors(instruction)) { + while (true) { + if (isInterestingInstruction(next)) { + result.putValue(instruction, next); + break; + } + if (next.getIndex() + 1 >= myInstructions.length) { + break; + } + next = myInstructions[next.getIndex() + 1]; + } + } + } + } + return result; + } + + private boolean isInterestingInstruction(Instruction instruction) { + if (instruction == myInstructions[0]) return true; + if (instruction instanceof PushInstruction) return ((PushInstruction)instruction).getValue() instanceof DfaVariableValue; + return instruction instanceof FinishElementInstruction || + instruction instanceof FlushVariableInstruction || + instruction instanceof GotoInstruction || + instruction instanceof ConditionalGotoInstruction || + instruction instanceof ReturnInstruction; + } + + @Nullable private Map findLiveVars() { final Map result = ContainerUtil.newHashMap(); - runDfa(false, new PairFunction() { + boolean ok = runDfa(false, new PairFunction() { @Override public BitSet fun(Instruction instruction, BitSet liveVars) { if (instruction instanceof FinishElementInstruction) { @@ -115,13 +151,16 @@ public class LiveVariablesAnalyzer { return liveVars; } }); - return result; + return ok ? result : null; } void flushDeadVariablesOnStatementFinish() { final Map liveVars = findLiveVars(); + if (liveVars == null) return; - runDfa(true, new PairFunction() { + final MultiMap toFlush = MultiMap.createSet(); + + boolean ok = runDfa(true, new PairFunction() { @Override @NotNull public BitSet fun(Instruction instruction, @NotNull BitSet prevLiveVars) { @@ -135,7 +174,7 @@ public class LiveVariablesAnalyzer { int setBit = prevLiveVars.nextSetBit(index); if (setBit < 0) break; if (!currentlyLive.get(setBit)) { - ((FinishElementInstruction)instruction).getVarsToFlush().add((DfaVariableValue)myFactory.getValue(setBit)); + toFlush.putValue((FinishElementInstruction)instruction, (DfaVariableValue)myFactory.getValue(setBit)); } index = setBit + 1; } @@ -145,9 +184,18 @@ public class LiveVariablesAnalyzer { return prevLiveVars; } }); + + if (ok) { + for (FinishElementInstruction instruction : toFlush.keySet()) { + instruction.getVarsToFlush().addAll(toFlush.get(instruction)); + } + } } - private void runDfa(boolean forward, PairFunction handleState) { + /** + * @return true if completed, false if "too complex" + */ + private boolean runDfa(boolean forward, PairFunction handleState) { Set entryPoints = ContainerUtil.newHashSet(); if (forward) { entryPoints.add(myInstructions[0]); @@ -160,25 +208,28 @@ public class LiveVariablesAnalyzer { queue.addLast(new InstructionState(i, new BitSet())); } - int steps = 0; + int limit = myForwardMap.size() * 20; Set processed = ContainerUtil.newHashSet(); while (!queue.isEmpty()) { - steps++; + int steps = processed.size(); + if (steps > limit) { + return false; + } + if (steps % 1024 == 0) { + ProgressManager.checkCanceled(); + } InstructionState state = queue.pullFirst(); Instruction instruction = state.first; - Collection nextInstructions = forward ? getSuccessors(instruction) : myBackwardMap.get(instruction); - boolean branching = nextInstructions.size() > 1 || !forward && instruction.getIndex() == 0; + Collection nextInstructions = forward ? myForwardMap.get(instruction) : myBackwardMap.get(instruction); BitSet nextVars = handleState.fun(instruction, state.second); for (Instruction next : nextInstructions) { InstructionState nextState = new InstructionState(next, nextVars); - if (!branching || processed.add(nextState)) { + if (processed.add(nextState)) { queue.addLast(nextState); } } } - if (steps > 10000) { - int a = 1; - } + return true; } private static class InstructionState extends Pair { diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java index 818e04a36426..a833365a118f 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java @@ -117,6 +117,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider { } }; myTree.setEditable(true); + myTree.setShowsRootHandles(root.getChildCount() > 1); MyTreeCellEditor treeCellEditor = new MyTreeCellEditor(); myTree.setCellEditor(treeCellEditor); treeCellEditor.addCellEditorListener(new CellEditorListener() { diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java index 169d09a19c73..12236ed4aefe 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java @@ -71,7 +71,6 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, public void render(@NotNull ColoredTreeCellRenderer renderer) { int repoFixedWidth = 120; int borderHOffset = myRepositoryPanel.getHBorderOffset(renderer); - int borderVOffset = myRepositoryPanel.getVBorderOffset(renderer); if (myLoading.get()) { renderer.setIcon(myLoadingIcon); renderer.setIconOnTheRight(false); @@ -81,27 +80,31 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, renderer.append(""); renderer.appendFixedTextFragmentWidth(checkBoxWidth + renderer.getIconTextGap() + borderHOffset); } - if (myCheckBoxVGap > 0) { - int shiftV = myCheckBoxVGap - borderVOffset; - renderer.setBorder(new EmptyBorder(shiftV / 2, 0, shiftV / 2, 0)); - } } else { if (myCheckBoxHGap <= 0) { renderer.append(""); renderer.appendFixedTextFragmentWidth(myRepositoryPanel.calculateRendererShiftH(renderer)); } - if (myCheckBoxVGap <= 0) { - int shiftV = -myCheckBoxVGap + borderVOffset; - renderer.setBorder(new EmptyBorder(shiftV / 2, 0, shiftV / 2, 0)); - } } - renderer.append(getRepoName(renderer, repoFixedWidth), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); + renderer.append(getRepoName(renderer, repoFixedWidth), + isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); renderer.appendFixedTextFragmentWidth(repoFixedWidth); - renderer.append(myRepositoryPanel.getSourceName(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); - renderer.append(myRepositoryPanel.getArrow(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); + renderer.append(myRepositoryPanel.getSourceName(), + isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); + renderer + .append(myRepositoryPanel.getArrow(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES); PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel(); pushTargetPanel.render(renderer); + + int maxSize = Math.max(myRepositoryPanel.getCheckBoxHeight(), myLoadingIcon.getIconHeight()); + int rendererHeight = renderer.getPreferredSize().height; + if (maxSize > rendererHeight) { + if (myCheckBoxVGap > 0 && isLoading() || myCheckBoxVGap < 0 && !isLoading()) { + int vShift = maxSize - rendererHeight; + renderer.setBorder(new EmptyBorder((vShift + 1) / 2, 0, (vShift) / 2, 0)); + } + } } @NotNull diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java index 833ae6aa6b4c..e54f867f72a8 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java @@ -52,6 +52,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePa private final int myCheckBoxLoadingIconGapV; private final LoadingIcon myLoadingIcon; private final int myCheckBoxWidth; + private final int myCheckBoxHeight; public RepositoryWithBranchPanel(@NotNull final Project project, @NotNull String repoName, @@ -102,6 +103,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePa emptyBorderCheckBox.setBorder(null); Dimension size = emptyBorderCheckBox.getPreferredSize(); myCheckBoxWidth = size.width; + myCheckBoxHeight = size.height; myLoadingIcon = LoadingIcon.create(myCheckBoxWidth, size.height); myCheckBoxLoadingIconGapH = myCheckBoxWidth - myLoadingIcon.getIconWidth(); myCheckBoxLoadingIconGapV = size.height - myLoadingIcon.getIconHeight(); @@ -223,6 +225,10 @@ public class RepositoryWithBranchPanel extends NonOpaquePa Border border = coloredRenderer.getMyBorder(); return border != null ? border.getBorderInsets(coloredRenderer).top : 0; } + + public int getCheckBoxHeight() { + return myCheckBoxHeight; + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index c229cda49d21..7c53708586de 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -26,7 +26,6 @@ import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLoadingPanel; import com.intellij.ui.components.JBScrollPane; -import com.intellij.ui.components.JBTextField; import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; @@ -69,10 +68,9 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @NotNull private final VcsLogGraphTable myGraphTable; @NotNull private final RefsPanel myRefsPanel; - @NotNull private final DataPanel myHashAuthorPanel; @NotNull private final DataPanel myMessageDataPanel; @NotNull private final ContainingBranchesPanel myContainingBranchesPanel; - @NotNull private final MessagePanel myMessagePanel; + @NotNull private final JLabel myMessageLabel; @NotNull private final JBLoadingPanel myLoadingPanel; @NotNull private VisiblePack myDataPack; @@ -84,7 +82,6 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myDataPack = initialDataPack; myRefsPanel = new RefsPanel(colorManager); - myHashAuthorPanel = new DataPanel(logDataHolder.getProject(), false); final JScrollPane scrollPane = new JBScrollPane() { @Override @@ -92,7 +89,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { return getVerticalScrollBar().isVisible() ? super.getBorder() : null; } }; - myMessageDataPanel = new DataPanel(logDataHolder.getProject(), true) { + myMessageDataPanel = new DataPanel(logDataHolder.getProject()) { @Override public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); @@ -105,20 +102,20 @@ class DetailsPanel extends JPanel implements ListSelectionListener { scrollPane.setViewportView(myMessageDataPanel); myContainingBranchesPanel = new ContainingBranchesPanel(); - myMessagePanel = new MessagePanel(); + myMessageLabel = new JLabel(); + myMessageLabel.setForeground(UIUtil.getInactiveTextColor()); + myMessageLabel.setHorizontalAlignment(SwingConstants.CENTER); + myMessageLabel.setVerticalAlignment(SwingConstants.CENTER); myLoadingPanel = new JBLoadingPanel(new BorderLayout(), logDataHolder, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS); - JPanel header = new NonOpaquePanel(new BorderLayout()); - header.add(myRefsPanel, BorderLayout.NORTH); - header.add(myHashAuthorPanel, BorderLayout.SOUTH); - myLoadingPanel.add(header, BorderLayout.NORTH); + myLoadingPanel.add(myRefsPanel, BorderLayout.NORTH); myLoadingPanel.add(scrollPane, BorderLayout.CENTER); myLoadingPanel.add(myContainingBranchesPanel, BorderLayout.SOUTH); myLoadingPanel.setOpaque(false); setLayout(new CardLayout()); add(myLoadingPanel, STANDARD_LAYER); - add(myMessagePanel, MESSAGE_LAYER); + add(myMessageLabel, MESSAGE_LAYER); setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); showMessage("No commits selected"); @@ -154,13 +151,11 @@ class DetailsPanel extends JPanel implements ListSelectionListener { } if (commitData instanceof LoadingDetails) { myLoadingPanel.startLoading(); - myHashAuthorPanel.setData(null); myMessageDataPanel.setData(null); myRefsPanel.setRefs(Collections.emptyList()); } else { myLoadingPanel.stopLoading(); - myHashAuthorPanel.setData(commitData); myMessageDataPanel.setData(commitData); myRefsPanel.setRefs(sortRefs(hash, commitData.getRoot())); } @@ -176,7 +171,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { private void showMessage(String text) { myLoadingPanel.stopLoading(); ((CardLayout)getLayout()).show(this, MESSAGE_LAYER); - myMessagePanel.setText(text); + myMessageLabel.setText(text); } @NotNull @@ -188,11 +183,9 @@ class DetailsPanel extends JPanel implements ListSelectionListener { private static class DataPanel extends JEditorPane { @NotNull private final Project myProject; - private final boolean myMessageMode; - DataPanel(@NotNull Project project, boolean messageMode) { + DataPanel(@NotNull Project project) { super(UIUtil.HTML_MIME, ""); - myMessageMode = messageMode; setEditable(false); myProject = project; addHyperlinkListener(BrowserHyperlinkListener.INSTANCE); @@ -205,12 +198,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { setText(""); } else { - String body; - if (myMessageMode) { - body = getMessageText(commit); - } else { - body = commit.getId().asString() + "
" + getAuthorText(commit); - } + String body = commit.getId().toShortString() + " " + getAuthorText(commit) + "
" + getMessageText(commit); setText("" + UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()) + "" + body + ""); setCaretPosition(0); } @@ -221,8 +209,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @Override public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); - int h = getFontMetrics(getFont()).getHeight(); - size.height = Math.max(size.height, myMessageMode ? 5 * h : 2 * h); + size.height = Math.max(size.height, 7 * getFontMetrics(getFont()).getHeight()); return size; } @@ -257,7 +244,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { private static class ContainingBranchesPanel extends JPanel { private final JComponent myLoadingComponent; - private final JTextField myBranchesList; + private final JTextArea myBranchesText; ContainingBranchesPanel() { JLabel label = new JBLabel("Contained in branches: ") { @@ -269,7 +256,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myLoadingComponent = new NonOpaquePanel(new BorderLayout()); myLoadingComponent.add(new AsyncProcessIcon("Loading..."), BorderLayout.WEST); myLoadingComponent.add(Box.createHorizontalGlue(), BorderLayout.CENTER); - myBranchesList = new JBTextField("") { + myBranchesText = new JTextArea("") { private final Border gtkBorder = new LineBorder(UIUtil.getTextFieldBackground(), 3) { @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { @@ -286,8 +273,10 @@ class DetailsPanel extends JPanel implements ListSelectionListener { return UIUtil.isUnderGTKLookAndFeel() ? gtkBorder : emptyBorder; } }; - myBranchesList.setOpaque(false); - myBranchesList.setEditable(false); + myBranchesText.setOpaque(false); + myBranchesText.setEditable(false); + myBranchesText.setWrapStyleWord(true); + myBranchesText.setLineWrap(true); setOpaque(false); setLayout(new BorderLayout()); add(label, BorderLayout.WEST); @@ -296,13 +285,13 @@ class DetailsPanel extends JPanel implements ListSelectionListener { void setBranches(@Nullable List branches) { if (branches == null) { - remove(myBranchesList); + remove(myBranchesText); add(myLoadingComponent, BorderLayout.CENTER); } else { remove(myLoadingComponent); - myBranchesList.setText(StringUtil.join(branches, ", ")); - add(myBranchesList, BorderLayout.CENTER); + myBranchesText.setText(StringUtil.join(branches, ", ")); + add(myBranchesText, BorderLayout.CENTER); } revalidate(); repaint(); @@ -333,22 +322,4 @@ class DetailsPanel extends JPanel implements ListSelectionListener { repaint(); } } - - private static class MessagePanel extends NonOpaquePanel { - - private final JLabel myLabel; - - MessagePanel() { - super(new BorderLayout()); - myLabel = new JLabel(); - myLabel.setForeground(UIUtil.getInactiveTextColor()); - myLabel.setHorizontalAlignment(SwingConstants.CENTER); - myLabel.setVerticalAlignment(SwingConstants.CENTER); - add(myLabel); - } - - void setText(String text) { - myLabel.setText(text); - } - } } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java index acb25dbda712..feb80939035b 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -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 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()); + } + } + 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; diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/TextBuffer.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/TextBuffer.java index 45d29c3359c5..e631a51a92e8 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/TextBuffer.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/TextBuffer.java @@ -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; + } } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java index f35d3d95cf4f..71494852443a 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java @@ -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;