private static void ComputeDiagnostics( ImmutableDictionary <AbstractLocation, DisposeAbstractValue> disposeData, ArrayBuilder <Diagnostic> notDisposedDiagnostics, ArrayBuilder <Diagnostic> mayBeNotDisposedDiagnostics, DisposeAnalysisResult disposeAnalysisResult, PointsToAnalysisResult pointsToAnalysisResult, DisposeAnalysisKind disposeAnalysisKind, bool isDisposeDataForExceptionPaths) { foreach (var kvp in disposeData) { AbstractLocation location = kvp.Key; DisposeAbstractValue disposeValue = kvp.Value; if (disposeValue.Kind == DisposeAbstractValueKind.NotDisposable || location.CreationOpt == null) { continue; } var isNotDisposed = disposeValue.Kind == DisposeAbstractValueKind.NotDisposed || (disposeValue.DisposingOrEscapingOperations.Count > 0 && disposeValue.DisposingOrEscapingOperations.All(d => d.IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph))); var isMayBeNotDisposed = !isNotDisposed && (disposeValue.Kind == DisposeAbstractValueKind.MaybeDisposed || disposeValue.Kind == DisposeAbstractValueKind.NotDisposedOrEscaped); if (isNotDisposed || (isMayBeNotDisposed && disposeAnalysisKind.AreMayBeNotDisposedViolationsEnabled())) { var syntax = location.TryGetNodeToReportDiagnostic(pointsToAnalysisResult); if (syntax == null) { continue; } // CA2000: Call System.IDisposable.Dispose on object created by '{0}' before all references to it are out of scope. var rule = GetRule(isNotDisposed); var argument = syntax.ToString(); var diagnostic = syntax.CreateDiagnostic(rule, argument); if (isNotDisposed) { notDisposedDiagnostics.Add(diagnostic); } else { mayBeNotDisposedDiagnostics.Add(diagnostic); } } } DiagnosticDescriptor GetRule(bool isNotDisposed) { if (isNotDisposed) { return(isDisposeDataForExceptionPaths ? NotDisposedOnExceptionPathsRule : NotDisposedRule); } else { return(isDisposeDataForExceptionPaths ? MayBeDisposedOnExceptionPathsRule : MayBeDisposedRule); } } }
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); }
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); }
private static void ComputeDiagnostics( ImmutableDictionary <AbstractLocation, DisposeAbstractValue> disposeData, ArrayBuilder <Diagnostic> notDisposedDiagnostics, ArrayBuilder <Diagnostic> mayBeNotDisposedDiagnostics, DisposeAnalysisResult disposeAnalysisResult, PointsToAnalysisResult pointsToAnalysisResult, DisposeAnalysisKind disposeAnalysisKind, bool isDisposeDataForExceptionPaths) { foreach (var kvp in disposeData) { AbstractLocation location = kvp.Key; DisposeAbstractValue disposeValue = kvp.Value; if (disposeValue.Kind == DisposeAbstractValueKind.NotDisposable || location.Creation == null) { continue; } var isNotDisposed = disposeValue.Kind == DisposeAbstractValueKind.NotDisposed || (!disposeValue.DisposingOrEscapingOperations.IsEmpty && disposeValue.DisposingOrEscapingOperations.All(d => d.IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph) && !location.GetTopOfCreationCallStackOrCreation().IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph))); var isMayBeNotDisposed = !isNotDisposed && (disposeValue.Kind == DisposeAbstractValueKind.MaybeDisposed || disposeValue.Kind == DisposeAbstractValueKind.NotDisposedOrEscaped); if (isNotDisposed || (isMayBeNotDisposed && disposeAnalysisKind.AreMayBeNotDisposedViolationsEnabled())) { var syntax = location.TryGetNodeToReportDiagnostic(pointsToAnalysisResult); if (syntax == null) { continue; } // CA2000: Call System.IDisposable.Dispose on object created by '{0}' before all references to it are out of scope. var rule = GetRule(isNotDisposed); // Ensure that we do not include multiple lines for the object creation expression in the diagnostic message. var argument = syntax.ToString(); var indexOfNewLine = argument.IndexOf(Environment.NewLine, StringComparison.Ordinal); if (indexOfNewLine > 0) { argument = argument.Substring(0, indexOfNewLine); } var diagnostic = syntax.CreateDiagnostic(rule, argument); if (isNotDisposed) { notDisposedDiagnostics.Add(diagnostic); } else { mayBeNotDisposedDiagnostics.Add(diagnostic); } } } DiagnosticDescriptor GetRule(bool isNotDisposed) { if (isNotDisposed) { return(isDisposeDataForExceptionPaths ? NotDisposedOnExceptionPathsRule : NotDisposedRule); } else { return(isDisposeDataForExceptionPaths ? MayBeDisposedOnExceptionPathsRule : MayBeDisposedRule); } } }