2
// VariableReferenceGraph.cs
5
// Mansheng Yang <lightyang0@gmail.com>
7
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
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.Analysis;
30
using ICSharpCode.NRefactory.CSharp.Resolver;
31
using System.Threading;
33
namespace ICSharpCode.NRefactory.CSharp.Refactoring
35
class VariableReferenceNode
37
public IList<AstNode> References {
42
public IList<VariableReferenceNode> NextNodes {
47
public IList<VariableReferenceNode> PreviousNodes {
52
public VariableReferenceNode ()
54
References = new List<AstNode> ();
55
NextNodes = new List<VariableReferenceNode> ();
56
PreviousNodes = new List<VariableReferenceNode> ();
59
public void AddNextNode (VariableReferenceNode node)
62
node.PreviousNodes.Add (this);
66
class VariableReferenceGraphBuilder
68
ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
69
CfgVariableReferenceNodeBuilder cfgVrNodeBuilder;
70
BaseRefactoringContext ctx;
72
public VariableReferenceGraphBuilder(BaseRefactoringContext ctx)
75
cfgVrNodeBuilder = new CfgVariableReferenceNodeBuilder (this);
78
public VariableReferenceNode Build (ISet<AstNode> references, CSharpAstResolver resolver,
79
Expression expression)
81
return ExpressionNodeCreationVisitor.CreateNode (references, resolver, new [] { expression });
84
public VariableReferenceNode Build (Statement statement, ISet<AstNode> references,
85
ISet<Statement> refStatements, BaseRefactoringContext context)
87
var cfg = cfgBuilder.BuildControlFlowGraph (statement, context.Resolver, context.CancellationToken);
89
return new VariableReferenceNode ();
90
return cfgVrNodeBuilder.Build (cfg [0], references, refStatements, context.Resolver);
93
public VariableReferenceNode Build (Statement statement, ISet<AstNode> references,
94
ISet<Statement> refStatements, CSharpAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken))
96
var cfg = cfgBuilder.BuildControlFlowGraph (statement, resolver, cancellationToken);
98
return new VariableReferenceNode();
99
return cfgVrNodeBuilder.Build (cfg [0], references, refStatements, resolver);
102
class GetExpressionsVisitor : DepthFirstAstVisitor<IEnumerable<Expression>>
105
public override IEnumerable<Expression> VisitIfElseStatement (IfElseStatement ifElseStatement)
107
yield return ifElseStatement.Condition;
110
public override IEnumerable<Expression> VisitSwitchStatement (SwitchStatement switchStatement)
112
yield return switchStatement.Expression;
115
public override IEnumerable<Expression> VisitForStatement (ForStatement forStatement)
117
yield return forStatement.Condition;
120
public override IEnumerable<Expression> VisitDoWhileStatement (DoWhileStatement doWhileStatement)
122
yield return doWhileStatement.Condition;
125
public override IEnumerable<Expression> VisitWhileStatement (WhileStatement whileStatement)
127
yield return whileStatement.Condition;
130
public override IEnumerable<Expression> VisitForeachStatement (ForeachStatement foreachStatement)
132
yield return foreachStatement.InExpression;
135
public override IEnumerable<Expression> VisitExpressionStatement (ExpressionStatement expressionStatement)
137
yield return expressionStatement.Expression;
140
public override IEnumerable<Expression> VisitLockStatement (LockStatement lockStatement)
142
yield return lockStatement.Expression;
145
public override IEnumerable<Expression> VisitReturnStatement (ReturnStatement returnStatement)
147
yield return returnStatement.Expression;
150
public override IEnumerable<Expression> VisitThrowStatement (ThrowStatement throwStatement)
152
yield return throwStatement.Expression;
155
public override IEnumerable<Expression> VisitUsingStatement (UsingStatement usingStatement)
157
var expr = usingStatement.ResourceAcquisition as Expression;
159
return new [] { expr };
161
return usingStatement.ResourceAcquisition.AcceptVisitor (this);
164
public override IEnumerable<Expression> VisitVariableDeclarationStatement (
165
VariableDeclarationStatement variableDeclarationStatement)
167
return variableDeclarationStatement.Variables.Select (v => v.Initializer);
170
public override IEnumerable<Expression> VisitYieldReturnStatement (YieldReturnStatement yieldReturnStatement)
172
yield return yieldReturnStatement.Expression;
175
public override IEnumerable<Expression> VisitBlockStatement(BlockStatement blockStatement)
181
class CfgVariableReferenceNodeBuilder
183
readonly VariableReferenceGraphBuilder variableReferenceGraphBuilder;
184
GetExpressionsVisitor getExpr = new GetExpressionsVisitor ();
186
ISet<AstNode> references;
187
ISet<Statement> refStatements;
188
CSharpAstResolver resolver;
189
Dictionary<ControlFlowNode, VariableReferenceNode> nodeDict;
191
public CfgVariableReferenceNodeBuilder(VariableReferenceGraphBuilder variableReferenceGraphBuilder)
193
this.variableReferenceGraphBuilder = variableReferenceGraphBuilder;
196
public VariableReferenceNode Build (ControlFlowNode startNode, ISet<AstNode> references,
197
ISet<Statement> refStatements, CSharpAstResolver resolver)
199
this.references = references;
200
this.refStatements = refStatements;
201
this.resolver = resolver;
202
nodeDict = new Dictionary<ControlFlowNode, VariableReferenceNode> ();
203
return AddNode (startNode);
206
static bool IsValidControlFlowNode (ControlFlowNode node)
208
if (node.NextStatement == null)
210
if (node.Type == ControlFlowNodeType.LoopCondition) {
211
if (node.NextStatement is ForeachStatement)
214
if (node.NextStatement is WhileStatement || node.NextStatement is DoWhileStatement ||
215
node.NextStatement is ForStatement)
221
VariableReferenceNode GetStatementEndNode (VariableReferenceNode currentNode, Statement statement)
223
var expressions = statement.AcceptVisitor (getExpr);
224
VariableReferenceNode endNode;
225
ExpressionNodeCreationVisitor.CreateNode (references, resolver, expressions, currentNode, out endNode);
229
VariableReferenceNode AddNode (ControlFlowNode startNode)
231
var node = new VariableReferenceNode ();
232
var cfNode = startNode;
234
if (variableReferenceGraphBuilder.ctx.CancellationToken.IsCancellationRequested)
236
if (nodeDict.ContainsKey (cfNode)) {
237
node.AddNextNode (nodeDict [cfNode]);
240
// create a new node for fork point
241
if (cfNode.Incoming.Count > 1 || cfNode.Outgoing.Count > 1) {
242
nodeDict [cfNode] = node;
244
var forkNode = new VariableReferenceNode ();
245
node.AddNextNode (forkNode);
248
nodeDict [cfNode] = node;
250
if (IsValidControlFlowNode (cfNode) && refStatements.Contains (cfNode.NextStatement)) {
251
node = GetStatementEndNode (node, cfNode.NextStatement);
254
if (cfNode.Outgoing.Count == 1) {
255
cfNode = cfNode.Outgoing [0].To;
257
foreach (var e in cfNode.Outgoing) {
258
node.AddNextNode (AddNode (e.To));
263
VariableReferenceNode result;
264
if (!nodeDict.TryGetValue (startNode, out result))
265
return new VariableReferenceNode ();
270
class ExpressionNodeCreationVisitor : DepthFirstAstVisitor
272
VariableReferenceNode startNode;
273
VariableReferenceNode endNode;
274
ISet<AstNode> references;
275
CSharpAstResolver resolver;
277
ExpressionNodeCreationVisitor (ISet<AstNode> references, CSharpAstResolver resolver,
278
VariableReferenceNode startNode)
280
this.references = references;
281
this.resolver = resolver;
282
this.startNode = this.endNode = startNode ?? new VariableReferenceNode ();
285
public static VariableReferenceNode CreateNode (ISet<AstNode> references, CSharpAstResolver resolver,
286
params Expression [] expressions)
288
VariableReferenceNode endNode;
289
return CreateNode (references, resolver, expressions, null, out endNode);
292
public static VariableReferenceNode CreateNode (ISet<AstNode> references, CSharpAstResolver resolver,
293
IEnumerable<Expression> expressions, VariableReferenceNode startNode, out VariableReferenceNode endNode)
295
startNode = startNode ?? new VariableReferenceNode ();
297
foreach (var expr in expressions) {
298
var visitor = CreateVisitor (references, resolver, expr, endNode);
299
endNode = visitor.endNode;
304
static ExpressionNodeCreationVisitor CreateVisitor (ISet<AstNode> references, CSharpAstResolver resolver,
305
Expression rootExpr, VariableReferenceNode startNode = null, VariableReferenceNode nextNode = null)
307
var visitor = new ExpressionNodeCreationVisitor (references, resolver, startNode);
308
rootExpr.AcceptVisitor (visitor);
309
if (nextNode != null)
310
visitor.endNode.AddNextNode (nextNode);
314
static VariableReferenceNode CreateNode (ISet<AstNode> references, CSharpAstResolver resolver,
315
Expression rootExpr, VariableReferenceNode startNode = null, VariableReferenceNode nextNode = null)
317
return CreateVisitor (references, resolver, rootExpr, startNode, nextNode).startNode;
320
#region Skipped Expressions
321
public override void VisitAnonymousMethodExpression (AnonymousMethodExpression anonymousMethodExpression)
325
public override void VisitLambdaExpression (LambdaExpression lambdaExpression)
329
public override void VisitBaseReferenceExpression (BaseReferenceExpression baseReferenceExpression)
333
public override void VisitNullReferenceExpression (NullReferenceExpression nullReferenceExpression)
337
public override void VisitPrimitiveExpression (PrimitiveExpression primitiveExpression)
341
public override void VisitSizeOfExpression (SizeOfExpression sizeOfExpression)
345
public override void VisitThisReferenceExpression (ThisReferenceExpression thisReferenceExpression)
349
public override void VisitTypeOfExpression (TypeOfExpression typeOfExpression)
353
public override void VisitTypeReferenceExpression (TypeReferenceExpression typeReferenceExpression)
357
public override void VisitUndocumentedExpression (UndocumentedExpression undocumentedExpression)
361
public override void VisitDefaultValueExpression (DefaultValueExpression defaultValueExpression)
365
public override void VisitEmptyExpression (EmptyExpression emptyExpression)
371
public override void VisitAssignmentExpression (AssignmentExpression assignmentExpression)
373
assignmentExpression.Right.AcceptVisitor (this);
374
assignmentExpression.Left.AcceptVisitor (this);
377
public override void VisitBinaryOperatorExpression (BinaryOperatorExpression binaryOperatorExpression)
379
binaryOperatorExpression.Left.AcceptVisitor (this);
380
binaryOperatorExpression.Right.AcceptVisitor (this);
383
public override void VisitCastExpression (CastExpression castExpression)
385
castExpression.Expression.AcceptVisitor (this);
388
public override void VisitCheckedExpression (CheckedExpression checkedExpression)
390
checkedExpression.Expression.AcceptVisitor (this);
393
public override void VisitConditionalExpression (ConditionalExpression conditionalExpression)
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);
401
conditionalExpression.FalseExpression.AcceptVisitor (this);
404
var nextEndNode = new VariableReferenceNode ();
405
var trueNode = CreateNode (references, resolver, conditionalExpression.TrueExpression, null,
407
var falseNode = CreateNode (references, resolver, conditionalExpression.FalseExpression, null,
409
endNode.AddNextNode (trueNode);
410
endNode.AddNextNode (falseNode);
411
endNode = nextEndNode;
414
public override void VisitIdentifierExpression (IdentifierExpression identifierExpression)
416
if (references.Contains (identifierExpression))
417
endNode.References.Add (identifierExpression);
420
public override void VisitIndexerExpression (IndexerExpression indexerExpression)
422
indexerExpression.Target.AcceptVisitor (this);
423
foreach (var arg in indexerExpression.Arguments)
424
arg.AcceptVisitor (this);
427
public override void VisitInvocationExpression (InvocationExpression invocationExpression)
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);
437
arg.AcceptVisitor (this);
439
foreach (var arg in outArguments)
440
arg.AcceptVisitor (this);
443
public override void VisitDirectionExpression (DirectionExpression directionExpression)
445
directionExpression.Expression.AcceptVisitor (this);
448
public override void VisitMemberReferenceExpression (MemberReferenceExpression memberReferenceExpression)
450
memberReferenceExpression.Target.AcceptVisitor (this);
453
public override void VisitObjectCreateExpression (ObjectCreateExpression objectCreateExpression)
455
foreach (var arg in objectCreateExpression.Arguments)
456
arg.AcceptVisitor (this);
457
objectCreateExpression.Initializer.AcceptVisitor (this);
460
public override void VisitAnonymousTypeCreateExpression (
461
AnonymousTypeCreateExpression anonymousTypeCreateExpression)
463
foreach (var init in anonymousTypeCreateExpression.Initializers)
464
init.AcceptVisitor (this);
467
public override void VisitArrayCreateExpression (ArrayCreateExpression arrayCreateExpression)
469
foreach (var arg in arrayCreateExpression.Arguments)
470
arg.AcceptVisitor (this);
471
arrayCreateExpression.Initializer.AcceptVisitor (this);
474
public override void VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression)
476
parenthesizedExpression.Expression.AcceptVisitor (this);
479
public override void VisitPointerReferenceExpression (PointerReferenceExpression pointerReferenceExpression)
481
pointerReferenceExpression.Target.AcceptVisitor (this);
484
public override void VisitStackAllocExpression (StackAllocExpression stackAllocExpression)
486
stackAllocExpression.CountExpression.AcceptVisitor (this);
489
public override void VisitUnaryOperatorExpression (UnaryOperatorExpression unaryOperatorExpression)
491
unaryOperatorExpression.Expression.AcceptVisitor (this);
494
public override void VisitUncheckedExpression (UncheckedExpression uncheckedExpression)
496
uncheckedExpression.Expression.AcceptVisitor (this);
499
public override void VisitAsExpression (AsExpression asExpression)
501
asExpression.Expression.AcceptVisitor (this);
504
public override void VisitIsExpression (IsExpression isExpression)
506
isExpression.Expression.AcceptVisitor (this);
509
public override void VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression)
511
foreach (var element in arrayInitializerExpression.Elements)
512
element.AcceptVisitor (this);
515
public override void VisitNamedArgumentExpression (NamedArgumentExpression namedArgumentExpression)
517
namedArgumentExpression.Expression.AcceptVisitor (this);
520
public override void VisitNamedExpression (NamedExpression namedExpression)
522
namedExpression.Expression.AcceptVisitor (this);
525
public override void VisitQueryExpression (QueryExpression queryExpression)
527
foreach (var clause in queryExpression.Clauses)
528
clause.AcceptVisitor (this);
531
#region Query Clauses
533
public override void VisitQueryContinuationClause (QueryContinuationClause queryContinuationClause)
535
queryContinuationClause.PrecedingQuery.AcceptVisitor (this);
538
public override void VisitQueryFromClause (QueryFromClause queryFromClause)
540
queryFromClause.Expression.AcceptVisitor (this);
543
public override void VisitQueryJoinClause (QueryJoinClause queryJoinClause)
545
queryJoinClause.InExpression.AcceptVisitor (this);
548
public override void VisitQueryLetClause (QueryLetClause queryLetClause)
552
public override void VisitQueryWhereClause (QueryWhereClause queryWhereClause)
556
public override void VisitQueryOrderClause (QueryOrderClause queryOrderClause)
560
public override void VisitQueryOrdering (QueryOrdering queryOrdering)
564
public override void VisitQuerySelectClause (QuerySelectClause querySelectClause)
568
public override void VisitQueryGroupClause (QueryGroupClause queryGroupClause)
b'\\ No newline at end of file'