private static void OnSymbolStart(SymbolStartAnalysisContext symbolStartContext) { if (!DisposeAnalysisHelper.TryGetOrCreate(symbolStartContext.Compilation, out DisposeAnalysisHelper? disposeAnalysisHelper) || !ShouldAnalyze(symbolStartContext, disposeAnalysisHelper)) { return; } var fieldDisposeValueMap = PooledConcurrentDictionary <IFieldSymbol, /*disposed*/ bool> .GetInstance(); var hasErrors = false; symbolStartContext.RegisterOperationAction(_ => hasErrors = true, OperationKind.Invalid); // Disposable fields with initializer at declaration must be disposed. symbolStartContext.RegisterOperationAction(OnFieldInitializer, OperationKind.FieldInitializer); // Instance fields initialized in constructor/method body with a locally created disposable object must be disposed. symbolStartContext.RegisterOperationBlockStartAction(OnOperationBlockStart); // Report diagnostics at symbol end. symbolStartContext.RegisterSymbolEndAction(OnSymbolEnd); return; // Local functions void AddOrUpdateFieldDisposedValue(IFieldSymbol field, bool disposed) { Debug.Assert(!field.IsStatic); Debug.Assert(disposeAnalysisHelper !.IsDisposable(field.Type)); fieldDisposeValueMap.AddOrUpdate(field, addValue: disposed, updateValueFactory: (f, currentValue) => currentValue || disposed); }
public static void OnSymbolStart(SymbolStartAnalysisContext symbolStartContext, DisposeAnalysisHelper disposeAnalysisHelper) { // We only want to analyze types which are disposable (implement System.IDisposable directly or indirectly) // and have at least one disposable field. var namedType = (INamedTypeSymbol)symbolStartContext.Symbol; if (!namedType.IsDisposable(disposeAnalysisHelper.IDisposableType)) { return; } var disposableFields = disposeAnalysisHelper.GetDisposableFields(namedType); if (disposableFields.IsEmpty) { return; } var analyzer = new SymbolAnalyzer(disposableFields, disposeAnalysisHelper); // Register an operation block action to analyze disposable assignments and dispose invocations for fields. symbolStartContext.RegisterOperationBlockStartAction(analyzer.OnOperationBlockStart); // Register symbol end action for containing type to report non-disposed fields. // We report fields that have disposable type (implement System.IDisposable directly or indirectly) // and were assigned a disposable object within this containing type, but were not disposed in // containing type's Dispose method. symbolStartContext.RegisterSymbolEndAction(analyzer.OnSymbolEnd); }
// Actions/Symbol private static void OnSymbol_Start(SymbolStartAnalysisContext context) // for specific SymbolKind //// CodeBlock //context.RegisterCodeBlockStartAction<SyntaxKind>( OnCodeBlock_Start ); //context.RegisterCodeBlockAction( OnCodeBlock ); // Symbol { context.RegisterSymbolEndAction(OnSymbol_End); }
static bool ShouldAnalyze(SymbolStartAnalysisContext symbolStartContext, DisposeAnalysisHelper disposeAnalysisHelper) { // We only want to analyze types which are disposable (implement System.IDisposable directly or indirectly) // and have at least one disposable field. var namedType = (INamedTypeSymbol)symbolStartContext.Symbol; return disposeAnalysisHelper.IsDisposable(namedType) && !disposeAnalysisHelper.GetDisposableFields(namedType).IsEmpty && !namedType.IsConfiguredToSkipAnalysis(symbolStartContext.Options, Rule, symbolStartContext.Compilation, symbolStartContext.CancellationToken); }
private void RegisterActions(SymbolStartAnalysisContext symbolStartContext) { symbolStartContext.RegisterOperationBlockStartAction(blockAction => { var isConstructor = blockAction.OwningSymbol is IMethodSymbol method && method.MethodKind == MethodKind.Constructor; blockAction.RegisterOperationAction( operationAction => AnalyzeAssignment(operationAction, isConstructor), OperationKind.SimpleAssignment); }); symbolStartContext.RegisterSymbolEndAction(SymbolEndAction); }
private void RegisterActions(SymbolStartAnalysisContext context) { context.RegisterOperationBlockStartAction(context => { if (context.OwningSymbol is IMethodSymbol { MethodKind: MethodKind.Constructor }) { // We are looking for assignment to 'this' outside the constructor scope return; } context.RegisterOperationAction(AnalyzeAssignment, OperationKind.SimpleAssignment); });
private void OnSymbolStart(SymbolStartAnalysisContext context) { context.RegisterOperationBlockStartAction(OnOperationBlock); context.RegisterSymbolEndAction(OnSymbolEnd); }
/// <summary> /// Override this method to register custom language specific actions to find symbol usages. /// </summary> protected virtual void HandleNamedTypeSymbolStart(SymbolStartAnalysisContext context, Action <ISymbol, ValueUsageInfo> onSymbolUsageFound) { }
// Actions/Symbol private static void OnSymbol_Start(SymbolStartAnalysisContext context) // for specific SymbolKind { context.RegisterSymbolEndAction(OnSymbol_End); }
static void OnSymbolStart( SymbolStartAnalysisContext symbolStartContext, WellKnownTypeProvider wellKnownTypeProvider, ImmutableArray <INamedTypeSymbol> skippedAttributes, bool isWebProject) { // Since property/event accessors cannot be marked static themselves and the associated symbol (property/event) // has to be marked static, we want to report the diagnostic on the property/event. // So we make a note of the property/event symbols which have at least one accessor with no instance access. // At symbol end, we report candidate property/event symbols whose all accessors are candidates to be marked static. var propertyOrEventCandidates = PooledConcurrentSet <ISymbol> .GetInstance(); var accessorCandidates = PooledConcurrentSet <IMethodSymbol> .GetInstance(); var methodCandidates = PooledConcurrentSet <IMethodSymbol> .GetInstance(); // Do not flag methods that are used as delegates: https://github.com/dotnet/roslyn-analyzers/issues/1511 var methodsUsedAsDelegates = PooledConcurrentSet <IMethodSymbol> .GetInstance(); symbolStartContext.RegisterOperationAction(OnMethodReference, OperationKind.MethodReference); symbolStartContext.RegisterOperationBlockStartAction(OnOperationBlockStart); symbolStartContext.RegisterSymbolEndAction(OnSymbolEnd); return; void OnMethodReference(OperationAnalysisContext operationContext) { var methodReference = (IMethodReferenceOperation)operationContext.Operation; methodsUsedAsDelegates.Add(methodReference.Method); } void OnOperationBlockStart(OperationBlockStartAnalysisContext blockStartContext) { #pragma warning disable IDE0083 // Use pattern matching - need new compiler if (!(blockStartContext.OwningSymbol is IMethodSymbol methodSymbol)) #pragma warning restore IDE0083 // Use pattern matching { return; } // Don't run any other check for this method if it isn't a valid analysis context if (!ShouldAnalyze(methodSymbol, wellKnownTypeProvider, skippedAttributes, blockStartContext.Options, isWebProject, blockStartContext.CancellationToken)) { return; } // Don't report methods which have a single throw statement // with NotImplementedException or NotSupportedException if (blockStartContext.IsMethodNotImplementedOrSupported()) { return; } bool isInstanceReferenced = false; blockStartContext.RegisterOperationAction(operationContext => { if (((IInstanceReferenceOperation)operationContext.Operation).ReferenceKind == InstanceReferenceKind.ContainingTypeInstance) { isInstanceReferenced = true; } }, OperationKind.InstanceReference); blockStartContext.RegisterOperationBlockEndAction(blockEndContext => { if (!isInstanceReferenced) { if (methodSymbol.IsAccessorMethod()) { accessorCandidates.Add(methodSymbol); propertyOrEventCandidates.Add(methodSymbol.AssociatedSymbol); } else if (methodSymbol.IsExternallyVisible()) { if (!IsOnObsoleteMemberChain(methodSymbol, wellKnownTypeProvider)) { blockEndContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule, methodSymbol.Name)); } } else { methodCandidates.Add(methodSymbol); } } }); } void OnSymbolEnd(SymbolAnalysisContext symbolEndContext) { foreach (var candidate in methodCandidates) { if (methodsUsedAsDelegates.Contains(candidate)) { continue; } if (!IsOnObsoleteMemberChain(candidate, wellKnownTypeProvider)) { symbolEndContext.ReportDiagnostic(candidate.CreateDiagnostic(Rule, candidate.Name)); } } foreach (var candidatePropertyOrEvent in propertyOrEventCandidates) { var allAccessorsAreCandidates = true; foreach (var accessor in candidatePropertyOrEvent.GetAccessors()) { if (!accessorCandidates.Contains(accessor) || IsOnObsoleteMemberChain(accessor, wellKnownTypeProvider)) { allAccessorsAreCandidates = false; break; } } if (allAccessorsAreCandidates) { symbolEndContext.ReportDiagnostic(candidatePropertyOrEvent.CreateDiagnostic(Rule, candidatePropertyOrEvent.Name)); } } propertyOrEventCandidates.Free(symbolEndContext.CancellationToken); accessorCandidates.Free(symbolEndContext.CancellationToken); methodCandidates.Free(symbolEndContext.CancellationToken); methodsUsedAsDelegates.Free(symbolEndContext.CancellationToken); } }
// Actions/Symbol private static void OnSymbol_Start(SymbolStartAnalysisContext context) { context.RegisterSymbolEndAction(OnSymbol_End); }