示例#1
0
        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));
        }
示例#2
0
        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);
        }
示例#8
0
 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));
 }
示例#10
0
 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));
 }
示例#11
0
 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));
 }
示例#12
0
 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)
 {
 }
示例#13
0
        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));
        }
示例#14
0
        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);
                        }
                    }
                }
            }
        }