/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken) .ConfigureAwait(false); if (syntaxRoot == null) { return; } var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken) .ConfigureAwait(false); foreach (var diagnostic in context.Diagnostics) { if (!IsSupportedDiagnostic(diagnostic)) { continue; } var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); if (string.IsNullOrEmpty(token.ValueText) || token.IsMissing) { continue; } var classDeclaration = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <ClassDeclarationSyntax>(); if (classDeclaration == null) { continue; } var type = semanticModel.GetDeclaredSymbolSafe(classDeclaration, context.CancellationToken); if (diagnostic.Id == IDISP009IsIDisposable.DiagnosticId) { context.RegisterCodeFix( CodeAction.Create( "Add IDisposable interface", cancellationToken => AddInterfaceAsync( context, cancellationToken, classDeclaration), nameof(ImplementIDisposableCodeFixProvider) + "add interface"), diagnostic); continue; } if (Disposable.IsAssignableTo(type) && Disposable.BaseTypeHasVirtualDisposeMethod(type)) { context.RegisterCodeFix( CodeAction.Create( "override Dispose(bool)", cancellationToken => OverrideDisposeAsync( context, semanticModel, cancellationToken, classDeclaration), nameof(ImplementIDisposableCodeFixProvider) + "override"), diagnostic); continue; } if (type.TryGetMethod("Dispose", out var disposeMethod) && !disposeMethod.IsStatic && disposeMethod.ReturnsVoid && disposeMethod.Parameters.Length == 0) { continue; } if (type.TryGetField("disposed", out _) || type.TryGetField("_disposed", out _)) { return; } if (type.IsSealed) { context.RegisterCodeFix( CodeAction.Create( "Implement IDisposable.", cancellationToken => ImplementIDisposableSealedAsync( context, semanticModel, cancellationToken, classDeclaration), nameof(ImplementIDisposableCodeFixProvider) + "Sealed"), diagnostic); continue; } if (type.IsAbstract) { context.RegisterCodeFix( CodeAction.Create( "Implement IDisposable with virtual dispose method.", cancellationToken => ImplementIDisposableVirtualAsync( context, semanticModel, cancellationToken, classDeclaration), nameof(ImplementIDisposableCodeFixProvider) + "Virtual"), diagnostic); continue; } context.RegisterCodeFix( CodeAction.Create( "Implement IDisposable and make class sealed.", cancellationToken => ImplementIDisposableSealedAsync( context, semanticModel, cancellationToken, classDeclaration), nameof(ImplementIDisposableCodeFixProvider) + "Sealed"), diagnostic); context.RegisterCodeFix( CodeAction.Create( "Implement IDisposable with virtual dispose method.", cancellationToken => ImplementIDisposableVirtualAsync( context, semanticModel, cancellationToken, classDeclaration), nameof(ImplementIDisposableCodeFixProvider) + "Virtual"), diagnostic); } }