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 output of the initial block // with the default abstract value of the domain. UpdateOutput(resultBuilder, entry, AnalysisDomain.Bottom); // Add all successor blocks of the initial // block to be processed. EnqueueRange(worklist, GetSuccessors(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); // 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) { // 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) { // 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())); }
private DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> Run(ControlFlowGraph cfg, DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> seedResultOpt) { 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 pendingBlocksNeedingAtLeastOnePass = new HashSet <BasicBlock>(cfg.Blocks); var entry = GetEntry(cfg); // Are we computing the analysis data from scratch? if (seedResultOpt == null) { // Initialize the input of the initial block // with the default abstract value of the domain. UpdateInput(resultBuilder, entry, AnalysisDomain.Bottom); } else { // Initialize the input and output of every block // with the previously computed value. foreach (var block in cfg.Blocks) { UpdateInput(resultBuilder, block, GetInputData(seedResultOpt[block])); } } // Add the block to the worklist. worklist.Enqueue(entry); while (worklist.Count > 0 || pendingBlocksNeedingAtLeastOnePass.Count > 0) { // Get the next block to process // and its associated result. var block = worklist.Count > 0 ? worklist.Dequeue() : pendingBlocksNeedingAtLeastOnePass.ElementAt(0); var needsAtLeastOnePass = pendingBlocksNeedingAtLeastOnePass.Remove(block); // 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. if (!needsAtLeastOnePass) { int 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) { continue; } } // 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(OperationVisitor, block, input); // Compare the previous output with the new output. if (!needsAtLeastOnePass) { int 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) { continue; } } // 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)); }