Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Refactoring/VariableReferenceGraph.cs @ 17120

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

#2077: created branch and added first version

File size: 18.3 KB
Line 
1//
2// VariableReferenceGraph.cs
3//
4// Author:
5//      Mansheng Yang <lightyang0@gmail.com>
6//
7// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
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.Analysis;
30using ICSharpCode.NRefactory.CSharp.Resolver;
31using System.Threading;
32
33namespace ICSharpCode.NRefactory.CSharp.Refactoring
34{
35  class VariableReferenceNode
36  {
37    public IList<AstNode> References {
38      get;
39      private set;
40    }
41
42    public IList<VariableReferenceNode> NextNodes {
43      get;
44      private set;
45    }
46
47    public IList<VariableReferenceNode> PreviousNodes {
48      get;
49      private set;
50    }
51
52    public VariableReferenceNode ()
53    {
54      References = new List<AstNode> ();
55      NextNodes = new List<VariableReferenceNode> ();
56      PreviousNodes = new List<VariableReferenceNode> ();
57    }
58
59    public void AddNextNode (VariableReferenceNode node)
60    {
61      if (node == null)
62        return;
63      NextNodes.Add (node);
64      node.PreviousNodes.Add (this);
65    }
66  }
67
68  class VariableReferenceGraphBuilder
69  {
70    ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
71    CfgVariableReferenceNodeBuilder cfgVrNodeBuilder;
72    BaseRefactoringContext ctx;
73
74    public VariableReferenceGraphBuilder(BaseRefactoringContext ctx)
75    {
76      this.ctx = ctx;
77      cfgVrNodeBuilder = new CfgVariableReferenceNodeBuilder (this);
78    }
79
80    public VariableReferenceNode Build (ISet<AstNode> references, CSharpAstResolver resolver,
81      Expression expression)
82    {
83      return ExpressionNodeCreationVisitor.CreateNode (references, resolver, new [] { expression });
84    }
85
86    public VariableReferenceNode Build (Statement statement, ISet<AstNode> references,
87      ISet<Statement> refStatements, BaseRefactoringContext context)
88    {
89      var cfg = cfgBuilder.BuildControlFlowGraph (statement, context.Resolver, context.CancellationToken);
90      if (cfg.Count == 0)
91        return new VariableReferenceNode ();
92      return cfgVrNodeBuilder.Build (cfg [0], references, refStatements, context.Resolver);
93    }
94
95    public VariableReferenceNode Build (Statement statement, ISet<AstNode> references,
96                                               ISet<Statement> refStatements, CSharpAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken))
97    {
98      var cfg = cfgBuilder.BuildControlFlowGraph (statement, resolver, cancellationToken);
99      if (cfg.Count == 0)
100        return new VariableReferenceNode();
101      return cfgVrNodeBuilder.Build (cfg [0], references, refStatements, resolver);
102    }
103
104    class GetExpressionsVisitor : DepthFirstAstVisitor<IEnumerable<Expression>>
105    {
106
107      public override IEnumerable<Expression> VisitIfElseStatement (IfElseStatement ifElseStatement)
108      {
109        yield return ifElseStatement.Condition;
110      }
111
112      public override IEnumerable<Expression> VisitSwitchStatement (SwitchStatement switchStatement)
113      {
114        yield return switchStatement.Expression;
115      }
116
117      public override IEnumerable<Expression> VisitForStatement (ForStatement forStatement)
118      {
119        yield return forStatement.Condition;
120      }
121
122      public override IEnumerable<Expression> VisitDoWhileStatement (DoWhileStatement doWhileStatement)
123      {
124        yield return doWhileStatement.Condition;
125      }
126
127      public override IEnumerable<Expression> VisitWhileStatement (WhileStatement whileStatement)
128      {
129        yield return whileStatement.Condition;
130      }
131
132      public override IEnumerable<Expression> VisitForeachStatement (ForeachStatement foreachStatement)
133      {
134        yield return foreachStatement.InExpression;
135      }
136
137      public override IEnumerable<Expression> VisitExpressionStatement (ExpressionStatement expressionStatement)
138      {
139        yield return expressionStatement.Expression;
140      }
141
142      public override IEnumerable<Expression> VisitLockStatement (LockStatement lockStatement)
143      {
144        yield return lockStatement.Expression;
145      }
146
147      public override IEnumerable<Expression> VisitReturnStatement (ReturnStatement returnStatement)
148      {
149        yield return returnStatement.Expression;
150      }
151
152      public override IEnumerable<Expression> VisitThrowStatement (ThrowStatement throwStatement)
153      {
154        yield return throwStatement.Expression;
155      }
156
157      public override IEnumerable<Expression> VisitUsingStatement (UsingStatement usingStatement)
158      {
159        var expr = usingStatement.ResourceAcquisition as Expression;
160        if (expr != null)
161          return new [] { expr };
162
163        return usingStatement.ResourceAcquisition.AcceptVisitor (this);
164      }
165
166      public override IEnumerable<Expression> VisitVariableDeclarationStatement (
167        VariableDeclarationStatement variableDeclarationStatement)
168      {
169        return variableDeclarationStatement.Variables.Select (v => v.Initializer);
170      }
171
172      public override IEnumerable<Expression> VisitYieldReturnStatement (YieldReturnStatement yieldReturnStatement)
173      {
174        yield return yieldReturnStatement.Expression;
175      }
176
177      public override IEnumerable<Expression> VisitBlockStatement(BlockStatement blockStatement)
178      {
179        yield break;
180      }
181    }
182
183    class CfgVariableReferenceNodeBuilder
184    {
185      readonly VariableReferenceGraphBuilder variableReferenceGraphBuilder;
186      GetExpressionsVisitor getExpr = new GetExpressionsVisitor ();
187
188      ISet<AstNode> references;
189      ISet<Statement> refStatements;
190      CSharpAstResolver resolver;
191      Dictionary<ControlFlowNode, VariableReferenceNode> nodeDict;
192
193      public CfgVariableReferenceNodeBuilder(VariableReferenceGraphBuilder variableReferenceGraphBuilder)
194      {
195        this.variableReferenceGraphBuilder = variableReferenceGraphBuilder;
196      }
197
198      public VariableReferenceNode Build (ControlFlowNode startNode, ISet<AstNode> references,
199        ISet<Statement> refStatements, CSharpAstResolver resolver)
200      {
201        this.references = references;
202        this.refStatements = refStatements;
203        this.resolver = resolver;
204        nodeDict = new Dictionary<ControlFlowNode, VariableReferenceNode> ();
205        return AddNode (startNode);
206      }
207
208      static bool IsValidControlFlowNode (ControlFlowNode node)
209      {
210        if (node.NextStatement == null)
211          return false;
212        if (node.Type == ControlFlowNodeType.LoopCondition) {
213          if (node.NextStatement is ForeachStatement)
214            return false;
215        } else {
216          if (node.NextStatement is WhileStatement || node.NextStatement is DoWhileStatement ||
217            node.NextStatement is ForStatement)
218            return false;
219        }
220        return true;
221      }
222
223      VariableReferenceNode GetStatementEndNode (VariableReferenceNode currentNode, Statement statement)
224      {
225        var expressions = statement.AcceptVisitor (getExpr);
226        VariableReferenceNode endNode;
227        ExpressionNodeCreationVisitor.CreateNode (references, resolver, expressions, currentNode, out endNode);
228        return endNode;
229      }
230
231      VariableReferenceNode AddNode (ControlFlowNode startNode)
232      {
233        var node = new VariableReferenceNode ();
234        var cfNode = startNode;
235        while (true) {
236          if (variableReferenceGraphBuilder.ctx.CancellationToken.IsCancellationRequested)
237            return null;
238          if (nodeDict.ContainsKey (cfNode)) {
239            node.AddNextNode (nodeDict [cfNode]);
240            break;
241          }
242          // create a new node for fork point
243          if (cfNode.Incoming.Count > 1 || cfNode.Outgoing.Count > 1) {
244            nodeDict [cfNode] = node;
245
246            var forkNode = new VariableReferenceNode ();
247            node.AddNextNode (forkNode);
248            node = forkNode;
249          }
250          nodeDict [cfNode] = node;
251
252          if (IsValidControlFlowNode (cfNode) && refStatements.Contains (cfNode.NextStatement)) {
253            node = GetStatementEndNode (node, cfNode.NextStatement);
254          }
255
256          if (cfNode.Outgoing.Count == 1) {
257            cfNode = cfNode.Outgoing [0].To;
258          } else {
259            foreach (var e in cfNode.Outgoing) {
260              node.AddNextNode (AddNode (e.To));
261            }
262            break;
263          }
264        }
265        VariableReferenceNode result;
266        if (!nodeDict.TryGetValue (startNode, out result))
267          return new VariableReferenceNode ();
268        return result;
269      }
270    }
271
272    class ExpressionNodeCreationVisitor : DepthFirstAstVisitor
273    {
274      VariableReferenceNode startNode;
275      VariableReferenceNode endNode;
276      ISet<AstNode> references;
277      CSharpAstResolver resolver;
278
279      ExpressionNodeCreationVisitor (ISet<AstNode> references, CSharpAstResolver resolver,
280        VariableReferenceNode startNode)
281      {
282        this.references = references;
283        this.resolver = resolver;
284        this.startNode = this.endNode = startNode ?? new VariableReferenceNode ();
285      }
286
287      public static VariableReferenceNode CreateNode (ISet<AstNode> references, CSharpAstResolver resolver,
288        params Expression [] expressions)
289      {
290        VariableReferenceNode endNode;
291        return CreateNode (references, resolver, expressions, null, out endNode);
292      }
293
294      public static VariableReferenceNode CreateNode (ISet<AstNode> references, CSharpAstResolver resolver,
295        IEnumerable<Expression> expressions, VariableReferenceNode startNode, out VariableReferenceNode endNode)
296      {
297        startNode = startNode ?? new VariableReferenceNode ();
298        endNode = startNode;
299        if (expressions != null) {
300          foreach (var expr in expressions) {
301            var visitor = CreateVisitor(references, resolver, expr, endNode);
302            endNode = visitor.endNode;
303          }
304        }
305        return startNode;
306      }
307
308      static ExpressionNodeCreationVisitor CreateVisitor (ISet<AstNode> references, CSharpAstResolver resolver,
309        Expression rootExpr, VariableReferenceNode startNode = null, VariableReferenceNode nextNode = null)
310      {
311        var visitor = new ExpressionNodeCreationVisitor (references, resolver, startNode);
312        rootExpr.AcceptVisitor (visitor);
313        if (nextNode != null)
314          visitor.endNode.AddNextNode (nextNode);
315        return visitor;
316      }
317
318      static VariableReferenceNode CreateNode (ISet<AstNode> references, CSharpAstResolver resolver,
319        Expression rootExpr, VariableReferenceNode startNode = null, VariableReferenceNode nextNode = null)
320      {
321        return CreateVisitor (references, resolver, rootExpr, startNode, nextNode).startNode;
322      }
323
324      #region Skipped Expressions
325      public override void VisitAnonymousMethodExpression (AnonymousMethodExpression anonymousMethodExpression)
326      {
327      }
328
329      public override void VisitLambdaExpression (LambdaExpression lambdaExpression)
330      {
331      }
332
333      public override void VisitBaseReferenceExpression (BaseReferenceExpression baseReferenceExpression)
334      {
335      }
336
337      public override void VisitNullReferenceExpression (NullReferenceExpression nullReferenceExpression)
338      {
339      }
340
341      public override void VisitPrimitiveExpression (PrimitiveExpression primitiveExpression)
342      {
343      }
344
345      public override void VisitSizeOfExpression (SizeOfExpression sizeOfExpression)
346      {
347      }
348
349      public override void VisitThisReferenceExpression (ThisReferenceExpression thisReferenceExpression)
350      {
351      }
352
353      public override void VisitTypeOfExpression (TypeOfExpression typeOfExpression)
354      {
355      }
356
357      public override void VisitTypeReferenceExpression (TypeReferenceExpression typeReferenceExpression)
358      {
359      }
360
361      public override void VisitUndocumentedExpression (UndocumentedExpression undocumentedExpression)
362      {
363      }
364
365      public override void VisitDefaultValueExpression (DefaultValueExpression defaultValueExpression)
366      {
367      }
368
369      #endregion
370
371      public override void VisitAssignmentExpression (AssignmentExpression assignmentExpression)
372      {
373        assignmentExpression.Right.AcceptVisitor (this);
374        assignmentExpression.Left.AcceptVisitor (this);
375      }
376
377      public override void VisitBinaryOperatorExpression (BinaryOperatorExpression binaryOperatorExpression)
378      {
379        binaryOperatorExpression.Left.AcceptVisitor (this);
380        binaryOperatorExpression.Right.AcceptVisitor (this);
381      }
382
383      public override void VisitCastExpression (CastExpression castExpression)
384      {
385        castExpression.Expression.AcceptVisitor (this);
386      }
387
388      public override void VisitCheckedExpression (CheckedExpression checkedExpression)
389      {
390        checkedExpression.Expression.AcceptVisitor (this);
391      }
392
393      public override void VisitConditionalExpression (ConditionalExpression conditionalExpression)
394      {
395        conditionalExpression.Condition.AcceptVisitor (this);
396        var resolveResult = resolver.Resolve (conditionalExpression.Condition);
397        if (resolveResult.ConstantValue is bool) {
398          if ((bool) resolveResult.ConstantValue)
399            conditionalExpression.TrueExpression.AcceptVisitor (this);
400          else
401            conditionalExpression.FalseExpression.AcceptVisitor (this);
402          return;
403        }
404        var nextEndNode = new VariableReferenceNode ();
405        var trueNode = CreateNode (references, resolver, conditionalExpression.TrueExpression, null,
406          nextEndNode);
407        var falseNode = CreateNode (references, resolver, conditionalExpression.FalseExpression, null,
408          nextEndNode);
409        endNode.AddNextNode (trueNode);
410        endNode.AddNextNode (falseNode);
411        endNode = nextEndNode;
412      }
413
414      public override void VisitIdentifierExpression (IdentifierExpression identifierExpression)
415      {
416        if (references.Contains (identifierExpression))
417          endNode.References.Add (identifierExpression);
418      }
419
420      public override void VisitIndexerExpression (IndexerExpression indexerExpression)
421      {
422        indexerExpression.Target.AcceptVisitor (this);
423        foreach (var arg in indexerExpression.Arguments)
424          arg.AcceptVisitor (this);
425      }
426
427      public override void VisitInvocationExpression (InvocationExpression invocationExpression)
428      {
429        invocationExpression.Target.AcceptVisitor (this);
430        var outArguments = new List<Expression> ();
431        foreach (var arg in invocationExpression.Arguments) {
432          var directionExpr = arg as DirectionExpression;
433          if (directionExpr != null && directionExpr.FieldDirection == FieldDirection.Out) {
434            outArguments.Add (directionExpr);
435            continue;
436          }
437          arg.AcceptVisitor (this);
438        }
439        foreach (var arg in outArguments)
440          arg.AcceptVisitor (this);
441      }
442
443      public override void VisitDirectionExpression (DirectionExpression directionExpression)
444      {
445        directionExpression.Expression.AcceptVisitor (this);
446      }
447
448      public override void VisitMemberReferenceExpression (MemberReferenceExpression memberReferenceExpression)
449      {
450        memberReferenceExpression.Target.AcceptVisitor (this);
451      }
452
453      public override void VisitObjectCreateExpression (ObjectCreateExpression objectCreateExpression)
454      {
455        foreach (var arg in objectCreateExpression.Arguments)
456          arg.AcceptVisitor (this);
457        objectCreateExpression.Initializer.AcceptVisitor (this);
458      }
459
460      public override void VisitAnonymousTypeCreateExpression (
461        AnonymousTypeCreateExpression anonymousTypeCreateExpression)
462      {
463        foreach (var init in anonymousTypeCreateExpression.Initializers)
464          init.AcceptVisitor (this);
465      }
466
467      public override void VisitArrayCreateExpression (ArrayCreateExpression arrayCreateExpression)
468      {
469        foreach (var arg in arrayCreateExpression.Arguments)
470          arg.AcceptVisitor (this);
471        arrayCreateExpression.Initializer.AcceptVisitor (this);
472      }
473
474      public override void VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression)
475      {
476        parenthesizedExpression.Expression.AcceptVisitor (this);
477      }
478
479      public override void VisitPointerReferenceExpression (PointerReferenceExpression pointerReferenceExpression)
480      {
481        pointerReferenceExpression.Target.AcceptVisitor (this);
482      }
483
484      public override void VisitStackAllocExpression (StackAllocExpression stackAllocExpression)
485      {
486        stackAllocExpression.CountExpression.AcceptVisitor (this);
487      }
488
489      public override void VisitUnaryOperatorExpression (UnaryOperatorExpression unaryOperatorExpression)
490      {
491        unaryOperatorExpression.Expression.AcceptVisitor (this);
492      }
493
494      public override void VisitUncheckedExpression (UncheckedExpression uncheckedExpression)
495      {
496        uncheckedExpression.Expression.AcceptVisitor (this);
497      }
498
499      public override void VisitAsExpression (AsExpression asExpression)
500      {
501        asExpression.Expression.AcceptVisitor (this);
502      }
503
504      public override void VisitIsExpression (IsExpression isExpression)
505      {
506        isExpression.Expression.AcceptVisitor (this);
507      }
508
509      public override void VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression)
510      {
511        foreach (var element in arrayInitializerExpression.Elements)
512          element.AcceptVisitor (this);
513      }
514
515      public override void VisitNamedArgumentExpression (NamedArgumentExpression namedArgumentExpression)
516      {
517        namedArgumentExpression.Expression.AcceptVisitor (this);
518      }
519
520      public override void VisitNamedExpression (NamedExpression namedExpression)
521      {
522        namedExpression.Expression.AcceptVisitor (this);
523      }
524
525      public override void VisitQueryExpression (QueryExpression queryExpression)
526      {
527        foreach (var clause in queryExpression.Clauses)
528          clause.AcceptVisitor (this);
529      }
530
531      #region Query Clauses
532
533      public override void VisitQueryContinuationClause (QueryContinuationClause queryContinuationClause)
534      {
535        queryContinuationClause.PrecedingQuery.AcceptVisitor (this);
536      }
537
538      public override void VisitQueryFromClause (QueryFromClause queryFromClause)
539      {
540        queryFromClause.Expression.AcceptVisitor (this);
541      }
542
543      public override void VisitQueryJoinClause (QueryJoinClause queryJoinClause)
544      {
545        queryJoinClause.InExpression.AcceptVisitor (this);
546      }
547
548      public override void VisitQueryLetClause (QueryLetClause queryLetClause)
549      {
550      }
551
552      public override void VisitQueryWhereClause (QueryWhereClause queryWhereClause)
553      {
554      }
555
556      public override void VisitQueryOrderClause (QueryOrderClause queryOrderClause)
557      {
558      }
559
560      public override void VisitQueryOrdering (QueryOrdering queryOrdering)
561      {
562      }
563
564      public override void VisitQuerySelectClause (QuerySelectClause querySelectClause)
565      {
566      }
567
568      public override void VisitQueryGroupClause (QueryGroupClause queryGroupClause)
569      {
570      }
571
572      #endregion
573    }
574  }
575}
Note: See TracBrowser for help on using the repository browser.