diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
index d1517435ec..37925b3369 100644
--- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
+++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
@@ -324,7 +324,6 @@
-
@@ -503,6 +502,7 @@
+
@@ -534,4 +534,4 @@
-
\ No newline at end of file
+
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
index 32a84ba23e..6f4ccfc720 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
@@ -36,6 +36,7 @@ using ICSharpCode.NRefactory.Editor;
using System.ComponentModel.Design;
using ICSharpCode.NRefactory.CSharp.Analysis;
using ICSharpCode.NRefactory.Utils;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -87,6 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
this.resolver = resolver;
this.cancellationToken = cancellationToken;
+ this.referenceFinder = new LocalReferenceFinder(resolver);
}
@@ -161,6 +163,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
return new CompositeFormatStringParser().Parse(source);
}
+
+ LocalReferenceFinder referenceFinder;
+
+ public IList FindReferences(AstNode rootNode, IVariable variable)
+ {
+ return referenceFinder.FindReferences(rootNode, variable);
+ }
+
#endregion
///
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
index c54af78854..d797d320dd 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
@@ -27,7 +27,6 @@
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp.Analysis;
-using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
@@ -35,7 +34,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public abstract class AccessToClosureIssue : ICodeIssueProvider
{
- static FindReferences refFinder = new FindReferences ();
static ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
public string Title
@@ -75,7 +73,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
- SyntaxTree unit;
string title;
AccessToClosureIssue issueProvider;
@@ -84,7 +81,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
: base (context)
{
this.title = context.TranslateString (issueProvider.Title);
- this.unit = unit;
this.issueProvider = issueProvider;
}
@@ -124,23 +120,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
base.VisitParameterDeclaration (parameterDeclaration);
}
- void FindLocalReferences (IVariable variable, FoundReferenceCallback callback)
+ void CheckVariable(IVariable variable, Statement env)
{
- refFinder.FindLocalReferences (variable, ctx.UnresolvedFile, unit, ctx.Compilation, callback,
- ctx.CancellationToken);
- }
-
- void CheckVariable (IVariable variable, Statement env)
- {
- if (!issueProvider.IsTargetVariable (variable))
+ if (!issueProvider.IsTargetVariable(variable))
return;
var root = new Environment (env, env);
var envLookup = new Dictionary ();
envLookup [env] = root;
- FindLocalReferences (variable, (astNode, resolveResult) =>
- AddNode (envLookup, new Node (astNode, issueProvider.GetNodeKind (astNode))));
+ foreach (var result in ctx.FindReferences(env, variable)) {
+ AddNode(envLookup, new Node(result.Node, issueProvider.GetNodeKind(result.Node)));
+ }
root.SortChildren ();
CollectIssues (root, variable.Name);
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs
index 78fa121783..4f2da17b48 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs
@@ -26,7 +26,6 @@
using System.Collections.Generic;
using System.Linq;
-using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.Semantics;
@@ -39,24 +38,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IssueMarker = IssueMarker.Underline)]
public class ForControlVariableNotModifiedIssue : ICodeIssueProvider
{
- static FindReferences refFinder = new FindReferences ();
-
public IEnumerable GetIssues (BaseRefactoringContext context)
{
- var unit = context.RootNode as SyntaxTree;
- if (unit == null)
- return Enumerable.Empty ();
-
- return new GatherVisitor (context, unit).GetIssues ();
+ return new GatherVisitor (context).GetIssues ();
}
class GatherVisitor : GatherVisitorBase
{
- SyntaxTree unit;
- public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
- this.unit = unit;
}
static VariableInitializer GetControlVariable(VariableDeclarationStatement variableDecl,
@@ -111,25 +102,24 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (localResolveResult == null)
return;
+ var results = ctx.FindReferences (forStatement, localResolveResult.Variable);
var modified = false;
- refFinder.FindLocalReferences (localResolveResult.Variable, ctx.UnresolvedFile, unit, ctx.Compilation,
- (node, resolveResult) =>
- {
- if (modified)
- return;
-
- var unary = node.Parent as UnaryOperatorExpression;
- if (unary != null && unary.Expression == node) {
- modified = unary.Operator == UnaryOperatorType.Decrement ||
- unary.Operator == UnaryOperatorType.PostDecrement ||
- unary.Operator == UnaryOperatorType.Increment ||
- unary.Operator == UnaryOperatorType.PostIncrement;
- return;
- }
-
- var assignment = node.Parent as AssignmentExpression;
- modified = assignment != null && assignment.Left == node;
- }, ctx.CancellationToken);
+ foreach (var result in results) {
+ if (modified)
+ break;
+ var node = result.Node;
+ var unary = node.Parent as UnaryOperatorExpression;
+ if (unary != null && unary.Expression == node) {
+ modified = unary.Operator == UnaryOperatorType.Decrement ||
+ unary.Operator == UnaryOperatorType.PostDecrement ||
+ unary.Operator == UnaryOperatorType.Increment ||
+ unary.Operator == UnaryOperatorType.PostIncrement;
+ continue;
+ }
+
+ var assignment = node.Parent as AssignmentExpression;
+ modified = assignment != null && assignment.Left == node;
+ }
if (!modified)
AddIssue (controlVariable.NameToken,
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs
index ae7778b53f..a9bd959e22 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/FormatStringIssues/FormatStringIssue.cs
@@ -54,6 +54,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void VisitInvocationExpression(InvocationExpression invocationExpression)
{
base.VisitInvocationExpression(invocationExpression);
+
+ // Speed up the inspector by discarding some invocations early
+ var hasEligibleArgument = invocationExpression.Arguments.Any(argument => {
+ var primitiveArg = argument as PrimitiveExpression;
+ return primitiveArg != null && primitiveArg.Value is string;
+ });
+ if (!hasEligibleArgument)
+ return;
+
var invocationResolveResult = context.Resolve(invocationExpression) as CSharpInvocationResolveResult;
if (invocationResolveResult == null)
return;
@@ -65,7 +74,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
}
var primitiveArgument = formatArgument as PrimitiveExpression;
- if (primitiveArgument == null || !(primitiveArgument.Value is String))
+ if (primitiveArgument == null || !(primitiveArgument.Value is string))
return;
var format = (string)primitiveArgument.Value;
var parsingResult = context.ParseFormatString(format);
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
index 6a39b2de52..dc7ab72d0f 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
@@ -58,9 +58,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression)
{
- var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult;
- if (type == null)
- return;
var parameters = objectCreateExpression.Arguments;
if (parameters.Count != 2)
return;
@@ -69,6 +66,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (firstParam == null || firstParam.Value.GetType() != typeof(string) ||
secondParam == null || firstParam.Value.GetType() != typeof(string))
return;
+ var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult;
+ if (type == null)
+ return;
var leftLength = (firstParam.Value as string).Length;
var rightLength = (secondParam.Value as string).Length;
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MultipleEnumerationIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MultipleEnumerationIssue.cs
index 5312964071..9ab54cd39e 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MultipleEnumerationIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MultipleEnumerationIssue.cs
@@ -42,11 +42,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public IEnumerable GetIssues (BaseRefactoringContext context)
{
- var unit = context.RootNode as SyntaxTree;
- if (unit == null)
- return Enumerable.Empty ();
-
- return new GatherVisitor (context, unit).GetIssues ();
+ return new GatherVisitor (context).GetIssues ();
}
class AnalysisStatementCollector : DepthFirstAstVisitor
@@ -110,15 +106,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
- static FindReferences refFinder = new FindReferences ();
-
- SyntaxTree unit;
HashSet collectedAstNodes;
- public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
- this.unit = unit;
this.collectedAstNodes = new HashSet ();
}
@@ -139,7 +131,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
base.VisitParameterDeclaration (parameterDeclaration);
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
- CollectIssues (parameterDeclaration, resolveResult);
+ CollectIssues (parameterDeclaration, parameterDeclaration.Parent, resolveResult);
}
public override void VisitVariableInitializer (VariableInitializer variableInitializer)
@@ -147,7 +139,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
base.VisitVariableInitializer (variableInitializer);
var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult;
- CollectIssues (variableInitializer, resolveResult);
+ CollectIssues (variableInitializer, variableInitializer.Parent.Parent, resolveResult);
}
static bool IsAssignment (AstNode node)
@@ -200,42 +192,42 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
HashSet collectedNodes;
Dictionary nodeDegree; // number of enumerations a node can reach
- void FindReferences (AstNode variableDecl, IVariable variable)
+ void FindReferences (AstNode variableDecl, AstNode rootNode, IVariable variable)
{
references = new HashSet ();
refStatements = new HashSet ();
lambdaExpressions = new HashSet ();
- refFinder.FindLocalReferences (variable, ctx.UnresolvedFile, unit, ctx.Compilation,
- (astNode, resolveResult) => {
- if (astNode == variableDecl)
- return;
-
- var parent = astNode.Parent;
- while (!(parent == null || parent is Statement || parent is LambdaExpression))
- parent = parent.Parent;
- if (parent == null)
- return;
-
- // lambda expression with expression body, should be analyzed separately
- var expr = parent as LambdaExpression;
- if (expr != null) {
- if (IsAssignment (astNode) || IsEnumeration (astNode)) {
- references.Add (astNode);
- lambdaExpressions.Add (expr);
- }
- return;
- }
+ foreach (var result in ctx.FindReferences (rootNode, variable)) {
+ var astNode = result.Node;
+ if (astNode == variableDecl)
+ continue;
- var statement = (Statement)parent;
+ var parent = astNode.Parent;
+ while (!(parent == null || parent is Statement || parent is LambdaExpression))
+ parent = parent.Parent;
+ if (parent == null)
+ continue;
+
+ // lambda expression with expression body, should be analyzed separately
+ var expr = parent as LambdaExpression;
+ if (expr != null) {
if (IsAssignment (astNode) || IsEnumeration (astNode)) {
references.Add (astNode);
- refStatements.Add (statement);
+ lambdaExpressions.Add (expr);
}
- }, ctx.CancellationToken);
+ continue;
+ }
+
+ if (IsAssignment (astNode) || IsEnumeration (astNode)) {
+ references.Add (astNode);
+ var statement = (Statement)parent;
+ refStatements.Add (statement);
+ }
+ }
}
- void CollectIssues (AstNode variableDecl, LocalResolveResult resolveResult)
+ void CollectIssues (AstNode variableDecl, AstNode rootNode, LocalResolveResult resolveResult)
{
if (resolveResult == null)
return;
@@ -246,7 +238,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
typeDef.KnownTypeCode != KnownTypeCode.IEnumerableOfT))
return;
- FindReferences (variableDecl, resolveResult.Variable);
+ FindReferences (variableDecl, rootNode, resolveResult.Variable);
var statements = AnalysisStatementCollector.Collect (variableDecl);
foreach (var statement in statements) {
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/OptionalParameterCouldBeSkippedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/OptionalParameterCouldBeSkippedIssue.cs
index 6c7f378a4d..792ac2fa9e 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/OptionalParameterCouldBeSkippedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/OptionalParameterCouldBeSkippedIssue.cs
@@ -66,15 +66,24 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
(invocation, args) => new InvocationExpression(invocation.Target.Clone(), args));
}
- void CheckMethodCall (T node, IEnumerable arguments, Func, T> generateReplacement) where T: AstNode
+ void CheckMethodCall (T node, IEnumerable args, Func, T> generateReplacement) where T: AstNode
{
+ // The first two checks are unnecessary, but eliminates the majority of calls early,
+ // improving performance.
+ var arguments = args.ToArray();
+ if (arguments.Length == 0)
+ return;
+ var lastArg = arguments[arguments.Length - 1];
+ if (!(lastArg is PrimitiveExpression || lastArg is NamedArgumentExpression))
+ return;
+
var invocationResolveResult = ctx.Resolve(node) as CSharpInvocationResolveResult;
if (invocationResolveResult == null)
return;
string actionMessage = ctx.TranslateString("Remove redundant arguments");
- var redundantArguments = GetRedundantArguments(arguments.ToArray(), invocationResolveResult);
+ var redundantArguments = GetRedundantArguments(arguments, invocationResolveResult);
var action = new CodeAction(actionMessage, script => {
var newArgumentList = arguments
.Where(arg => !redundantArguments.Contains(arg))
@@ -84,7 +93,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
});
var issueMessage = ctx.TranslateString("Argument is identical to the default value");
var lastPositionalArgument = redundantArguments.FirstOrDefault(expression => !(expression is NamedArgumentExpression));
- bool hasNamedArguments = false;
foreach (var argument in redundantArguments) {
var localArgument = argument;
@@ -100,7 +108,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var newInvocation = generateReplacement(node, newArgumentList);
script.Replace(node, newInvocation);
}));
- hasNamedArguments = true;
} else {
var title = ctx.TranslateString("Remove this and the following positional arguments");
actions.Add(new CodeAction(title, script => {
@@ -116,11 +123,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
}
- IEnumerable GetRedundantArguments(Expression[] arguments, CSharpInvocationResolveResult invocationResolveResult)
+ IList GetRedundantArguments(Expression[] arguments, CSharpInvocationResolveResult invocationResolveResult)
{
var argumentToParameterMap = invocationResolveResult.GetArgumentToParameterMap();
var resolvedParameters = invocationResolveResult.Member.Parameters;
+ IList redundantArguments = new List();
+
for (int i = arguments.Length - 1; i >= 0; i--) {
var parameterIndex = argumentToParameterMap[i];
if (parameterIndex == -1)
@@ -141,7 +150,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
// Stop here since any arguments before this one has to be there
// to enable the passing of this argument
break;
- yield return argument;
+ redundantArguments.Add(argument);
} else if (argument is NamedArgumentExpression) {
var expression = ((NamedArgumentExpression)argument).Expression as PrimitiveExpression;
if (expression == null)
@@ -150,12 +159,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (expressionResolveResult == null || parameter.ConstantValue != expressionResolveResult.ConstantValue)
// continue, since there can still be more arguments that are redundant
continue;
- yield return argument;
+ redundantArguments.Add(argument);
} else {
// This is a non-constant positional argument => no more redundancies are possible
break;
}
}
+ return redundantArguments;
}
}
}
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs
index 3effea84aa..96d56b23bd 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs
@@ -26,7 +26,6 @@
using System.Collections.Generic;
using System.Linq;
-using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
@@ -48,14 +47,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
- static FindReferences refFinder = new FindReferences ();
-
- SyntaxTree unit;
-
public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
: base (ctx)
{
- this.unit = unit;
}
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
@@ -89,34 +83,39 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
if (rootStatement == null || resolveResult == null)
return;
+
var references = new HashSet ();
var refStatements = new HashSet ();
var usedInLambda = false;
- refFinder.FindLocalReferences (resolveResult.Variable, ctx.UnresolvedFile, unit, ctx.Compilation,
- (astNode, rr) => {
- if (usedInLambda || astNode == variableDecl)
- return;
-
- var parent = astNode.Parent;
- while (!(parent == null || parent is Statement || parent is LambdaExpression))
- parent = parent.Parent;
- if (parent == null)
- return;
-
- var statement = parent as Statement;
- if (statement != null) {
- references.Add (astNode);
- refStatements.Add (statement);
- }
+ var results = ctx.FindReferences (rootStatement, resolveResult.Variable);
+ foreach (var result in results) {
+ var node = result.Node;
+ if (node == variableDecl)
+ continue;
+
+ var parent = node.Parent;
+ while (!(parent == null || parent is Statement || parent is LambdaExpression))
+ parent = parent.Parent;
+ if (parent == null)
+ continue;
+
+ var statement = parent as Statement;
+ if (statement != null) {
+ references.Add (node);
+ refStatements.Add (statement);
+ }
- while (parent != null && parent != rootStatement) {
- if (parent is LambdaExpression || parent is AnonymousMethodExpression) {
- usedInLambda = true;
- break;
- }
- parent = parent.Parent;
+ while (parent != null && parent != rootStatement) {
+ if (parent is LambdaExpression || parent is AnonymousMethodExpression) {
+ usedInLambda = true;
+ break;
}
- }, ctx.CancellationToken);
+ parent = parent.Parent;
+ }
+ if (usedInLambda) {
+ break;
+ }
+ }
// stop analyzing if the variable is used in any lambda expression or anonymous method
if (usedInLambda)
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs
index 8d7df7b841..ef39599247 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantToStringIssue.cs
@@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void CheckExpressionInAutoCallContext(Expression expression)
{
- if (expression is InvocationExpression) {
+ if (expression is InvocationExpression && !processedNodes.Contains(expression)) {
CheckInvocationInAutoCallContext((InvocationExpression)expression);
}
}
@@ -75,12 +75,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (memberExpression == null) {
return;
}
- var resolveResult = ctx.Resolve(invocationExpression) as CSharpInvocationResolveResult;
- if (resolveResult == null) {
+ if (memberExpression.MemberName != "ToString" || invocationExpression.Arguments.Any ()) {
return;
}
- var member = resolveResult.Member;
- if (member.Name != "ToString" || member.Parameters.Count != 0) {
+
+ var resolveResult = ctx.Resolve(invocationExpression) as CSharpInvocationResolveResult;
+ if (resolveResult == null) {
return;
}
AddRedundantToStringIssue(memberExpression, invocationExpression);
@@ -88,9 +88,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void AddRedundantToStringIssue(MemberReferenceExpression memberExpression, InvocationExpression invocationExpression)
{
- if (processedNodes.Contains(invocationExpression)) {
- return;
- }
+ // Simon Lindgren 2012-09-14: Previously there was a check here to see if the node had already been processed
+ // This has been moved out to the callers, to check it earlier for a 30-40% run time reduction
processedNodes.Add(invocationExpression);
AddIssue(memberExpression.DotToken.StartLocation, invocationExpression.RParToken.EndLocation,
@@ -176,7 +175,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void CheckTargetedObject(InvocationExpression invocationExpression, IType type, IMember member)
{
var memberExpression = invocationExpression.Target as MemberReferenceExpression;
- if (memberExpression != null) {
+ if (memberExpression != null && !processedNodes.Contains(invocationExpression)) {
if (type.IsKnownType(KnownTypeCode.String) && member.Name == "ToString") {
AddRedundantToStringIssue(memberExpression, invocationExpression);
}
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceEqualsCalledWithValueTypeIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceEqualsCalledWithValueTypeIssue.cs
index 24f6671fd5..f9d6571491 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceEqualsCalledWithValueTypeIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceEqualsCalledWithValueTypeIssue.cs
@@ -54,6 +54,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
base.VisitInvocationExpression (invocationExpression);
+ // Quickly determine if this invocation is eligible to speed up the inspector
+ var nameToken = invocationExpression.Target.GetChildByRole(Roles.Identifier);
+ if (nameToken.Name != "ReferenceEquals")
+ return;
+
var resolveResult = ctx.Resolve (invocationExpression) as InvocationResolveResult;
if (resolveResult == null ||
resolveResult.Member.DeclaringTypeDefinition == null ||
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
index 6a35677b6a..8d0412c412 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
@@ -45,13 +45,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
- readonly BaseRefactoringContext context;
-
- readonly FindReferences findRef = new FindReferences();
-
public GatherVisitor(BaseRefactoringContext context, ValueParameterUnusedIssue inspector) : base (context)
{
- this.context = context;
}
public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
@@ -77,22 +72,22 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (!IsEligible(body))
return;
- var localResolveResult = context.GetResolverStateBefore(body)
+ var localResolveResult = ctx.GetResolverStateBefore(body)
.LookupSimpleNameOrTypeName("value", new List(), NameLookupMode.Expression) as LocalResolveResult;
if (localResolveResult == null)
return;
- var variable = localResolveResult.Variable;
bool referenceFound = false;
- var syntaxTree = (SyntaxTree)context.RootNode;
- findRef.FindLocalReferences(variable, context.UnresolvedFile, syntaxTree, context.Compilation, (n, entity) => {
- if (n.StartLocation >= body.StartLocation && n.EndLocation <= body.EndLocation) {
+ foreach (var result in ctx.FindReferences (body, localResolveResult.Variable)) {
+ var node = result.Node;
+ if (node.StartLocation >= body.StartLocation && node.EndLocation <= body.EndLocation) {
referenceFound = true;
+ break;
}
- }, CancellationToken.None);
+ }
if(!referenceFound)
- AddIssue(anchor, context.TranslateString("The " + accessorName + " does not use the 'value' parameter"));
+ AddIssue(anchor, ctx.TranslateString("The " + accessorName + " does not use the 'value' parameter"));
}
static bool IsEligible(BlockStatement body)
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs
index f6645bf9ef..4eebbc615a 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs
@@ -25,6 +25,8 @@
// THE SOFTWARE.
using ICSharpCode.NRefactory.Semantics;
+using System.Linq;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -33,21 +35,22 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
Category = IssueCategories.Redundancies,
Severity = Severity.Warning,
IssueMarker = IssueMarker.GrayOut)]
- public class LocalVariableNotUsedIssue : VariableNotUsedIssue
+ public class LocalVariableNotUsedIssue : ICodeIssueProvider
{
- internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context, SyntaxTree unit)
+ #region ICodeIssueProvider implementation
+
+ public System.Collections.Generic.IEnumerable GetIssues(BaseRefactoringContext context)
{
- return new GatherVisitor (context, unit);
+ return new GatherVisitor (context).GetIssues ();
}
+ #endregion
+
class GatherVisitor : GatherVisitorBase
{
- SyntaxTree unit;
-
- public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
- this.unit = unit;
}
public override void VisitVariableInitializer (VariableInitializer variableInitializer)
@@ -65,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolveResult == null)
return;
- if (FindUsage (ctx, unit, resolveResult.Variable, variableInitializer))
+ if (IsUsed (decl.Parent, resolveResult.Variable, variableInitializer))
return;
AddIssue (variableInitializer.NameToken, ctx.TranslateString ("Remove unused local variable"),
@@ -90,11 +93,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (resolveResult == null)
return;
- if (FindUsage (ctx, unit, resolveResult.Variable, foreachStatement.VariableNameToken))
+ if (IsUsed (foreachStatement, resolveResult.Variable, foreachStatement.VariableNameToken))
return;
AddIssue (foreachStatement.VariableNameToken, ctx.TranslateString ("Local variable is never used"));
}
+
+ bool IsUsed(AstNode rootNode, IVariable variable, AstNode variableNode)
+ {
+ return ctx.FindReferences(rootNode, variable).Any(result => result.Node != variableNode);
+ }
}
}
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
index d8b24b8b56..cb9a51d76d 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
@@ -27,6 +27,7 @@
using ICSharpCode.NRefactory.Semantics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -35,22 +36,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
Category = IssueCategories.Redundancies,
Severity = Severity.Warning,
IssueMarker = IssueMarker.GrayOut)]
- public class ParameterNotUsedIssue : VariableNotUsedIssue
+ public class ParameterNotUsedIssue : ICodeIssueProvider
{
-
- internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context, SyntaxTree unit)
+ #region ICodeIssueProvider implementation
+ public IEnumerable GetIssues(BaseRefactoringContext context)
{
- return new GatherVisitor (context, unit);
+ return new GatherVisitor (context).GetIssues ();
}
+ #endregion
class GatherVisitor : GatherVisitorBase
{
- SyntaxTree unit;
-
- public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
- this.unit = unit;
}
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
@@ -81,7 +80,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
if (resolveResult == null)
return;
- if (FindUsage (ctx, unit, resolveResult.Variable, parameterDeclaration))
+
+ if (ctx.FindReferences (parameterDeclaration.Parent, resolveResult.Variable).Any(r => r.Node != parameterDeclaration))
return;
AddIssue (parameterDeclaration.NameToken, ctx.TranslateString ("Parameter is never used"));
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs
deleted file mode 100644
index c00869dddf..0000000000
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// VariableNotUsedIssue.cs
-//
-// Author:
-// Mansheng Yang
-//
-// Copyright (c) 2012 Mansheng Yang
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System.Collections.Generic;
-using System.Linq;
-using ICSharpCode.NRefactory.CSharp.Resolver;
-using ICSharpCode.NRefactory.TypeSystem;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- public abstract class VariableNotUsedIssue : ICodeIssueProvider
- {
- static FindReferences refFinder = new FindReferences ();
-
- public IEnumerable GetIssues (BaseRefactoringContext context)
- {
- var unit = context.RootNode as SyntaxTree;
- if (unit == null)
- return Enumerable.Empty ();
- return GetGatherVisitor(context, unit).GetIssues ();
- }
-
- protected static bool FindUsage (BaseRefactoringContext context, SyntaxTree unit, IVariable variable,
- AstNode declaration)
- {
- var found = false;
- refFinder.FindLocalReferences (variable, context.UnresolvedFile, unit, context.Compilation,
- (node, resolveResult) =>
- {
- found = found || node != declaration;
- }, context.CancellationToken);
- return found;
- }
-
- internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context, SyntaxTree unit);
- }
-}
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
index c619d03157..d30d245654 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
@@ -36,19 +36,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IssueMarker = IssueMarker.Underline)]
public class LocalVariableOnlyAssignedIssue : VariableOnlyAssignedIssue
{
- internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx)
{
- return new GatherVisitor (ctx, unit);
+ return new GatherVisitor (ctx);
}
class GatherVisitor : GatherVisitorBase
{
- SyntaxTree unit;
-
- public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
- this.unit = unit;
}
public override void VisitVariableInitializer (VariableInitializer variableInitializer)
@@ -62,7 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult;
if (resolveResult == null)
return;
- if (!TestOnlyAssigned (ctx, unit, resolveResult.Variable))
+ if (!TestOnlyAssigned (ctx, decl.Parent, resolveResult.Variable))
return;
AddIssue (variableInitializer.NameToken,
ctx.TranslateString ("Local variable is assigned by its value is never used"));
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
index bea8b1599e..0d5ab0c8da 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
@@ -23,7 +23,6 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
@@ -35,33 +34,33 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IssueMarker = IssueMarker.Underline)]
public class ParameterOnlyAssignedIssue : VariableOnlyAssignedIssue
{
- internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ internal override GatherVisitorBase GetGatherVisitor(BaseRefactoringContext ctx)
{
- return new GatherVisitor (ctx, unit);
+ return new GatherVisitor(ctx);
}
private class GatherVisitor : GatherVisitorBase
{
- SyntaxTree unit;
-
- public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit)
+ public GatherVisitor(BaseRefactoringContext ctx)
: base (ctx)
{
- this.unit = unit;
}
- public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
+ public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration)
{
- base.VisitParameterDeclaration (parameterDeclaration);
+ base.VisitParameterDeclaration(parameterDeclaration);
- var resolveResult = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
+ var resolveResult = ctx.Resolve(parameterDeclaration) as LocalResolveResult;
if (resolveResult == null)
return;
- if (parameterDeclaration.ParameterModifier == ParameterModifier.Out || parameterDeclaration.ParameterModifier == ParameterModifier.Ref
- || !TestOnlyAssigned (ctx, unit, resolveResult.Variable))
+
+ var parameterModifier = parameterDeclaration.ParameterModifier;
+ if (parameterModifier == ParameterModifier.Out || parameterModifier == ParameterModifier.Ref ||
+ !TestOnlyAssigned(ctx, parameterDeclaration.Parent, resolveResult.Variable)) {
return;
- AddIssue (parameterDeclaration.NameToken,
- ctx.TranslateString ("Parameter is assigned by its value is never used"));
+ }
+ AddIssue(parameterDeclaration.NameToken,
+ ctx.TranslateString("Parameter is assigned by its value is never used"));
}
}
}
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
index a4b965ed69..6c6d6820c2 100644
--- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
@@ -25,68 +25,61 @@
// THE SOFTWARE.
using System.Collections.Generic;
-using System.Linq;
-using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public abstract class VariableOnlyAssignedIssue : ICodeIssueProvider
{
- static FindReferences refFinder = new FindReferences ();
public IEnumerable GetIssues (BaseRefactoringContext context)
{
- var unit = context.RootNode as SyntaxTree;
- if (unit == null)
- return Enumerable.Empty ();
- return GetGatherVisitor (context, unit).GetIssues ();
+ return GetGatherVisitor (context).GetIssues ();
}
- protected static bool TestOnlyAssigned (BaseRefactoringContext ctx, SyntaxTree unit, IVariable variable)
+ protected static bool TestOnlyAssigned(BaseRefactoringContext ctx, AstNode rootNode, IVariable variable)
{
var assignment = false;
var nonAssignment = false;
- refFinder.FindLocalReferences (variable, ctx.UnresolvedFile, unit, ctx.Compilation,
- (node, resolveResult) =>
- {
- if (node is ParameterDeclaration)
- return;
+ foreach (var result in ctx.FindReferences(rootNode, variable)) {
+ var node = result.Node;
+ if (node is ParameterDeclaration)
+ continue;
- if (node is VariableInitializer) {
- if (!(node as VariableInitializer).Initializer.IsNull)
- assignment = true;
- return;
- }
+ if (node is VariableInitializer) {
+ if (!(node as VariableInitializer).Initializer.IsNull)
+ assignment = true;
+ continue;
+ }
- if (node is IdentifierExpression) {
- var parent = node.Parent;
- if (parent is AssignmentExpression) {
- if (((AssignmentExpression)parent).Left == node) {
- assignment = true;
- return;
- }
- } else if (parent is UnaryOperatorExpression) {
- var op = ((UnaryOperatorExpression)parent).Operator;
- switch (op) {
+ if (node is IdentifierExpression) {
+ var parent = node.Parent;
+ if (parent is AssignmentExpression) {
+ if (((AssignmentExpression)parent).Left == node) {
+ assignment = true;
+ continue;
+ }
+ } else if (parent is UnaryOperatorExpression) {
+ var op = ((UnaryOperatorExpression)parent).Operator;
+ switch (op) {
case UnaryOperatorType.Increment:
case UnaryOperatorType.PostIncrement:
case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostDecrement:
assignment = true;
- return;
- }
- } else if (parent is DirectionExpression) {
- if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) {
- assignment = true;
- return;
- }
+ continue;
+ }
+ } else if (parent is DirectionExpression) {
+ if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) {
+ assignment = true;
+ continue;
}
}
- nonAssignment = true;
- }, ctx.CancellationToken);
+ }
+ nonAssignment = true;
+ }
return assignment && !nonAssignment;
}
- internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit);
+ internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx);
}
}
diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs
new file mode 100644
index 0000000000..0cde50ada6
--- /dev/null
+++ b/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs
@@ -0,0 +1,157 @@
+//
+// LocalReferenceFinder.cs
+//
+// Author:
+// Simon Lindgren
+//
+// Copyright (c) 2012 Simon Lindgren
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Collections.Generic;
+using System.Linq;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.NRefactory.Utils;
+using System.Diagnostics;
+
+namespace ICSharpCode.NRefactory.CSharp.Refactoring
+{
+
+ ///
+ /// Finds references to IVariables.
+ ///
+ ///
+ /// This class is more efficient than
+ /// if there is already a resolved tree or if multiple searches needs
+ /// to be performed.
+ ///
+ public class LocalReferenceFinder
+ {
+ LocalReferenceLocator locator;
+
+ MultiDictionary references = new MultiDictionary();
+
+ HashSet visitedRoots = new HashSet();
+
+ public LocalReferenceFinder(CSharpAstResolver resolver)
+ {
+ locator = new LocalReferenceLocator(resolver, this);
+ }
+
+ public LocalReferenceFinder(BaseRefactoringContext context) : this(context.Resolver)
+ {
+ }
+
+ void VisitIfNeccessary(AstNode rootNode)
+ {
+ // If any of the parent nodes are recorded as visited,
+ // we don't need to traverse rootNode this time.
+ var tmpRoot = rootNode;
+ while(tmpRoot != null){
+ if (visitedRoots.Contains(tmpRoot))
+ return;
+ tmpRoot = tmpRoot.Parent;
+ }
+
+ locator.ProccessRoot (rootNode);
+ }
+
+ ///
+ /// Finds the references to .
+ ///
+ ///
+ /// Root node for the search.
+ ///
+ ///
+ /// The variable to find references for.
+ ///
+ ///
+ /// Will be called for each reference found.
+ ///
+ ///
+ /// When a single is reused for multiple
+ /// searches, which references outside of are
+ /// or are not reported is undefined.
+ ///
+ public IList FindReferences(AstNode rootNode, IVariable variable)
+ {
+ lock (locator) {
+ VisitIfNeccessary(rootNode);
+ var lookup = (ILookup)references;
+ if (!lookup.Contains(variable))
+ return new List();
+ // Clone the list for thread safety
+ return references[variable].ToList();
+ }
+ }
+
+ class LocalReferenceLocator : DepthFirstAstVisitor
+ {
+ CSharpAstResolver resolver;
+
+ LocalReferenceFinder referenceFinder;
+
+ public LocalReferenceLocator(CSharpAstResolver resolver, LocalReferenceFinder referenceFinder)
+ {
+ this.resolver = resolver;
+ this.referenceFinder = referenceFinder;
+ }
+
+ IList processedVariables = new List();
+
+ public void ProccessRoot (AstNode rootNode)
+ {
+ rootNode.AcceptVisitor(this);
+ referenceFinder.visitedRoots.Add(rootNode);
+ }
+
+ protected override void VisitChildren(AstNode node)
+ {
+ if (referenceFinder.visitedRoots.Contains(node))
+ return;
+ var localResolveResult = resolver.Resolve(node) as LocalResolveResult;
+ if (localResolveResult != null && !processedVariables.Contains(localResolveResult.Variable)) {
+ referenceFinder.references.Add(localResolveResult.Variable, new ReferenceResult(node, localResolveResult));
+
+ processedVariables.Add(localResolveResult.Variable);
+ base.VisitChildren(node);
+ Debug.Assert(processedVariables.Contains(localResolveResult.Variable), "Variable should still be in the list of processed variables.");
+ processedVariables.Remove(localResolveResult.Variable);
+ } else {
+ base.VisitChildren(node);
+ }
+ }
+ }
+ }
+
+ public class ReferenceResult
+ {
+ public ReferenceResult (AstNode node, LocalResolveResult resolveResult)
+ {
+ Node = node;
+ ResolveResult = resolveResult;
+ }
+
+ public AstNode Node { get; private set; }
+
+ public LocalResolveResult ResolveResult { get; private set; }
+ }
+}