1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using System.Collections.Generic;
21
using System.Diagnostics;
23
using System.Threading;
25
using ICSharpCode.NRefactory.CSharp.Resolver;
26
using ICSharpCode.NRefactory.TypeSystem;
28
namespace ICSharpCode.NRefactory.CSharp.Analysis
31
/// Represents a node in the control flow graph of a C# method.
33
public class ControlFlowNode
35
public readonly Statement PreviousStatement;
36
public readonly Statement NextStatement;
38
public readonly ControlFlowNodeType Type;
40
public readonly List<ControlFlowEdge> Outgoing = new List<ControlFlowEdge>();
41
public readonly List<ControlFlowEdge> Incoming = new List<ControlFlowEdge>();
43
public ControlFlowNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
45
if (previousStatement == null && nextStatement == null)
46
throw new ArgumentException("previousStatement and nextStatement must not be both null");
47
this.PreviousStatement = previousStatement;
48
this.NextStatement = nextStatement;
53
public enum ControlFlowNodeType
60
/// Node in front of a statement
64
/// Node between two statements
68
/// Node at the end of a statement list
72
/// Node representing the position before evaluating the condition of a loop.
77
public class ControlFlowEdge
79
public readonly ControlFlowNode From;
80
public readonly ControlFlowNode To;
81
public readonly ControlFlowEdgeType Type;
83
List<TryCatchStatement> jumpOutOfTryFinally;
85
public ControlFlowEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type)
88
throw new ArgumentNullException("from");
90
throw new ArgumentNullException("to");
96
internal void AddJumpOutOfTryFinally(TryCatchStatement tryFinally)
98
if (jumpOutOfTryFinally == null)
99
jumpOutOfTryFinally = new List<TryCatchStatement>();
100
jumpOutOfTryFinally.Add(tryFinally);
104
/// Gets whether this control flow edge is leaving any try-finally statements.
106
public bool IsLeavingTryFinally {
107
get { return jumpOutOfTryFinally != null; }
111
/// Gets the try-finally statements that this control flow edge is leaving.
113
public IEnumerable<TryCatchStatement> TryFinallyStatements {
114
get { return jumpOutOfTryFinally ?? EmptyList<TryCatchStatement>.Instance; }
118
public enum ControlFlowEdgeType
121
/// Regular control flow.
125
/// Conditional control flow (edge taken if condition is true)
129
/// Conditional control flow (edge taken if condition is false)
133
/// A jump statement (goto, goto case, break or continue)
139
/// Constructs the control flow graph for C# statements.
141
public class ControlFlowGraphBuilder
143
// Written according to the reachability rules in the C# spec (§8.1 End points and reachability)
145
protected virtual ControlFlowNode CreateNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
147
return new ControlFlowNode(previousStatement, nextStatement, type);
150
protected virtual ControlFlowEdge CreateEdge(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type)
152
return new ControlFlowEdge(from, to, type);
155
Statement rootStatement;
156
ResolveVisitor resolveVisitor;
157
List<ControlFlowNode> nodes;
158
Dictionary<string, ControlFlowNode> labels;
159
List<ControlFlowNode> gotoStatements;
161
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ITypeResolveContext context)
163
return BuildControlFlowGraph(statement, context, CancellationToken.None);
166
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ITypeResolveContext context, CancellationToken cancellationToken)
168
return BuildControlFlowGraph(statement, new ResolveVisitor(
169
new CSharpResolver(context, cancellationToken),
173
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ResolveVisitor resolveVisitor)
175
if (statement == null)
176
throw new ArgumentNullException("statement");
177
if (resolveVisitor == null)
178
throw new ArgumentNullException("resolveVisitor");
180
NodeCreationVisitor nodeCreationVisitor = new NodeCreationVisitor();
181
nodeCreationVisitor.builder = this;
183
this.nodes = new List<ControlFlowNode>();
184
this.labels = new Dictionary<string, ControlFlowNode>();
185
this.gotoStatements = new List<ControlFlowNode>();
186
this.rootStatement = statement;
187
this.resolveVisitor = resolveVisitor;
188
ControlFlowNode entryPoint = CreateStartNode(statement);
189
statement.AcceptVisitor(nodeCreationVisitor, entryPoint);
191
// Resolve goto statements:
192
foreach (ControlFlowNode gotoStmt in gotoStatements) {
193
string label = ((GotoStatement)gotoStmt.NextStatement).Label;
194
ControlFlowNode labelNode;
195
if (labels.TryGetValue(label, out labelNode))
196
nodeCreationVisitor.Connect(gotoStmt, labelNode, ControlFlowEdgeType.Jump);
199
AnnotateLeaveEdgesWithTryFinallyBlocks();
205
this.gotoStatements = null;
206
this.rootStatement = null;
207
this.resolveVisitor = null;
211
void AnnotateLeaveEdgesWithTryFinallyBlocks()
213
foreach (ControlFlowEdge edge in nodes.SelectMany(n => n.Outgoing)) {
214
if (edge.Type != ControlFlowEdgeType.Jump) {
215
// Only jumps are potential candidates for leaving try-finally blocks.
216
// Note that the regular edges leaving try or catch blocks are already annotated by the visitor.
219
Statement gotoStatement = edge.From.NextStatement;
220
Debug.Assert(gotoStatement is GotoStatement || gotoStatement is GotoDefaultStatement || gotoStatement is GotoCaseStatement || gotoStatement is BreakStatement || gotoStatement is ContinueStatement);
221
Statement targetStatement = edge.To.PreviousStatement ?? edge.To.NextStatement;
222
if (gotoStatement.Parent == targetStatement.Parent)
224
HashSet<TryCatchStatement> targetParentTryCatch = new HashSet<TryCatchStatement>(targetStatement.Ancestors.OfType<TryCatchStatement>());
225
for (AstNode node = gotoStatement.Parent; node != null; node = node.Parent) {
226
TryCatchStatement leftTryCatch = node as TryCatchStatement;
227
if (leftTryCatch != null) {
228
if (targetParentTryCatch.Contains(leftTryCatch))
230
if (!leftTryCatch.FinallyBlock.IsNull)
231
edge.AddJumpOutOfTryFinally(leftTryCatch);
238
ControlFlowNode CreateStartNode(Statement statement)
240
ControlFlowNode node = CreateNode(null, statement, ControlFlowNodeType.StartNode);
245
ControlFlowNode CreateSpecialNode(Statement statement, ControlFlowNodeType type, bool addToNodeList = true)
247
ControlFlowNode node = CreateNode(null, statement, type);
253
ControlFlowNode CreateEndNode(Statement statement, bool addToNodeList = true)
255
Statement nextStatement;
256
if (statement == rootStatement) {
257
nextStatement = null;
259
// Find the next statement in the same role:
260
AstNode next = statement;
262
next = next.NextSibling;
263
} while (next != null && next.Role != statement.Role);
264
nextStatement = next as Statement;
266
ControlFlowNodeType type = nextStatement != null ? ControlFlowNodeType.BetweenStatements : ControlFlowNodeType.EndNode;
267
ControlFlowNode node = CreateNode(statement, nextStatement, type);
274
#region Constant evaluation
276
/// Gets/Sets whether to handle only primitive expressions as constants (no complex expressions like "a + b").
278
public bool EvaluateOnlyPrimitiveConstants { get; set; }
281
/// Evaluates an expression.
283
/// <returns>The constant value of the expression; or null if the expression is not a constant.</returns>
284
ConstantResolveResult EvaluateConstant(Expression expr)
286
if (EvaluateOnlyPrimitiveConstants) {
287
if (!(expr is PrimitiveExpression || expr is NullReferenceExpression))
290
return resolveVisitor.Resolve(expr) as ConstantResolveResult;
294
/// Evaluates an expression.
296
/// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns>
297
bool? EvaluateCondition(Expression expr)
299
ConstantResolveResult rr = EvaluateConstant(expr);
301
return rr.ConstantValue as bool?;
306
bool AreEqualConstants(ConstantResolveResult c1, ConstantResolveResult c2)
308
if (c1 == null || c2 == null)
310
CSharpResolver r = new CSharpResolver(resolveVisitor.TypeResolveContext, resolveVisitor.CancellationToken);
311
ResolveResult c = r.ResolveBinaryOperator(BinaryOperatorType.Equality, c1, c2);
312
return c.IsCompileTimeConstant && (c.ConstantValue as bool?) == true;
316
sealed class NodeCreationVisitor : DepthFirstAstVisitor<ControlFlowNode, ControlFlowNode>
318
// 'data' parameter: input control flow node (start of statement being visited)
319
// Return value: result control flow node (end of statement being visited)
321
internal ControlFlowGraphBuilder builder;
322
Stack<ControlFlowNode> breakTargets = new Stack<ControlFlowNode>();
323
Stack<ControlFlowNode> continueTargets = new Stack<ControlFlowNode>();
324
List<ControlFlowNode> gotoCaseOrDefault = new List<ControlFlowNode>();
326
internal ControlFlowEdge Connect(ControlFlowNode from, ControlFlowNode to, ControlFlowEdgeType type = ControlFlowEdgeType.Normal)
328
ControlFlowEdge edge = builder.CreateEdge(from, to, type);
329
from.Outgoing.Add(edge);
330
to.Incoming.Add(edge);
335
/// Creates an end node for <c>stmt</c> and connects <c>from</c> with the new node.
337
ControlFlowNode CreateConnectedEndNode(Statement stmt, ControlFlowNode from)
339
ControlFlowNode newNode = builder.CreateEndNode(stmt);
340
Connect(from, newNode);
344
protected override ControlFlowNode VisitChildren(AstNode node, ControlFlowNode data)
346
// We have overrides for all possible expressions and should visit expressions only.
347
throw new NotImplementedException();
350
public override ControlFlowNode VisitBlockStatement(BlockStatement blockStatement, ControlFlowNode data)
352
// C# 4.0 spec: §8.2 Blocks
353
ControlFlowNode childNode = HandleStatementList(blockStatement.Statements, data);
354
return CreateConnectedEndNode(blockStatement, childNode);
357
ControlFlowNode HandleStatementList(AstNodeCollection<Statement> statements, ControlFlowNode source)
359
ControlFlowNode childNode = null;
360
foreach (Statement stmt in statements) {
361
if (childNode == null) {
362
childNode = builder.CreateStartNode(stmt);
364
Connect(source, childNode);
366
Debug.Assert(childNode.NextStatement == stmt);
367
childNode = stmt.AcceptVisitor(this, childNode);
368
Debug.Assert(childNode.PreviousStatement == stmt);
370
return childNode ?? source;
373
public override ControlFlowNode VisitEmptyStatement(EmptyStatement emptyStatement, ControlFlowNode data)
375
return CreateConnectedEndNode(emptyStatement, data);
378
public override ControlFlowNode VisitLabelStatement(LabelStatement labelStatement, ControlFlowNode data)
380
ControlFlowNode end = CreateConnectedEndNode(labelStatement, data);
381
builder.labels[labelStatement.Label] = end;
385
public override ControlFlowNode VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, ControlFlowNode data)
387
return CreateConnectedEndNode(variableDeclarationStatement, data);
390
public override ControlFlowNode VisitExpressionStatement(ExpressionStatement expressionStatement, ControlFlowNode data)
392
return CreateConnectedEndNode(expressionStatement, data);
395
public override ControlFlowNode VisitIfElseStatement(IfElseStatement ifElseStatement, ControlFlowNode data)
397
bool? cond = builder.EvaluateCondition(ifElseStatement.Condition);
398
ControlFlowNode trueBegin = builder.CreateStartNode(ifElseStatement.TrueStatement);
400
Connect(data, trueBegin, ControlFlowEdgeType.ConditionTrue);
401
ControlFlowNode trueEnd = ifElseStatement.TrueStatement.AcceptVisitor(this, trueBegin);
402
ControlFlowNode falseEnd;
403
if (ifElseStatement.FalseStatement.IsNull) {
406
ControlFlowNode falseBegin = builder.CreateStartNode(ifElseStatement.FalseStatement);
408
Connect(data, falseBegin, ControlFlowEdgeType.ConditionFalse);
409
falseEnd = ifElseStatement.FalseStatement.AcceptVisitor(this, falseBegin);
411
ControlFlowNode end = builder.CreateEndNode(ifElseStatement);
412
Connect(trueEnd, end);
413
if (falseEnd != null) {
414
Connect(falseEnd, end);
415
} else if (cond != true) {
416
Connect(data, end, ControlFlowEdgeType.ConditionFalse);
421
public override ControlFlowNode VisitSwitchStatement(SwitchStatement switchStatement, ControlFlowNode data)
423
// First, figure out which switch section will get called (if the expression is constant):
424
ConstantResolveResult constant = builder.EvaluateConstant(switchStatement.Expression);
425
SwitchSection defaultSection = null;
426
SwitchSection sectionMatchedByConstant = null;
427
foreach (SwitchSection section in switchStatement.SwitchSections) {
428
foreach (CaseLabel label in section.CaseLabels) {
429
if (label.Expression.IsNull) {
430
defaultSection = section;
431
} else if (constant != null) {
432
ConstantResolveResult labelConstant = builder.EvaluateConstant(label.Expression);
433
if (builder.AreEqualConstants(constant, labelConstant))
434
sectionMatchedByConstant = section;
438
if (constant != null && sectionMatchedByConstant == null)
439
sectionMatchedByConstant = defaultSection;
441
int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count;
443
ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false);
444
breakTargets.Push(end);
445
foreach (SwitchSection section in switchStatement.SwitchSections) {
446
if (constant == null || section == sectionMatchedByConstant) {
447
HandleStatementList(section.Statements, data);
449
// This section is unreachable: pass null to HandleStatementList.
450
HandleStatementList(section.Statements, null);
452
// Don't bother connecting the ends of the sections: the 'break' statement takes care of that.
455
if (defaultSection == null && sectionMatchedByConstant == null) {
459
if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) {
460
// Resolve 'goto case' statements:
461
throw new NotImplementedException();
464
builder.nodes.Add(end);
468
public override ControlFlowNode VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, ControlFlowNode data)
470
gotoCaseOrDefault.Add(data);
471
return builder.CreateEndNode(gotoCaseStatement);
474
public override ControlFlowNode VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement, ControlFlowNode data)
476
gotoCaseOrDefault.Add(data);
477
return builder.CreateEndNode(gotoDefaultStatement);
480
public override ControlFlowNode VisitWhileStatement(WhileStatement whileStatement, ControlFlowNode data)
482
// <data> <condition> while (cond) { <bodyStart> embeddedStmt; <bodyEnd> } <end>
483
ControlFlowNode end = builder.CreateEndNode(whileStatement, addToNodeList: false);
484
ControlFlowNode conditionNode = builder.CreateSpecialNode(whileStatement, ControlFlowNodeType.LoopCondition);
485
breakTargets.Push(end);
486
continueTargets.Push(conditionNode);
488
Connect(data, conditionNode);
490
bool? cond = builder.EvaluateCondition(whileStatement.Condition);
491
ControlFlowNode bodyStart = builder.CreateStartNode(whileStatement.EmbeddedStatement);
493
Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue);
494
ControlFlowNode bodyEnd = whileStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
495
Connect(bodyEnd, conditionNode);
497
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
500
continueTargets.Pop();
501
builder.nodes.Add(end);
505
public override ControlFlowNode VisitDoWhileStatement(DoWhileStatement doWhileStatement, ControlFlowNode data)
507
// <data> do { <bodyStart> embeddedStmt; <bodyEnd>} <condition> while(cond); <end>
508
ControlFlowNode end = builder.CreateEndNode(doWhileStatement, addToNodeList: false);
509
ControlFlowNode conditionNode = builder.CreateSpecialNode(doWhileStatement, ControlFlowNodeType.LoopCondition, addToNodeList: false);
510
breakTargets.Push(end);
511
continueTargets.Push(conditionNode);
513
ControlFlowNode bodyStart = builder.CreateStartNode(doWhileStatement.EmbeddedStatement);
514
Connect(data, bodyStart);
515
ControlFlowNode bodyEnd = doWhileStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
516
Connect(bodyEnd, conditionNode);
518
bool? cond = builder.EvaluateCondition(doWhileStatement.Condition);
520
Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue);
522
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
525
continueTargets.Pop();
526
builder.nodes.Add(conditionNode);
527
builder.nodes.Add(end);
531
public override ControlFlowNode VisitForStatement(ForStatement forStatement, ControlFlowNode data)
533
data = HandleStatementList(forStatement.Initializers, data);
534
// for (initializers <data>; <condition>cond; <iteratorStart>iterators<iteratorEnd>) { <bodyStart> embeddedStmt; <bodyEnd> } <end>
535
ControlFlowNode end = builder.CreateEndNode(forStatement, addToNodeList: false);
536
ControlFlowNode conditionNode = builder.CreateSpecialNode(forStatement, ControlFlowNodeType.LoopCondition);
537
Connect(data, conditionNode);
539
int iteratorStartNodeID = builder.nodes.Count;
540
ControlFlowNode iteratorEnd = HandleStatementList(forStatement.Iterators, null);
541
ControlFlowNode iteratorStart;
542
if (iteratorEnd != null) {
543
iteratorStart = builder.nodes[iteratorStartNodeID];
544
Connect(iteratorEnd, conditionNode);
546
iteratorStart = conditionNode;
549
breakTargets.Push(end);
550
continueTargets.Push(iteratorStart);
552
ControlFlowNode bodyStart = builder.CreateStartNode(forStatement.EmbeddedStatement);
553
ControlFlowNode bodyEnd = forStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
554
Connect(bodyEnd, iteratorStart);
557
continueTargets.Pop();
559
bool? cond = forStatement.Condition.IsNull ? true : builder.EvaluateCondition(forStatement.Condition);
561
Connect(conditionNode, bodyStart, ControlFlowEdgeType.ConditionTrue);
563
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
565
builder.nodes.Add(end);
569
ControlFlowNode HandleEmbeddedStatement(Statement embeddedStatement, ControlFlowNode source)
571
if (embeddedStatement == null || embeddedStatement.IsNull)
573
ControlFlowNode bodyStart = builder.CreateStartNode(embeddedStatement);
575
Connect(source, bodyStart);
576
return embeddedStatement.AcceptVisitor(this, bodyStart);
579
public override ControlFlowNode VisitForeachStatement(ForeachStatement foreachStatement, ControlFlowNode data)
581
// <data> foreach (<condition>...) { <bodyStart>embeddedStmt<bodyEnd> } <end>
582
ControlFlowNode end = builder.CreateEndNode(foreachStatement, addToNodeList: false);
583
ControlFlowNode conditionNode = builder.CreateSpecialNode(foreachStatement, ControlFlowNodeType.LoopCondition);
584
Connect(data, conditionNode);
586
breakTargets.Push(end);
587
continueTargets.Push(conditionNode);
589
ControlFlowNode bodyEnd = HandleEmbeddedStatement(foreachStatement.EmbeddedStatement, conditionNode);
590
Connect(bodyEnd, conditionNode);
593
continueTargets.Pop();
595
Connect(conditionNode, end);
596
builder.nodes.Add(end);
600
public override ControlFlowNode VisitBreakStatement(BreakStatement breakStatement, ControlFlowNode data)
602
if (breakTargets.Count > 0)
603
Connect(data, breakTargets.Peek(), ControlFlowEdgeType.Jump);
604
return builder.CreateEndNode(breakStatement);
607
public override ControlFlowNode VisitContinueStatement(ContinueStatement continueStatement, ControlFlowNode data)
609
if (continueTargets.Count > 0)
610
Connect(data, continueTargets.Peek(), ControlFlowEdgeType.Jump);
611
return builder.CreateEndNode(continueStatement);
614
public override ControlFlowNode VisitGotoStatement(GotoStatement gotoStatement, ControlFlowNode data)
616
builder.gotoStatements.Add(data);
617
return builder.CreateEndNode(gotoStatement);
620
public override ControlFlowNode VisitReturnStatement(ReturnStatement returnStatement, ControlFlowNode data)
622
return builder.CreateEndNode(returnStatement); // end not connected with data
625
public override ControlFlowNode VisitThrowStatement(ThrowStatement throwStatement, ControlFlowNode data)
627
return builder.CreateEndNode(throwStatement); // end not connected with data
630
public override ControlFlowNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, ControlFlowNode data)
632
ControlFlowNode end = builder.CreateEndNode(tryCatchStatement, addToNodeList: false);
633
var edge = Connect(HandleEmbeddedStatement(tryCatchStatement.TryBlock, data), end);
634
if (!tryCatchStatement.FinallyBlock.IsNull)
635
edge.AddJumpOutOfTryFinally(tryCatchStatement);
636
foreach (CatchClause cc in tryCatchStatement.CatchClauses) {
637
edge = Connect(HandleEmbeddedStatement(cc.Body, data), end);
638
if (!tryCatchStatement.FinallyBlock.IsNull)
639
edge.AddJumpOutOfTryFinally(tryCatchStatement);
641
if (!tryCatchStatement.FinallyBlock.IsNull) {
642
// Don't connect the end of the try-finally block to anything.
643
// Consumers of the CFG will have to special-case try-finally.
644
HandleEmbeddedStatement(tryCatchStatement.FinallyBlock, data);
646
builder.nodes.Add(end);
650
public override ControlFlowNode VisitCheckedStatement(CheckedStatement checkedStatement, ControlFlowNode data)
652
ControlFlowNode bodyEnd = HandleEmbeddedStatement(checkedStatement.Body, data);
653
return CreateConnectedEndNode(checkedStatement, bodyEnd);
656
public override ControlFlowNode VisitUncheckedStatement(UncheckedStatement uncheckedStatement, ControlFlowNode data)
658
ControlFlowNode bodyEnd = HandleEmbeddedStatement(uncheckedStatement.Body, data);
659
return CreateConnectedEndNode(uncheckedStatement, bodyEnd);
662
public override ControlFlowNode VisitLockStatement(LockStatement lockStatement, ControlFlowNode data)
664
ControlFlowNode bodyEnd = HandleEmbeddedStatement(lockStatement.EmbeddedStatement, data);
665
return CreateConnectedEndNode(lockStatement, bodyEnd);
668
public override ControlFlowNode VisitUsingStatement(UsingStatement usingStatement, ControlFlowNode data)
670
data = HandleEmbeddedStatement(usingStatement.ResourceAcquisition as Statement, data);
671
ControlFlowNode bodyEnd = HandleEmbeddedStatement(usingStatement.EmbeddedStatement, data);
672
return CreateConnectedEndNode(usingStatement, bodyEnd);
675
public override ControlFlowNode VisitYieldReturnStatement(YieldReturnStatement yieldStatement, ControlFlowNode data)
677
return CreateConnectedEndNode(yieldStatement, data);
680
public override ControlFlowNode VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement, ControlFlowNode data)
682
return builder.CreateEndNode(yieldBreakStatement); // end not connected with data
685
public override ControlFlowNode VisitUnsafeStatement(UnsafeStatement unsafeStatement, ControlFlowNode data)
687
ControlFlowNode bodyEnd = HandleEmbeddedStatement(unsafeStatement.Body, data);
688
return CreateConnectedEndNode(unsafeStatement, bodyEnd);
691
public override ControlFlowNode VisitFixedStatement(FixedStatement fixedStatement, ControlFlowNode data)
693
ControlFlowNode bodyEnd = HandleEmbeddedStatement(fixedStatement.EmbeddedStatement, data);
694
return CreateConnectedEndNode(fixedStatement, bodyEnd);