From 6c2336b58225bff4daa496a9e88ecb6afd8063e9 Mon Sep 17 00:00:00 2001 From: Simon Lindgren Date: Sat, 15 Sep 2012 14:11:23 +0200 Subject: [PATCH] [CodeIssues] Add helper FindReferences(AstNode, IVariable) to BaseRefactoringContext. --- .../ICSharpCode.NRefactory.CSharp.csproj | 1 - .../Refactoring/BaseRefactoringContext.cs | 10 ++++ .../AccessToClosureIssue.cs | 18 ++---- .../ForControlVariableNotModifiedIssue.cs | 36 ++++++------ .../CodeIssues/RedundantAssignmentIssue.cs | 53 ++++++++--------- .../LocalVariableNotUsedIssue.cs | 30 +++++----- .../ParameterNotUsedIssue.cs | 20 +++---- .../VariableNotUsedIssue.cs | 54 ------------------ .../LocalVariableOnlyAssignedIssue.cs | 4 +- .../ParameterOnlyAssignedIssue.cs | 26 ++++----- .../VariableOnlyAssignedIssue.cs | 57 ++++++++++--------- .../Refactoring/LocalReferenceFinder.cs | 49 +++++++++++----- 12 files changed, 160 insertions(+), 198 deletions(-) delete mode 100644 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index ccaca925cb..37925b3369 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -324,7 +324,6 @@ - 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 9f108acfe9..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; @@ -82,7 +81,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring : base (context) { this.title = context.TranslateString (issueProvider.Title); - this.referenceFinder = new LocalReferenceFinder(context); this.issueProvider = issueProvider; } @@ -122,24 +120,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring base.VisitParameterDeclaration (parameterDeclaration); } - LocalReferenceFinder referenceFinder; - - void FindLocalReferences (AstNode rootNode, IVariable variable, FoundReferenceCallback callback) + void CheckVariable(IVariable variable, Statement env) { - referenceFinder.FindReferences(rootNode, variable, callback); - } - - 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 (env, 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 cb259f433c..4f2da17b48 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ForControlVariableNotModifiedIssue.cs @@ -45,12 +45,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring class GatherVisitor : GatherVisitorBase { - LocalReferenceFinder referenceFinder; - public GatherVisitor (BaseRefactoringContext ctx) : base (ctx) { - this.referenceFinder = new LocalReferenceFinder(ctx); } static VariableInitializer GetControlVariable(VariableDeclarationStatement variableDecl, @@ -105,25 +102,24 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (localResolveResult == null) return; + var results = ctx.FindReferences (forStatement, localResolveResult.Variable); var modified = false; - referenceFinder.FindReferences (forStatement, localResolveResult.Variable, - (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; - } + 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; - }); + 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/RedundantAssignmentIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantAssignmentIssue.cs index ebfcee99b2..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,12 +47,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring class GatherVisitor : GatherVisitorBase { - LocalReferenceFinder referenceFinder; - public GatherVisitor (BaseRefactoringContext ctx, SyntaxTree unit) : base (ctx) { - referenceFinder = new LocalReferenceFinder(ctx); } public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration) @@ -91,30 +87,35 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring var references = new HashSet (); var refStatements = new HashSet (); var usedInLambda = false; - referenceFinder.FindReferences (rootStatement, resolveResult.Variable, (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; } - }); + 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/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/LocalVariableNotUsedIssue.cs index c6900afc93..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,24 +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) + #region ICodeIssueProvider implementation + + public System.Collections.Generic.IEnumerable GetIssues(BaseRefactoringContext context) { - return new GatherVisitor (context, this); + return new GatherVisitor (context).GetIssues (); } + #endregion + class GatherVisitor : GatherVisitorBase { - LocalReferenceFinder referenceFinder; - - VariableNotUsedIssue inspector; - - public GatherVisitor (BaseRefactoringContext ctx, VariableNotUsedIssue inspector) + public GatherVisitor (BaseRefactoringContext ctx) : base (ctx) { - this.inspector = inspector; - this.referenceFinder = new LocalReferenceFinder(ctx); } public override void VisitVariableInitializer (VariableInitializer variableInitializer) @@ -68,8 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (resolveResult == null) return; - var b = inspector.FindUsage(referenceFinder, decl.Parent, resolveResult.Variable, variableInitializer); - if (b) + if (IsUsed (decl.Parent, resolveResult.Variable, variableInitializer)) return; AddIssue (variableInitializer.NameToken, ctx.TranslateString ("Remove unused local variable"), @@ -94,11 +93,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (resolveResult == null) return; - if (inspector.FindUsage (referenceFinder, foreachStatement, 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 6cf5bfbc5a..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,25 +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) + #region ICodeIssueProvider implementation + public IEnumerable GetIssues(BaseRefactoringContext context) { - return new GatherVisitor (context, this); + return new GatherVisitor (context).GetIssues (); } + #endregion class GatherVisitor : GatherVisitorBase { - VariableNotUsedIssue inspector; - - LocalReferenceFinder referenceFinder; - - public GatherVisitor (BaseRefactoringContext ctx, VariableNotUsedIssue inspector) + public GatherVisitor (BaseRefactoringContext ctx) : base (ctx) { - this.inspector = inspector; - this.referenceFinder = new LocalReferenceFinder(ctx); } public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) @@ -85,7 +81,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (resolveResult == null) return; - if (inspector.FindUsage (referenceFinder, parameterDeclaration.Parent, 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 9e33c81bd6..0000000000 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/VariableNotUsedIssue.cs +++ /dev/null @@ -1,54 +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.TypeSystem; - -namespace ICSharpCode.NRefactory.CSharp.Refactoring -{ - public abstract class VariableNotUsedIssue : ICodeIssueProvider - { - public IEnumerable GetIssues (BaseRefactoringContext context) - { - var unit = context.RootNode as SyntaxTree; - if (unit == null) - return Enumerable.Empty (); - return GetGatherVisitor(context).GetIssues (); - } - - public bool FindUsage (LocalReferenceFinder referenceFinder, AstNode rootNode, IVariable variable, AstNode declaration) - { - var found = false; - referenceFinder.FindReferences (rootNode, variable, (node, resolveResult) => { - found |= node != declaration; - }); - return found; - } - - internal abstract GatherVisitorBase GetGatherVisitor (BaseRefactoringContext context); - } -} diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs index 0e6eacbc1f..d30d245654 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs @@ -43,11 +43,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring class GatherVisitor : GatherVisitorBase { - LocalReferenceFinder referenceFinder; public GatherVisitor (BaseRefactoringContext ctx) : base (ctx) { - referenceFinder = new LocalReferenceFinder(ctx); } public override void VisitVariableInitializer (VariableInitializer variableInitializer) @@ -61,7 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult; if (resolveResult == null) return; - if (!TestOnlyAssigned (referenceFinder, decl.Parent, 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 4a8abe3732..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,32 +34,33 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring IssueMarker = IssueMarker.Underline)] public class ParameterOnlyAssignedIssue : VariableOnlyAssignedIssue { - internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx) + internal override GatherVisitorBase GetGatherVisitor(BaseRefactoringContext ctx) { - return new GatherVisitor (ctx); + return new GatherVisitor(ctx); } private class GatherVisitor : GatherVisitorBase { - LocalReferenceFinder referenceFinder; - public GatherVisitor (BaseRefactoringContext ctx) + public GatherVisitor(BaseRefactoringContext ctx) : base (ctx) { - referenceFinder = new LocalReferenceFinder(ctx); } - 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 (referenceFinder, parameterDeclaration.Parent, 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 d86c334959..6c6d6820c2 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs @@ -36,46 +36,47 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return GetGatherVisitor (context).GetIssues (); } - protected static bool TestOnlyAssigned (LocalReferenceFinder referenceFinder, AstNode rootNode, IVariable variable) + protected static bool TestOnlyAssigned(BaseRefactoringContext ctx, AstNode rootNode, IVariable variable) { var assignment = false; var nonAssignment = false; - referenceFinder.FindReferences (rootNode, variable, (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; - }); + } + nonAssignment = true; + } return assignment && !nonAssignment; } diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs index 04de48afab..0cde50ada6 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/LocalReferenceFinder.cs @@ -29,7 +29,6 @@ using System.Linq; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; -using System; using ICSharpCode.NRefactory.Utils; using System.Diagnostics; @@ -48,7 +47,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { LocalReferenceLocator locator; - MultiDictionary> references = new MultiDictionary>(); + MultiDictionary references = new MultiDictionary(); + + HashSet visitedRoots = new HashSet(); public LocalReferenceFinder(CSharpAstResolver resolver) { @@ -59,8 +60,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { } - HashSet visitedRoots = new HashSet(); - void VisitIfNeccessary(AstNode rootNode) { // If any of the parent nodes are recorded as visited, @@ -72,8 +71,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring tmpRoot = tmpRoot.Parent; } - rootNode.AcceptVisitor(locator); - visitedRoots.Add(rootNode); + locator.ProccessRoot (rootNode); } /// @@ -93,15 +91,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring /// searches, which references outside of are /// or are not reported is undefined. /// - public void FindReferences (AstNode rootNode, IVariable variable, FoundReferenceCallback action) + public IList FindReferences(AstNode rootNode, IVariable variable) { - VisitIfNeccessary(rootNode); - var lookup = (ILookup>)references; - if (!lookup.Contains(variable)) - return; - var iList = references[variable]; - foreach (var reference in iList) { - action(reference.Item1, reference.Item2); + 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(); } } @@ -119,11 +117,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring 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, Tuple.Create(node, localResolveResult)); + referenceFinder.references.Add(localResolveResult.Variable, new ReferenceResult(node, localResolveResult)); processedVariables.Add(localResolveResult.Variable); base.VisitChildren(node); @@ -135,4 +141,17 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring } } } + + 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; } + } }