Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Refactoring/LocalReferenceFinder.cs @ 12966

Last change on this file since 12966 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 5.0 KB
Line 
1//
2// LocalReferenceFinder.cs
3//
4// Author:
5//       Simon Lindgren <simon.n.lindgren@gmail.com>
6//
7// Copyright (c) 2012 Simon Lindgren
8//
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:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
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
25// THE SOFTWARE.
26
27using System.Collections.Generic;
28using System.Linq;
29using ICSharpCode.NRefactory.CSharp.Resolver;
30using ICSharpCode.NRefactory.Semantics;
31using ICSharpCode.NRefactory.TypeSystem;
32using ICSharpCode.NRefactory.Utils;
33using System.Diagnostics;
34
35namespace ICSharpCode.NRefactory.CSharp.Refactoring
36{
37
38  /// <summary>
39  /// Finds references to <see cref="IVariable">IVariables</see>.
40  /// </summary>
41  /// <remarks>
42  /// This class is more efficient than <see cref="FindReferences"/>
43  /// if there is already a resolved tree or if multiple searches needs
44  /// to be performed.
45  /// </remarks>   
46  public class LocalReferenceFinder
47  {
48    LocalReferenceLocator locator;
49
50    MultiDictionary<IVariable, ReferenceResult> references = new MultiDictionary<IVariable, ReferenceResult>();
51   
52    HashSet<AstNode> visitedRoots = new HashSet<AstNode>();
53   
54    public LocalReferenceFinder(CSharpAstResolver resolver)
55    {
56      locator = new LocalReferenceLocator(resolver, this);
57    }
58
59    public LocalReferenceFinder(BaseRefactoringContext context) : this(context.Resolver)
60    {
61    }
62
63    void VisitIfNeccessary(AstNode rootNode)
64    {
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))
70          return;
71        tmpRoot = tmpRoot.Parent;
72      }
73
74      locator.ProccessRoot (rootNode);
75    }
76
77    /// <summary>
78    /// Finds the references to <paramref name="variable"/>.
79    /// </summary>
80    /// <param name='rootNode'>
81    /// Root node for the search.
82    /// </param>
83    /// <param name='variable'>
84    /// The variable to find references for.
85    /// </param>
86    /// <remarks>
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.
90    /// </remarks>
91    public IList<ReferenceResult> FindReferences(AstNode rootNode, IVariable variable)
92    {
93      lock (locator) {
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();
100      }
101    }
102
103    class LocalReferenceLocator : DepthFirstAstVisitor
104    {
105      CSharpAstResolver resolver;
106
107      LocalReferenceFinder referenceFinder;
108
109      public LocalReferenceLocator(CSharpAstResolver resolver, LocalReferenceFinder referenceFinder)
110      {
111        this.resolver = resolver;
112        this.referenceFinder = referenceFinder;
113      }
114
115      IList<IVariable> processedVariables = new List<IVariable>();
116
117      public void ProccessRoot (AstNode rootNode)
118      {
119        rootNode.AcceptVisitor(this);
120        referenceFinder.visitedRoots.Add(rootNode);
121      }
122
123      public override void VisitCSharpTokenNode(CSharpTokenNode token)
124      {
125        // Nothing
126      }
127
128      protected override void VisitChildren(AstNode node)
129      {
130        if (referenceFinder.visitedRoots.Contains(node))
131          return;
132        var localResolveResult = resolver.Resolve(node) as LocalResolveResult;
133        if (localResolveResult != null && !processedVariables.Contains(localResolveResult.Variable)) {
134          referenceFinder.references.Add(localResolveResult.Variable, new ReferenceResult(node, localResolveResult));
135
136          processedVariables.Add(localResolveResult.Variable);
137          base.VisitChildren(node);
138          Debug.Assert(processedVariables.Contains(localResolveResult.Variable), "Variable should still be in the list of processed variables.");
139          processedVariables.Remove(localResolveResult.Variable);
140        } else {
141          base.VisitChildren(node);
142        }
143      }
144    }
145  }
146
147  public class ReferenceResult
148  {
149    public ReferenceResult (AstNode node, LocalResolveResult resolveResult)
150    {
151      Node = node;
152      ResolveResult = resolveResult;
153    }
154
155    public AstNode Node { get; private set; }
156
157    public LocalResolveResult ResolveResult { get; private set; }
158  }
159}
Note: See TracBrowser for help on using the repository browser.