/// <summary> /// Runs a fast, non-precise operation tree based analysis to compute symbol usage results /// for symbol read/writes. /// </summary> public static SymbolUsageResult Run(IOperation rootOperation, ISymbol owningSymbol, CancellationToken cancellationToken) { AnalysisData analysisData = null; using (analysisData = OperationTreeAnalysisData.Create(owningSymbol, AnalyzeLocalFunction)) { var operations = SpecializedCollections.SingletonEnumerable(rootOperation); Walker.AnalyzeOperationsAndUpdateData(operations, analysisData, cancellationToken); return(analysisData.ToResult()); } // Local functions. BasicBlockAnalysisData AnalyzeLocalFunction(IMethodSymbol localFunction) { var localFunctionOperation = rootOperation.Descendants() .FirstOrDefault(o => Equals((o as ILocalFunctionOperation)?.Symbol, localFunction)); // Can likely be null for broken code. if (localFunctionOperation != null) { var operations = SpecializedCollections.SingletonEnumerable(localFunctionOperation); Walker.AnalyzeOperationsAndUpdateData(operations, analysisData, cancellationToken); } return(analysisData.CurrentBlockAnalysisData); } }
public override BasicBlockAnalysisData AnalyzeBlock(BasicBlock basicBlock, CancellationToken cancellationToken) { BeforeBlockAnalysis(); Walker.AnalyzeOperationsAndUpdateData(basicBlock.Operations, _analysisData, cancellationToken); AfterBlockAnalysis(); return(_analysisData.CurrentBlockAnalysisData); // Local functions. void BeforeBlockAnalysis() { // Initialize current block analysis data. _analysisData.SetCurrentBlockAnalysisDataFrom(basicBlock, cancellationToken); // At start of entry block, handle parameter definitions from method declaration. if (basicBlock.Kind == BasicBlockKind.Entry) { _analysisData.SetAnalysisDataOnEntryBlockStart(); } } void AfterBlockAnalysis() { // If we are exiting the control flow graph, handle ref/out parameter definitions from method declaration. if (basicBlock.FallThroughSuccessor?.Destination == null && basicBlock.ConditionalSuccessor?.Destination == null) { _analysisData.SetAnalysisDataOnMethodExit(); } } }
public override BasicBlockAnalysisData AnalyzeBlock(BasicBlock basicBlock, CancellationToken cancellationToken) { BeforeBlockAnalysis(); Walker.AnalyzeOperationsAndUpdateData(basicBlock.Operations, _analysisData, cancellationToken); AfterBlockAnalysis(); return(_analysisData.CurrentBlockAnalysisData); // Local functions. void BeforeBlockAnalysis() { // Initialize current block analysis data. _analysisData.SetCurrentBlockAnalysisDataFrom(basicBlock); // At start of entry block, handle parameter definitions from method declaration. if (basicBlock.Kind == BasicBlockKind.Entry) { _analysisData.SetAnalysisDataOnEntryBlockStart(); } } void AfterBlockAnalysis() { // At end of entry block, handle ref/out parameter definitions from method declaration. if (basicBlock.Kind == BasicBlockKind.Exit) { _analysisData.SetAnalysisDataOnExitBlockEnd(); } } }
private BasicBlockAnalysisData AnalyzeBranch( ControlFlowBranch branch, BasicBlock basicBlock, BasicBlockAnalysisData currentBlockAnalysisData, CancellationToken cancellationToken ) { // Initialize current analysis data _analysisData.SetCurrentBlockAnalysisDataFrom(currentBlockAnalysisData); // Analyze the branch value var operations = SpecializedCollections.SingletonEnumerable(basicBlock.BranchValue); Walker.AnalyzeOperationsAndUpdateData( _analysisData.OwningSymbol, operations, _analysisData, cancellationToken ); ProcessOutOfScopeLocals(); return(_analysisData.CurrentBlockAnalysisData); // Local functions void ProcessOutOfScopeLocals() { if (branch == null) { return; } if ( basicBlock.EnclosingRegion.Kind == ControlFlowRegionKind.Catch && !branch.FinallyRegions.IsEmpty ) { // Bail out for branches from the catch block // as the locals are still accessible in the finally region. return; } foreach (var region in branch.LeavingRegions) { foreach (var local in region.Locals) { _analysisData.CurrentBlockAnalysisData.Clear(local); } if (region.Kind == ControlFlowRegionKind.TryAndFinally) { // Locals defined in the outer regions of try/finally might be used in finally region. break; } } } }
private BasicBlockAnalysisData AnalyzeBranch( BasicBlock basicBlock, BasicBlockAnalysisData currentBlockAnalysisData, CancellationToken cancellationToken) { // Initialize current analysis data _analysisData.SetCurrentBlockAnalysisDataFrom(currentBlockAnalysisData); // Analyze the branch value var operations = SpecializedCollections.SingletonEnumerable(basicBlock.BranchValue); Walker.AnalyzeOperationsAndUpdateData(operations, _analysisData, cancellationToken); return(_analysisData.CurrentBlockAnalysisData); }