public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction( compilationStartAnalysisContext => { Compilation compilation = compilationStartAnalysisContext.Compilation; ImmutableHashSet <INamedTypeSymbol> nativeResourceTypes = ImmutableHashSet.Create( WellKnownTypes.IntPtr(compilation), WellKnownTypes.UIntPtr(compilation), WellKnownTypes.HandleRef(compilation) ); var disposableType = WellKnownTypes.IDisposable(compilation); compilationStartAnalysisContext.RegisterOperationAction( operationAnalysisContext => { var assignment = (IAssignmentOperation)operationAnalysisContext.Operation; IOperation target = assignment.Target; if (target == null) { // This can happen if the left-hand side is an undefined symbol. return; } if (target.Kind != OperationKind.FieldReference) { return; } var fieldReference = (IFieldReferenceOperation)target; var field = fieldReference.Member as IFieldSymbol; if (field == null || field.Kind != SymbolKind.Field || field.IsStatic) { return; } if (!nativeResourceTypes.Contains(field.Type)) { return; } INamedTypeSymbol containingType = field.ContainingType; if (containingType == null || containingType.IsValueType) { return; } if (!containingType.AllInterfaces.Contains(disposableType)) { return; } if (containingType.HasFinalizer()) { return; } if (assignment.Value == null || assignment.Value.Kind != OperationKind.Invocation) { return; } var invocation = (IInvocationOperation)assignment.Value; if (invocation == null) { return; } IMethodSymbol method = invocation.TargetMethod; // TODO: What about COM? if (method.GetDllImportData() == null) { return; } operationAnalysisContext.ReportDiagnostic(containingType.CreateDiagnostic(Rule)); }, OperationKind.SimpleAssignment); }); }