diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs
new file mode 100644
index 000000000..785ff4bf8
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs
@@ -0,0 +1,516 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+
+namespace ICSharpCode.NRefactory.CSharp.Analysis
+{
+ ///
+ /// Represents a node in the control flow graph of a C# method.
+ ///
+ public class ControlFlowNode
+ {
+ public readonly Statement PreviousStatement;
+ public readonly Statement NextStatement;
+
+ public ControlFlowNodeType Type;
+
+ public readonly List Predecessors = new List();
+ public readonly List Successors = new List();
+
+ public ControlFlowNode(Statement previousStatement, Statement nextStatement)
+ {
+ if (previousStatement == null && nextStatement == null)
+ throw new ArgumentException("previousStatement and nextStatement must not be both null");
+ this.PreviousStatement = previousStatement;
+ this.NextStatement = nextStatement;
+ }
+
+ ///
+ /// Creates a control flow edge from source to this.
+ ///
+ internal ControlFlowNode ConnectWith(ControlFlowNode source)
+ {
+ source.Successors.Add(this);
+ this.Predecessors.Add(source);
+ return this;
+ }
+ }
+
+ public enum ControlFlowNodeType
+ {
+ ///
+ /// Unknown node type
+ ///
+ None,
+ ///
+ /// Node in front of a statement
+ ///
+ StartNode,
+ ///
+ /// Node between two statements
+ ///
+ BetweenStatements,
+ ///
+ /// Node at the end of a statement list
+ ///
+ EndNode,
+ ///
+ /// Node representing the position before evaluating the condition of a loop.
+ ///
+ LoopCondition
+ }
+
+ public class ControlFlowGraphBuilder
+ {
+ protected virtual ControlFlowNode CreateNode(Statement previousStatement, Statement nextStatement)
+ {
+ return new ControlFlowNode(previousStatement, nextStatement);
+ }
+
+ List nodes;
+ Dictionary labels;
+ List gotoStatements;
+
+ public ControlFlowNode[] BuildControlFlowGraph(BlockStatement block)
+ {
+ NodeCreationVisitor nodeCreationVisitor = new NodeCreationVisitor();
+ nodeCreationVisitor.builder = this;
+ try {
+ nodes = new List();
+ labels = new Dictionary();
+ gotoStatements = new List();
+ ControlFlowNode entryPoint = CreateStartNode(block);
+ nodeCreationVisitor.VisitBlockStatement(block, entryPoint);
+
+ // Resolve goto statements:
+ foreach (ControlFlowNode gotoStmt in gotoStatements) {
+ string label = ((GotoStatement)gotoStmt.NextStatement).Label;
+ ControlFlowNode labelNode;
+ if (labels.TryGetValue(label, out labelNode))
+ labelNode.ConnectWith(gotoStmt);
+ }
+
+ return nodes.ToArray();
+ } finally {
+ nodes = null;
+ labels = null;
+ gotoStatements = null;
+ }
+ }
+
+ ControlFlowNode CreateStartNode(Statement statement)
+ {
+ ControlFlowNode node = CreateNode(null, statement);
+ node.Type = ControlFlowNodeType.StartNode;
+ nodes.Add(node);
+ return node;
+ }
+
+ ControlFlowNode CreateSpecialNode(Statement statement, ControlFlowNodeType type)
+ {
+ ControlFlowNode node = CreateNode(statement, null);
+ node.Type = type;
+ nodes.Add(node);
+ return node;
+ }
+
+ ControlFlowNode CreateEndNode(Statement statement)
+ {
+ // Find the next statement in the same role:
+ AstNode next = statement;
+ do {
+ next = next.NextSibling;
+ } while (next != null && next.Role != statement.Role);
+
+ Statement nextStatement = next as Statement;
+ ControlFlowNode node = CreateNode(statement, nextStatement);
+ node.Type = nextStatement != null ? ControlFlowNodeType.BetweenStatements : ControlFlowNodeType.EndNode;
+ nodes.Add(node);
+ return node;
+ }
+
+ #region Constant evaluation
+ ///
+ /// Evaluates an expression.
+ ///
+ /// The constant value of the expression; or null if the expression is not a constant.
+ ConstantResolveResult EvaluateConstant(Expression expr)
+ {
+ return null; // TODO: implement this using the C# resolver
+ }
+
+ ///
+ /// Evaluates an expression.
+ ///
+ /// The value of the constant boolean expression; or null if the value is not a constant boolean expression.
+ bool? EvaluateCondition(Expression expr)
+ {
+ ConstantResolveResult crr = EvaluateConstant(expr);
+ if (crr != null)
+ return crr.ConstantValue as bool?;
+ else
+ return null;
+ }
+
+ bool AreEqualConstants(ConstantResolveResult c1, ConstantResolveResult c2)
+ {
+ return false; // TODO: implement this using the resolver's operator==
+ }
+ #endregion
+
+ sealed class NodeCreationVisitor : DepthFirstAstVisitor
+ {
+ // 'data' parameter: input control flow node (start of statement being visited)
+ // Return value: result control flow node (end of statement being visited)
+
+ internal ControlFlowGraphBuilder builder;
+ Stack breakTargets = new Stack();
+ Stack continueTargets = new Stack();
+ List gotoCaseOrDefault = new List();
+
+ protected override ControlFlowNode VisitChildren(AstNode node, ControlFlowNode data)
+ {
+ // We have overrides for all possible expressions and should visit expressions only.
+ throw new NotImplementedException();
+ }
+
+ public override ControlFlowNode VisitBlockStatement(BlockStatement blockStatement, ControlFlowNode data)
+ {
+ // C# 4.0 spec: §8.2 Blocks
+ ControlFlowNode childNode = HandleStatementList(blockStatement.Statements, data);
+ return builder.CreateEndNode(blockStatement).ConnectWith(childNode);
+ }
+
+ ControlFlowNode HandleStatementList(AstNodeCollection statements, ControlFlowNode source)
+ {
+ ControlFlowNode childNode = null;
+ foreach (Statement stmt in statements) {
+ if (childNode == null) {
+ childNode = builder.CreateStartNode(stmt);
+ childNode.ConnectWith(source);
+ }
+ Debug.Assert(childNode.NextStatement == stmt);
+ childNode = stmt.AcceptVisitor(this, childNode);
+ Debug.Assert(childNode.PreviousStatement == stmt);
+ }
+ return childNode ?? source;
+ }
+
+ public override ControlFlowNode VisitEmptyStatement(EmptyStatement emptyStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(emptyStatement).ConnectWith(data);
+ }
+
+ public override ControlFlowNode VisitLabelStatement(LabelStatement labelStatement, ControlFlowNode data)
+ {
+ ControlFlowNode end = builder.CreateEndNode(labelStatement);
+ builder.labels[labelStatement.Label] = end;
+ return end.ConnectWith(data);
+ }
+
+ public override ControlFlowNode VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(variableDeclarationStatement).ConnectWith(data);
+ }
+
+ public override ControlFlowNode VisitExpressionStatement(ExpressionStatement expressionStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(expressionStatement).ConnectWith(data);
+ }
+
+ public override ControlFlowNode VisitIfElseStatement(IfElseStatement ifElseStatement, ControlFlowNode data)
+ {
+ bool? cond = builder.EvaluateCondition(ifElseStatement.Condition);
+ ControlFlowNode trueBegin = builder.CreateStartNode(ifElseStatement.TrueStatement);
+ if (cond != false)
+ trueBegin.ConnectWith(data);
+ ControlFlowNode trueEnd = ifElseStatement.TrueStatement.AcceptVisitor(this, trueBegin);
+ ControlFlowNode falseEnd;
+ if (ifElseStatement.FalseStatement.IsNull) {
+ falseEnd = null;
+ } else {
+ ControlFlowNode falseBegin = builder.CreateStartNode(ifElseStatement.FalseStatement);
+ if (cond != true)
+ falseBegin.ConnectWith(data);
+ falseEnd = ifElseStatement.FalseStatement.AcceptVisitor(this, falseBegin);
+ }
+ ControlFlowNode end = builder.CreateEndNode(ifElseStatement);
+ end.ConnectWith(trueEnd);
+ if (falseEnd != null) {
+ end.ConnectWith(falseEnd);
+ } else if (cond != true) {
+ end.ConnectWith(data);
+ }
+ return end;
+ }
+
+ public override ControlFlowNode VisitSwitchStatement(SwitchStatement switchStatement, ControlFlowNode data)
+ {
+ // First, figure out which switch section will get called (if the expression is constant):
+ ConstantResolveResult constant = builder.EvaluateConstant(switchStatement.Expression);
+ SwitchSection defaultSection = null;
+ SwitchSection sectionMatchedByConstant = null;
+ foreach (SwitchSection section in switchStatement.SwitchSections) {
+ foreach (CaseLabel label in section.CaseLabels) {
+ if (label.Expression.IsNull) {
+ defaultSection = section;
+ } else if (constant != null) {
+ ConstantResolveResult labelConstant = builder.EvaluateConstant(label.Expression);
+ if (builder.AreEqualConstants(constant, labelConstant))
+ sectionMatchedByConstant = section;
+ }
+ }
+ }
+ if (constant != null && sectionMatchedByConstant == null)
+ sectionMatchedByConstant = defaultSection;
+
+ int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count;
+
+ ControlFlowNode end = builder.CreateEndNode(switchStatement);
+ breakTargets.Push(end);
+ foreach (SwitchSection section in switchStatement.SwitchSections) {
+ if (constant == null || section == sectionMatchedByConstant) {
+ HandleStatementList(section.Statements, data);
+ } else {
+ // This section is unreachable: pass null to HandleStatementList.
+ HandleStatementList(section.Statements, null);
+ }
+ // Don't bother connecting the ends of the sections: the 'break' statement takes care of that.
+ }
+ breakTargets.Pop();
+ if (defaultSection == null && sectionMatchedByConstant == null) {
+ end.ConnectWith(data);
+ }
+
+ if (gotoCaseOrDefault.Count > gotoCaseOrDefaultInOuterScope) {
+ // Resolve 'goto case' statements:
+ throw new NotImplementedException();
+ }
+
+ return end;
+ }
+
+ public override ControlFlowNode VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, ControlFlowNode data)
+ {
+ gotoCaseOrDefault.Add(data);
+ return builder.CreateEndNode(gotoCaseStatement);
+ }
+
+ public override ControlFlowNode VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement, ControlFlowNode data)
+ {
+ gotoCaseOrDefault.Add(data);
+ return builder.CreateEndNode(gotoDefaultStatement);
+ }
+
+ public override ControlFlowNode VisitWhileStatement(WhileStatement whileStatement, ControlFlowNode data)
+ {
+ // while (cond) { embeddedStmt; }
+ ControlFlowNode end = builder.CreateEndNode(whileStatement);
+ ControlFlowNode conditionNode = builder.CreateSpecialNode(whileStatement, ControlFlowNodeType.LoopCondition);
+ breakTargets.Push(end);
+ continueTargets.Push(conditionNode);
+
+ conditionNode.ConnectWith(data);
+
+ bool? cond = builder.EvaluateCondition(whileStatement.Condition);
+ ControlFlowNode bodyStart = builder.CreateStartNode(whileStatement.EmbeddedStatement);
+ if (cond != false)
+ bodyStart.ConnectWith(conditionNode);
+ ControlFlowNode bodyEnd = whileStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
+ conditionNode.ConnectWith(bodyEnd);
+ if (cond != true)
+ end.ConnectWith(conditionNode);
+
+ breakTargets.Pop();
+ continueTargets.Pop();
+ return end;
+ }
+
+ public override ControlFlowNode VisitDoWhileStatement(DoWhileStatement doWhileStatement, ControlFlowNode data)
+ {
+ // do { embeddedStmt; } while(cond);
+ ControlFlowNode end = builder.CreateEndNode(doWhileStatement);
+ ControlFlowNode conditionNode = builder.CreateSpecialNode(doWhileStatement, ControlFlowNodeType.LoopCondition);
+ breakTargets.Push(end);
+ continueTargets.Push(conditionNode);
+
+ ControlFlowNode bodyStart = builder.CreateStartNode(doWhileStatement.EmbeddedStatement);
+ bodyStart.ConnectWith(data);
+ ControlFlowNode bodyEnd = doWhileStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
+ conditionNode.ConnectWith(bodyEnd);
+
+ bool? cond = builder.EvaluateCondition(doWhileStatement.Condition);
+ if (cond != false)
+ bodyStart.ConnectWith(conditionNode);
+ if (cond != true)
+ end.ConnectWith(conditionNode);
+
+ breakTargets.Pop();
+ continueTargets.Pop();
+ return end;
+ }
+
+ public override ControlFlowNode VisitForStatement(ForStatement forStatement, ControlFlowNode data)
+ {
+ data = HandleStatementList(forStatement.Initializers, data);
+ // for (initializers ; cond; iterators) { embeddedStmt; }
+ ControlFlowNode end = builder.CreateEndNode(forStatement);
+ ControlFlowNode conditionNode = builder.CreateSpecialNode(forStatement, ControlFlowNodeType.LoopCondition);
+ conditionNode.ConnectWith(data);
+
+ int iteratorStartNodeID = builder.nodes.Count;
+ ControlFlowNode iteratorEnd = HandleStatementList(forStatement.Iterators, null);
+ ControlFlowNode iteratorStart;
+ if (iteratorEnd != null) {
+ iteratorStart = builder.nodes[iteratorStartNodeID];
+ iteratorEnd.ConnectWith(conditionNode);
+ } else {
+ iteratorStart = conditionNode;
+ }
+
+ breakTargets.Push(end);
+ continueTargets.Push(iteratorStart);
+
+ ControlFlowNode bodyStart = builder.CreateStartNode(forStatement.EmbeddedStatement);
+ ControlFlowNode bodyEnd = forStatement.EmbeddedStatement.AcceptVisitor(this, bodyStart);
+ iteratorStart.ConnectWith(bodyEnd);
+
+ breakTargets.Pop();
+ continueTargets.Pop();
+
+ bool? cond = forStatement.Condition.IsNull ? true : builder.EvaluateCondition(forStatement.Condition);
+ if (cond != false)
+ bodyStart.ConnectWith(conditionNode);
+ if (cond != true)
+ end.ConnectWith(conditionNode);
+
+ return end;
+ }
+
+ ControlFlowNode HandleEmbeddedStatement(Statement embeddedStatement, ControlFlowNode source)
+ {
+ if (embeddedStatement == null || embeddedStatement.IsNull)
+ return source;
+ ControlFlowNode bodyStart = builder.CreateStartNode(embeddedStatement);
+ if (source != null)
+ bodyStart.ConnectWith(source);
+ return embeddedStatement.AcceptVisitor(this, bodyStart);
+ }
+
+ public override ControlFlowNode VisitForeachStatement(ForeachStatement foreachStatement, ControlFlowNode data)
+ {
+ // foreach (...) { embeddedStmt }
+ ControlFlowNode end = builder.CreateEndNode(foreachStatement);
+ ControlFlowNode conditionNode = builder.CreateSpecialNode(foreachStatement, ControlFlowNodeType.LoopCondition);
+ conditionNode.ConnectWith(data);
+
+ breakTargets.Push(end);
+ continueTargets.Push(conditionNode);
+
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(foreachStatement.EmbeddedStatement, conditionNode);
+ conditionNode.ConnectWith(bodyEnd);
+
+ breakTargets.Pop();
+ continueTargets.Pop();
+
+ return end.ConnectWith(conditionNode);
+ }
+
+ public override ControlFlowNode VisitBreakStatement(BreakStatement breakStatement, ControlFlowNode data)
+ {
+ if (breakTargets.Count > 0)
+ breakTargets.Peek().ConnectWith(data);
+ return builder.CreateEndNode(breakStatement);
+ }
+
+ public override ControlFlowNode VisitContinueStatement(ContinueStatement continueStatement, ControlFlowNode data)
+ {
+ if (continueTargets.Count > 0)
+ continueTargets.Peek().ConnectWith(data);
+ return builder.CreateEndNode(continueStatement);
+ }
+
+ public override ControlFlowNode VisitGotoStatement(GotoStatement gotoStatement, ControlFlowNode data)
+ {
+ builder.gotoStatements.Add(data);
+ return builder.CreateEndNode(gotoStatement);
+ }
+
+ public override ControlFlowNode VisitReturnStatement(ReturnStatement returnStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(returnStatement); // end not connected with data
+ }
+
+ public override ControlFlowNode VisitThrowStatement(ThrowStatement throwStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(throwStatement); // end not connected with data
+ }
+
+ public override ControlFlowNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, ControlFlowNode data)
+ {
+ ControlFlowNode end = builder.CreateEndNode(tryCatchStatement);
+ end.ConnectWith(HandleEmbeddedStatement(tryCatchStatement.TryBlock, data));
+ foreach (CatchClause cc in tryCatchStatement.CatchClauses) {
+ end.ConnectWith(HandleEmbeddedStatement(cc.Body, data));
+ }
+ if (!tryCatchStatement.FinallyBlock.IsNull) {
+ // Don't connect the end of the try-finally block to anything.
+ // Consumers of the CFG will have to special-case try-finally.
+ HandleEmbeddedStatement(tryCatchStatement.FinallyBlock, data);
+ }
+ return end;
+ }
+
+ public override ControlFlowNode VisitCheckedStatement(CheckedStatement checkedStatement, ControlFlowNode data)
+ {
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(checkedStatement.Body, data);
+ return builder.CreateEndNode(checkedStatement).ConnectWith(bodyEnd);
+ }
+
+ public override ControlFlowNode VisitUncheckedStatement(UncheckedStatement uncheckedStatement, ControlFlowNode data)
+ {
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(uncheckedStatement.Body, data);
+ return builder.CreateEndNode(uncheckedStatement).ConnectWith(bodyEnd);
+ }
+
+ public override ControlFlowNode VisitLockStatement(LockStatement lockStatement, ControlFlowNode data)
+ {
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(lockStatement.EmbeddedStatement, data);
+ return builder.CreateEndNode(lockStatement).ConnectWith(bodyEnd);
+ }
+
+ public override ControlFlowNode VisitUsingStatement(UsingStatement usingStatement, ControlFlowNode data)
+ {
+ data = HandleEmbeddedStatement(usingStatement.ResourceAcquisition as Statement, data);
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(usingStatement.EmbeddedStatement, data);
+ return builder.CreateEndNode(usingStatement).ConnectWith(bodyEnd);
+ }
+
+ public override ControlFlowNode VisitYieldStatement(YieldStatement yieldStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(yieldStatement).ConnectWith(data);
+ }
+
+ public override ControlFlowNode VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement, ControlFlowNode data)
+ {
+ return builder.CreateEndNode(yieldBreakStatement); // end not connected with data
+ }
+
+ public override ControlFlowNode VisitUnsafeStatement(UnsafeStatement unsafeStatement, ControlFlowNode data)
+ {
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(unsafeStatement.Body, data);
+ return builder.CreateEndNode(unsafeStatement).ConnectWith(bodyEnd);
+ }
+
+ public override ControlFlowNode VisitFixedStatement(FixedStatement fixedStatement, ControlFlowNode data)
+ {
+ ControlFlowNode bodyEnd = HandleEmbeddedStatement(fixedStatement.EmbeddedStatement, data);
+ return builder.CreateEndNode(fixedStatement).ConnectWith(bodyEnd);
+ }
+ }
+ }
+}
diff --git a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
index b72cd1146..b0595a6e2 100644
--- a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
+++ b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
@@ -61,6 +61,7 @@
+
@@ -354,5 +355,8 @@
Mono.Cecil
+
+
+
\ No newline at end of file