mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-28 09:51:37 +08:00
GP-6751 - Decompiler - Updated highlights to be painted using the
highlight controller and not from the color value in the token. This fixes shared highlight state issues in snapshots.
This commit is contained in:
+2
-3
@@ -241,9 +241,8 @@ public class DecompilerCodeComparisonView extends CodeComparisonView {
|
||||
private void linkHighlightControllers() {
|
||||
DiffClangHighlightController left = cDisplays.get(LEFT).getHighlightController();
|
||||
DiffClangHighlightController right = cDisplays.get(RIGHT).getHighlightController();
|
||||
left.addListener(right);
|
||||
right.addListener(left);
|
||||
|
||||
left.setTokenChangedListener(right);
|
||||
right.setTokenChangedListener(left);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+196
-149
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -17,18 +17,16 @@ package ghidra.features.codecompare.decompile;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import docking.widgets.EventTrigger;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.decompiler.ClangSyntaxToken;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.decompiler.component.*;
|
||||
import ghidra.features.codecompare.graphanalysis.TokenBin;
|
||||
import ghidra.util.ColorUtils;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Class to handle Function Difference highlights for a decompiled function.
|
||||
@@ -40,202 +38,251 @@ public class DiffClangHighlightController extends LocationClangHighlightControll
|
||||
private Set<ClangToken> diffTokenSet = new HashSet<>();
|
||||
private ClangToken locationToken;
|
||||
private TokenBin locationTokenBin;
|
||||
private List<TokenBin> highlightBins;
|
||||
private List<DiffClangHighlightListener> listenerList = new ArrayList<>();
|
||||
private TokenBin matchingTokenBin;
|
||||
private List<TokenBin> allTokenBins;
|
||||
private DecompilerCodeComparisonOptions comparisonOptions;
|
||||
private DiffClangHighlightListener listener = new DummyListener();
|
||||
|
||||
private DiffTokenHighlighter diffColorHighlighter;
|
||||
private BasicTokenHighlighter currentTokenHighlighter;
|
||||
|
||||
// highlights the token in this highlighter for the selected token in the other highlighter
|
||||
private BasicTokenHighlighter matchingTokenHighlighter;
|
||||
|
||||
public DiffClangHighlightController(DecompilerCodeComparisonOptions comparisonOptions) {
|
||||
this.comparisonOptions = comparisonOptions;
|
||||
}
|
||||
|
||||
public void clearDiffHighlights() {
|
||||
doClearDiffHighlights();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
private void doClearDiffHighlights() {
|
||||
ClangToken[] array = diffTokenSet.toArray(new ClangToken[diffTokenSet.size()]);
|
||||
for (ClangToken clangToken : array) {
|
||||
clearDiffHighlight(clangToken);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearDiffHighlight(ClangToken clangToken) {
|
||||
Color highlight = clangToken.getHighlight();
|
||||
if (highlight != null && highlight.equals(comparisonOptions.getDiffHighlightColor())) {
|
||||
clangToken.setHighlight(null);
|
||||
}
|
||||
diffTokenSet.remove(clangToken);
|
||||
}
|
||||
|
||||
private void clearNonDiffHighlight(ClangToken clangToken) {
|
||||
if (diffTokenSet.contains(clangToken)) {
|
||||
clangToken.setHighlight(comparisonOptions.getDiffHighlightColor());
|
||||
}
|
||||
else {
|
||||
clangToken.setHighlight(null);
|
||||
}
|
||||
if (clangToken.isMatchingToken()) {
|
||||
clangToken.setMatchingToken(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDiffHighlights(List<TokenBin> highlightBins, Set<ClangToken> tokenSet) {
|
||||
this.highlightBins = highlightBins;
|
||||
doClearDiffHighlights();
|
||||
for (ClangToken clangToken : tokenSet) {
|
||||
clangToken.setHighlight(comparisonOptions.getDiffHighlightColor());
|
||||
diffTokenSet.add(clangToken);
|
||||
this.allTokenBins = highlightBins;
|
||||
|
||||
clearDiffHighlights();
|
||||
|
||||
if (!tokenSet.isEmpty()) {
|
||||
Color color = comparisonOptions.getDiffHighlightColor();
|
||||
diffColorHighlighter = new DiffTokenHighlighter(new ArrayList<>(tokenSet), color);
|
||||
diffColorHighlighter.applyHighlights();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldLocationChanged(FieldLocation location, Field field, EventTrigger trigger) {
|
||||
public void fieldLocationChanged(FieldLocation location, Field field,
|
||||
EventTrigger trigger) {
|
||||
|
||||
if (!(field instanceof ClangTextField)) {
|
||||
if (!(field instanceof ClangTextField textField)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the token for the location so we can highlight its token bin.
|
||||
// Also we will use it when notifying the other panel to highlight.
|
||||
ClangToken tok = ((ClangTextField) field).getToken(location);
|
||||
if (SystemUtilities.isEqual(locationToken, tok)) {
|
||||
return; // Current location's token hasn't changed.
|
||||
// Get the token for the location so we can highlight its token bin. Also we will use it
|
||||
// when notifying the other panel to highlight.
|
||||
ClangToken tok = textField.getToken(location);
|
||||
if (Objects.equals(locationToken, tok)) {
|
||||
return; // current location's token hasn't changed
|
||||
}
|
||||
|
||||
// Undo any highlight of the previous matching tokenBin.
|
||||
if (matchingTokenBin != null && matchingTokenBin.getMatch() != null) {
|
||||
clearTokenBinHighlight(matchingTokenBin.getMatch());
|
||||
matchingTokenBin = null;
|
||||
}
|
||||
|
||||
clearCurrentLocationHighlight();
|
||||
|
||||
clearPrimaryHighlights();
|
||||
addPrimaryHighlight(tok, defaultHighlightColor);
|
||||
if (tok instanceof ClangSyntaxToken) {
|
||||
List<ClangToken> tokens = addPrimaryHighlightToTokensForParenthesis(
|
||||
(ClangSyntaxToken) tok, defaultParenColor);
|
||||
reHighlightDiffs(tokens);
|
||||
addPrimaryHighlightToTokensForBrace((ClangSyntaxToken) tok, defaultParenColor);
|
||||
clearCurrentLocationHighlight();
|
||||
clearMatchingTokenBin();
|
||||
|
||||
highlightTokensBetweenParens(tok);
|
||||
highlightCurrentLocationToken(tok);
|
||||
|
||||
listener.locationTokenChanged(locationTokenBin);
|
||||
}
|
||||
|
||||
private void highlightTokensBetweenParens(ClangToken tok) {
|
||||
|
||||
if (!(tok instanceof ClangSyntaxToken syntaxToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addPrimaryHighlightToTokensForParenthesis(syntaxToken, defaultParenColor);
|
||||
addPrimaryHighlightToTokensForBrace(syntaxToken, defaultParenColor);
|
||||
}
|
||||
|
||||
private void highlightCurrentLocationToken(ClangToken tok) {
|
||||
|
||||
TokenBin tokenBin = null;
|
||||
if (tok != null) {
|
||||
Color highlightColor = comparisonOptions.getFocusedTokenIneligibleHighlightColor(); // Don't know
|
||||
if (highlightBins != null) {
|
||||
tokenBin = TokenBin.getBinContainingToken(highlightBins, tok);
|
||||
if (tokenBin != null) {
|
||||
if (tokenBin.getMatch() != null) {
|
||||
highlightColor = comparisonOptions.getFocusedTokenMatchHighlightColor();
|
||||
}
|
||||
else if (tokenBin.getMatch() == null) {
|
||||
highlightColor = comparisonOptions.getFocusedTokenUnmatchedHighlightColor();
|
||||
}
|
||||
else {
|
||||
// All the tokens that didn't fall into the "has a match" or "no match"
|
||||
// categories above are in a single token bin.
|
||||
// We don't want all these highlighted at the same time, so set the
|
||||
// tokenBin to null. By doing this, only the current token gets highlighted.
|
||||
tokenBin = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
locationToken = tok;
|
||||
locationTokenBin = tokenBin;
|
||||
if (tokenBin == null) {
|
||||
addPrimaryHighlight(tok, highlightColor);
|
||||
if (tok != null && allTokenBins != null) {
|
||||
tokenBin = TokenBin.getBinContainingToken(allTokenBins, tok);
|
||||
}
|
||||
|
||||
Color binHlColor = comparisonOptions.getFocusedTokenIneligibleHighlightColor();
|
||||
if (tokenBin != null) {
|
||||
if (tokenBin.getMatch() != null) {
|
||||
binHlColor = comparisonOptions.getFocusedTokenMatchHighlightColor();
|
||||
}
|
||||
else {
|
||||
addTokenBinHighlight(tokenBin, highlightColor);
|
||||
binHlColor = comparisonOptions.getFocusedTokenUnmatchedHighlightColor();
|
||||
}
|
||||
}
|
||||
|
||||
// Notify other decompiler panel highlight controller we have a new location token.
|
||||
for (DiffClangHighlightListener listener : listenerList) {
|
||||
listener.locationTokenChanged(tok, tokenBin);
|
||||
locationToken = tok;
|
||||
locationTokenBin = tokenBin;
|
||||
|
||||
List<ClangToken> tokens = List.of();
|
||||
if (tokenBin != null) {
|
||||
tokens = toList(tokenBin);
|
||||
}
|
||||
else if (tok != null) {
|
||||
tokens = List.of(tok);
|
||||
}
|
||||
|
||||
installCurrentTokenHighlighter(tokens, binHlColor);
|
||||
refreshDiffHighlightsForCurrentLocationChange();
|
||||
}
|
||||
|
||||
/*
|
||||
* The diff highlighter is smart enough to ignore the token at the current location. We have to
|
||||
* kick it when the location changes so it will update the highlights.
|
||||
*/
|
||||
private void refreshDiffHighlightsForCurrentLocationChange() {
|
||||
if (diffColorHighlighter != null) {
|
||||
diffColorHighlighter.clearHighlights();
|
||||
diffColorHighlighter.applyHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
private void reHighlightDiffs(List<ClangToken> tokenList) {
|
||||
Color averageColor =
|
||||
ColorUtils.blend(defaultParenColor, comparisonOptions.getDiffHighlightColor(), 0.5);
|
||||
for (ClangToken clangToken : tokenList) {
|
||||
if (diffTokenSet.contains(clangToken)) {
|
||||
clangToken.setHighlight(averageColor);
|
||||
}
|
||||
}
|
||||
private static List<ClangToken> toList(TokenBin tokens) {
|
||||
return StreamSupport.stream(tokens.spliterator(), false).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void clearCurrentLocationHighlight() {
|
||||
if (locationTokenBin != null) {
|
||||
clearTokenBinHighlight(locationTokenBin);
|
||||
locationTokenBin = null;
|
||||
locationToken = null;
|
||||
|
||||
if (currentTokenHighlighter != null) {
|
||||
currentTokenHighlighter.dispose();
|
||||
currentTokenHighlighter = null;
|
||||
}
|
||||
if (locationToken != null) {
|
||||
clearNonDiffHighlight(locationToken);
|
||||
locationToken = null;
|
||||
|
||||
locationTokenBin = null;
|
||||
locationToken = null;
|
||||
}
|
||||
|
||||
private void clearDiffHighlights() {
|
||||
|
||||
if (diffColorHighlighter != null) {
|
||||
diffColorHighlighter.dispose();
|
||||
diffColorHighlighter = null;
|
||||
}
|
||||
|
||||
diffTokenSet.clear();
|
||||
}
|
||||
|
||||
private void clearMatchingTokenBin() {
|
||||
if (matchingTokenHighlighter != null) {
|
||||
matchingTokenHighlighter.dispose();
|
||||
matchingTokenHighlighter = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addTokenBinHighlight(TokenBin tokenBin, Color highlightColor) {
|
||||
for (ClangToken token : tokenBin) {
|
||||
addPrimaryHighlight(token, highlightColor);
|
||||
private void installCurrentTokenHighlighter(List<ClangToken> tokens, Color highlightColor) {
|
||||
if (tokens.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentTokenHighlighter = new BasicTokenHighlighter(tokens, highlightColor);
|
||||
currentTokenHighlighter.applyHighlights();
|
||||
}
|
||||
|
||||
private void clearTokenBinHighlight(TokenBin tokenBin) {
|
||||
for (ClangToken token : tokenBin) {
|
||||
clearNonDiffHighlight(token);
|
||||
private void installMatchingTokenBinHighlighter(TokenBin tokenBin, Color highlightColor) {
|
||||
|
||||
clearMatchingTokenBin();
|
||||
|
||||
if (tokenBin == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
matchingTokenHighlighter = new BasicTokenHighlighter(tokenBin, highlightColor);
|
||||
matchingTokenHighlighter.applyHighlights();
|
||||
}
|
||||
|
||||
private void doClearHighlights(TokenHighlights tokens) {
|
||||
List<ClangToken> clangTokens =
|
||||
CollectionUtils.asStream(tokens).map(ht -> ht.getToken()).collect(Collectors.toList());
|
||||
for (ClangToken clangToken : clangTokens) {
|
||||
clearNonDiffHighlight(clangToken);
|
||||
}
|
||||
tokens.clear();
|
||||
notifyListeners();
|
||||
public void setTokenChangedListener(DiffClangHighlightListener listener) {
|
||||
this.listener = listener == null ? new DummyListener() : listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPrimaryHighlights() {
|
||||
doClearHighlights(getPrimaryHighlights());
|
||||
}
|
||||
|
||||
public boolean addListener(DiffClangHighlightListener listener) {
|
||||
return listenerList.add(listener);
|
||||
}
|
||||
|
||||
public boolean removeListener(DiffClangHighlightListener listener) {
|
||||
return listenerList.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void locationTokenChanged(ClangToken tok, TokenBin tokenBin) {
|
||||
public void locationTokenChanged(TokenBin tokenBin) {
|
||||
clearCurrentLocationHighlight();
|
||||
refreshDiffHighlightsForCurrentLocationChange();
|
||||
|
||||
// The token Changed in our other matching DiffClangHighlightController
|
||||
highlightMatchingToken(tok, tokenBin);
|
||||
if (tokenBin != null) {
|
||||
TokenBin match = tokenBin.getMatch();
|
||||
Color color = comparisonOptions.getFocusedTokenMatchHighlightColor();
|
||||
installMatchingTokenBinHighlighter(match, color);
|
||||
}
|
||||
}
|
||||
|
||||
private void highlightMatchingToken(ClangToken tok, TokenBin tokenBin) {
|
||||
// Undo any highlight of the previous matching tokenBin.
|
||||
if (matchingTokenBin != null && matchingTokenBin.getMatch() != null) {
|
||||
clearTokenBinHighlight(matchingTokenBin.getMatch());
|
||||
//=================================================================================================
|
||||
// Inner Classes
|
||||
//=================================================================================================
|
||||
|
||||
/**
|
||||
* Highlights a given set of tokens with the given color.
|
||||
*/
|
||||
private class BasicTokenHighlighter implements DecompilerHighlighter {
|
||||
|
||||
private String id;
|
||||
protected List<ClangToken> tokens;
|
||||
private Color color;
|
||||
|
||||
BasicTokenHighlighter(TokenBin tokens, Color color) {
|
||||
this(toList(tokens), color);
|
||||
}
|
||||
|
||||
// Highlight the new matching tokenBin.
|
||||
if (tokenBin != null && tokenBin.getMatch() != null) {
|
||||
addTokenBinHighlight(tokenBin.getMatch(),
|
||||
comparisonOptions.getFocusedTokenMatchHighlightColor());
|
||||
BasicTokenHighlighter(List<ClangToken> tokens, Color color) {
|
||||
this.color = color;
|
||||
UUID uuId = UUID.randomUUID();
|
||||
this.id = uuId.toString();
|
||||
this.tokens = tokens;
|
||||
}
|
||||
|
||||
matchingTokenBin = tokenBin;
|
||||
// subclass overrides this method
|
||||
protected List<ClangToken> getCurrentTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyHighlights() {
|
||||
Supplier<? extends Collection<ClangToken>> tokenSupplier = this::getCurrentTokens;
|
||||
ColorProvider cp = t -> color;
|
||||
addHighlighterHighlights(this, tokenSupplier, cp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHighlights() {
|
||||
removeHighlighterHighlights(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
removeHighlighterHighlights(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
private class DiffTokenHighlighter extends BasicTokenHighlighter {
|
||||
|
||||
DiffTokenHighlighter(List<ClangToken> tokens, Color color) {
|
||||
super(tokens, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ClangToken> getCurrentTokens() {
|
||||
// ignore the selected token so that it paints with its own color and does not get
|
||||
// blended with this highlighter's color
|
||||
return tokens.stream().filter(t -> t != locationToken).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyListener implements DiffClangHighlightListener {
|
||||
@Override
|
||||
public void locationTokenChanged(TokenBin tokenBin) {
|
||||
// stub
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -15,16 +15,14 @@
|
||||
*/
|
||||
package ghidra.features.codecompare.decompile;
|
||||
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.features.codecompare.graphanalysis.TokenBin;
|
||||
|
||||
public interface DiffClangHighlightListener {
|
||||
|
||||
/**
|
||||
* Notifier that the current location changed to the specified token.
|
||||
* @param tok the token
|
||||
* @param tokenBin the bin which contains the token. Otherwise, null.
|
||||
*/
|
||||
public void locationTokenChanged(ClangToken tok, TokenBin tokenBin);
|
||||
public void locationTokenChanged(TokenBin tokenBin);
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -33,7 +33,6 @@ public class ClangCommentToken extends ClangToken {
|
||||
newToken.setText(text);
|
||||
newToken.setLineParent(source.getLineParent());
|
||||
newToken.setSyntaxType(source.getSyntaxType());
|
||||
newToken.setHighlight(source.getHighlight());
|
||||
newToken.srcaddr = source.srcaddr;
|
||||
return newToken;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.decompiler;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
@@ -45,12 +44,6 @@ public interface ClangNode {
|
||||
*/
|
||||
public Address getMaxAddress();
|
||||
|
||||
/**
|
||||
* Set a highlighting background color for all text elements
|
||||
* @param c is the color to set
|
||||
*/
|
||||
public void setHighlight(Color c);
|
||||
|
||||
/**
|
||||
* Return the number of immediate groupings this text breaks up into
|
||||
* @return the number of child groupings
|
||||
|
||||
@@ -18,7 +18,6 @@ package ghidra.app.decompiler;
|
||||
import static ghidra.program.model.pcode.AttributeId.*;
|
||||
import static ghidra.program.model.pcode.ElementId.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -49,13 +48,11 @@ public class ClangToken implements ClangNode {
|
||||
private ClangLine lineparent;
|
||||
private String text;
|
||||
private int syntax_type;
|
||||
private Color highlight; // Color to highlight with or null if no highlight
|
||||
private boolean matchingToken;
|
||||
|
||||
public ClangToken(ClangNode par) {
|
||||
parent = par;
|
||||
text = null;
|
||||
highlight = null;
|
||||
syntax_type = DEFAULT_COLOR;
|
||||
lineparent = null;
|
||||
}
|
||||
@@ -63,14 +60,12 @@ public class ClangToken implements ClangNode {
|
||||
public ClangToken(ClangNode par, String txt) {
|
||||
parent = par;
|
||||
text = txt;
|
||||
highlight = null;
|
||||
syntax_type = DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
public ClangToken(ClangNode par, String txt, int color) {
|
||||
parent = par;
|
||||
text = txt;
|
||||
highlight = null;
|
||||
syntax_type = color;
|
||||
}
|
||||
|
||||
@@ -123,19 +118,6 @@ public class ClangToken implements ClangNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHighlight(Color val) {
|
||||
highlight = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the background highlight color used to render this token, or null if not highlighted
|
||||
* @return the Color or null
|
||||
*/
|
||||
public Color getHighlight() {
|
||||
return highlight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not additional "matching" highlighting is applied to this token.
|
||||
* Currently this means a bounding box is drawn around the token.
|
||||
|
||||
+3
-13
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -17,7 +17,6 @@ package ghidra.app.decompiler;
|
||||
|
||||
import static ghidra.program.model.pcode.ElementId.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -97,13 +96,6 @@ public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
|
||||
return parent.getClangFunction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHighlight(Color val) {
|
||||
for (ClangNode element : tokgroup) {
|
||||
element.setHighlight(val);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flatten(List<ClangNode> list) {
|
||||
for (ClangNode element : tokgroup) {
|
||||
@@ -168,9 +160,7 @@ public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
|
||||
public String toString() {
|
||||
String lastTokenStr = null;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
Iterator<ClangNode> iter = tokgroup.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ClangNode node = iter.next();
|
||||
for (ClangNode node : tokgroup) {
|
||||
String tokenStr = node.toString();
|
||||
if (tokenStr.length() == 0) {
|
||||
continue;
|
||||
|
||||
+10
-7
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -27,9 +27,12 @@ import ghidra.app.decompiler.ClangToken;
|
||||
public class ClangFieldElement extends AbstractTextFieldElement {
|
||||
|
||||
private final ClangToken token;
|
||||
private ClangHighlightController hlController;
|
||||
|
||||
public ClangFieldElement(ClangToken token, AttributedString as, int col) {
|
||||
public ClangFieldElement(ClangHighlightController hlController, ClangToken token,
|
||||
AttributedString as, int col) {
|
||||
super(as, 0, col);
|
||||
this.hlController = hlController;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@@ -39,7 +42,7 @@ public class ClangFieldElement extends AbstractTextFieldElement {
|
||||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||
Color highlightColor = token.getHighlight();
|
||||
Color highlightColor = hlController.getCombinedColor(token);
|
||||
if (highlightColor != null) {
|
||||
g.setColor(highlightColor);
|
||||
g.fillRect(x, y - getHeightAbove(), getStringWidth(),
|
||||
@@ -63,12 +66,12 @@ public class ClangFieldElement extends AbstractTextFieldElement {
|
||||
if (as == attributedString) {
|
||||
return this;
|
||||
}
|
||||
return new ClangFieldElement(token, as, column + start);
|
||||
return new ClangFieldElement(hlController, token, as, column + start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldElement replaceAll(char[] targets, char replacement) {
|
||||
return new ClangFieldElement(token, attributedString.replaceAll(targets, replacement),
|
||||
column);
|
||||
AttributedString as = attributedString.replaceAll(targets, replacement);
|
||||
return new ClangFieldElement(hlController, token, as, column);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-34
@@ -30,6 +30,7 @@ import ghidra.program.model.pcode.HighFunction;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.util.ColorUtils;
|
||||
import util.CollectionUtils;
|
||||
import utility.function.Dummy;
|
||||
|
||||
/**
|
||||
* Class to handle highlights for a decompiled function.
|
||||
@@ -86,7 +87,6 @@ public abstract class ClangHighlightController {
|
||||
|
||||
// arbitrary value chosen by guessing; this can be changed if needed
|
||||
private int maxColorBlendSize = 5;
|
||||
private boolean isRebuilding;
|
||||
|
||||
private List<ClangHighlightListener> listeners = new ArrayList<>();
|
||||
|
||||
@@ -169,33 +169,19 @@ public abstract class ClangHighlightController {
|
||||
// finished. This allows all highlights to calculate their matches without the color
|
||||
// blending affecting performance.
|
||||
//
|
||||
isRebuilding = true;
|
||||
Set<DecompilerHighlighter> service = getServiceHighlighters();
|
||||
Set<DecompilerHighlighter> secondary = getSecondaryHighlighters(function);
|
||||
Iterable<DecompilerHighlighter> it = CollectionUtils.asIterable(service, secondary);
|
||||
|
||||
try {
|
||||
for (DecompilerHighlighter highlighter : it) {
|
||||
highlighter.clearHighlights();
|
||||
highlighter.applyHighlights();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
isRebuilding = false;
|
||||
for (DecompilerHighlighter highlighter : it) {
|
||||
highlighter.clearHighlights();
|
||||
highlighter.applyHighlights();
|
||||
}
|
||||
|
||||
// gather all highlighted tokens and then update their color
|
||||
Set<ClangToken> allTokens = new HashSet<>();
|
||||
it = CollectionUtils.asIterable(service, secondary);
|
||||
for (DecompilerHighlighter highlighter : it) {
|
||||
TokenHighlights hlTokens = userHighlights.add(highlighter);
|
||||
for (HighlightToken hlToken : hlTokens) {
|
||||
allTokens.add(hlToken.getToken());
|
||||
}
|
||||
}
|
||||
|
||||
for (ClangToken token : allTokens) {
|
||||
updateHighlightColor(token);
|
||||
userHighlights.add(highlighter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +224,6 @@ public abstract class ClangHighlightController {
|
||||
public void clearPrimaryHighlights() {
|
||||
Consumer<ClangToken> clearAll = token -> {
|
||||
token.setMatchingToken(false);
|
||||
updateHighlightColor(token);
|
||||
};
|
||||
|
||||
doClearHighlights(contextHighlightTokens, clearAll);
|
||||
@@ -297,7 +282,7 @@ public abstract class ClangHighlightController {
|
||||
|
||||
for (DecompilerHighlighter highlighter : highlighters) {
|
||||
TokenHighlights highlights = userHighlights.getHighlights(highlighter);
|
||||
Consumer<ClangToken> clearHighlight = token -> updateHighlightColor(token);
|
||||
Consumer<ClangToken> clearHighlight = Dummy.consumer();
|
||||
doClearHighlights(highlights, clearHighlight);
|
||||
}
|
||||
highlighters.clear();
|
||||
@@ -333,7 +318,7 @@ public abstract class ClangHighlightController {
|
||||
return;
|
||||
}
|
||||
|
||||
Consumer<ClangToken> clearHighlight = token -> updateHighlightColor(token);
|
||||
Consumer<ClangToken> clearHighlight = Dummy.consumer();
|
||||
doClearHighlights(highlighterTokens, clearHighlight);
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -417,18 +402,6 @@ public abstract class ClangHighlightController {
|
||||
|
||||
// store the actual requested color
|
||||
currentHighlights.add(new HighlightToken(clangToken, highlightColor));
|
||||
updateHighlightColor(clangToken);
|
||||
}
|
||||
|
||||
private void updateHighlightColor(ClangToken t) {
|
||||
|
||||
if (isRebuilding) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set the color to the current combined value of all highlight types
|
||||
Color combinedColor = getCombinedColor(t);
|
||||
t.setHighlight(combinedColor);
|
||||
}
|
||||
|
||||
private void add(Set<Color> colors, HighlightToken hlToken) {
|
||||
|
||||
+3
-2
@@ -183,20 +183,21 @@ public class ClangLayoutController implements LayoutModel, LayoutModelListener {
|
||||
|
||||
FieldElement[] elements = new FieldElement[tokens.size()];
|
||||
int columnPosition = 0;
|
||||
Program program = decompilerPanel.getProgram();
|
||||
ClangHighlightController hlController = decompilerPanel.getHighlightController();
|
||||
for (int i = 0; i < tokens.size(); ++i) {
|
||||
ClangToken token = tokens.get(i);
|
||||
Color color = getTokenColor(token);
|
||||
|
||||
if (token instanceof ClangCommentToken) {
|
||||
AttributedString prototype = new AttributedString("prototype", color, metrics);
|
||||
Program program = decompilerPanel.getProgram();
|
||||
elements[i] =
|
||||
CommentUtils.parseTextForAnnotations(token.getText(), program, prototype, 0);
|
||||
columnPosition += elements[i].length();
|
||||
}
|
||||
else {
|
||||
AttributedString as = new AttributedString(token.getText(), color, metrics);
|
||||
elements[i] = new ClangFieldElement(token, as, columnPosition);
|
||||
elements[i] = new ClangFieldElement(hlController, token, as, columnPosition);
|
||||
columnPosition += as.length();
|
||||
}
|
||||
}
|
||||
|
||||
+16
-9
@@ -2048,7 +2048,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
private void assertCombinedHighlightColor(ClangToken token) {
|
||||
|
||||
Color combinedColor = getCombinedHighlightColor(token);
|
||||
Color actual = token.getHighlight();
|
||||
Color actual = getHighlight(provider, token);
|
||||
assertEquals(combinedColor, actual);
|
||||
}
|
||||
|
||||
@@ -2139,7 +2139,8 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
DecompilerController controller = provider.getController();
|
||||
DecompilerPanel panel = controller.getDecompilerPanel();
|
||||
Color hlColor = panel.getCurrentVariableHighlightColor();
|
||||
assertEquals(hlColor, token.getHighlight());
|
||||
Color actual = getHighlight(provider, token);
|
||||
assertEquals(hlColor, actual);
|
||||
}
|
||||
|
||||
private void rename(String newName) {
|
||||
@@ -2265,7 +2266,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
// test the token under the cursor directly, as that may have a combined highlight applied
|
||||
Color combinedColor = getCombinedHighlightColor(theProvider, cursorToken);
|
||||
ColorMatcher cm = new ColorMatcher(color, combinedColor);
|
||||
Color actual = cursorToken.getHighlight();
|
||||
Color actual = getHighlight(theProvider, cursorToken);
|
||||
assertTrue("Token is not highlighted: '" + cursorToken + "'" + "\n\texpected: " + cm +
|
||||
"; found: " + toString(actual), cm.matches(actual));
|
||||
}
|
||||
@@ -2283,7 +2284,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
// test the token under the cursor directly, as that may have a combined highlight applied
|
||||
Color combinedColor = getCombinedHighlightColor(token);
|
||||
ColorMatcher cm = new ColorMatcher(color, combinedColor);
|
||||
Color actual = token.getHighlight();
|
||||
Color actual = getHighlight(provider, token);
|
||||
String tokenString = token.toString() + " at line " + token.getLineParent().getLineNumber();
|
||||
assertTrue("Token is not highlighted: '" + tokenString + "'" + "\n\texpected: " + cm +
|
||||
"; found: " + toString(actual), cm.matches(actual));
|
||||
@@ -2330,7 +2331,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
continue;
|
||||
}
|
||||
|
||||
Color actual = token.getHighlight();
|
||||
Color actual = getHighlight(provider, token);
|
||||
assertTrue("Token is not highlighted: '" + token + "'" + "\n\texpected: " + cm +
|
||||
"; found: " + toString(actual), cm.matches(actual));
|
||||
}
|
||||
@@ -2357,7 +2358,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
continue;
|
||||
}
|
||||
|
||||
Color actual = token.getHighlight();
|
||||
Color actual = getHighlight(theProvider, token);
|
||||
assertTrue("Token is not highlighted: '" + token + "'" + "\n\texpected: " + cm +
|
||||
"; found: " + toString(actual), cm.matches(actual));
|
||||
}
|
||||
@@ -2378,7 +2379,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
assertAllFieldsHighlighted(theProvider, name, cm, ignores);
|
||||
|
||||
// test the token under the cursor directly, as that may have a combined highlight applied
|
||||
Color actual = token.getHighlight();
|
||||
Color actual = getHighlight(theProvider, token);
|
||||
assertTrue("Token is not highlighted: '" + token + "'" + "\n\texpected: " + cm +
|
||||
"; found: " + toString(actual), cm.matches(actual));
|
||||
}
|
||||
@@ -2394,7 +2395,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
continue;
|
||||
}
|
||||
|
||||
Color actual = otherToken.getHighlight();
|
||||
Color actual = getHighlight(theProvider, otherToken);
|
||||
assertTrue("Token is not highlighted: '" + otherToken + "'" + "\n\texpected: " +
|
||||
colorMatcher + "; found: " + toString(actual), colorMatcher.matches(actual));
|
||||
}
|
||||
@@ -2411,7 +2412,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
continue;
|
||||
}
|
||||
|
||||
Color actual = otherToken.getHighlight();
|
||||
Color actual = getHighlight(theProvider, otherToken);
|
||||
Color combinedColor = getCombinedHighlightColor(otherToken);
|
||||
ColorMatcher combinedColorMatcher = colorMatcher.with(combinedColor);
|
||||
assertTrue(
|
||||
@@ -2421,6 +2422,12 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private Color getHighlight(DecompilerProvider theProvider, ClangToken token) {
|
||||
DecompilerPanel panel = theProvider.getController().getDecompilerPanel();
|
||||
ClangHighlightController highlightController = panel.getHighlightController();
|
||||
return highlightController.getCombinedColor(token);
|
||||
}
|
||||
|
||||
private String toString(Color c) {
|
||||
if (c == null) {
|
||||
return "Color{null}";
|
||||
|
||||
Reference in New Issue
Block a user