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. 57
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  3. 38
      ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
  4. 15
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  5. 11
      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. 26
      ILSpy/TextView/DecompilerTextView.cs
  11. 3
      ILSpy/TextView/ReferenceElementGenerator.cs

3
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

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

57
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -43,11 +43,25 @@ namespace ICSharpCode.Decompiler.Ast @@ -43,11 +43,25 @@ namespace ICSharpCode.Decompiler.Ast
public void WriteIdentifier(string identifier)
{
MemberReference memberRef = GetCurrentMemberReference();
object memberRef = GetCurrentMemberReference();
if (memberRef != null)
if (memberRef != null) {
output.WriteReference(identifier, memberRef);
else
return;
}
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);
}
@ -61,6 +75,43 @@ namespace ICSharpCode.Decompiler.Ast @@ -61,6 +75,43 @@ namespace ICSharpCode.Decompiler.Ast
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)
{
output.Write(keyword);

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

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Analysis;
@ -35,6 +36,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -35,6 +36,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
public AstType Type;
public string Name;
public ILVariable Variable;
public AssignmentExpression ReplacedAssignment;
public Statement InsertionPoint;
@ -57,9 +59,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -57,9 +59,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var v in variablesToDeclare) {
if (v.ReplacedAssignment == null) {
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(
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.
@ -67,9 +72,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -67,9 +72,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (v.ReplacedAssignment != null) {
// 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.
var variableInit = new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach())
.CopyAnnotationsFrom(v.ReplacedAssignment)
.CopyAnnotationsFrom(v.ReplacedAssignment.Left)
.WithAnnotation(v.Variable);
VariableDeclarationStatement varDecl = new VariableDeclarationStatement {
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;
if (es != null) {
@ -102,7 +111,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -102,7 +111,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (VariableDeclarationStatement varDecl in variables) {
string variableName = varDecl.Variables.Single().Name;
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 @@ -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
Statement declarationPoint = null;
@ -127,52 +137,52 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -127,52 +137,52 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
ForStatement forStmt = stmt as ForStatement;
if (forStmt != null && forStmt.Initializers.Count == 1) {
// 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;
}
UsingStatement usingStmt = stmt as UsingStatement;
if (usingStmt != null && usingStmt.ResourceAcquisition is AssignmentExpression) {
// 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;
}
foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) {
DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops);
DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops, ilVariable);
} else if (HasNestedBlocks(child)) {
foreach (BlockStatement nestedSubBlock in child.Children.OfType<BlockStatement>()) {
DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, allowPassIntoLoops);
DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, allowPassIntoLoops, ilVariable);
}
}
}
}
} else {
// 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
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
ExpressionStatement es = declarationPoint as ExpressionStatement;
if (es != null) {
return TryConvertAssignmentExpressionIntoVariableDeclaration(es.Expression, type, variableName);
return TryConvertAssignmentExpressionIntoVariableDeclaration(es.Expression, type, variableName, ilVariable);
}
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;
if (ae != null && ae.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression ident = ae.Left as IdentifierExpression;
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;
}
}

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

@ -386,7 +386,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -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)
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) {
if (field.IsStatic)
continue; // skip static fields
@ -397,8 +397,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -397,8 +397,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
capturedVariableName = capturedVariableName.Substring(10);
EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
currentlyUsedVariableNames.Add(capturedVariableName);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName));
dict[field] = new IdentifierExpression(capturedVariableName);
ILVariable ilVar = new ILVariable
{
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:
@ -414,8 +420,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -414,8 +420,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
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(tuple.Item2);
blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
}
}

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

@ -227,6 +227,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -227,6 +227,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Name = variableName,
Initializer = m1.Get<Expression>("initializer").Single().Detach()
}.CopyAnnotationsFrom(node.Expression)
.WithAnnotation(m1.Get<AstNode>("variable").Single().Annotation<ILVariable>())
}
}.CopyAnnotationsFrom(node);
} else {
@ -382,7 +383,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -382,7 +383,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
VariableName = itemVar.Identifier,
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
};
}.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
if (foreachStatement.InExpression is BaseReferenceExpression) {
foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
}
@ -472,9 +473,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -472,9 +473,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (declarationPoint != loop)
return null;
ForeachStatement foreachStatement = new ForeachStatement();
foreachStatement.VariableType = itemVarDecl.Type.Clone();
foreachStatement.VariableName = itemVar.Identifier;
ForeachStatement foreachStatement = new ForeachStatement
{
VariableType = itemVarDecl.Type.Clone(),
VariableName = itemVar.Identifier,
}.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
BlockStatement body = new BlockStatement();
foreachStatement.EmbeddedStatement = body;
((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement);

2
ICSharpCode.Decompiler/ITextOutput.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler @@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler
void Write(string text);
void WriteLine();
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 MarkFoldEnd();

2
ICSharpCode.Decompiler/PlainTextOutput.cs

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

4
ILSpy/AvalonEdit/TextMarkerService.cs

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

9
ILSpy/TextView/AvalonEditTextOutput.cs

@ -36,6 +36,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -36,6 +36,8 @@ namespace ICSharpCode.ILSpy.TextView
sealed class ReferenceSegment : TextSegment
{
public object Reference;
public bool IsLocal;
public bool IsLocalTarget;
}
/// <summary>
@ -197,17 +199,20 @@ namespace ICSharpCode.ILSpy.TextView @@ -197,17 +199,20 @@ namespace ICSharpCode.ILSpy.TextView
public void WriteDefinition(string text, object definition)
{
WriteIndent();
int start = this.TextLength;
b.Append(text);
int end = 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();
int start = this.TextLength;
b.Append(text);
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)

26
ILSpy/TextView/DecompilerTextView.cs

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

3
ILSpy/TextView/ReferenceElementGenerator.cs

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

Loading…
Cancel
Save