mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+65
-14
@@ -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<Instruction, Instruction> myForwardMap;
|
||||
private final MultiMap<Instruction, Instruction> 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<Instruction, Instruction> calcBackwardMap() {
|
||||
MultiMap<Instruction, Instruction> 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<Instruction, Instruction> calcForwardMap() {
|
||||
MultiMap<Instruction, Instruction> 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<FinishElementInstruction, BitSet> findLiveVars() {
|
||||
final Map<FinishElementInstruction, BitSet> result = ContainerUtil.newHashMap();
|
||||
|
||||
runDfa(false, new PairFunction<Instruction, BitSet, BitSet>() {
|
||||
boolean ok = runDfa(false, new PairFunction<Instruction, BitSet, BitSet>() {
|
||||
@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<FinishElementInstruction, BitSet> liveVars = findLiveVars();
|
||||
if (liveVars == null) return;
|
||||
|
||||
runDfa(true, new PairFunction<Instruction, BitSet, BitSet>() {
|
||||
final MultiMap<FinishElementInstruction, DfaVariableValue> toFlush = MultiMap.createSet();
|
||||
|
||||
boolean ok = runDfa(true, new PairFunction<Instruction, BitSet, BitSet>() {
|
||||
@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<Instruction, BitSet, BitSet> handleState) {
|
||||
/**
|
||||
* @return true if completed, false if "too complex"
|
||||
*/
|
||||
private boolean runDfa(boolean forward, PairFunction<Instruction, BitSet, BitSet> handleState) {
|
||||
Set<Instruction> 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<InstructionState> 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<Instruction> nextInstructions = forward ? getSuccessors(instruction) : myBackwardMap.get(instruction);
|
||||
boolean branching = nextInstructions.size() > 1 || !forward && instruction.getIndex() == 0;
|
||||
Collection<Instruction> 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<Instruction, BitSet> {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -52,6 +52,7 @@ public class RepositoryWithBranchPanel<T extends PushTarget> 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<T extends PushTarget> 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<T extends PushTarget> extends NonOpaquePa
|
||||
Border border = coloredRenderer.getMyBorder();
|
||||
return border != null ? border.getBorderInsets(coloredRenderer).top : 0;
|
||||
}
|
||||
|
||||
public int getCheckBoxHeight() {
|
||||
return myCheckBoxHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.<VcsRef>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() + "<br/>" + getAuthorText(commit);
|
||||
}
|
||||
String body = commit.getId().toShortString() + " " + getAuthorText(commit) + "<br>" + getMessageText(commit);
|
||||
setText("<html><head>" + UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()) + "</head><body>" + body + "</body></html>");
|
||||
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<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
-8
@@ -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<Integer, Integer> lineStartOffsets = new HashMap<Integer, 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());
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
+9
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user