Browse Source

Order the control flow nodes lexically, and allow restricting definite assignment analysis to a specific lexical range.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
a2fb74bee6
  1. 36
      NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs
  2. 151
      NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs

36
NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs

@ -222,14 +222,15 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return node; return node;
} }
ControlFlowNode CreateSpecialNode(Statement statement, ControlFlowNodeType type) ControlFlowNode CreateSpecialNode(Statement statement, ControlFlowNodeType type, bool addToNodeList = true)
{ {
ControlFlowNode node = CreateNode(null, statement, type); ControlFlowNode node = CreateNode(null, statement, type);
nodes.Add(node); if (addToNodeList)
nodes.Add(node);
return node; return node;
} }
ControlFlowNode CreateEndNode(Statement statement) ControlFlowNode CreateEndNode(Statement statement, bool addToNodeList = true)
{ {
Statement nextStatement; Statement nextStatement;
if (statement == rootStatement) { if (statement == rootStatement) {
@ -244,7 +245,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
} }
ControlFlowNodeType type = nextStatement != null ? ControlFlowNodeType.BetweenStatements : ControlFlowNodeType.EndNode; ControlFlowNodeType type = nextStatement != null ? ControlFlowNodeType.BetweenStatements : ControlFlowNodeType.EndNode;
ControlFlowNode node = CreateNode(statement, nextStatement, type); ControlFlowNode node = CreateNode(statement, nextStatement, type);
nodes.Add(node); if (addToNodeList)
nodes.Add(node);
return node; return node;
} }
#endregion #endregion
@ -259,7 +261,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// Evaluates an expression. /// Evaluates an expression.
/// </summary> /// </summary>
/// <returns>The constant value of the expression; or null if the expression is not a constant.</returns> /// <returns>The constant value of the expression; or null if the expression is not a constant.</returns>
internal ConstantResolveResult EvaluateConstant(Expression expr) ConstantResolveResult EvaluateConstant(Expression expr)
{ {
if (EvaluateOnlyPrimitiveConstants) { if (EvaluateOnlyPrimitiveConstants) {
if (!(expr is PrimitiveExpression || expr is NullReferenceExpression)) if (!(expr is PrimitiveExpression || expr is NullReferenceExpression))
@ -272,7 +274,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// Evaluates an expression. /// Evaluates an expression.
/// </summary> /// </summary>
/// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns> /// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns>
internal bool? EvaluateCondition(Expression expr) bool? EvaluateCondition(Expression expr)
{ {
ConstantResolveResult rr = EvaluateConstant(expr); ConstantResolveResult rr = EvaluateConstant(expr);
if (rr != null) if (rr != null)
@ -418,7 +420,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count; int gotoCaseOrDefaultInOuterScope = gotoCaseOrDefault.Count;
ControlFlowNode end = builder.CreateEndNode(switchStatement); ControlFlowNode end = builder.CreateEndNode(switchStatement, addToNodeList: false);
breakTargets.Push(end); breakTargets.Push(end);
foreach (SwitchSection section in switchStatement.SwitchSections) { foreach (SwitchSection section in switchStatement.SwitchSections) {
if (constant == null || section == sectionMatchedByConstant) { if (constant == null || section == sectionMatchedByConstant) {
@ -439,6 +441,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
throw new NotImplementedException(); throw new NotImplementedException();
} }
builder.nodes.Add(end);
return end; return end;
} }
@ -457,7 +460,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public override ControlFlowNode VisitWhileStatement(WhileStatement whileStatement, ControlFlowNode data) public override ControlFlowNode VisitWhileStatement(WhileStatement whileStatement, ControlFlowNode data)
{ {
// <data> <condition> while (cond) { <bodyStart> embeddedStmt; <bodyEnd> } <end> // <data> <condition> while (cond) { <bodyStart> embeddedStmt; <bodyEnd> } <end>
ControlFlowNode end = builder.CreateEndNode(whileStatement); ControlFlowNode end = builder.CreateEndNode(whileStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(whileStatement, ControlFlowNodeType.LoopCondition); ControlFlowNode conditionNode = builder.CreateSpecialNode(whileStatement, ControlFlowNodeType.LoopCondition);
breakTargets.Push(end); breakTargets.Push(end);
continueTargets.Push(conditionNode); continueTargets.Push(conditionNode);
@ -475,14 +478,15 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
breakTargets.Pop(); breakTargets.Pop();
continueTargets.Pop(); continueTargets.Pop();
builder.nodes.Add(end);
return end; return end;
} }
public override ControlFlowNode VisitDoWhileStatement(DoWhileStatement doWhileStatement, ControlFlowNode data) public override ControlFlowNode VisitDoWhileStatement(DoWhileStatement doWhileStatement, ControlFlowNode data)
{ {
// <data> do { <bodyStart> embeddedStmt; <bodyEnd>} <condition> while(cond); <end> // <data> do { <bodyStart> embeddedStmt; <bodyEnd>} <condition> while(cond); <end>
ControlFlowNode end = builder.CreateEndNode(doWhileStatement); ControlFlowNode end = builder.CreateEndNode(doWhileStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(doWhileStatement, ControlFlowNodeType.LoopCondition); ControlFlowNode conditionNode = builder.CreateSpecialNode(doWhileStatement, ControlFlowNodeType.LoopCondition, addToNodeList: false);
breakTargets.Push(end); breakTargets.Push(end);
continueTargets.Push(conditionNode); continueTargets.Push(conditionNode);
@ -499,6 +503,8 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
breakTargets.Pop(); breakTargets.Pop();
continueTargets.Pop(); continueTargets.Pop();
builder.nodes.Add(conditionNode);
builder.nodes.Add(end);
return end; return end;
} }
@ -506,7 +512,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
{ {
data = HandleStatementList(forStatement.Initializers, data); data = HandleStatementList(forStatement.Initializers, data);
// for (initializers <data>; <condition>cond; <iteratorStart>iterators<iteratorEnd>) { <bodyStart> embeddedStmt; <bodyEnd> } <end> // for (initializers <data>; <condition>cond; <iteratorStart>iterators<iteratorEnd>) { <bodyStart> embeddedStmt; <bodyEnd> } <end>
ControlFlowNode end = builder.CreateEndNode(forStatement); ControlFlowNode end = builder.CreateEndNode(forStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(forStatement, ControlFlowNodeType.LoopCondition); ControlFlowNode conditionNode = builder.CreateSpecialNode(forStatement, ControlFlowNodeType.LoopCondition);
Connect(data, conditionNode); Connect(data, conditionNode);
@ -536,6 +542,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
if (cond != true) if (cond != true)
Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse); Connect(conditionNode, end, ControlFlowEdgeType.ConditionFalse);
builder.nodes.Add(end);
return end; return end;
} }
@ -552,7 +559,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public override ControlFlowNode VisitForeachStatement(ForeachStatement foreachStatement, ControlFlowNode data) public override ControlFlowNode VisitForeachStatement(ForeachStatement foreachStatement, ControlFlowNode data)
{ {
// <data> foreach (<condition>...) { <bodyStart>embeddedStmt<bodyEnd> } <end> // <data> foreach (<condition>...) { <bodyStart>embeddedStmt<bodyEnd> } <end>
ControlFlowNode end = builder.CreateEndNode(foreachStatement); ControlFlowNode end = builder.CreateEndNode(foreachStatement, addToNodeList: false);
ControlFlowNode conditionNode = builder.CreateSpecialNode(foreachStatement, ControlFlowNodeType.LoopCondition); ControlFlowNode conditionNode = builder.CreateSpecialNode(foreachStatement, ControlFlowNodeType.LoopCondition);
Connect(data, conditionNode); Connect(data, conditionNode);
@ -566,7 +573,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
continueTargets.Pop(); continueTargets.Pop();
Connect(conditionNode, end); Connect(conditionNode, end);
builder.nodes.Add(end);
return end; return end;
} }
@ -602,7 +609,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public override ControlFlowNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, ControlFlowNode data) public override ControlFlowNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, ControlFlowNode data)
{ {
ControlFlowNode end = builder.CreateEndNode(tryCatchStatement); ControlFlowNode end = builder.CreateEndNode(tryCatchStatement, addToNodeList: false);
var edge = Connect(HandleEmbeddedStatement(tryCatchStatement.TryBlock, data), end); var edge = Connect(HandleEmbeddedStatement(tryCatchStatement.TryBlock, data), end);
if (!tryCatchStatement.FinallyBlock.IsNull) if (!tryCatchStatement.FinallyBlock.IsNull)
edge.AddJumpOutOfTryFinally(tryCatchStatement); edge.AddJumpOutOfTryFinally(tryCatchStatement);
@ -616,6 +623,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
// Consumers of the CFG will have to special-case try-finally. // Consumers of the CFG will have to special-case try-finally.
HandleEmbeddedStatement(tryCatchStatement.FinallyBlock, data); HandleEmbeddedStatement(tryCatchStatement.FinallyBlock, data);
} }
builder.nodes.Add(end);
return end; return end;
} }

151
NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs

@ -44,21 +44,40 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// </summary> /// </summary>
public class DefiniteAssignmentAnalysis public class DefiniteAssignmentAnalysis
{ {
readonly ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder(); sealed class DefiniteAssignmentNode : ControlFlowNode
{
public int Index;
public DefiniteAssignmentStatus NodeStatus;
public DefiniteAssignmentNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
: base(previousStatement, nextStatement, type)
{
}
}
sealed class DerivedControlFlowGraphBuilder : ControlFlowGraphBuilder
{
protected override ControlFlowNode CreateNode(Statement previousStatement, Statement nextStatement, ControlFlowNodeType type)
{
return new DefiniteAssignmentNode(previousStatement, nextStatement, type);
}
}
readonly DerivedControlFlowGraphBuilder cfgBuilder = new DerivedControlFlowGraphBuilder();
readonly DefiniteAssignmentVisitor visitor = new DefiniteAssignmentVisitor(); readonly DefiniteAssignmentVisitor visitor = new DefiniteAssignmentVisitor();
readonly List<ControlFlowNode> allNodes = new List<ControlFlowNode>(); readonly List<DefiniteAssignmentNode> allNodes = new List<DefiniteAssignmentNode>();
readonly Dictionary<Statement, ControlFlowNode> beginNodeDict = new Dictionary<Statement, ControlFlowNode>(); readonly Dictionary<Statement, DefiniteAssignmentNode> beginNodeDict = new Dictionary<Statement, DefiniteAssignmentNode>();
readonly Dictionary<Statement, ControlFlowNode> endNodeDict = new Dictionary<Statement, ControlFlowNode>(); readonly Dictionary<Statement, DefiniteAssignmentNode> endNodeDict = new Dictionary<Statement, DefiniteAssignmentNode>();
readonly Dictionary<Statement, ControlFlowNode> conditionNodeDict = new Dictionary<Statement, ControlFlowNode>(); readonly Dictionary<Statement, DefiniteAssignmentNode> conditionNodeDict = new Dictionary<Statement, DefiniteAssignmentNode>();
readonly ResolveVisitor resolveVisitor; readonly ResolveVisitor resolveVisitor;
readonly CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
Dictionary<ControlFlowNode, DefiniteAssignmentStatus> nodeStatus = new Dictionary<ControlFlowNode, DefiniteAssignmentStatus>();
Dictionary<ControlFlowEdge, DefiniteAssignmentStatus> edgeStatus = new Dictionary<ControlFlowEdge, DefiniteAssignmentStatus>(); Dictionary<ControlFlowEdge, DefiniteAssignmentStatus> edgeStatus = new Dictionary<ControlFlowEdge, DefiniteAssignmentStatus>();
string variableName; string variableName;
List<IdentifierExpression> unassignedVariableUses = new List<IdentifierExpression>(); List<IdentifierExpression> unassignedVariableUses = new List<IdentifierExpression>();
int analyzedRangeStart, analyzedRangeEnd;
Queue<ControlFlowNode> nodesWithModifiedInput = new Queue<ControlFlowNode>(); Queue<DefiniteAssignmentNode> nodesWithModifiedInput = new Queue<DefiniteAssignmentNode>();
public DefiniteAssignmentAnalysis(Statement rootStatement, CancellationToken cancellationToken = default(CancellationToken)) public DefiniteAssignmentAnalysis(Statement rootStatement, CancellationToken cancellationToken = default(CancellationToken))
: this(rootStatement, null, cancellationToken) : this(rootStatement, null, cancellationToken)
@ -83,20 +102,18 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
if (resolveVisitor.TypeResolveContext is MinimalResolveContext) { if (resolveVisitor.TypeResolveContext is MinimalResolveContext) {
cfgBuilder.EvaluateOnlyPrimitiveConstants = true; cfgBuilder.EvaluateOnlyPrimitiveConstants = true;
} }
allNodes.AddRange(cfgBuilder.BuildControlFlowGraph(rootStatement, resolveVisitor)); allNodes.AddRange(cfgBuilder.BuildControlFlowGraph(rootStatement, resolveVisitor).Cast<DefiniteAssignmentNode>());
foreach (AstNode descendant in rootStatement.Descendants) { for (int i = 0; i < allNodes.Count; i++) {
// Anonymous methods have separate control flow graphs, but we also need to analyze those. DefiniteAssignmentNode node = allNodes[i];
AnonymousMethodExpression ame = descendant as AnonymousMethodExpression; node.Index = i; // assign numbers to the nodes
if (ame != null) if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements) {
allNodes.AddRange(cfgBuilder.BuildControlFlowGraph(ame.Body, resolveVisitor)); // Anonymous methods have separate control flow graphs, but we also need to analyze those.
LambdaExpression lambda = descendant as LambdaExpression; // Iterate backwards so that anonymous methods are inserted in the correct order
if (lambda != null && lambda.Body is Statement) for (AstNode child = node.NextStatement.LastChild; child != null; child = child.PrevSibling) {
allNodes.AddRange(cfgBuilder.BuildControlFlowGraph((Statement)lambda.Body, resolveVisitor)); InsertAnonymousMethods(i + 1, child);
} }
// Verify that we created nodes for all statements: }
Debug.Assert(!rootStatement.DescendantsAndSelf.OfType<Statement>().Except(allNodes.Select(n => n.NextStatement)).Any()); // Now register the node in the dictionaries:
// Now register the nodes in the dictionaries:
foreach (ControlFlowNode node in allNodes) {
if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements) if (node.Type == ControlFlowNodeType.StartNode || node.Type == ControlFlowNodeType.BetweenStatements)
beginNodeDict.Add(node.NextStatement, node); beginNodeDict.Add(node.NextStatement, node);
if (node.Type == ControlFlowNodeType.BetweenStatements || node.Type == ControlFlowNodeType.EndNode) if (node.Type == ControlFlowNodeType.BetweenStatements || node.Type == ControlFlowNodeType.EndNode)
@ -104,6 +121,32 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
if (node.Type == ControlFlowNodeType.LoopCondition) if (node.Type == ControlFlowNodeType.LoopCondition)
conditionNodeDict.Add(node.NextStatement, node); conditionNodeDict.Add(node.NextStatement, node);
} }
// Verify that we created nodes for all statements:
Debug.Assert(!rootStatement.DescendantsAndSelf.OfType<Statement>().Except(allNodes.Select(n => n.NextStatement)).Any());
this.analyzedRangeStart = 0;
this.analyzedRangeEnd = allNodes.Count - 1;
}
void InsertAnonymousMethods(int insertPos, AstNode node)
{
// Ignore any statements, as those have their own ControlFlowNode and get handled separately
if (node is Statement)
return;
AnonymousMethodExpression ame = node as AnonymousMethodExpression;
if (ame != null) {
allNodes.InsertRange(insertPos, cfgBuilder.BuildControlFlowGraph(ame.Body, resolveVisitor).Cast<DefiniteAssignmentNode>());
return;
}
LambdaExpression lambda = node as LambdaExpression;
if (lambda != null && lambda.Body is Statement) {
allNodes.InsertRange(insertPos, cfgBuilder.BuildControlFlowGraph((Statement)lambda.Body, resolveVisitor).Cast<DefiniteAssignmentNode>());
return;
}
// Descend into child expressions
// Iterate backwards so that anonymous methods are inserted in the correct order
for (AstNode child = node.LastChild; child != null; child = child.PrevSibling) {
InsertAnonymousMethods(insertPos, child);
}
} }
/// <summary> /// <summary>
@ -115,21 +158,37 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
} }
} }
/// <summary>
/// Sets the range of statements to be analyzed.
/// This method can be used to restrict the analysis to only a part of the method.
/// Only the control flow paths that are fully contained within the selected part will be analyzed.
/// </summary>
/// <remarks>Both 'start' and 'end' are inclusive.</remarks>
public void SetAnalyzedRange(Statement start, Statement end)
{
int startIndex = beginNodeDict[start].Index;
int endIndex = endNodeDict[end].Index;
if (startIndex > endIndex)
throw new ArgumentException("The start statement must be lexically preceding the end statement");
this.analyzedRangeStart = startIndex;
this.analyzedRangeEnd = endIndex;
}
public void Analyze(string variable, DefiniteAssignmentStatus initialStatus = DefiniteAssignmentStatus.PotentiallyAssigned) public void Analyze(string variable, DefiniteAssignmentStatus initialStatus = DefiniteAssignmentStatus.PotentiallyAssigned)
{ {
this.variableName = variable; this.variableName = variable;
// Reset the status: // Reset the status:
unassignedVariableUses.Clear(); unassignedVariableUses.Clear();
foreach (ControlFlowNode node in allNodes) { foreach (DefiniteAssignmentNode node in allNodes) {
nodeStatus[node] = DefiniteAssignmentStatus.CodeUnreachable; node.NodeStatus = DefiniteAssignmentStatus.CodeUnreachable;
foreach (ControlFlowEdge edge in node.Outgoing) foreach (ControlFlowEdge edge in node.Outgoing)
edgeStatus[edge] = DefiniteAssignmentStatus.CodeUnreachable; edgeStatus[edge] = DefiniteAssignmentStatus.CodeUnreachable;
} }
ChangeNodeStatus(allNodes[0], initialStatus); ChangeNodeStatus(allNodes[analyzedRangeStart], initialStatus);
// Iterate as long as the input status of some nodes is changing: // Iterate as long as the input status of some nodes is changing:
while (nodesWithModifiedInput.Count > 0) { while (nodesWithModifiedInput.Count > 0) {
ControlFlowNode node = nodesWithModifiedInput.Dequeue(); DefiniteAssignmentNode node = nodesWithModifiedInput.Dequeue();
DefiniteAssignmentStatus inputStatus = DefiniteAssignmentStatus.CodeUnreachable; DefiniteAssignmentStatus inputStatus = DefiniteAssignmentStatus.CodeUnreachable;
foreach (ControlFlowEdge edge in node.Incoming) { foreach (ControlFlowEdge edge in node.Incoming) {
inputStatus = MergeStatus(inputStatus, edgeStatus[edge]); inputStatus = MergeStatus(inputStatus, edgeStatus[edge]);
@ -140,17 +199,17 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public DefiniteAssignmentStatus GetStatusBefore(Statement statement) public DefiniteAssignmentStatus GetStatusBefore(Statement statement)
{ {
return nodeStatus[beginNodeDict[statement]]; return beginNodeDict[statement].NodeStatus;
} }
public DefiniteAssignmentStatus GetStatusAfter(Statement statement) public DefiniteAssignmentStatus GetStatusAfter(Statement statement)
{ {
return nodeStatus[endNodeDict[statement]]; return endNodeDict[statement].NodeStatus;
} }
public DefiniteAssignmentStatus GetStatusBeforeLoopCondition(Statement statement) public DefiniteAssignmentStatus GetStatusBeforeLoopCondition(Statement statement)
{ {
return nodeStatus[conditionNodeDict[statement]]; return conditionNodeDict[statement].NodeStatus;
} }
/// <summary> /// <summary>
@ -161,7 +220,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
GraphVizGraph g = new GraphVizGraph(); GraphVizGraph g = new GraphVizGraph();
g.Title = "DefiniteAssignment - " + variableName; g.Title = "DefiniteAssignment - " + variableName;
for (int i = 0; i < allNodes.Count; i++) { for (int i = 0; i < allNodes.Count; i++) {
string name = nodeStatus[allNodes[i]].ToString() + Environment.NewLine; string name = "#" + i + " = " + allNodes[i].NodeStatus.ToString() + Environment.NewLine;
switch (allNodes[i].Type) { switch (allNodes[i].Type) {
case ControlFlowNodeType.StartNode: case ControlFlowNodeType.StartNode:
case ControlFlowNodeType.BetweenStatements: case ControlFlowNodeType.BetweenStatements:
@ -179,7 +238,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
} }
g.AddNode(new GraphVizNode(i) { label = name }); g.AddNode(new GraphVizNode(i) { label = name });
foreach (ControlFlowEdge edge in allNodes[i].Outgoing) { foreach (ControlFlowEdge edge in allNodes[i].Outgoing) {
GraphVizEdge ge = new GraphVizEdge(i, allNodes.IndexOf(edge.To)); GraphVizEdge ge = new GraphVizEdge(i, ((DefiniteAssignmentNode)edge.To).Index);
if (edgeStatus.Count > 0) if (edgeStatus.Count > 0)
ge.label = edgeStatus[edge].ToString(); ge.label = edgeStatus[edge].ToString();
if (edge.IsLeavingTryFinally) if (edge.IsLeavingTryFinally)
@ -218,11 +277,11 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return DefiniteAssignmentStatus.PotentiallyAssigned; return DefiniteAssignmentStatus.PotentiallyAssigned;
} }
void ChangeNodeStatus(ControlFlowNode node, DefiniteAssignmentStatus inputStatus) void ChangeNodeStatus(DefiniteAssignmentNode node, DefiniteAssignmentStatus inputStatus)
{ {
if (nodeStatus[node] == inputStatus) if (node.NodeStatus == inputStatus)
return; return;
nodeStatus[node] = inputStatus; node.NodeStatus = inputStatus;
DefiniteAssignmentStatus outputStatus; DefiniteAssignmentStatus outputStatus;
switch (node.Type) { switch (node.Type) {
case ControlFlowNodeType.StartNode: case ControlFlowNodeType.StartNode:
@ -312,7 +371,9 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
throw new InvalidOperationException("Invalid value for DefiniteAssignmentStatus"); throw new InvalidOperationException("Invalid value for DefiniteAssignmentStatus");
} }
edgeStatus[edge] = newStatus; edgeStatus[edge] = newStatus;
nodesWithModifiedInput.Enqueue(edge.To); DefiniteAssignmentNode targetNode = (DefiniteAssignmentNode)edge.To;
if (analyzedRangeStart <= targetNode.Index && targetNode.Index <= analyzedRangeEnd)
nodesWithModifiedInput.Enqueue(targetNode);
} }
/// <summary> /// <summary>
@ -321,7 +382,11 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// <returns>The constant value of the expression; or null if the expression is not a constant.</returns> /// <returns>The constant value of the expression; or null if the expression is not a constant.</returns>
ConstantResolveResult EvaluateConstant(Expression expr) ConstantResolveResult EvaluateConstant(Expression expr)
{ {
return cfgBuilder.EvaluateConstant(expr); if (resolveVisitor.TypeResolveContext is MinimalResolveContext) {
if (!(expr is PrimitiveExpression || expr is NullReferenceExpression))
return null;
}
return resolveVisitor.Resolve(expr) as ConstantResolveResult;
} }
/// <summary> /// <summary>
@ -330,7 +395,11 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns> /// <returns>The value of the constant boolean expression; or null if the value is not a constant boolean expression.</returns>
bool? EvaluateCondition(Expression expr) bool? EvaluateCondition(Expression expr)
{ {
return cfgBuilder.EvaluateCondition(expr); ConstantResolveResult rr = EvaluateConstant(expr);
if (rr != null)
return rr.ConstantValue as bool?;
else
return null;
} }
static DefiniteAssignmentStatus CleanSpecialValues(DefiniteAssignmentStatus status) static DefiniteAssignmentStatus CleanSpecialValues(DefiniteAssignmentStatus status)
@ -633,10 +702,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public override DefiniteAssignmentStatus VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, DefiniteAssignmentStatus data) public override DefiniteAssignmentStatus VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, DefiniteAssignmentStatus data)
{ {
BlockStatement body = anonymousMethodExpression.Body; BlockStatement body = anonymousMethodExpression.Body;
foreach (ControlFlowNode node in analysis.allNodes) { analysis.ChangeNodeStatus(analysis.beginNodeDict[body], data);
if (node.NextStatement == body)
analysis.ChangeNodeStatus(node, data);
}
return data; return data;
} }
@ -644,10 +710,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
{ {
Statement body = lambdaExpression.Body as Statement; Statement body = lambdaExpression.Body as Statement;
if (body != null) { if (body != null) {
foreach (ControlFlowNode node in analysis.allNodes) { analysis.ChangeNodeStatus(analysis.beginNodeDict[body], data);
if (node.NextStatement == body)
analysis.ChangeNodeStatus(node, data);
}
} else { } else {
lambdaExpression.Body.AcceptVisitor(this, data); lambdaExpression.Body.AcceptVisitor(this, data);
} }

Loading…
Cancel
Save