Browse Source

Highlighting references to clicked variable or parameter.

pull/219/head
Artur Zgodziński 14 years ago
parent
commit
c42bf520b8
  1. 3
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 61
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  3. 40
      ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
  4. 17
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  5. 13
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  6. 2
      ICSharpCode.Decompiler/ITextOutput.cs
  7. 2
      ICSharpCode.Decompiler/PlainTextOutput.cs
  8. 4
      ILSpy/AvalonEdit/TextMarkerService.cs
  9. 9
      ILSpy/TextView/AvalonEditTextOutput.cs
  10. 28
      ILSpy/TextView/DecompilerTextView.cs
  11. 5
      ILSpy/TextView/ReferenceElementGenerator.cs

3
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -128,6 +128,7 @@ namespace ICSharpCode.Decompiler.Ast
else else
type = AstBuilder.ConvertType(v.Type); type = AstBuilder.ConvertType(v.Type);
var newVarDecl = new VariableDeclarationStatement(type, v.Name); var newVarDecl = new VariableDeclarationStatement(type, v.Name);
newVarDecl.Variables.Single().AddAnnotation(v);
astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
} }
@ -210,7 +211,7 @@ namespace ICSharpCode.Decompiler.Ast
Type = AstBuilder.ConvertType(catchClause.ExceptionType), Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name, VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name,
Body = TransformBlock(catchClause) Body = TransformBlock(catchClause)
}); }.WithAnnotation(catchClause.ExceptionVariable));
} }
} }
if (tryCatchNode.FinallyBlock != null) if (tryCatchNode.FinallyBlock != null)

61
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -43,12 +43,26 @@ namespace ICSharpCode.Decompiler.Ast
public void WriteIdentifier(string identifier) public void WriteIdentifier(string identifier)
{ {
MemberReference memberRef = GetCurrentMemberReference(); object memberRef = GetCurrentMemberReference();
if (memberRef != null) if (memberRef != null) {
output.WriteReference(identifier, memberRef); output.WriteReference(identifier, memberRef);
else return;
output.Write(identifier); }
var definition = GetCurrentLocalDefinition();
if (definition != null) {
output.WriteDefinition(identifier, definition);
return;
}
memberRef = GetCurrentLocalReference();
if (memberRef != null) {
output.WriteReference(identifier, memberRef, true);
return;
}
output.Write(identifier);
} }
MemberReference GetCurrentMemberReference() MemberReference GetCurrentMemberReference()
@ -60,6 +74,43 @@ namespace ICSharpCode.Decompiler.Ast
} }
return memberRef; return memberRef;
} }
object GetCurrentLocalReference()
{
AstNode node = nodeStack.Peek();
ILVariable variable = node.Annotation<ILVariable>();
if (variable != null) {
if (variable.OriginalParameter != null)
return variable.OriginalParameter;
//if (variable.OriginalVariable != null)
// return variable.OriginalVariable;
return variable;
}
return null;
}
object GetCurrentLocalDefinition()
{
AstNode node = nodeStack.Peek();
var parameterDef = node.Annotation<ParameterDefinition>();
if (parameterDef != null)
return parameterDef;
if (node is VariableInitializer || node is CatchClause || node is ForeachStatement) {
var variable = node.Annotation<ILVariable>();
if (variable != null) {
if (variable.OriginalParameter != null)
return variable.OriginalParameter;
//if (variable.OriginalVariable != null)
// return variable.OriginalVariable;
return variable;
} else {
}
}
return null;
}
public void WriteKeyword(string keyword) public void WriteKeyword(string keyword)
{ {

40
ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs

@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Analysis; using ICSharpCode.NRefactory.CSharp.Analysis;
@ -35,6 +36,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{ {
public AstType Type; public AstType Type;
public string Name; public string Name;
public ILVariable Variable;
public AssignmentExpression ReplacedAssignment; public AssignmentExpression ReplacedAssignment;
public Statement InsertionPoint; public Statement InsertionPoint;
@ -57,9 +59,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var v in variablesToDeclare) { foreach (var v in variablesToDeclare) {
if (v.ReplacedAssignment == null) { if (v.ReplacedAssignment == null) {
BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; BlockStatement block = (BlockStatement)v.InsertionPoint.Parent;
var vds = new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name);
if(v.Variable != null)
vds.Variables.First().AddAnnotation(v.Variable);
block.Statements.InsertBefore( block.Statements.InsertBefore(
v.InsertionPoint, v.InsertionPoint,
new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name)); vds);
} }
} }
// First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST. // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST.
@ -67,9 +72,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (v.ReplacedAssignment != null) { if (v.ReplacedAssignment != null) {
// We clone the right expression so that it doesn't get removed from the old ExpressionStatement, // We clone the right expression so that it doesn't get removed from the old ExpressionStatement,
// which might be still in use by the definite assignment graph. // which might be still in use by the definite assignment graph.
var variableInit = new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach())
.CopyAnnotationsFrom(v.ReplacedAssignment)
.CopyAnnotationsFrom(v.ReplacedAssignment.Left)
.WithAnnotation(v.Variable);
VariableDeclarationStatement varDecl = new VariableDeclarationStatement { VariableDeclarationStatement varDecl = new VariableDeclarationStatement {
Type = (AstType)v.Type.Clone(), Type = (AstType)v.Type.Clone(),
Variables = { new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment) } Variables = { variableInit }
}; };
ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement;
if (es != null) { if (es != null) {
@ -102,7 +111,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (VariableDeclarationStatement varDecl in variables) { foreach (VariableDeclarationStatement varDecl in variables) {
string variableName = varDecl.Variables.Single().Name; string variableName = varDecl.Variables.Single().Name;
bool allowPassIntoLoops = varDecl.Variables.Single().Annotation<DelegateConstruction.CapturedVariableAnnotation>() == null; bool allowPassIntoLoops = varDecl.Variables.Single().Annotation<DelegateConstruction.CapturedVariableAnnotation>() == null;
DeclareVariableInBlock(daa, block, varDecl.Type, variableName, allowPassIntoLoops); ILVariable ilVariable = varDecl.Variables.Single().Annotation<ILVariable>();
DeclareVariableInBlock(daa, block, varDecl.Type, variableName, allowPassIntoLoops, ilVariable);
} }
} }
} }
@ -111,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
} }
void DeclareVariableInBlock(DefiniteAssignmentAnalysis daa, BlockStatement block, AstType type, string variableName, bool allowPassIntoLoops) void DeclareVariableInBlock(DefiniteAssignmentAnalysis daa, BlockStatement block, AstType type, string variableName, bool allowPassIntoLoops, ILVariable ilVariable)
{ {
// declarationPoint: The point where the variable would be declared, if we decide to declare it in this block // declarationPoint: The point where the variable would be declared, if we decide to declare it in this block
Statement declarationPoint = null; Statement declarationPoint = null;
@ -127,52 +137,52 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
ForStatement forStmt = stmt as ForStatement; ForStatement forStmt = stmt as ForStatement;
if (forStmt != null && forStmt.Initializers.Count == 1) { if (forStmt != null && forStmt.Initializers.Count == 1) {
// handle the special case of moving a variable into the for initializer // handle the special case of moving a variable into the for initializer
if (TryConvertAssignmentExpressionIntoVariableDeclaration(forStmt.Initializers.Single(), type, variableName)) if (TryConvertAssignmentExpressionIntoVariableDeclaration(forStmt.Initializers.Single(), type, variableName, ilVariable))
continue; continue;
} }
UsingStatement usingStmt = stmt as UsingStatement; UsingStatement usingStmt = stmt as UsingStatement;
if (usingStmt != null && usingStmt.ResourceAcquisition is AssignmentExpression) { if (usingStmt != null && usingStmt.ResourceAcquisition is AssignmentExpression) {
// handle the special case of moving a variable into a using statement // handle the special case of moving a variable into a using statement
if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName)) if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName, ilVariable))
continue; continue;
} }
foreach (AstNode child in stmt.Children) { foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement; BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) { if (subBlock != null) {
DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops); DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops, ilVariable);
} else if (HasNestedBlocks(child)) { } else if (HasNestedBlocks(child)) {
foreach (BlockStatement nestedSubBlock in child.Children.OfType<BlockStatement>()) { foreach (BlockStatement nestedSubBlock in child.Children.OfType<BlockStatement>()) {
DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, allowPassIntoLoops); DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, allowPassIntoLoops, ilVariable);
} }
} }
} }
} }
} else { } else {
// Try converting an assignment expression into a VariableDeclarationStatement // Try converting an assignment expression into a VariableDeclarationStatement
if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName)) { if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName, ilVariable)) {
// Declare the variable in front of declarationPoint // Declare the variable in front of declarationPoint
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, InsertionPoint = declarationPoint }); variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, InsertionPoint = declarationPoint, Variable = ilVariable });
} }
} }
} }
bool TryConvertAssignmentExpressionIntoVariableDeclaration(Statement declarationPoint, AstType type, string variableName) bool TryConvertAssignmentExpressionIntoVariableDeclaration(Statement declarationPoint, AstType type, string variableName, ILVariable ilVariable)
{ {
// convert the declarationPoint into a VariableDeclarationStatement // convert the declarationPoint into a VariableDeclarationStatement
ExpressionStatement es = declarationPoint as ExpressionStatement; ExpressionStatement es = declarationPoint as ExpressionStatement;
if (es != null) { if (es != null) {
return TryConvertAssignmentExpressionIntoVariableDeclaration(es.Expression, type, variableName); return TryConvertAssignmentExpressionIntoVariableDeclaration(es.Expression, type, variableName, ilVariable);
} }
return false; return false;
} }
bool TryConvertAssignmentExpressionIntoVariableDeclaration(Expression expression, AstType type, string variableName) bool TryConvertAssignmentExpressionIntoVariableDeclaration(Expression expression, AstType type, string variableName, ILVariable ilVariable)
{ {
AssignmentExpression ae = expression as AssignmentExpression; AssignmentExpression ae = expression as AssignmentExpression;
if (ae != null && ae.Operator == AssignmentOperatorType.Assign) { if (ae != null && ae.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression ident = ae.Left as IdentifierExpression; IdentifierExpression ident = ae.Left as IdentifierExpression;
if (ident != null && ident.Identifier == variableName) { if (ident != null && ident.Identifier == variableName) {
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ReplacedAssignment = ae }); variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ReplacedAssignment = ae, Variable = ilVariable });
return true; return true;
} }
} }

17
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -386,7 +386,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
// Now create variables for all fields of the display class (except for those that we already handled as parameters) // Now create variables for all fields of the display class (except for those that we already handled as parameters)
List<Tuple<AstType, string>> variablesToDeclare = new List<Tuple<AstType, string>>(); List<Tuple<AstType, ILVariable>> variablesToDeclare = new List<Tuple<AstType, ILVariable>>();
foreach (FieldDefinition field in type.Fields) { foreach (FieldDefinition field in type.Fields) {
if (field.IsStatic) if (field.IsStatic)
continue; // skip static fields continue; // skip static fields
@ -397,8 +397,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
capturedVariableName = capturedVariableName.Substring(10); capturedVariableName = capturedVariableName.Substring(10);
EnsureVariableNameIsAvailable(blockStatement, capturedVariableName); EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
currentlyUsedVariableNames.Add(capturedVariableName); currentlyUsedVariableNames.Add(capturedVariableName);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName)); ILVariable ilVar = new ILVariable
dict[field] = new IdentifierExpression(capturedVariableName); {
IsGenerated = true,
Name = capturedVariableName,
Type = field.FieldType,
};
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar));
dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar);
} }
// Now figure out where the closure was accessed and use the simpler replacement expression there: // Now figure out where the closure was accessed and use the simpler replacement expression there:
@ -414,15 +420,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works): // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
Statement insertionPoint = blockStatement.Statements.FirstOrDefault(); Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
foreach (var tuple in variablesToDeclare) { foreach (var tuple in variablesToDeclare) {
var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2); var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name);
newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation()); newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
newVarDecl.Variables.Single().AddAnnotation(tuple.Item2);
blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl); blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
} }
} }
currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock); currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
return null; return null;
} }
void EnsureVariableNameIsAvailable(AstNode currentNode, string name) void EnsureVariableNameIsAvailable(AstNode currentNode, string name)
{ {
int pos = currentlyUsedVariableNames.IndexOf(name); int pos = currentlyUsedVariableNames.IndexOf(name);

13
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -227,6 +227,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Name = variableName, Name = variableName,
Initializer = m1.Get<Expression>("initializer").Single().Detach() Initializer = m1.Get<Expression>("initializer").Single().Detach()
}.CopyAnnotationsFrom(node.Expression) }.CopyAnnotationsFrom(node.Expression)
.WithAnnotation(m1.Get<AstNode>("variable").Single().Annotation<ILVariable>())
} }
}.CopyAnnotationsFrom(node); }.CopyAnnotationsFrom(node);
} else { } else {
@ -382,7 +383,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
VariableName = itemVar.Identifier, VariableName = itemVar.Identifier,
InExpression = m.Get<Expression>("collection").Single().Detach(), InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody EmbeddedStatement = newBody
}; }.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
if (foreachStatement.InExpression is BaseReferenceExpression) { if (foreachStatement.InExpression is BaseReferenceExpression) {
foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
} }
@ -471,10 +472,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// We just care that we can move it in front of the loop: // We just care that we can move it in front of the loop:
if (declarationPoint != loop) if (declarationPoint != loop)
return null; return null;
ForeachStatement foreachStatement = new ForeachStatement(); ForeachStatement foreachStatement = new ForeachStatement
foreachStatement.VariableType = itemVarDecl.Type.Clone(); {
foreachStatement.VariableName = itemVar.Identifier; VariableType = itemVarDecl.Type.Clone(),
VariableName = itemVar.Identifier,
}.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
BlockStatement body = new BlockStatement(); BlockStatement body = new BlockStatement();
foreachStatement.EmbeddedStatement = body; foreachStatement.EmbeddedStatement = body;
((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement); ((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement);

2
ICSharpCode.Decompiler/ITextOutput.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler
void Write(string text); void Write(string text);
void WriteLine(); void WriteLine();
void WriteDefinition(string text, object definition); void WriteDefinition(string text, object definition);
void WriteReference(string text, object reference); void WriteReference(string text, object reference, bool isLocal = false);
void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false); void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false);
void MarkFoldEnd(); void MarkFoldEnd();

2
ICSharpCode.Decompiler/PlainTextOutput.cs

@ -104,7 +104,7 @@ namespace ICSharpCode.Decompiler
Write(text); Write(text);
} }
public void WriteReference(string text, object reference) public void WriteReference(string text, object reference, bool isLocal)
{ {
Write(text); Write(text);
} }

4
ILSpy/AvalonEdit/TextMarkerService.cs

@ -124,7 +124,7 @@ namespace ICSharpCode.ILSpy.AvalonEdit
int lineStart = line.Offset; int lineStart = line.Offset;
int lineEnd = lineStart + line.Length; int lineEnd = lineStart + line.Length;
foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length).Reverse()) { foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length).Reverse()) {
if (!marker.IsVisible(marker.Bookmark)) if (marker.Bookmark != null && !marker.IsVisible(marker.Bookmark))
continue; continue;
Brush foregroundBrush = null; Brush foregroundBrush = null;
@ -167,7 +167,7 @@ namespace ICSharpCode.ILSpy.AvalonEdit
int viewStart = visualLines.First().FirstDocumentLine.Offset; int viewStart = visualLines.First().FirstDocumentLine.Offset;
int viewEnd = visualLines.Last().LastDocumentLine.Offset + visualLines.Last().LastDocumentLine.Length; int viewEnd = visualLines.Last().LastDocumentLine.Offset + visualLines.Last().LastDocumentLine.Length;
foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart).Reverse()) { foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart).Reverse()) {
if (!marker.IsVisible(marker.Bookmark)) if (marker.Bookmark != null && !marker.IsVisible(marker.Bookmark))
continue; continue;
if (marker.BackgroundColor != null) { if (marker.BackgroundColor != null) {

9
ILSpy/TextView/AvalonEditTextOutput.cs

@ -36,6 +36,8 @@ namespace ICSharpCode.ILSpy.TextView
sealed class ReferenceSegment : TextSegment sealed class ReferenceSegment : TextSegment
{ {
public object Reference; public object Reference;
public bool IsLocal;
public bool IsLocalTarget;
} }
/// <summary> /// <summary>
@ -197,17 +199,20 @@ namespace ICSharpCode.ILSpy.TextView
public void WriteDefinition(string text, object definition) public void WriteDefinition(string text, object definition)
{ {
WriteIndent(); WriteIndent();
int start = this.TextLength;
b.Append(text); b.Append(text);
int end = this.TextLength;
this.DefinitionLookup.AddDefinition(definition, this.TextLength); this.DefinitionLookup.AddDefinition(definition, this.TextLength);
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = definition, IsLocal = true, IsLocalTarget = true });
} }
public void WriteReference(string text, object reference) public void WriteReference(string text, object reference, bool isLocal)
{ {
WriteIndent(); WriteIndent();
int start = this.TextLength; int start = this.TextLength;
b.Append(text); b.Append(text);
int end = this.TextLength; int end = this.TextLength;
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference }); references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = isLocal });
} }
public void MarkFoldStart(string collapsedText, bool defaultCollapsed) public void MarkFoldStart(string collapsedText, bool defaultCollapsed)

28
ILSpy/TextView/DecompilerTextView.cs

@ -29,6 +29,7 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Threading; using System.Windows.Threading;
using System.Xml; using System.Xml;
@ -68,11 +69,13 @@ namespace ICSharpCode.ILSpy.TextView
ILSpyTreeNode[] decompiledNodes; ILSpyTreeNode[] decompiledNodes;
DefinitionLookup definitionLookup; DefinitionLookup definitionLookup;
TextSegmentCollection<ReferenceSegment> references;
CancellationTokenSource currentCancellationTokenSource; CancellationTokenSource currentCancellationTokenSource;
internal readonly IconBarManager manager; internal readonly IconBarManager manager;
readonly IconBarMargin iconMargin; readonly IconBarMargin iconMargin;
readonly TextMarkerService textMarkerService; readonly TextMarkerService textMarkerService;
readonly List<ITextMarker> localReferenceMarks = new List<ITextMarker>();
[ImportMany(typeof(ITextEditorListener))] [ImportMany(typeof(ITextEditorListener))]
IEnumerable<ITextEditorListener> textEditorListeners; IEnumerable<ITextEditorListener> textEditorListeners;
@ -315,7 +318,8 @@ namespace ICSharpCode.ILSpy.TextView
{ {
Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength); Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength);
Stopwatch w = Stopwatch.StartNew(); Stopwatch w = Stopwatch.StartNew();
ClearLocalReferenceMarks();
textEditor.ScrollToHome(); textEditor.ScrollToHome();
if (foldingManager != null) { if (foldingManager != null) {
FoldingManager.Uninstall(foldingManager); FoldingManager.Uninstall(foldingManager);
@ -324,6 +328,7 @@ namespace ICSharpCode.ILSpy.TextView
textEditor.Document = null; // clear old document while we're changing the highlighting textEditor.Document = null; // clear old document while we're changing the highlighting
uiElementGenerator.UIElements = textOutput.UIElements; uiElementGenerator.UIElements = textOutput.UIElements;
referenceElementGenerator.References = textOutput.References; referenceElementGenerator.References = textOutput.References;
references = textOutput.References;
definitionLookup = textOutput.DefinitionLookup; definitionLookup = textOutput.DefinitionLookup;
textEditor.SyntaxHighlighting = highlighting; textEditor.SyntaxHighlighting = highlighting;
@ -609,6 +614,19 @@ namespace ICSharpCode.ILSpy.TextView
internal void JumpToReference(ReferenceSegment referenceSegment) internal void JumpToReference(ReferenceSegment referenceSegment)
{ {
object reference = referenceSegment.Reference; object reference = referenceSegment.Reference;
if (referenceSegment.IsLocal) {
ClearLocalReferenceMarks();
if (references != null) {
foreach (var r in references) {
if (r.Reference == reference) {
var mark = textMarkerService.Create(r.StartOffset, r.Length);
mark.BackgroundColor = r.IsLocalTarget ? Colors.LightSeaGreen : Colors.GreenYellow;
localReferenceMarks.Add(mark);
}
}
}
return;
}
if (definitionLookup != null) { if (definitionLookup != null) {
int pos = definitionLookup.GetDefinitionPosition(reference); int pos = definitionLookup.GetDefinitionPosition(reference);
if (pos >= 0) { if (pos >= 0) {
@ -624,6 +642,14 @@ namespace ICSharpCode.ILSpy.TextView
} }
MainWindow.Instance.JumpToReference(reference); MainWindow.Instance.JumpToReference(reference);
} }
void ClearLocalReferenceMarks()
{
foreach (var mark in localReferenceMarks) {
textMarkerService.Remove(mark);
}
localReferenceMarks.Clear();
}
/// <summary> /// <summary>
/// Filters all ReferenceSegments that are no real links. /// Filters all ReferenceSegments that are no real links.

5
ILSpy/TextView/ReferenceElementGenerator.cs

@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy.TextView
protected override void OnQueryCursor(QueryCursorEventArgs e) protected override void OnQueryCursor(QueryCursorEventArgs e)
{ {
e.Handled = true; e.Handled = true;
e.Cursor = Cursors.Hand; e.Cursor = referenceSegment.IsLocal ? Cursors.Arrow : Cursors.Hand;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -110,7 +110,8 @@ namespace ICSharpCode.ILSpy.TextView
{ {
if (e.ChangedButton == MouseButton.Left && !e.Handled) { if (e.ChangedButton == MouseButton.Left && !e.Handled) {
parent.JumpToReference(referenceSegment); parent.JumpToReference(referenceSegment);
e.Handled = true; if(!referenceSegment.IsLocal)
e.Handled = true;
} }
} }

Loading…
Cancel
Save