protected DataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, ISymbol owningSymbol, bool pessimisticAnalysis, DataFlowAnalysisResult <NullBlockAnalysisResult, NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) { Debug.Assert(owningSymbol != null); Debug.Assert(owningSymbol.Kind == SymbolKind.Method || owningSymbol.Kind == SymbolKind.Field || owningSymbol.Kind == SymbolKind.Property || owningSymbol.Kind == SymbolKind.Event); ValueDomain = valueDomain; OwningSymbol = owningSymbol; PessimisticAnalysis = pessimisticAnalysis; _nullAnalysisResultOpt = nullAnalysisResultOpt; _pointsToAnalysisResultOpt = pointsToAnalysisResultOpt; _valueCacheBuilder = ImmutableDictionary.CreateBuilder <IOperation, TAbstractAnalysisValue>(); _pendingArgumentsToReset = new List <IArgumentOperation>(); ThisOrMePointsToAbstractValue = GetThisOrMeInstancePointsToValue(owningSymbol.ContainingType); AnalysisEntityFactory = new AnalysisEntityFactory( (pointsToAnalysisResultOpt != null || IsPointsToAnalysis) ? GetPointsToAbstractValue : (Func <IOperation, PointsToAbstractValue>)null, owningSymbol.ContainingType); }
protected AbstractLocationDataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, INamedTypeSymbol containingTypeSymbol, DataFlowAnalysisResult <NullAnalysis.NullBlockAnalysisResult, NullAnalysis.NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <PointsToAnalysis.PointsToBlockAnalysisResult, PointsToAnalysis.PointsToAbstractValue> pointsToAnalysisResultOpt) : base(valueDomain, containingTypeSymbol, nullAnalysisResultOpt, pointsToAnalysisResultOpt) { }
protected AnalysisEntityDataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, ISymbol owningSymbol, bool pessimisticAnalysis, DataFlowAnalysisResult <NullBlockAnalysisResult, NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) : base(valueDomain, owningSymbol, pessimisticAnalysis, nullAnalysisResultOpt, pointsToAnalysisResultOpt) { }
protected AnalysisEntityDataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, bool pessimisticAnalysis, bool predicateAnalysis, DataFlowAnalysisResult <CopyBlockAnalysisResult, CopyAbstractValue> copyAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) : base(valueDomain, owningSymbol, wellKnownTypeProvider, pessimisticAnalysis, predicateAnalysis, copyAnalysisResultOpt, pointsToAnalysisResultOpt) { }
protected DataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, INamedTypeSymbol containingTypeSymbol, DataFlowAnalysisResult <NullBlockAnalysisResult, NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) { ValueDomain = valueDomain; _nullAnalysisResultOpt = nullAnalysisResultOpt; _pointsToAnalysisResultOpt = pointsToAnalysisResultOpt; _valueCacheBuilder = ImmutableDictionary.CreateBuilder <IOperation, TAbstractAnalysisValue>(); _pendingArgumentsToReset = new List <IArgumentOperation>(); ThisOrMePointsToAbstractValue = GetThisOrMeInstancePointsToValue(containingTypeSymbol); }
protected AnalysisEntityDataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, INamedTypeSymbol containingTypeSymbol, DataFlowAnalysisResult <NullBlockAnalysisResult, NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) : base(valueDomain, containingTypeSymbol, nullAnalysisResultOpt, pointsToAnalysisResultOpt) { AnalysisEntityFactory = new AnalysisEntityFactory( (pointsToAnalysisResultOpt != null || IsPointsToAnalysis) ? GetPointsToAbstractValue : (Func <IOperation, PointsToAbstractValue>)null, containingTypeSymbol); }
protected AbstractLocationDataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, bool pessimisticAnalysis, bool predicateAnalysis, DataFlowAnalysisResult <NullAnalysis.NullBlockAnalysisResult, NullAnalysis.NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <CopyAnalysis.CopyBlockAnalysisResult, CopyAnalysis.CopyAbstractValue> copyAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) : base(valueDomain, owningSymbol, wellKnownTypeProvider, pessimisticAnalysis, predicateAnalysis, nullAnalysisResultOpt, copyAnalysisResultOpt, pointsToAnalysisResultOpt) { Debug.Assert(pointsToAnalysisResultOpt != null); }
protected DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> GetOrComputeResultCore( ControlFlowGraph cfg, bool cacheResult, DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> seedResultOpt = null) { if (!cacheResult) { return(Run(cfg, seedResultOpt)); } var analysisResultsMap = s_resultCache.GetOrCreateValue(cfg.RootOperation); return(analysisResultsMap.GetOrAdd(OperationVisitor, _ => Run(cfg, seedResultOpt))); }
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)); }
protected DataFlowOperationVisitor(AbstractDomain <TAbstractAnalysisValue> valueDomain, DataFlowAnalysisResult <NullBlockAnalysisResult, NullAbstractValue> nullAnalysisResultOpt) { ValueDomain = valueDomain; _nullAnalysisResultOpt = nullAnalysisResultOpt; _valueCacheBuilder = ImmutableDictionary.CreateBuilder <IOperation, TAbstractAnalysisValue>(); }