private DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> Run(ControlFlowGraph cfg) { var resultBuilder = new DataFlowAnalysisResultBuilder <TAnalysisData>(); // Add each basic block to the result. foreach (var block in cfg.Blocks) { resultBuilder.Add(block); } var worklist = new Queue <BasicBlock>(); var entry = GetEntry(cfg); // Initialize the input of the initial block // with the default abstract value of the domain. UpdateInput(resultBuilder, entry, AnalysisDomain.Bottom); // Add the entry block to the worklist. worklist.Enqueue(entry); while (worklist.Count > 0) { // Get the next block to process // and its associated result. var block = worklist.Dequeue(); // Get the outputs of all predecessor blocks of the current block. var inputs = GetPredecessors(block).Select(b => GetOutput(resultBuilder[b])); // Merge all the outputs to get the new input of the current block. var input = AnalysisDomain.Merge(inputs); // Merge might return one of the original input values if only one of them is a valid non-null value. if (inputs.Any(i => ReferenceEquals(input, i))) { input = AnalysisDomain.Clone(input); } // Temporary workaround due to lack of *real* CFG // TODO: Remove the below if statement once we move to compiler's CFG // https://github.com/dotnet/roslyn-analyzers/issues/1567 if (block.Kind == BasicBlockKind.Exit && OperationVisitor.MergedAnalysisDataAtReturnStatements != null) { input = AnalysisDomain.Merge(input, OperationVisitor.MergedAnalysisDataAtReturnStatements); } // Compare the previous input with the new input. var compare = AnalysisDomain.Compare(GetInput(resultBuilder[block]), input); // The newly computed abstract values for each basic block // must be always greater or equal than the previous value // to ensure termination. Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one."); // Is old input value < new input value ? if (compare < 0 || block.Kind == BasicBlockKind.Entry) { // The newly computed value is greater than the previous value, // so we need to update the current block result's // input values with the new ones. UpdateInput(resultBuilder, block, AnalysisDomain.Clone(input)); // Flow the new input through the block to get a new output. var output = Flow(block, input); // Compare the previous output with the new output. compare = AnalysisDomain.Compare(GetOutput(resultBuilder[block]), output); // The newly computed abstract values for each basic block // must be always greater or equal than the previous value // to ensure termination. Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one."); // Is old output value < new output value ? if (compare < 0 || block.Kind == BasicBlockKind.Entry) { // The newly computed value is greater than the previous value, // so we need to update the current block result's // output values with the new ones. UpdateOutput(resultBuilder, block, output); // Since the new output value is different than the previous one, // we need to propagate it to all the successor blocks of the current block. EnqueueRange(worklist, GetSuccessors(block)); } } } return(resultBuilder.ToResult(ToResult, OperationVisitor.GetStateMap(), OperationVisitor.GetPredicateValueKindMap(), OperationVisitor.GetMergedDataForUnhandledThrowOperations(), cfg, OperationVisitor.ValueDomain.UnknownOrMayBeValue)); }