public void ExplodedGraph_SequentialInput_Max() { var inputBuilder = new StringBuilder(); for (int i = 0; i < ExplodedGraph.MaxStepCount / 2 + 1; i++) { inputBuilder.AppendLine($"var x{i} = true;"); } string testInput = inputBuilder.ToString(); SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var maxStepCountReached = false; explodedGraph.MaxStepCountReached += (sender, args) => { maxStepCountReached = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; explodedGraph.Walk(); Assert.IsFalse(explorationEnded); Assert.IsTrue(maxStepCountReached); Assert.AreEqual(0, numberOfExitBlockReached); }
private void CheckForEmptyCollectionAccess(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var check = new EmptyCollectionAccessedCheck(explodedGraph); explodedGraph.AddExplodedGraphCheck(check); var emptyCollections = new HashSet <SyntaxNode>(); var nonEmptyCollections = new HashSet <SyntaxNode>(); EventHandler <CollectionAccessedEventArgs> collectionAccessedHandler = (sender, args) => (args.IsEmpty ? emptyCollections : nonEmptyCollections).Add(args.Node); check.CollectionAccessed += collectionAccessedHandler; try { explodedGraph.Walk(); } finally { check.CollectionAccessed -= collectionAccessedHandler; } foreach (var node in emptyCollections.Except(nonEmptyCollections)) { context.ReportDiagnostic(Diagnostic.Create(rule, node.GetLocation())); } }
public void ExplodedGraph_BothBranchesVisited_NonCondition() { string testInput = "var str = this?.ToString();"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var countConditionEvaluated = 0; explodedGraph.ConditionEvaluated += (sender, args) => { countConditionEvaluated++; }; var visitedBlocks = new HashSet <Block>(); explodedGraph.InstructionProcessed += (sender, args) => { visitedBlocks.Add(args.ProgramPoint.Block); }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(cfg.Blocks.Count() - 1 /* Exit block */, visitedBlocks.Count); Assert.AreEqual(0, countConditionEvaluated); }
private static void CheckForNullDereference(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var nullPointerCheck = new NullPointerCheck(explodedGraph); explodedGraph.AddExplodedGraphCheck(nullPointerCheck); var nullIdentifiers = new HashSet<IdentifierNameSyntax>(); EventHandler<MemberAccessedEventArgs> memberAccessedHandler = (sender, args) => CollectMemberAccesses(args, nullIdentifiers, context.SemanticModel); nullPointerCheck.MemberAccessed += memberAccessedHandler; try { explodedGraph.Walk(); } finally { nullPointerCheck.MemberAccessed -= memberAccessedHandler; } foreach (var nullIdentifier in nullIdentifiers) { context.ReportDiagnostic(Diagnostic.Create(Rule, nullIdentifier.GetLocation(), nullIdentifier.Identifier.ValueText)); } }
public void ExplodedGraph_LoopExploration() { string testInput = "var i = 0; while (i < 1) { i = i + 1; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var exceeded = 0; explodedGraph.ProgramPointVisitCountExceedLimit += (sender, args) => { exceeded++; args.ProgramPoint.Block.Instructions.Where(i => i.ToString() == "i < 1").Should().NotBeEmpty(); }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, exceeded); }
private static void CheckEmptyNullableAccess(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var nullPointerCheck = new NullValueAccessedCheck(explodedGraph); explodedGraph.AddExplodedGraphCheck(nullPointerCheck); var nullIdentifiers = new HashSet<IdentifierNameSyntax>(); EventHandler<MemberAccessedEventArgs> nullValueAccessedHandler = (sender, args) => nullIdentifiers.Add(args.Identifier); nullPointerCheck.ValuePropertyAccessed += nullValueAccessedHandler; try { explodedGraph.Walk(); } finally { nullPointerCheck.ValuePropertyAccessed -= nullValueAccessedHandler; } foreach (var nullIdentifier in nullIdentifiers) { context.ReportDiagnostic(Diagnostic.Create(Rule, nullIdentifier.Parent.GetLocation(), nullIdentifier.Identifier.ValueText)); } }
private static void CheckEmptyNullableAccess(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var nullPointerCheck = new NullValueAccessedCheck(explodedGraph); explodedGraph.AddExplodedGraphCheck(nullPointerCheck); var nullIdentifiers = new HashSet <IdentifierNameSyntax>(); EventHandler <MemberAccessedEventArgs> nullValueAccessedHandler = (sender, args) => nullIdentifiers.Add(args.Identifier); nullPointerCheck.ValuePropertyAccessed += nullValueAccessedHandler; try { explodedGraph.Walk(); } finally { nullPointerCheck.ValuePropertyAccessed -= nullValueAccessedHandler; } foreach (var nullIdentifier in nullIdentifiers) { context.ReportDiagnostic(Diagnostic.Create(rule, nullIdentifier.Parent.GetLocation(), nullIdentifier.Identifier.ValueText)); } }
private static void CheckForNullDereference(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var nullPointerCheck = new NullPointerCheck(explodedGraph); explodedGraph.AddExplodedGraphCheck(nullPointerCheck); var nullIdentifiers = new HashSet <IdentifierNameSyntax>(); EventHandler <MemberAccessedEventArgs> memberAccessedHandler = (sender, args) => CollectMemberAccesses(args, nullIdentifiers, context.SemanticModel); nullPointerCheck.MemberAccessed += memberAccessedHandler; try { explodedGraph.Walk(); } finally { nullPointerCheck.MemberAccessed -= memberAccessedHandler; } foreach (var nullIdentifier in nullIdentifiers) { context.ReportDiagnostic(Diagnostic.Create(Rule, nullIdentifier.GetLocation(), nullIdentifier.Identifier.ValueText)); } }
public void ExplodedGraph_SingleBranchVisited_If() { string testInput = "var a = false; bool b; if (a) { b = true; } else { b = false; } a = b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = false") { Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); } if (args.Instruction.ToString() == "b = true") { Assert.Fail("We should never get into this branch"); } if (args.Instruction.ToString() == "b = false") { Assert.IsTrue(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.False); Assert.IsNull(args.ProgramState.GetSymbolValue(aSymbol), "a is dead, so there should be no associated value to it."); } if (args.Instruction.ToString() == "a = b") { numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(10, numberOfProcessedInstructions); Assert.AreEqual(1, numberOfExitBlockReached); Assert.AreEqual(1, numberOfLastInstructionVisits); }
public void ExplodedGraph_SequentialInput() { string testInput = "var a = true; var b = false; b = !b; a = (b);"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = true") { Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "b = false") { Assert.IsTrue(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.False); } if (args.Instruction.ToString() == "b = !b") { Assert.IsFalse(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.False); Assert.IsFalse(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "a = (b)") { Assert.AreEqual( args.ProgramState.GetSymbolValue(bSymbol), args.ProgramState.GetSymbolValue(aSymbol)); } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(11, numberOfProcessedInstructions); Assert.AreEqual(1, numberOfExitBlockReached); }
public void ExplodedGraph_SequentialInput() { string testInput = "var a = true; var b = false; b = !b; a = (b);"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType<VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = true") { Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "b = false") { Assert.IsTrue(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.False); } if (args.Instruction.ToString() == "b = !b") { Assert.IsFalse(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.False); Assert.IsFalse(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "a = (b)") { Assert.AreEqual( args.ProgramState.GetSymbolValue(bSymbol), args.ProgramState.GetSymbolValue(aSymbol)); } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(11, numberOfProcessedInstructions); Assert.AreEqual(1, numberOfExitBlockReached); }
public void ExplodedGraph_AllBranchesVisited() { string testInput = "int i = 1; switch (i) { case 1: default: cw1(); break; case 2: cw2(); break; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfCw1InstructionVisits = 0; var numberOfCw2InstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "cw1()") { numberOfCw1InstructionVisits++; } if (args.Instruction.ToString() == "cw2()") { numberOfCw2InstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, numberOfExitBlockReached); Assert.AreEqual(1, numberOfCw1InstructionVisits); Assert.AreEqual(1, numberOfCw2InstructionVisits); }
public void ExplodedGraph_SingleBranchVisited_And() { string testInput = "var a = false; if (a && !a) { a = true; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = !true") { Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); // Roslyn is clever !true has const value. } if (args.Instruction.ToString() == "!a") { Assert.Fail("We should never get into this branch"); } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, numberOfExitBlockReached); }
public void ExplodedGraph_NonLocalSymbolBranching() { string testInput = "if (field) { cw(); }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var fieldSymbol = semanticModel.GetSymbolInfo( method.DescendantNodes().OfType <IdentifierNameSyntax>().First(d => d.Identifier.ToString() == "field")).Symbol; Assert.IsNotNull(fieldSymbol); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "field") { Assert.IsNull(args.ProgramState.GetSymbolValue(fieldSymbol)); } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, numberOfExitBlockReached); }
private static void CheckForRedundantConditions(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var conditionTrue = new HashSet <SyntaxNode>(); var conditionFalse = new HashSet <SyntaxNode>(); EventHandler <ConditionEvaluatedEventArgs> collectConditions = (sender, args) => CollectConditions(args, conditionTrue, conditionFalse); EventHandler explorationEnded = (sender, args) => ProcessVisitedBlocks(conditionTrue, conditionFalse, context); explodedGraph.ExplorationEnded += explorationEnded; explodedGraph.ConditionEvaluated += collectConditions; try { explodedGraph.Walk(); } finally { explodedGraph.ExplorationEnded -= explorationEnded; explodedGraph.ConditionEvaluated -= collectConditions; } }
private static void CheckForRedundantConditions(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { var conditionTrue = new HashSet<SyntaxNode>(); var conditionFalse = new HashSet<SyntaxNode>(); EventHandler<ConditionEvaluatedEventArgs> collectConditions = (sender, args) => CollectConditions(args, conditionTrue, conditionFalse); EventHandler explorationEnded = (sender, args) => ProcessVisitedBlocks(conditionTrue, conditionFalse, context); explodedGraph.ExplorationEnded += explorationEnded; explodedGraph.ConditionEvaluated += collectConditions; try { explodedGraph.Walk(); } finally { explodedGraph.ExplorationEnded -= explorationEnded; explodedGraph.ConditionEvaluated -= collectConditions; } }
public void ExplodedGraph_SingleBranchVisited_If() { string testInput = "var a = false; bool b; if (a) { b = true; } else { b = false; } a = b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType<VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = false") { Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); } if (args.Instruction.ToString() == "b = true") { Assert.Fail("We should never get into this branch"); } if (args.Instruction.ToString() == "b = false") { Assert.IsTrue(args.ProgramState.GetSymbolValue(bSymbol) == SymbolicValue.False); Assert.IsNull(args.ProgramState.GetSymbolValue(aSymbol), "a is dead, so there should be no associated value to it."); } if (args.Instruction.ToString() == "a = b") { numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(10, numberOfProcessedInstructions); Assert.AreEqual(1, numberOfExitBlockReached); Assert.AreEqual(1, numberOfLastInstructionVisits); }
public NullValueAccessedCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_SequentialInput_Max() { var inputBuilder = new StringBuilder(); for (int i = 0; i < ExplodedGraph.MaxStepCount / 2 + 1; i++) { inputBuilder.AppendLine($"var x{i} = true;"); } string testInput = inputBuilder.ToString(); SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var maxStepCountReached = false; explodedGraph.MaxStepCountReached += (sender, args) => { maxStepCountReached = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; explodedGraph.Walk(); Assert.IsFalse(explorationEnded); Assert.IsTrue(maxStepCountReached); Assert.AreEqual(0, numberOfExitBlockReached); }
public NullableCastCheck(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) : this(explodedGraph) { this.context = context; }
public NullValueAccessedCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_BothBranchesVisited_NonCondition() { string testInput = "var str = this?.ToString();"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var countConditionEvaluated = 0; explodedGraph.ConditionEvaluated += (sender, args) => { countConditionEvaluated++; }; var visitedBlocks = new HashSet<Block>(); explodedGraph.InstructionProcessed += (sender, args) => { visitedBlocks.Add(args.ProgramPoint.Block); }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(cfg.Blocks.Count() - 1 /* Exit block */, visitedBlocks.Count); Assert.AreEqual(0, countConditionEvaluated); }
public void ExplodedGraph_BothBranchesVisited() { string testInput = "var a = false; bool b; if (inParameter) { b = inParameter; } else { b = !inParameter; } a = b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var parameters = method.DescendantNodes().OfType <ParameterSyntax>(); var inParameterSymbol = semanticModel.GetDeclaredSymbol(parameters.First(d => d.Identifier.ToString() == "inParameter")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; var visitedBlocks = new HashSet <Block>(); var branchesVisited = 0; explodedGraph.InstructionProcessed += (sender, args) => { visitedBlocks.Add(args.ProgramPoint.Block); numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = false") { branchesVisited++; Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); // Roslyn is clever !true has const value. } if (args.Instruction.ToString() == "b = inParameter") { branchesVisited++; Assert.IsTrue(bSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); Assert.IsTrue(inParameterSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); } if (args.Instruction.ToString() == "b = !inParameter") { branchesVisited++; // b has value, but not true or false Assert.IsNotNull(args.ProgramState.GetSymbolValue(bSymbol)); Assert.IsFalse(bSymbol.HasConstraint(BoolConstraint.False, args.ProgramState)); Assert.IsFalse(bSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); Assert.IsTrue(inParameterSymbol.HasConstraint(BoolConstraint.False, args.ProgramState)); } if (args.Instruction.ToString() == "a = b") { branchesVisited++; Assert.IsNull(args.ProgramState.GetSymbolValue(inParameterSymbol)); // not out/ref parameter and LVA says dead numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(4 + 1, branchesVisited); Assert.AreEqual(1, numberOfExitBlockReached, "All variables are dead at the ExitBlock, so whenever we get there, the ExplodedGraph nodes should be the same, " + "and thus should be processed only once."); Assert.AreEqual(2, numberOfLastInstructionVisits); Assert.AreEqual(cfg.Blocks.Count() - 1 /* Exit block */, visitedBlocks.Count); }
public NullPointerCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_NonDecisionMakingAssignments() { string testInput = "var a = true; a |= false; var b = 42; b++; ++b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType<VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); SymbolicValue sv = null; var numberOfProcessedInstructions = 0; var branchesVisited = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = true") { branchesVisited++; Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "a |= false") { branchesVisited++; Assert.IsNotNull(args.ProgramState.GetSymbolValue(aSymbol)); Assert.IsFalse(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); Assert.IsFalse(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "b = 42") { branchesVisited++; sv = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(sv); } if (args.Instruction.ToString() == "b++") { branchesVisited++; var svNew = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(svNew); Assert.AreNotEqual(sv, svNew); } if (args.Instruction.ToString() == "++b") { branchesVisited++; var svNew = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(svNew); Assert.AreNotEqual(sv, svNew); } }; explodedGraph.Walk(); Assert.AreEqual(11, numberOfProcessedInstructions); Assert.AreEqual(5, branchesVisited); }
private static void CheckEmptyNullableCast(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { explodedGraph.AddExplodedGraphCheck(new NullableCastCheck(explodedGraph, context)); explodedGraph.Walk(); }
protected ExplodedGraphCheck(ExplodedGraph explodedGraph) { this.explodedGraph = explodedGraph; this.semanticModel = explodedGraph.SemanticModel; }
private static void Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action<ExplodedGraph, SyntaxNodeAnalysisContext> analyze, SyntaxNodeAnalysisContext context) { if (declarationBody == null || declarationBody.ContainsDiagnostics) { return; } IControlFlowGraph cfg; if (!ControlFlowGraph.TryGet(declarationBody, context.SemanticModel, out cfg)) { return; } var lva = LiveVariableAnalysis.Analyze(cfg, symbol, context.SemanticModel); var explodedGraph = new ExplodedGraph(cfg, symbol, context.SemanticModel, lva); analyze(explodedGraph, context); }
public void ExplodedGraph_NonLocalSymbolBranching() { string testInput = "if (field) { cw(); }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var fieldSymbol = semanticModel.GetSymbolInfo( method.DescendantNodes().OfType<IdentifierNameSyntax>().First(d => d.Identifier.ToString() == "field")).Symbol; Assert.IsNotNull(fieldSymbol); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "field") { Assert.IsNull(args.ProgramState.GetSymbolValue(fieldSymbol)); } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, numberOfExitBlockReached); }
public NullableCastCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_SingleBranchVisited_And() { string testInput = "var a = false; if (a && !a) { a = true; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType<VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = !true") { Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); // Roslyn is clever !true has const value. } if (args.Instruction.ToString() == "!a") { Assert.Fail("We should never get into this branch"); } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, numberOfExitBlockReached); }
public NullPointerCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_BothBranchesVisited() { string testInput = "var a = false; bool b; if (inParameter) { b = inParameter; } else { b = !inParameter; } a = b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType<VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var parameters = method.DescendantNodes().OfType<ParameterSyntax>(); var inParameterSymbol = semanticModel.GetDeclaredSymbol(parameters.First(d => d.Identifier.ToString() == "inParameter")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; var visitedBlocks = new HashSet<Block>(); var branchesVisited = 0; explodedGraph.InstructionProcessed += (sender, args) => { visitedBlocks.Add(args.ProgramPoint.Block); numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = false") { branchesVisited++; Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); // Roslyn is clever !true has const value. } if (args.Instruction.ToString() == "b = inParameter") { branchesVisited++; Assert.IsTrue(bSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); Assert.IsTrue(inParameterSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); } if (args.Instruction.ToString() == "b = !inParameter") { branchesVisited++; // b has value, but not true or false Assert.IsNotNull(args.ProgramState.GetSymbolValue(bSymbol)); Assert.IsFalse(bSymbol.HasConstraint(BoolConstraint.False, args.ProgramState)); Assert.IsFalse(bSymbol.HasConstraint(BoolConstraint.True, args.ProgramState)); Assert.IsTrue(inParameterSymbol.HasConstraint(BoolConstraint.False, args.ProgramState)); } if (args.Instruction.ToString() == "a = b") { branchesVisited++; Assert.IsNull(args.ProgramState.GetSymbolValue(inParameterSymbol)); // not out/ref parameter and LVA says dead numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(4 + 1, branchesVisited); Assert.AreEqual(1, numberOfExitBlockReached, "All variables are dead at the ExitBlock, so whenever we get there, the ExplodedGraph nodes should be the same, " + "and thus should be processed only once."); Assert.AreEqual(2, numberOfLastInstructionVisits); Assert.AreEqual(cfg.Blocks.Count() - 1 /* Exit block */, visitedBlocks.Count); }
public NullableCastCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_AllBranchesVisited() { string testInput = "int i = 1; switch (i) { case 1: default: cw1(); break; case 2: cw2(); break; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfCw1InstructionVisits = 0; var numberOfCw2InstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "cw1()") { numberOfCw1InstructionVisits++; } if (args.Instruction.ToString() == "cw2()") { numberOfCw2InstructionVisits++; } }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, numberOfExitBlockReached); Assert.AreEqual(1, numberOfCw1InstructionVisits); Assert.AreEqual(1, numberOfCw2InstructionVisits); }
public NullableCastCheck(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) : this(explodedGraph) { this.context = context; }
private static void CheckEmptyNullableCast(ExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) { explodedGraph.AddExplodedGraphCheck(new NullableCastCheck(explodedGraph, context)); explodedGraph.Walk(); }
public EmptyCollectionAccessedCheck(ExplodedGraph explodedGraph) : base(explodedGraph) { }
public void ExplodedGraph_LoopExploration() { string testInput = "var i = 0; while (i < 1) { i = i + 1; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var exceeded = 0; explodedGraph.ProgramPointVisitCountExceedLimit += (sender, args) => { exceeded++; args.ProgramPoint.Block.Instructions.Where(i => i.ToString() == "i < 1").Should().NotBeEmpty(); }; explodedGraph.Walk(); Assert.IsTrue(explorationEnded); Assert.AreEqual(1, exceeded); }
public void ExplodedGraph_NonDecisionMakingAssignments() { string testInput = "var a = true; a |= false; var b = 42; b++; ++b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.Compile(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = ControlFlowGraph.Create(method.Body, semanticModel); var lva = LiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new ExplodedGraph(cfg, methodSymbol, semanticModel, lva); SymbolicValue sv = null; var numberOfProcessedInstructions = 0; var branchesVisited = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = true") { branchesVisited++; Assert.IsTrue(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "a |= false") { branchesVisited++; Assert.IsNotNull(args.ProgramState.GetSymbolValue(aSymbol)); Assert.IsFalse(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.False); Assert.IsFalse(args.ProgramState.GetSymbolValue(aSymbol) == SymbolicValue.True); } if (args.Instruction.ToString() == "b = 42") { branchesVisited++; sv = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(sv); } if (args.Instruction.ToString() == "b++") { branchesVisited++; var svNew = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(svNew); Assert.AreNotEqual(sv, svNew); } if (args.Instruction.ToString() == "++b") { branchesVisited++; var svNew = args.ProgramState.GetSymbolValue(bSymbol); Assert.IsNotNull(svNew); Assert.AreNotEqual(sv, svNew); } }; explodedGraph.Walk(); Assert.AreEqual(11, numberOfProcessedInstructions); Assert.AreEqual(5, branchesVisited); }