public static ValueContentAnalysisResult TryGetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, AnalyzerOptions analyzerOptions, DiagnosticDescriptor rule, CancellationToken cancellationToken, out CopyAnalysisResult copyAnalysisResultOpt, out PointsToAnalysisResult pointsToAnalysisResultOpt, InterproceduralAnalysisKind interproceduralAnalysisKind = InterproceduralAnalysisKind.None, bool pessimisticAnalysis = true, bool performPointsToAnalysis = true, bool performCopyAnalysisIfNotUserConfigured = false, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null) { Debug.Assert(!owningSymbol.IsConfiguredToSkipAnalysis(analyzerOptions, rule, wellKnownTypeProvider.Compilation, cancellationToken)); var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create( analyzerOptions, rule, interproceduralAnalysisKind, cancellationToken); return(TryGetOrComputeResult(cfg, owningSymbol, analyzerOptions, wellKnownTypeProvider, interproceduralAnalysisConfig, out copyAnalysisResultOpt, out pointsToAnalysisResultOpt, pessimisticAnalysis, performPointsToAnalysis, performCopyAnalysis: analyzerOptions.GetCopyAnalysisOption(rule, defaultValue: performCopyAnalysisIfNotUserConfigured, cancellationToken), interproceduralAnalysisPredicateOpt: interproceduralAnalysisPredicateOpt)); }
internal static ValueContentAnalysisResult TryGetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, AnalyzerOptions analyzerOptions, WellKnownTypeProvider wellKnownTypeProvider, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, out CopyAnalysisResult copyAnalysisResultOpt, out PointsToAnalysisResult pointsToAnalysisResultOpt, bool pessimisticAnalysis = true, bool performPointsToAnalysis = true, bool performCopyAnalysis = false, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null) { copyAnalysisResultOpt = null; pointsToAnalysisResultOpt = performPointsToAnalysis ? PointsToAnalysis.PointsToAnalysis.TryGetOrComputeResult(cfg, owningSymbol, analyzerOptions, wellKnownTypeProvider, out copyAnalysisResultOpt, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, pessimisticAnalysis, performCopyAnalysis) : null; if (cfg == null) { Debug.Fail("Expected non-null CFG"); return(null); } var analysisContext = ValueContentAnalysisContext.Create( ValueContentAbstractValueDomain.Default, wellKnownTypeProvider, cfg, owningSymbol, analyzerOptions, interproceduralAnalysisConfig, pessimisticAnalysis, copyAnalysisResultOpt, pointsToAnalysisResultOpt, TryGetOrComputeResultForAnalysisContext, interproceduralAnalysisPredicateOpt); return(TryGetOrComputeResultForAnalysisContext(analysisContext)); }
public bool TryGetOrComputeResult( OperationBlockAnalysisContext context, IMethodSymbol containingMethod, DiagnosticDescriptor rule, InterproceduralAnalysisKind interproceduralAnalysisKind, bool trackInstanceFields, out DisposeAnalysisResult disposeAnalysisResult, out PointsToAnalysisResult pointsToAnalysisResult, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null) { // Compute the dispose analysis result - skip Attribute blocks (OperationKind.None) foreach (var operationBlock in context.OperationBlocks.Where(o => o.Kind != OperationKind.None)) { var cfg = context.GetControlFlowGraph(operationBlock); if (cfg != null) { var wellKnownTypeProvider = Analyzer.Utilities.WellKnownTypeProvider.GetOrCreate(context.Compilation); disposeAnalysisResult = FlowAnalysis.DataFlow.DisposeAnalysis.DisposeAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, context.Options, rule, _disposeOwnershipTransferLikelyTypes, trackInstanceFields, exceptionPathsAnalysis: false, context.CancellationToken, out pointsToAnalysisResult, interproceduralAnalysisKind, interproceduralAnalysisPredicateOpt: interproceduralAnalysisPredicateOpt, defaultDisposeOwnershipTransferAtConstructor: true, defaultDisposeOwnershipTransferAtMethodCall: true); if (disposeAnalysisResult != null) { return(true); } } } disposeAnalysisResult = null; pointsToAnalysisResult = null; return(false); }
private static DisposeAnalysisResult TryGetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt, ImmutableHashSet <INamedTypeSymbol> disposeOwnershipTransferLikelyTypes, bool disposeOwnershipTransferAtConstructor, bool trackInstanceFields, bool exceptionPathsAnalysis, bool performCopyAnalysis, out PointsToAnalysisResult pointsToAnalysisResult) { Debug.Assert(cfg != null); Debug.Assert(wellKnownTypeProvider.IDisposable != null); Debug.Assert(owningSymbol != null); pointsToAnalysisResult = PointsToAnalysis.PointsToAnalysis.TryGetOrComputeResult( cfg, owningSymbol, wellKnownTypeProvider, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, PessimisticAnalysis, performCopyAnalysis, exceptionPathsAnalysis); if (pointsToAnalysisResult == null) { return(null); } var analysisContext = DisposeAnalysisContext.Create( DisposeAbstractValueDomain.Default, wellKnownTypeProvider, cfg, owningSymbol, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, PessimisticAnalysis, exceptionPathsAnalysis, pointsToAnalysisResult, TryGetOrComputeResultForAnalysisContext, disposeOwnershipTransferLikelyTypes, disposeOwnershipTransferAtConstructor, trackInstanceFields); return(TryGetOrComputeResultForAnalysisContext(analysisContext)); }
public static DisposeAnalysisResult TryGetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, AnalyzerOptions analyzerOptions, DiagnosticDescriptor rule, ImmutableHashSet <INamedTypeSymbol> disposeOwnershipTransferLikelyTypes, bool trackInstanceFields, bool exceptionPathsAnalysis, CancellationToken cancellationToken, out PointsToAnalysisResult pointsToAnalysisResult, InterproceduralAnalysisKind interproceduralAnalysisKind = InterproceduralAnalysisKind.ContextSensitive, bool performCopyAnalysisIfNotUserConfigured = false, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null, bool defaultDisposeOwnershipTransferAtConstructor = false) { var interproceduralAnalysisConfig = InterproceduralAnalysisConfiguration.Create( analyzerOptions, rule, interproceduralAnalysisKind, cancellationToken); var disposeOwnershipTransferAtConstructor = analyzerOptions.GetDisposeOwnershipTransferAtConstructorOption( rule, defaultValue: defaultDisposeOwnershipTransferAtConstructor, cancellationToken); return(TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, disposeOwnershipTransferLikelyTypes, disposeOwnershipTransferAtConstructor, trackInstanceFields, exceptionPathsAnalysis, performCopyAnalysis: analyzerOptions.GetCopyAnalysisOption(rule, defaultValue: performCopyAnalysisIfNotUserConfigured, cancellationToken), out pointsToAnalysisResult)); }
private DisposeAnalysisContext( AbstractValueDomain <DisposeAbstractValue> valueDomain, WellKnownTypeProvider wellKnownTypeProvider, ControlFlowGraph controlFlowGraph, ISymbol owningSymbol, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, bool pessimisticAnalysis, bool exceptionPathsAnalysis, PointsToAnalysisResult pointsToAnalysisResultOpt, Func <DisposeAnalysisContext, DisposeAnalysisResult> tryGetOrComputeAnalysisResult, ImmutableHashSet <INamedTypeSymbol> disposeOwnershipTransferLikelyTypes, bool disposeOwnershipTransferAtConstructor, bool disposeOwnershipTransferAtMethodCall, bool trackInstanceFields, ControlFlowGraph parentControlFlowGraphOpt, InterproceduralDisposeAnalysisData interproceduralAnalysisDataOpt, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt) : base(valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol, interproceduralAnalysisConfig, pessimisticAnalysis, predicateAnalysis: false, exceptionPathsAnalysis, copyAnalysisResultOpt: null, pointsToAnalysisResultOpt, valueContentAnalysisResultOpt: null, tryGetOrComputeAnalysisResult, parentControlFlowGraphOpt, interproceduralAnalysisDataOpt, interproceduralAnalysisPredicateOpt) { DisposeOwnershipTransferLikelyTypes = disposeOwnershipTransferLikelyTypes; DisposeOwnershipTransferAtConstructor = disposeOwnershipTransferAtConstructor; DisposeOwnershipTransferAtMethodCall = disposeOwnershipTransferAtMethodCall; TrackInstanceFields = trackInstanceFields; }
public bool TryGetOrComputeResult( ImmutableArray <IOperation> operationBlocks, IMethodSymbol containingMethod, AnalyzerOptions analyzerOptions, DiagnosticDescriptor rule, bool trackInstanceFields, bool trackExceptionPaths, CancellationToken cancellationToken, out DisposeAnalysisResult disposeAnalysisResult, out PointsToAnalysisResult pointsToAnalysisResult, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null, bool defaultDisposeOwnershipTransferAtConstructor = false) { var cfg = operationBlocks.GetControlFlowGraph(); if (cfg != null) { disposeAnalysisResult = DisposeAnalysis.GetOrComputeResult(cfg, containingMethod, _wellKnownTypeProvider, analyzerOptions, rule, _disposeOwnershipTransferLikelyTypes, trackInstanceFields, trackExceptionPaths, cancellationToken, out pointsToAnalysisResult, interproceduralAnalysisPredicateOpt: interproceduralAnalysisPredicateOpt, defaultDisposeOwnershipTransferAtConstructor: defaultDisposeOwnershipTransferAtConstructor); return(true); } disposeAnalysisResult = null; pointsToAnalysisResult = null; return(false); }
internal static DisposeAnalysisContext Create( AbstractValueDomain <DisposeAbstractValue> valueDomain, WellKnownTypeProvider wellKnownTypeProvider, ControlFlowGraph controlFlowGraph, ISymbol owningSymbol, AnalyzerOptions analyzerOptions, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt, bool pessimisticAnalysis, bool exceptionPathsAnalysis, PointsToAnalysisResult pointsToAnalysisResultOpt, Func <DisposeAnalysisContext, DisposeAnalysisResult> tryGetOrComputeAnalysisResult, ImmutableHashSet <INamedTypeSymbol> disposeOwnershipTransferLikelyTypes, bool disposeOwnershipTransferAtConstructor, bool disposeOwnershipTransferAtMethodCall, bool trackInstanceFields) { return(new DisposeAnalysisContext( valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol, analyzerOptions, interproceduralAnalysisConfig, pessimisticAnalysis, exceptionPathsAnalysis, pointsToAnalysisResultOpt, tryGetOrComputeAnalysisResult, disposeOwnershipTransferLikelyTypes, disposeOwnershipTransferAtConstructor, disposeOwnershipTransferAtMethodCall, trackInstanceFields, parentControlFlowGraphOpt: null, interproceduralAnalysisDataOpt: null, interproceduralAnalysisPredicateOpt)); }
public static PointsToAnalysisResult TryGetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt, bool pessimisticAnalysis = true, bool performCopyAnalysis = true, bool exceptionPathsAnalysis = false) { return(TryGetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider, out var _, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, pessimisticAnalysis, performCopyAnalysis, exceptionPathsAnalysis)); }
internal static PointsToAnalysisContext Create( AbstractValueDomain <PointsToAbstractValue> valueDomain, WellKnownTypeProvider wellKnownTypeProvider, ControlFlowGraph controlFlowGraph, ISymbol owningSymbol, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, bool pessimisticAnalysis, bool exceptionPathsAnalysis, CopyAnalysisResult copyAnalysisResultOpt, Func <PointsToAnalysisContext, PointsToAnalysisResult> getOrComputeAnalysisResult, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt) { return(new PointsToAnalysisContext(valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol, interproceduralAnalysisConfig, pessimisticAnalysis, exceptionPathsAnalysis, copyAnalysisResultOpt, getOrComputeAnalysisResult, parentControlFlowGraphOpt: null, interproceduralAnalysisDataOpt: null, interproceduralAnalysisPredicateOpt)); }
internal static ValueContentAnalysisContext Create( AbstractValueDomain <ValueContentAbstractValue> valueDomain, WellKnownTypeProvider wellKnownTypeProvider, ControlFlowGraph controlFlowGraph, ISymbol owningSymbol, AnalyzerOptions analyzerOptions, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, bool pessimisticAnalysis, CopyAnalysisResult copyAnalysisResultOpt, PointsToAnalysisResult pointsToAnalysisResultOpt, Func <ValueContentAnalysisContext, ValueContentAnalysisResult> tryGetOrComputeAnalysisResult, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt) { return(new ValueContentAnalysisContext( valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol, analyzerOptions, interproceduralAnalysisConfig, pessimisticAnalysis, copyAnalysisResultOpt, pointsToAnalysisResultOpt, tryGetOrComputeAnalysisResult, parentControlFlowGraphOpt: null, interproceduralAnalysisDataOpt: null, interproceduralAnalysisPredicateOpt)); }
private PointsToAnalysisContext( AbstractValueDomain <PointsToAbstractValue> valueDomain, WellKnownTypeProvider wellKnownTypeProvider, ControlFlowGraph controlFlowGraph, ISymbol owningSymbol, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, bool pessimisticAnalysis, bool exceptionPathsAnalysis, CopyAnalysisResult copyAnalysisResultOpt, Func <PointsToAnalysisContext, PointsToAnalysisResult> getOrComputeAnalysisResult, ControlFlowGraph parentControlFlowGraphOpt, InterproceduralPointsToAnalysisData interproceduralAnalysisDataOpt, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt) : base(valueDomain, wellKnownTypeProvider, controlFlowGraph, owningSymbol, interproceduralAnalysisConfig, pessimisticAnalysis, predicateAnalysis: true, exceptionPathsAnalysis, copyAnalysisResultOpt, pointsToAnalysisResultOpt: null, getOrComputeAnalysisResult, parentControlFlowGraphOpt, interproceduralAnalysisDataOpt, interproceduralAnalysisPredicateOpt) { }
public static CopyAnalysisResult GetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt, bool pessimisticAnalysis = true, bool performPointsToAnalysis = true, bool exceptionPathsAnalysis = false) { var pointsToAnalysisResultOpt = performPointsToAnalysis ? PointsToAnalysis.PointsToAnalysis.GetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, pessimisticAnalysis, performCopyAnalysis: false, exceptionPathsAnalysis) : null; var analysisContext = CopyAnalysisContext.Create(CopyAbstractValueDomain.Default, wellKnownTypeProvider, cfg, owningSymbol, interproceduralAnalysisConfig, pessimisticAnalysis, exceptionPathsAnalysis, pointsToAnalysisResultOpt, GetOrComputeResultForAnalysisContext, interproceduralAnalysisPredicateOpt); return(GetOrComputeResultForAnalysisContext(analysisContext)); }
internal static ValueContentAnalysisResult GetOrComputeResult( ControlFlowGraph cfg, ISymbol owningSymbol, WellKnownTypeProvider wellKnownTypeProvider, InterproceduralAnalysisConfiguration interproceduralAnalysisConfig, out CopyAnalysisResult copyAnalysisResultOpt, out PointsToAnalysisResult pointsToAnalysisResultOpt, bool pessimisticAnalysis = true, bool performPointsToAnalysis = true, bool performCopyAnalysis = true, InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null) { copyAnalysisResultOpt = null; pointsToAnalysisResultOpt = performPointsToAnalysis ? PointsToAnalysis.PointsToAnalysis.GetOrComputeResult(cfg, owningSymbol, wellKnownTypeProvider, out copyAnalysisResultOpt, interproceduralAnalysisConfig, interproceduralAnalysisPredicateOpt, pessimisticAnalysis, performCopyAnalysis) : null; var analysisContext = ValueContentAnalysisContext.Create( ValueContentAbstractValueDomain.Default, wellKnownTypeProvider, cfg, owningSymbol, interproceduralAnalysisConfig, pessimisticAnalysis, copyAnalysisResultOpt, pointsToAnalysisResultOpt, GetOrComputeResultForAnalysisContext, interproceduralAnalysisPredicateOpt); return(GetOrComputeResultForAnalysisContext(analysisContext)); }
private void PerformFlowAnalysisOnOperationBlock( OperationBlockAnalysisContext operationBlockContext, DisposeAnalysisHelper disposeAnalysisHelper, ConcurrentDictionary <Location, bool> reportedLocations, IMethodSymbol containingMethod) { // We can skip interprocedural analysis for certain invocations. var interproceduralAnalysisPredicateOpt = new InterproceduralAnalysisPredicate( skipAnalysisForInvokedMethodPredicateOpt: SkipInterproceduralAnalysis, skipAnalysisForInvokedLambdaOrLocalFunctionPredicateOpt: null, skipAnalysisForInvokedContextPredicateOpt: null); // Compute dispose dataflow analysis result for the operation block. if (disposeAnalysisHelper.TryGetOrComputeResult(operationBlockContext, containingMethod, _disposeObjectsBeforeLosingScopeRule, InterproceduralAnalysisKind.ContextSensitive, trackInstanceFields: false, out var disposeAnalysisResult, out var pointsToAnalysisResult, interproceduralAnalysisPredicateOpt)) { var notDisposedDiagnostics = ArrayBuilder <Diagnostic> .GetInstance(); var mayBeNotDisposedDiagnostics = ArrayBuilder <Diagnostic> .GetInstance(); try { // Compute diagnostics for undisposed objects at exit block. var exitBlock = disposeAnalysisResult.ControlFlowGraph.ExitBlock(); var disposeDataAtExit = disposeAnalysisResult.ExitBlockOutput.Data; ComputeDiagnostics(disposeDataAtExit, notDisposedDiagnostics, mayBeNotDisposedDiagnostics, disposeAnalysisResult, pointsToAnalysisResult); if (disposeAnalysisResult.ControlFlowGraph.OriginalOperation.HasAnyOperationDescendant(o => o.Kind == OperationKind.None)) { // Workaround for https://github.com/dotnet/roslyn/issues/32100 // Bail out in presence of OperationKind.None - not implemented IOperation. return; } // Report diagnostics preferring *not* disposed diagnostics over may be not disposed diagnostics // and avoiding duplicates. foreach (var diagnostic in notDisposedDiagnostics.Concat(mayBeNotDisposedDiagnostics)) { if (reportedLocations.TryAdd(diagnostic.Location, true)) { operationBlockContext.ReportDiagnostic(diagnostic); } } } finally { notDisposedDiagnostics.Free(); mayBeNotDisposedDiagnostics.Free(); } } return; // Local functions. bool SkipInterproceduralAnalysis(IMethodSymbol invokedMethod) { // Skip interprocedural analysis if we are invoking a method and not passing any disposable object as an argument // and not receiving a disposable object as a return value. // We also check that we are not passing any object type argument which might hold disposable object // and also check that we are not passing delegate type argument which can // be a lambda or local function that has access to disposable object in current method's scope. if (CanBeDisposable(invokedMethod.ReturnType)) { return(false); } foreach (var p in invokedMethod.Parameters) { if (CanBeDisposable(p.Type)) { return(false); } } return(true); bool CanBeDisposable(ITypeSymbol type) => type.SpecialType == SpecialType.System_Object || type.IsDisposable(disposeAnalysisHelper.IDisposableType) || type.TypeKind == TypeKind.Delegate; } void ComputeDiagnostics( ImmutableDictionary <AbstractLocation, DisposeAbstractValue> disposeData, ArrayBuilder <Diagnostic> notDisposedDiagnostics, ArrayBuilder <Diagnostic> mayBeNotDisposedDiagnostics, DisposeAnalysisResult disposeAnalysisResult, PointsToAnalysisResult pointsToAnalysisResult) { foreach (var kvp in disposeData) { var location = kvp.Key; var disposeValue = kvp.Value; // Ignore non-disposable locations and locations without a Creation operation. if (disposeValue.Kind == DisposeAbstractValueKind.NotDisposable || location.CreationOpt == null) { continue; } // Check if the disposable creation is definitely not disposed or may be not disposed. var isNotDisposed = disposeValue.Kind == DisposeAbstractValueKind.NotDisposed || (disposeValue.DisposingOrEscapingOperations.Count > 0 && disposeValue.DisposingOrEscapingOperations.All(d => d.IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph) && !location.CreationOpt.IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph))); var isMayBeNotDisposed = !isNotDisposed && (disposeValue.Kind == DisposeAbstractValueKind.MaybeDisposed || disposeValue.Kind == DisposeAbstractValueKind.NotDisposedOrEscaped); if (isNotDisposed || isMayBeNotDisposed) { var syntax = location.TryGetNodeToReportDiagnostic(pointsToAnalysisResult); if (syntax == null) { continue; } var rule = isNotDisposed ? _disposeObjectsBeforeLosingScopeRule : _useRecommendedDisposePatternRule; // Ensure that we do not include multiple lines for the object creation expression in the diagnostic message. var objectCreationText = syntax.ToString(); var indexOfNewLine = objectCreationText.IndexOf(Environment.NewLine); if (indexOfNewLine > 0) { objectCreationText = objectCreationText.Substring(0, indexOfNewLine); } var diagnostic = Diagnostic.Create( rule, syntax.GetLocation(), additionalLocations: null, properties: null, objectCreationText); if (isNotDisposed) { notDisposedDiagnostics.Add(diagnostic); } else { mayBeNotDisposedDiagnostics.Add(diagnostic); } } } } }