public static bool TryGet(CSharpSyntaxNode node, SemanticModel semanticModel, out IControlFlowGraph cfg) { cfg = null; try { if (node != null) { cfg = Create(node, semanticModel); } else { return false; } } catch (Exception exc) when (exc is InvalidOperationException || exc is ArgumentException || exc is NotSupportedException) { // These are expected } catch (Exception exc) when (exc is NotImplementedException) { Debug.Fail(exc.ToString()); } return cfg != null; }
protected AbstractExplodedGraph(IControlFlowGraph cfg, ISymbol declaration, SemanticModel semanticModel, AbstractLiveVariableAnalysis lva) { this.cfg = cfg; this.declaration = declaration; this.lva = lva; SemanticModel = semanticModel; this.declarationParameters = declaration.GetParameters(); this.nonInDeclarationParameters = this.declarationParameters.Where(p => p.RefKind != RefKind.None); }
public static string ToDot(this IControlFlowGraph graph) { var sb = new StringBuilder(); sb.AppendLine("digraph {"); sb.AppendLine(" node [fontsize = \"12\"];"); sb.AppendLine(" edge [fontsize = \"8\"];"); // Add root node var root = graph.Vertices.Single(a => a.Type == BasicBlockType.Entry); sb.AppendLine($" {ID(root.ID)} [label=\"entry\" shape=circle rank=min];");
/// <summary> /// Removed error/continue edges which we know cannot happen due to type info /// </summary> /// <param name="graph"></param> /// <param name="types"></param> /// <returns></returns> public static IControlFlowGraph TypeDrivenEdgeTrimming(this IControlFlowGraph graph, ITypeAssignments types) { return(graph.Trim(edge => { // Find last statement in previous block var stmt = edge.Start.Statements.LastOrDefault(); var tass = stmt as TypedAssignment; var err = stmt as ErrorStatement; // If type is unassigned we can't make a judgement if (tass?.Type == Execution.Type.Unassigned) { return true; } if (edge.Type == EdgeType.RuntimeError) { // If it's an error statement keep it if (err != null) { return true; } // If there is no statement at all then it can't be an error if (tass == null) { return false; } // Only keep edge if type has an error return tass.Type.HasFlag(Execution.Type.Error); } else { // If it's an error statement remove it if (err != null) { return false; } // If there is no typed assignment we can't judge if (tass == null) { return true; } return tass.Type != Execution.Type.Error; } })); }
[NotNull] private static IControlFlowGraph RemoveTypeAssignments([NotNull] this IControlFlowGraph graph) { return(graph.Modify((a, b) => { foreach (var stmt in a.Statements) { if (stmt is TypedAssignment tass) { b.Add(new Assignment(tass.Left, tass.Right)); } else { b.Add(stmt); } } })); }
/// <summary> /// Find variables which are guaranteed to be `0` or `1` /// </summary> /// <param name="cfg"></param> /// <param name="ssa"></param> /// <param name="types"></param> /// <returns></returns> [NotNull] public static ISet <VariableName> FindBooleanVariables([NotNull] this IControlFlowGraph cfg, ISingleStaticAssignmentTable ssa, ITypeAssignments types) { var booleans = new HashSet <VariableName>(); // Keep finding more constants until no more are found var count = -1; while (count != booleans.Count) { count = booleans.Count; cfg.VisitBlocks(() => new FindBooleanVariables(booleans, ssa, types)); } var result = new HashSet <VariableName>(booleans.Where(n => !n.IsExternal)); return(result); }
private static HashSet <IControlFlowEdge> GetEdges(IControlFlowGraph graph) { var edges = new HashSet <IControlFlowEdge>(new EdgeEqualityComparer()); foreach (var element in graph.AllElements) { foreach (var edge in element.Exits) { edges.Add(edge); } foreach (var edge in element.Entries) { edges.Add(edge); } } return(FudgeGraph(graph, edges)); }
public static IReadOnlyCollection <VariableName> FindUnreadAssignments(this IControlFlowGraph cfg) { var assigned = new FindAssignedVariables(); var read = new FindReadVariables(); foreach (var bb in cfg.Vertices) { assigned.Visit(bb); read.Visit(bb); } var result = new HashSet <VariableName>(assigned.Names.Where(n => !n.IsExternal)); result.ExceptWith(read.Names); return(result); }
/// <summary> /// Replace expressions which result in a constant with the result /// </summary> /// <param name="cfg"></param> /// <param name="ssa"></param> /// <returns></returns> [NotNull] public static IControlFlowGraph FoldConstants([NotNull] this IControlFlowGraph cfg, ISingleStaticAssignmentTable ssa) { // Keep finding and replacing constants until nothing is found cfg = cfg.Fixpoint(c => { // Find variables which are assigned a value which is not tainted by external reads var constants = c.FindConstants(ssa); // Replace reads of a constant variable with the expression assigned to that variable c = c.VisitBlocks(() => new ReplaceConstantSubexpressions(constants)); return(c); }); // Replace constant subexpressions with their value cfg = cfg.VisitBlocks(() => new ConstantFoldingVisitor(true)); return(cfg); }
/// <summary> /// Copy graph and modify vertices /// </summary> /// <param name="input"></param> /// <param name="copy"></param> /// <returns></returns> [NotNull] public static IMutableControlFlowGraph Modify([NotNull] this IControlFlowGraph input, [NotNull] Action <IBasicBlock, IMutableBasicBlock> copy) { var cfg = new ControlFlowGraph(); // Copy vertices (but leave empty) var replacementVertices = input.CloneVertices(cfg, __ => true, (___, ____) => { }); // Copy edges var _ = input.CloneEdges(cfg, replacementVertices, __ => true); // Apply clone function to vertices foreach (var(key, value) in replacementVertices) { copy(key, value); } return(cfg); }
[NotNull] public static IMutableControlFlowGraph Modify([NotNull] this IControlFlowGraph input, [NotNull] Action <IEdge, Action <IBasicBlock, IBasicBlock, EdgeType> > copy) { var cfg = new ControlFlowGraph(); // Copy vertices var replacementVertices = input.CloneVertices(cfg, __ => true); // Copy edges foreach (var edge in input.Edges) { copy(edge, (s, e, t) => { var ss = replacementVertices[s]; var ee = replacementVertices[e]; cfg.CreateEdge(ss, ee, t); }); } return(cfg); }
private static HashSet <IControlFlowEdge> FudgeGraph(IControlFlowGraph graph, HashSet <IControlFlowEdge> edges) { // The C# graph treats the unary negation operator `!` as a conditional. It's not, // but having it so means that the CC can be way higher than it should be. var dodgyEdges = new HashSet <IControlFlowEdge>(new EdgeEqualityComparer()); // Look at all of the non-leaf elements (the graph is a tree as well as a graph. // The tree represents the structure of the code, with the control flow graph // running through it) foreach (var element in graph.AllElements.Where(e => e.Children.Count != 0)) { var unaryOperatorExpression = element.SourceElement as IUnaryOperatorExpression; if (unaryOperatorExpression != null && unaryOperatorExpression.UnaryOperatorType == UnaryOperatorType.EXCL) { // The unary operator shouldn't have 2 exits. It's not a conditional. If it does, // remove one of the edges, and it's path, from the collected edges. if (element.Exits.Count == 2) { var edge = element.Exits[0]; do { dodgyEdges.Add(edge); // Get the source of the exit edge. This is the node in the control flow graph, // not the element in the program structure tree. var source = edge.Source; edge = null; // Walk back to the control flow graph node that represents the exit of the // dodgy condition, so keep going until we have an element with 2 exits. if (source.Entries.Count == 1 && source.Exits.Count == 1) { edge = source.Entries[0]; } } while (edge != null); } } } edges.ExceptWith(dodgyEdges); return(edges); }
private static void CheckInfiniteJumpLoop(BlockSyntax body, IControlFlowGraph cfg, string declarationType, SyntaxNodeAnalysisContext analysisContext) { if (body == null) { return; } var reachableFromBlock = cfg.Blocks.Except(new[] { cfg.ExitBlock }).ToDictionary( b => b, b => b.AllSuccessorBlocks); var alreadyProcessed = new HashSet <Block>(); foreach (var reachable in reachableFromBlock) { if (!reachable.Key.AllPredecessorBlocks.Contains(cfg.EntryBlock) || alreadyProcessed.Contains(reachable.Key) || reachable.Value.Contains(cfg.ExitBlock)) { continue; } alreadyProcessed.UnionWith(reachable.Value); alreadyProcessed.Add(reachable.Key); var reportOnOptions = reachable.Value.OfType <JumpBlock>() .Where(jb => jb.JumpNode is GotoStatementSyntax) .ToList(); if (!reportOnOptions.Any()) { continue; } // Calculate stable report location: var lastJumpLocation = reportOnOptions.Max(b => b.JumpNode.SpanStart); var reportOn = reportOnOptions.First(b => b.JumpNode.SpanStart == lastJumpLocation); analysisContext.ReportDiagnosticWhenActive(Diagnostic.Create(rule, reportOn.JumpNode.GetLocation(), declarationType)); } }
public LiveVariableAnalysisContext(string methodBody, string localFunctionName = null) { var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, methodBody), "Main", out var semanticModel); IMethodSymbol symbol; CSharpSyntaxNode body; if (localFunctionName == null) { symbol = semanticModel.GetDeclaredSymbol(method); body = method.Body; } else { var function = (LocalFunctionStatementSyntaxWrapper)method.DescendantNodes().Single(x => x.Kind() == SyntaxKindEx.LocalFunctionStatement && ((LocalFunctionStatementSyntaxWrapper)x).Identifier.Text == localFunctionName); symbol = semanticModel.GetDeclaredSymbol(function) as IMethodSymbol; body = (CSharpSyntaxNode)function.Body ?? function.ExpressionBody; } this.CFG = CSharpControlFlowGraph.Create(body, semanticModel); this.LVA = CSharpLiveVariableAnalysis.Analyze(this.CFG, symbol, semanticModel); }
/// <summary> /// Merge together basic blocks on the same line connected only by a continue edge /// </summary> /// <param name="cfg"></param> /// <returns></returns> public static IControlFlowGraph MergeAdjacentBasicBlocks(this IControlFlowGraph cfg) { // This keeps looping until it finds no work to do while (true) { // Find all candidates for merging var candidates = (from vertex in cfg.Vertices where vertex.Type == BasicBlockType.Basic where vertex.Outgoing.Count() == 1 let outgoing = vertex.Outgoing.Single() where outgoing.Type == EdgeType.Continue where outgoing.End.LineNumber == vertex.LineNumber where outgoing.End.Type == BasicBlockType.Basic where outgoing.End.Incoming.Count() == 1 select(vertex, outgoing.End)); // Select a single candidate pair (A -> B), if there is no work then exit now var work = candidates.FirstOrDefault(); if (work == default) { return(cfg); } // Move all the items from the A into B, leaving A empty cfg = cfg.Modify((a, b) => { if (a.ID == work.End.ID) { work.vertex.CopyTo(b); a.CopyTo(b); } else if (a.ID != work.vertex.ID) { a.CopyTo(b); } }); // Remove all empty blocks cfg = cfg.RemoveEmptyBlocks(); } }
public ExplodedGraph(IControlFlowGraph cfg, ISymbol declaration, SemanticModel semanticModel, Common.LiveVariableAnalysis lva) { this.cfg = cfg; this.semanticModel = semanticModel; this.declaration = declaration; this.lva = lva; var methodSymbol = declaration as IMethodSymbol; if (methodSymbol != null) { declarationParameters = methodSymbol.Parameters; } var propertySymbol = declaration as IPropertySymbol; if (propertySymbol != null) { declarationParameters = propertySymbol.Parameters; } nonInDeclarationParameters = declarationParameters.Where(p => p.RefKind != RefKind.None); }
private static IReadOnlyDictionary <IEdge, IEdge> CloneEdges( [NotNull] this IControlFlowGraph input, IMutableControlFlowGraph output, IReadOnlyDictionary <IBasicBlock, IMutableBasicBlock> vertexReplacements, [NotNull] Func <IEdge, bool> keep) { var replacements = new Dictionary <IEdge, IEdge>(); foreach (var edge in input.Edges) { if (!keep(edge)) { continue; } replacements.Add( edge, output.CreateEdge(vertexReplacements[edge.Start], vertexReplacements[edge.End], edge.Type) ); } return(replacements); }
[NotNull] public static IControlFlowGraph StaticSingleAssignment([NotNull] this IControlFlowGraph graph, [NotNull] out ISingleStaticAssignmentTable ssa) { var ssaMut = new SingleStaticAssignmentTable(); ssa = ssaMut; var finalNamesInBlock = new Dictionary <IBasicBlock, IReadOnlyDictionary <VariableName, VariableName> >(); // Replace every variable assignment with a new name, keep track of the last name in each block var output = graph.Modify((a, b) => { var finalNames = new Dictionary <VariableName, VariableName>(); finalNamesInBlock[b] = finalNames; foreach (var stmt in a.Statements) { if (stmt is Assignment ass && !ass.Left.IsExternal) { var sname = ssaMut.Assign(ass.Left); b.Add(new Assignment(sname, ass.Right)); // Store the final name assigned to this var in this block finalNames[ass.Left] = sname; }
/// <summary> /// Remove blocks that cannot be reached from the entry node /// </summary> /// <param name="graph"></param> /// <returns></returns> public static IControlFlowGraph RemoveUnreachableBlocks(this IControlFlowGraph graph) { var reachable = new HashSet <IBasicBlock>(); var queue = new Queue <IBasicBlock>(); void Mark(IBasicBlock block) { if (reachable.Add(block)) { foreach (var edge in block.Outgoing) { queue.Enqueue(edge.End); } } } queue.Enqueue(graph.Vertices.Single(v => v.Type == BasicBlockType.Entry)); while (queue.Count > 0) { Mark(queue.Dequeue()); } return(graph.Trim(reachable.Contains)); }
private LiveVariableAnalysis(IControlFlowGraph controlFlowGraph, ISymbol declaration, SemanticModel semanticModel) : base(controlFlowGraph) { this.declaration = declaration; this.semanticModel = semanticModel; }
private static void VerifyBasicCfgProperties(IControlFlowGraph cfg) { cfg.Should().NotBeNull(); cfg.EntryBlock.Should().NotBeNull(); cfg.ExitBlock.Should().NotBeNull(); cfg.ExitBlock.SuccessorBlocks.Should().BeEmpty(); cfg.ExitBlock.Instructions.Should().BeEmpty(); }
private static void VerifyEmptyCfg(IControlFlowGraph cfg) { VerifyCfg(cfg, 1); }
private static void VerifyCfg(IControlFlowGraph cfg, int numberOfBlocks) { VerifyBasicCfgProperties(cfg); cfg.Blocks.Should().HaveCount(numberOfBlocks); if (numberOfBlocks > 1) { cfg.EntryBlock.Should().NotBeSameAs(cfg.ExitBlock); cfg.Blocks.Should().ContainInOrder(new[] { cfg.EntryBlock, cfg.ExitBlock }); } else { cfg.EntryBlock.Should().BeSameAs(cfg.ExitBlock); cfg.Blocks.Should().Contain(cfg.EntryBlock); } }
private static void CheckInfiniteJumpLoop(BlockSyntax body, IControlFlowGraph cfg, string declarationType, SyntaxNodeAnalysisContext analysisContext) { if (body == null) { return; } var reachableFromBlock = cfg.Blocks.Except(new[] { cfg.ExitBlock }).ToDictionary( b => b, b => b.AllSuccessorBlocks); var alreadyProcessed = new HashSet<Block>(); foreach (var reachable in reachableFromBlock) { if (!reachable.Key.AllPredecessorBlocks.Contains(cfg.EntryBlock) || alreadyProcessed.Contains(reachable.Key) || reachable.Value.Contains(cfg.ExitBlock)) { continue; } alreadyProcessed.UnionWith(reachable.Value); alreadyProcessed.Add(reachable.Key); var reportOnOptions = reachable.Value.OfType<JumpBlock>() .Where(jb => jb.JumpNode is GotoStatementSyntax) .ToList(); if (!reportOnOptions.Any()) { continue; } // Calculate stable report location: var lastJumpLocation = reportOnOptions.Max(b => b.JumpNode.SpanStart); var reportOn = reportOnOptions.First(b => b.JumpNode.SpanStart == lastJumpLocation); analysisContext.ReportDiagnostic(Diagnostic.Create(Rule, reportOn.JumpNode.GetLocation(), declarationType)); } }
protected CfgRecursionSearcher(IControlFlowGraph cfg, ISymbol declaringSymbol, SemanticModel semanticModel, Action reportIssue) : base(cfg) { this.declaringSymbol = declaringSymbol; this.semanticModel = semanticModel; this.reportIssue = reportIssue; }
protected CfgAllPathValidator(IControlFlowGraph cfg) { this.cfg = cfg; }
protected CfgAllPathValidator(IControlFlowGraph cfg) { this.cfg = cfg; }
private static void VerifyJumpWithExpression(IControlFlowGraph cfg, SyntaxKind kind) { VerifyCfg(cfg, 4); var branchBlock = cfg.EntryBlock as BinaryBranchBlock; var blocks = cfg.Blocks.ToList(); var trueBlock = blocks[1] as JumpBlock; var falseBlock = blocks[2]; var exitBlock = cfg.ExitBlock; branchBlock.SuccessorBlocks.Should().OnlyContainInOrder(trueBlock, falseBlock); trueBlock.SuccessorBlocks.Should().OnlyContain(exitBlock); trueBlock.JumpNode.Kind().Should().Be(kind); trueBlock.Instructions.FirstOrDefault(n => n.IsKind(SyntaxKind.IdentifierName) && n.ToString() == "ii").Should().NotBeNull(); exitBlock.PredecessorBlocks.Should().OnlyContain(trueBlock, falseBlock); }
[NotNull] public static IControlFlowGraph FlowTypingAssignment( [NotNull] this IControlFlowGraph graph, [NotNull] ISingleStaticAssignmentTable ssa, // We require the SSA object because SSA must be done before flow typing [NotNull] out ITypeAssignments types, [NotNull] params (VariableName, Execution.Type)[] hints)
/// <summary> /// Add edges to the graph /// </summary> /// <param name="input"></param> /// <param name="create"></param> /// <returns></returns> [NotNull] public static IMutableControlFlowGraph Add([NotNull] this IControlFlowGraph input, [NotNull] IEnumerable <(Guid, Guid, EdgeType)> create)
private static void VerifySimpleJumpBlock(IControlFlowGraph cfg, SyntaxKind kind) { VerifyCfg(cfg, 3); var jumpBlock = cfg.EntryBlock as JumpBlock; var bodyBlock = cfg.Blocks.ToList()[1]; var exitBlock = cfg.ExitBlock; jumpBlock.SuccessorBlocks.Should().OnlyContain(bodyBlock); bodyBlock.SuccessorBlocks.Should().OnlyContain(exitBlock); jumpBlock.JumpNode.Kind().Should().Be(kind); }
internal LiveVariableAnalysis(IControlFlowGraph controlFlowGraph) { this.controlFlowGraph = controlFlowGraph; this.reversedBlocks = controlFlowGraph.Blocks.Reverse().ToList(); }
[NotNull] public static IReadOnlyDictionary <VariableName, BaseExpression> FindConstants([NotNull] this IControlFlowGraph cfg, ISingleStaticAssignmentTable ssa) { var constants = new Dictionary <VariableName, BaseExpression>(); var count = -1; // Keep finding more constants until no more are found while (count != constants.Count) { count = constants.Count; cfg.VisitBlocks(() => new FindConstantVariables(constants, ssa)); } return(constants); }
public static Common.LiveVariableAnalysis Analyze(IControlFlowGraph controlFlowGraph, ISymbol declaration, SemanticModel semanticModel) { var lva = new LiveVariableAnalysis(controlFlowGraph, declaration, semanticModel); lva.PerformAnalysis(); return lva; }
public static bool TryGet(CSharpSyntaxNode node, SemanticModel semanticModel, out IControlFlowGraph cfg) { cfg = null; try { if (node != null) { cfg = Create(node, semanticModel); } else { return(false); } } catch (Exception exc) when(exc is InvalidOperationException || exc is ArgumentException || exc is NotSupportedException) { // These are expected } catch (Exception exc) when(exc is NotImplementedException) { Debug.Fail(exc.ToString()); } return(cfg != null); }
private static void VerifyJumpWithNoExpression(IControlFlowGraph cfg, SyntaxKind kind) { VerifyCfg(cfg, 4); var branchBlock = cfg.EntryBlock as BinaryBranchBlock; var blocks = cfg.Blocks.ToList(); var trueBlock = blocks[1] as JumpBlock; var falseBlock = blocks[2]; var exitBlock = cfg.ExitBlock; branchBlock.SuccessorBlocks.Should().OnlyContainInOrder(trueBlock, falseBlock); trueBlock.SuccessorBlocks.Should().OnlyContain(exitBlock); trueBlock.JumpNode.Kind().Should().Be(kind); exitBlock.PredecessorBlocks.Should().OnlyContain(trueBlock, falseBlock); }
public static void Serialize(string methodName, IControlFlowGraph cfg, TextWriter writer) { new CfgWalker(new DotWriter(writer)).Visit(methodName, cfg); }
public static IControlFlowGraph RecomposeModify(this IControlFlowGraph cfg) { return(cfg.VisitBlocks(() => new RecomposeModifyIR())); }
public UCFG Build(SemanticModel semanticModel, SyntaxNode syntaxNode, IMethodSymbol methodSymbol, IControlFlowGraph cfg) { var ucfg = new UCFG { MethodId = GetMethodId(methodSymbol), Location = GetLocation(syntaxNode), }; ucfg.BasicBlocks.AddRange(cfg.Blocks.Select(b => CreateBasicBlock(b, semanticModel))); ucfg.Parameters.AddRange(methodSymbol.GetParameters().Select(p => p.Name)); if (syntaxNode is BaseMethodDeclarationSyntax methodDeclaration && EntryPointRecognizer.IsEntryPoint(methodSymbol)) { var entryPointBlock = CreateEntryPointBlock(semanticModel, methodDeclaration, methodSymbol, blockId.Get(cfg.EntryBlock)); ucfg.BasicBlocks.Add(entryPointBlock); ucfg.Entries.Add(entryPointBlock.Id); }
private static void VerifyForStatementEmpty(IControlFlowGraph cfg) { VerifyCfg(cfg, 4); var initializerBlock = cfg.EntryBlock as ForInitializerBlock; var blocks = cfg.Blocks.ToList(); var branchBlock = blocks[1] as BinaryBranchBlock; var loopBodyBlock = cfg.Blocks .First(b => b.Instructions.Any(n => n.ToString() == "x = 10")); var exitBlock = cfg.ExitBlock; initializerBlock.SuccessorBlock.ShouldBeEquivalentTo(branchBlock); branchBlock.SuccessorBlocks.Should().OnlyContainInOrder(loopBodyBlock, exitBlock); branchBlock.BranchingNode.Kind().Should().Be(SyntaxKind.ForStatement); loopBodyBlock.SuccessorBlocks.Should().OnlyContain(branchBlock); branchBlock.PredecessorBlocks.Should().OnlyContain(loopBodyBlock, initializerBlock); exitBlock.PredecessorBlocks.Should().OnlyContain(branchBlock); }
public RecursionAnalysisContext(IControlFlowGraph controlFlowGraph, ISymbol analyzedSymbol, Location issueLocation, SyntaxNodeAnalysisContext analysisContext) { ControlFlowGraph = controlFlowGraph; AnalyzedSymbol = analyzedSymbol; IssueLocation = issueLocation; AnalysisContext = analysisContext; SemanticModel = analysisContext.SemanticModel; }
/// <summary> /// Replace inc/dec operations on numbers with a+=1 and a-=1 /// </summary> /// <param name="cfg"></param> /// <param name="types"></param> /// <returns></returns> public static IControlFlowGraph SimplifyModificationExpressions(this IControlFlowGraph cfg, ITypeAssignments types) { return(cfg.VisitBlocks(() => new SimplifyModify(types))); }
private LiveVariableAnalysis(IControlFlowGraph controlFlowGraph, ISymbol declaration, SemanticModel semanticModel) : base(controlFlowGraph) { this.declaration = declaration; this.semanticModel = semanticModel; }
private static void VerifyForStatement(IControlFlowGraph cfg) { VerifyCfg(cfg, 5); var initBlock = cfg.EntryBlock; var blocks = cfg.Blocks.ToList(); var branchBlock = blocks[1] as BinaryBranchBlock; var incrementorBlock = blocks[3]; var loopBodyBlock = blocks[2]; var exitBlock = cfg.ExitBlock; initBlock.SuccessorBlocks.Should().OnlyContain(branchBlock); branchBlock.SuccessorBlocks.Should().OnlyContainInOrder(loopBodyBlock, exitBlock); branchBlock.BranchingNode.Kind().Should().Be(SyntaxKind.ForStatement); loopBodyBlock.SuccessorBlocks.Should().OnlyContain(incrementorBlock); incrementorBlock.SuccessorBlocks.Should().OnlyContain(branchBlock); branchBlock.PredecessorBlocks.Should().OnlyContain(initBlock, incrementorBlock); exitBlock.PredecessorBlocks.Should().OnlyContain(branchBlock); }
private static void VerifyMinimalCfg(IControlFlowGraph cfg) { VerifyCfg(cfg, 2); cfg.EntryBlock.SuccessorBlocks.Should().OnlyContain(cfg.ExitBlock); }
internal LiveVariableAnalysis(IControlFlowGraph controlFlowGraph) { this.controlFlowGraph = controlFlowGraph; this.reversedBlocks = controlFlowGraph.Blocks.Reverse().ToList(); }
public MemberInitializerRedundancyChecker(IControlFlowGraph cfg, ISymbol memberToCheck, SemanticModel semanticModel) : base(cfg) { this.memberToCheck = memberToCheck; this.semanticModel = semanticModel; }
public PopTreeGraph(IControlFlowGraph cfg) { _cfg = cfg; }