2
// LocalReferenceFinder.cs
5
// Simon Lindgren <simon.n.lindgren@gmail.com>
7
// Copyright (c) 2012 Simon Lindgren
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using System.Collections.Generic;
29
using ICSharpCode.NRefactory.CSharp.Resolver;
30
using ICSharpCode.NRefactory.Semantics;
31
using ICSharpCode.NRefactory.TypeSystem;
32
using ICSharpCode.NRefactory.Utils;
33
using System.Diagnostics;
35
namespace ICSharpCode.NRefactory.CSharp.Refactoring
39
/// Finds references to <see cref="IVariable">IVariables</see>.
42
/// This class is more efficient than <see cref="FindReferences"/>
43
/// if there is already a resolved tree or if multiple searches needs
46
public class LocalReferenceFinder
48
LocalReferenceLocator locator;
50
MultiDictionary<IVariable, ReferenceResult> references = new MultiDictionary<IVariable, ReferenceResult>();
52
HashSet<AstNode> visitedRoots = new HashSet<AstNode>();
54
public LocalReferenceFinder(CSharpAstResolver resolver)
56
locator = new LocalReferenceLocator(resolver, this);
59
public LocalReferenceFinder(BaseRefactoringContext context) : this(context.Resolver)
63
void VisitIfNeccessary(AstNode rootNode)
65
// If any of the parent nodes are recorded as visited,
66
// we don't need to traverse rootNode this time.
67
var tmpRoot = rootNode;
68
while(tmpRoot != null){
69
if (visitedRoots.Contains(tmpRoot))
71
tmpRoot = tmpRoot.Parent;
74
locator.ProccessRoot (rootNode);
78
/// Finds the references to <paramref name="variable"/>.
80
/// <param name='rootNode'>
81
/// Root node for the search.
83
/// <param name='variable'>
84
/// The variable to find references for.
87
/// When a single <see cref="LocalReferenceFinder"/> is reused for multiple
88
/// searches, which references outside of <paramref name="rootNode"/> are
89
/// or are not reported is undefined.
91
public IList<ReferenceResult> FindReferences(AstNode rootNode, IVariable variable)
94
VisitIfNeccessary(rootNode);
95
var lookup = (ILookup<IVariable, ReferenceResult>)references;
96
if (!lookup.Contains(variable))
97
return new List<ReferenceResult>();
98
// Clone the list for thread safety
99
return references[variable].ToList();
103
class LocalReferenceLocator : DepthFirstAstVisitor
105
CSharpAstResolver resolver;
107
LocalReferenceFinder referenceFinder;
109
public LocalReferenceLocator(CSharpAstResolver resolver, LocalReferenceFinder referenceFinder)
111
this.resolver = resolver;
112
this.referenceFinder = referenceFinder;
115
IList<IVariable> processedVariables = new List<IVariable>();
117
public void ProccessRoot (AstNode rootNode)
119
rootNode.AcceptVisitor(this);
120
referenceFinder.visitedRoots.Add(rootNode);
123
protected override void VisitChildren(AstNode node)
125
if (referenceFinder.visitedRoots.Contains(node))
127
var localResolveResult = resolver.Resolve(node) as LocalResolveResult;
128
if (localResolveResult != null && !processedVariables.Contains(localResolveResult.Variable)) {
129
referenceFinder.references.Add(localResolveResult.Variable, new ReferenceResult(node, localResolveResult));
131
processedVariables.Add(localResolveResult.Variable);
132
base.VisitChildren(node);
133
Debug.Assert(processedVariables.Contains(localResolveResult.Variable), "Variable should still be in the list of processed variables.");
134
processedVariables.Remove(localResolveResult.Variable);
136
base.VisitChildren(node);
142
public class ReferenceResult
144
public ReferenceResult (AstNode node, LocalResolveResult resolveResult)
147
ResolveResult = resolveResult;
150
public AstNode Node { get; private set; }
152
public LocalResolveResult ResolveResult { get; private set; }