private static void AddCodeFixWithNewPublicConstructor(CodeFixContext context, SyntaxNode root, Diagnostic diagnostic, ClassDeclarationSyntax classNode) { // Generated from http://roslynquoter.azurewebsites.net/ var constructor = SyntaxFactory.ConstructorDeclaration(classNode.Identifier) .WithModifiers( SyntaxFactory.TokenList( SyntaxFactory.Token(SyntaxKind.PublicKeyword))) .WithParameterList(SyntaxFactory.ParameterList() .WithOpenParenToken( SyntaxFactory.Token(SyntaxKind.OpenParenToken)) .WithCloseParenToken( SyntaxFactory.Token( SyntaxKind.CloseParenToken))) .WithBody(SyntaxFactory.Block() .WithOpenBraceToken( SyntaxFactory.Token( SyntaxKind.OpenBraceToken)) .WithCloseBraceToken( SyntaxFactory.Token( SyntaxKind.CloseBraceToken))).NormalizeWhitespace().WithAdditionalAnnotations(Formatter.Annotation); var newClassNode = classNode.AddMembers(constructor); var newRoot = root.ReplaceNode(classNode, newClassNode); context.RegisterCodeFix( CodeAction.Create( CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.AddPublicConstructorDescription, _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)), CheckConstructorsAnalyzerPublicConstructorCodeFixConstants.AddPublicConstructorDescription), diagnostic); }
public override Task RegisterCodeFixesAsync(CodeFixContext context) { context.RegisterCodeFix(new MyCodeAction( c => FixAsync(context.Document, context.Diagnostics.First(), c)), context.Diagnostics); return SpecializedTasks.EmptyTask; }
private static void AddCodeFix(CodeFixContext context, SyntaxNode root, Diagnostic diagnostic, ClassDeclarationSyntax classNode) { var newRoot = IsBusinessObjectSerializableMakeSerializableCodeFix.AddAttribute( root, classNode, IsBusinessObjectSerializableMakeSerializableCodeFixConstants.SerializableName); if (!root.HasUsing(IsBusinessObjectSerializableMakeSerializableCodeFixConstants.SystemNamespace)) { newRoot = (newRoot as CompilationUnitSyntax).AddUsings( SyntaxFactory.UsingDirective(SyntaxFactory.ParseName( IsBusinessObjectSerializableMakeSerializableCodeFixConstants.SystemNamespace))); } if (!root.HasUsing(IsBusinessObjectSerializableMakeSerializableCodeFixConstants.CslaSerializationNamespace)) { newRoot = (newRoot as CompilationUnitSyntax).AddUsings( SyntaxFactory.UsingDirective(SyntaxFactory.ParseName( IsBusinessObjectSerializableMakeSerializableCodeFixConstants.CslaSerializationNamespace))); } context.RegisterCodeFix( CodeAction.Create( IsBusinessObjectSerializableMakeSerializableCodeFixConstants.AddSerializableAndUsingDescription, _ => Task.FromResult<Document>(context.Document.WithSyntaxRoot(newRoot))), diagnostic); }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { var documentRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode syntax = documentRoot.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true); if (syntax == null) { continue; } XmlElementSyntax xmlElementSyntax = syntax as XmlElementSyntax; if (xmlElementSyntax == null) { // We continue even for placeholders if they are empty elements (XmlEmptyElementSyntax) continue; } if (string.IsNullOrWhiteSpace(xmlElementSyntax.Content.ToString())) { // The placeholder hasn't been updated yet. continue; } context.RegisterCodeFix( CodeAction.Create( DocumentationResources.SA1651CodeFix, cancellationToken => this.GetTransformedDocumentAsync(context.Document, xmlElementSyntax, cancellationToken), nameof(SA1651CodeFixProvider)), diagnostic); } }
public async override Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var cancellationToken = context.CancellationToken; var span = context.Span; var diagnostics = context.Diagnostics; var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (model.IsFromGeneratedCode(cancellationToken)) return; var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var diagnostic = diagnostics.First(); var node = root.FindNode(context.Span); context.RegisterCodeFix(CodeActionFactory.Create( node.Span, diagnostic.Severity, GettextCatalog.GetString("Add 'new' modifier"), token => { SyntaxNode newRoot; if (node.Kind() != SyntaxKind.VariableDeclarator) newRoot = root.ReplaceNode(node, AddNewModifier(node)); else //this one wants to be awkward - you can't add modifiers to a variable declarator { SyntaxNode declaringNode = node.Parent.Parent; if (declaringNode is FieldDeclarationSyntax) newRoot = root.ReplaceNode(node.Parent.Parent, (node.Parent.Parent as FieldDeclarationSyntax).AddModifiers(SyntaxFactory.Token(SyntaxKind.NewKeyword))); else //it's an event declaration newRoot = root.ReplaceNode(node.Parent.Parent, (node.Parent.Parent as EventFieldDeclarationSyntax).AddModifiers(SyntaxFactory.Token(SyntaxKind.NewKeyword))); } return Task.FromResult(document.WithSyntaxRoot(newRoot.WithAdditionalAnnotations(Formatter.Annotation))); }), diagnostic); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var declaration = root.FindNode(context.Span); if (declaration == null) { return; } // find a Dispose method var iDisposableType = model.Compilation.GetSpecialType(SpecialType.System_IDisposable); var iDisposable_Dispose = (iDisposableType?.GetMembers(DisposableFieldsShouldBeDisposedAnalyzer.Dispose))?.Single(); if (iDisposableType == null || iDisposable_Dispose == null) { return; } var fieldSymbol = model.GetDeclaredSymbol(declaration, context.CancellationToken) as IFieldSymbol; var disposeMethod = fieldSymbol?.ContainingType?.FindImplementationForInterfaceMember(iDisposable_Dispose) as IMethodSymbol; if (disposeMethod == null) { return; } // We cannot have multiple overlapping diagnostics of this id. var diagnostic = context.Diagnostics.Single(); context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DisposableFieldsShouldBeDisposedMessage, async ct => await AddDisposeCall(context.Document, declaration, fieldSymbol, disposeMethod, iDisposableType, iDisposable_Dispose, ct).ConfigureAwait(false)), diagnostic); }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); foreach (var diagnostic in context.Diagnostics) { SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); if (node == null || node.IsMissing) { continue; } SyntaxNode declarationNode = FindParentDeclarationNode(node); if (declarationNode == null) { continue; } context.RegisterCodeFix( CodeAction.Create( MaintainabilityResources.SA1400CodeFix, cancellationToken => GetTransformedDocumentAsync(context.Document, root, declarationNode), nameof(SA1400CodeFixProvider)), diagnostic); } }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); foreach (var diagnostic in context.Diagnostics) { if (!this.FixableDiagnosticIds.Contains(diagnostic.Id)) { continue; } SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); if (node.IsMissing) { continue; } // Check if we are interested in this node node = (SyntaxNode)(node as ParameterListSyntax) ?? node as AttributeArgumentListSyntax; if (node != null) { context.RegisterCodeFix(CodeAction.Create(MaintainabilityResources.SA1410SA1411CodeFix, token => GetTransformedDocumentAsync(context.Document, root, node), equivalenceKey: nameof(SA1410SA1411CodeFixProvider)), diagnostic); } } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var node = root.FindNode(context.Span); var fieldNode = GetFieldDeclarationNode(node); if(fieldNode == null) { return; } var diagnostic = context.Diagnostics.Single(); // Fix 1: Add a NonSerialized attribute to the field context.RegisterCodeFix(new MyCodeAction(AnalyzerPowerPackFixersResources.AddNonSerializedAttribute, async ct => await AddNonSerializedAttribute(context.Document, fieldNode, ct).ConfigureAwait(false)), diagnostic); // Fix 2: If the type of the field is defined in source, then add the serializable attribute to the type. var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var fieldSymbol = model.GetDeclaredSymbol(node, context.CancellationToken) as IFieldSymbol; var type = fieldSymbol?.Type; if (type != null && type.Locations.Any(l => l.IsInSource)) { context.RegisterCodeFix(new MyCodeAction(AnalyzerPowerPackFixersResources.AddSerializableAttribute, async ct => await AddSerializableAttributeToType(context.Document, type, ct).ConfigureAwait(false)), diagnostic); } }
public async override Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var cancellationToken = context.CancellationToken; var diagnostics = context.Diagnostics; var root = await document.GetSyntaxRootAsync(cancellationToken); var diagnostic = diagnostics.First(); var node = root.FindNode(context.Span) as BinaryExpressionSyntax; if (node == null) return; StatementSyntax expression = null; var ifStatement = node.Parent as IfStatementSyntax; if (ifStatement == null) return; var statement = ifStatement.Statement; if (statement is BlockSyntax) expression = ((BlockSyntax)statement).Statements[0]; else expression = statement; if (expression == null) return; context.RegisterCodeFix(CodeAction.Create("Remove redundant check", async token => { var editor = await DocumentEditor.CreateAsync(document, cancellationToken); expression = expression .WithOrderedTriviaFromSubTree(ifStatement) .WithAdditionalAnnotations(Formatter.Annotation); editor.ReplaceNode(ifStatement, expression); return editor.GetChangedDocument(); }, string.Empty), diagnostic); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var syntaxFactoryService = SyntaxGenerator.GetGenerator(context.Document); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var node = root.FindNode(context.Span); // We cannot have multiple overlapping diagnostics of this id. var diagnostic = context.Diagnostics.Single(); if (IsInArgumentContext(node)) { // StringComparison.CurrentCulture => StringComparison.Ordinal // StringComparison.CurrentCultureIgnoreCase => StringComparison.OrdinalIgnoreCase context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.UseOrdinalStringComparisonTitle, async ct => await FixArgument(context.Document, syntaxFactoryService, root, node).ConfigureAwait(false)), diagnostic); } else if (IsInIdentifierNameContext(node)) { // string.Equals(a, b) => string.Equals(a, b, StringComparison.Ordinal) // string.Compare(a, b) => string.Compare(a, b, StringComparison.Ordinal) context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.UseOrdinalStringComparisonTitle, async ct => await FixIdentifierName(context.Document, syntaxFactoryService, root, node, context.CancellationToken).ConfigureAwait(false)), diagnostic); } else if (IsInEqualsContext(node)) { // "a == b" => "string.Equals(a, b, StringComparison.Ordinal)" // "a != b" => "!string.Equals(a, b, StringComparison.Ordinal)" context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.UseOrdinalStringComparisonTitle, async ct => await FixEquals(context.Document, syntaxFactoryService, root, node, context.CancellationToken).ConfigureAwait(false)), diagnostic); } }
public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); context.RegisterCodeFix( CodeAction.Create("Use ?.Invoke operator and method to fire an event.", ct => UseInvokeAsync(context.Document, diagnostic, ct)), diagnostic); return Task.FromResult(0); }
/// <summary> /// Register the property fix for property documentation. /// </summary> /// <param name="root">the syntax root node.</param> /// <param name="context">the code fix context, containing the location of the fix.</param> /// <param name="diagnostic">the diagnostic, where the invalid code was located.</param> private void RegisterMethodDocumentationCodeFix(SyntaxNode root, CodeFixContext context, Diagnostic diagnostic) { var startNode = root.FindNode(diagnostic.Location.SourceSpan); var constructorDeclaration = startNode as ConstructorDeclarationSyntax; if (constructorDeclaration != null) this.RegisterConstructorCodeFix(constructorDeclaration, root, context, diagnostic); }
/// <inheritdoc/> public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var root = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); foreach (var diagnostic in context.Diagnostics) { if (!diagnostic.Id.Equals(SA1309FieldNamesMustNotBeginWithUnderscore.DiagnosticId)) { continue; } var token = root.FindToken(diagnostic.Location.SourceSpan.Start); if (token.IsMissing) { continue; } if (!string.IsNullOrEmpty(token.ValueText)) { var newName = token.ValueText.TrimStart(new[] { '_' }); if (string.IsNullOrEmpty(newName)) { // The variable consisted of only underscores. In this case we cannot // generate a valid variable name and thus will not offer a code fix. continue; } context.RegisterCodeFix(CodeAction.Create(string.Format(NamingResources.SA1309CodeFix, newName), cancellationToken => RenameHelper.RenameSymbolAsync(document, root, token, newName, cancellationToken), equivalenceKey: nameof(SA1309CodeFixProvider)), diagnostic); } } }
public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); context.RegisterCodeFix( CodeAction.Create("Call GC.SuppressFinalize", ct => AddSuppressFinalizeAsync(context.Document, diagnostic, ct), nameof(DisposablesShouldCallSuppressFinalizeCodeFixProvider)), diagnostic); return Task.FromResult(0); }
public async Task VerifyGetFixesWhenUsingSystemDoesNotExist() { var code = File.ReadAllText( $@"Targets\{nameof(IsBusinessObjectSerializableMakeSerializableCodeFixTests)}.{(nameof(this.VerifyGetFixesWhenUsingSystemDoesNotExist))}.cs"); var document = TestHelpers.Create(code); var tree = await document.GetSyntaxTreeAsync(); var diagnostics = await TestHelpers.GetDiagnosticsAsync(code, new IsBusinessObjectSerializableAnalyzer()); var sourceSpan = diagnostics[0].Location.SourceSpan; var actions = new List<CodeAction>(); var codeActionRegistration = new Action<CodeAction, ImmutableArray<Diagnostic>>( (a, _) => { actions.Add(a); }); var fix = new IsBusinessObjectSerializableMakeSerializableCodeFix(); var codeFixContext = new CodeFixContext(document, diagnostics[0], codeActionRegistration, new CancellationToken(false)); await fix.RegisterCodeFixesAsync(codeFixContext); Assert.AreEqual(2, actions.Count, nameof(actions.Count)); await TestHelpers.VerifyActionAsync(actions, IsBusinessObjectSerializableMakeSerializableCodeFixConstants.AddSystemSerializableDescription, document, tree, $"{Environment.NewLine}[System.Serializable]"); await TestHelpers.VerifyActionAsync(actions, IsBusinessObjectSerializableMakeSerializableCodeFixConstants.AddSerializableAndUsingDescription, document, tree, $"using System;{Environment.NewLine}{Environment.NewLine}[Serializable]"); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); if (context.CancellationToken.IsCancellationRequested) { return; } var diagnostic = context.Diagnostics.First(); var classNode = root.FindNode(diagnostic.Location.SourceSpan) as ClassDeclarationSyntax; if (context.CancellationToken.IsCancellationRequested) { return; } var hasNonPublicNoArgumentConstructor = bool.Parse(diagnostic.Properties[PublicNoArgumentConstructorIsMissingConstants.HasNonPublicNoArgumentConstructor]); if(hasNonPublicNoArgumentConstructor) { CheckConstructorsAnalyzerPublicConstructorCodeFix.AddCodeFixWithUpdatingNonPublicConstructor( context, root, diagnostic, classNode); } else { CheckConstructorsAnalyzerPublicConstructorCodeFix.AddCodeFixWithNewPublicConstructor( context, root, diagnostic, classNode); } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var token = root.FindToken(context.Span.Start); if (!token.Span.IntersectsWith(context.Span)) { return; } var generator = SyntaxGenerator.GetGenerator(context.Document); var classDecl = generator.GetDeclaration(token.Parent); if (classDecl == null) { return; } // Register fixes. // 1) Apply C# DiagnosticAnalyzerAttribute. var title = string.Format(CodeAnalysisDiagnosticsResources.ApplyDiagnosticAnalyzerAttribute_1, LanguageNames.CSharp); AddFix(title, context, root, classDecl, generator, LanguageNames.CSharp); // 2) Apply VB DiagnosticAnalyzerAttribute. title = string.Format(CodeAnalysisDiagnosticsResources.ApplyDiagnosticAnalyzerAttribute_1, LanguageNames.VisualBasic); AddFix(title, context, root, classDecl, generator, LanguageNames.VisualBasic); // 3) Apply both C# and VB DiagnosticAnalyzerAttributes. title = string.Format(CodeAnalysisDiagnosticsResources.ApplyDiagnosticAnalyzerAttribute_2, LanguageNames.CSharp, LanguageNames.VisualBasic); AddFix(title, context, root, classDecl, generator, LanguageNames.CSharp, LanguageNames.VisualBasic); }
public async Task GetFixes() { var code = @"using System.ServiceModel; public class AClass { [OperationContract(IsOneWay = true)] public string AMethod() { return string.Empty; } }"; var document = TestHelpers.Create(code); var tree = await document.GetSyntaxTreeAsync(); var diagnostics = await TestHelpers.GetDiagnosticsAsync( code, new IsOneWayOperationAnalyzer()); var sourceSpan = diagnostics[0].Location.SourceSpan; var actions = new List<CodeAction>(); var codeActionRegistration = new Action<CodeAction, ImmutableArray<Diagnostic>>( (a, _) => { actions.Add(a); }); var fix = new IsOneWayOperationMakeIsOneWayFalseCodeFix(); var codeFixContext = new CodeFixContext(document, diagnostics[0], codeActionRegistration, new CancellationToken(false)); await fix.RegisterCodeFixesAsync(codeFixContext); Assert.Equal(1, actions.Count); await TestHelpers.VerifyActionAsync(actions, IsOneWayOperationMakeIsOneWayFalseCodeFixConstants.Description, document, tree, new[] { "fals" }); }
private void AddFix(string codeFixTitle, CodeFixContext context, SyntaxNode root, SyntaxNode classDecl, SyntaxGenerator generator, params string[] languages) { var fix = new MyCodeAction( codeFixTitle, c => GetFix(context.Document, root, classDecl, generator, languages)); context.RegisterCodeFix(fix, context.Diagnostics); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); if (context.CancellationToken.IsCancellationRequested) { return; } var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var nowToken = root.FindToken(diagnosticSpan.Start) .Parent.AncestorsAndSelf().OfType<IdentifierNameSyntax>().First().GetFirstToken(); var utcNowToken = SyntaxFactory.Identifier(nowToken.LeadingTrivia, "UtcNow", nowToken.TrailingTrivia); var newRoot = root.ReplaceToken(nowToken, utcNowToken); context.RegisterCodeFix( CodeAction.Create( FindingDateTimeNowConstants.Title, _ => Task.FromResult<Document>(context.Document.WithSyntaxRoot(newRoot))), diagnostic); }
public override sealed Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); if (diagnostic.Properties["kind"] == "missingDoc") context.RegisterCodeFix(CodeAction.Create(Resources.XmlDocumentationCreateMissingParametersCodeFixProvider_Title, c => FixParametersAsync(context.Document, diagnostic, c)), diagnostic); return Task.FromResult(0); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var generator = SyntaxGenerator.GetGenerator(context.Document); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var declaration = root.FindNode(context.Span); declaration = generator.GetDeclaration(declaration); if (declaration == null) { return; } var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var typeSymbol = model.GetDeclaredSymbol(declaration) as INamedTypeSymbol; if (typeSymbol?.TypeKind != TypeKind.Class && typeSymbol?.TypeKind != TypeKind.Struct) { return; } // We cannot have multiple overlapping diagnostics of this id. var diagnostic = context.Diagnostics.Single(); context.RegisterCodeFix(new MyCodeAction(MicrosoftApiDesignGuidelinesAnalyzersResources.ImplementComparable, async ct => await ImplementComparable(context.Document, declaration, typeSymbol, ct).ConfigureAwait(false)), diagnostic); }
public override sealed async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var initializer = root.FindNode(diagnosticSpan) as ConstructorInitializerSyntax; if (initializer == null) { return; } var constructor = initializer.Parent as ConstructorDeclarationSyntax; if (constructor == null) { return; } context.RegisterCodeFix( CodeAction.Create( Title, c => { var newRoot = RemoveInitializer(root, constructor); return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); }), context.Diagnostics); }
public override sealed async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; // var syntaxNode = root.FindNode(diagnosticSpan); //var declaration = root.FindToken(diagnosticSpan.Start); // var firstToken = declaration.GetFirstToken(); // var leadingTrivia = firstToken.LeadingTrivia; // var trimmedLocal = declaration.ReplaceToken(firstToken, firstToken.WithLeadingTrivia(SyntaxTriviaList.Empty)); var cw = new AdhocWorkspace(); OptionSet options = cw.Options; options = options.WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInMethods, false); options = options.WithChangedOption(CSharpFormattingOptions.IndentBlock, false); context.RegisterCodeFix( CodeAction.Create( Title, async c => { var oldNode = root.FindTrivia(diagnosticSpan.Start); var newRoot = root.ReplaceTrivia(oldNode, SyntaxTriviaList.Empty); newRoot = newRoot.WithAdditionalAnnotations(Formatter.Annotation); newRoot = Formatter.Format(newRoot, new AdhocWorkspace(),options); //TODO:Need to remove empty line if it followed by a comment(Formatting). return await Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); }), context.Diagnostics); }
public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics.First(); context.RegisterCodeFix(CodeAction.Create( "Removes redundant comparision", c => RemoveRedundantComparisonAsync(context.Document, diagnostic, c), nameof(SimplifyRedundantBooleanComparisonsCodeFixProvider)), diagnostic); return Task.FromResult(0); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var generator = SyntaxGenerator.GetGenerator(context.Document); var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var declaration = root.FindNode(context.Span); declaration = generator.GetDeclaration(declaration); if (declaration == null) { return; } var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var typeSymbol = model.GetDeclaredSymbol(declaration) as INamedTypeSymbol; if (typeSymbol == null) { return; } // We cannot have multiple overlapping diagnostics of this id. var diagnostic = context.Diagnostics.Single(); context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.OverloadOperatorEqualsOnOverridingValueTypeEquals, async ct => await ImplementOperatorEquals(context.Document, declaration, typeSymbol, ct).ConfigureAwait(false)), diagnostic); }
public override sealed async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var syntaxNode = root.FindNode(diagnosticSpan, getInnermostNodeForTie: true); var statement = syntaxNode as StatementSyntax; var assignment = syntaxNode as AssignmentExpressionSyntax; var binary = syntaxNode as BinaryExpressionSyntax; if (statement != null || assignment != null || binary != null) { context.RegisterCodeFix( CodeAction.Create( Title, c => { var newRoot = CalculateNewRoot(root, diagnostic, statement, assignment, binary); return Task.FromResult(context.Document.WithSyntaxRoot(newRoot)); }), context.Diagnostics); } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var span = context.Span; var cancellationToken = context.CancellationToken; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(span.Start); if (!token.Span.IntersectsWith(span)) { return; } var service = document.GetLanguageService<IImplementInterfaceService>(); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var actions = token.Parent.GetAncestorsOrThis<TypeSyntax>() .Where(_interfaceName) .Select(n => service.GetCodeActions(document, model, n, cancellationToken)) .FirstOrDefault(_codeActionAvailable); if (_codeActionAvailable(actions)) { context.RegisterFixes(actions, context.Diagnostics); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); context.CancellationToken.ThrowIfCancellationRequested(); var diagnostic = context.Diagnostics.First(); var invocationNode = root.FindNode(diagnostic.Location.SourceSpan) as InvocationExpressionSyntax; var invocationIdentifier = ((invocationNode.Expression as MemberAccessExpressionSyntax) .Expression as IdentifierNameSyntax).Identifier; var leadingTrivia = invocationIdentifier.HasLeadingTrivia ? invocationIdentifier.LeadingTrivia : new SyntaxTriviaList(); var newInvocationIdentifier = invocationIdentifier.WithLeadingTrivia(new SyntaxTriviaList()); var newInvocationNode = invocationNode.ReplaceToken(invocationIdentifier, newInvocationIdentifier); context.CancellationToken.ThrowIfCancellationRequested(); var simpleAssignmentExpressionNode = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(newInvocationIdentifier), newInvocationNode) .WithLeadingTrivia(leadingTrivia); var newRoot = root.ReplaceNode(invocationNode, simpleAssignmentExpressionNode); context.RegisterCodeFix( CodeAction.Create( FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFixConstants.AddAssignmentDescription, _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)), FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFixConstants.AddAssignmentDescription), diagnostic); }
/// <summary> /// General verifier for codefixes. /// Creates a Document from the source string, then gets diagnostics on it and applies the relevant codefixes. /// Then gets the string after the codefix is applied and compares it with the expected result. /// Note: If any codefix causes new diagnostics to show up, the test fails unless allowNewCompilerDiagnostics is set to true. /// </summary> /// <param name="language">The language the source code is in</param> /// <param name="analyzer">The analyzer to be applied to the source code</param> /// <param name="codeFixProvider">The codefix to be applied to the code wherever the relevant Diagnostic is found</param> /// <param name="oldSource">A class in the form of a string before the CodeFix was applied to it</param> /// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param> /// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param> /// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param> private void VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int?codeFixIndex, bool allowNewCompilerDiagnostics) { var document = CreateDocument(oldSource, language); var analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); var compilerDiagnostics = GetCompilerDiagnostics(document); var attempts = analyzerDiagnostics.Length; for (int i = 0; i < attempts; ++i) { var actions = new List <CodeAction>(); var context = new Microsoft.CodeAnalysis.CodeFixes.CodeFixContext(document, analyzerDiagnostics[0], (a, d) => actions.Add(a), CancellationToken.None); codeFixProvider.RegisterCodeFixesAsync(context).Wait(); if (!actions.Any()) { break; } if (codeFixIndex != null) { document = ApplyFix(document, actions.ElementAt((int)codeFixIndex)); break; } document = ApplyFix(document, actions.ElementAt(0)); analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, new[] { document }); var newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); //check if applying the code fix introduced any new compiler diagnostics if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any()) { // Format and get the compiler diagnostics again so that the locations make sense in the output document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace)); newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); var newCode = GetStringFromDocument(document); Assert.IsTrue(false, string.Format("Fix introduced new compiler diagnostics:\r\n{0}\r\n\r\nNew document:\r\n{1}\r\n", string.Join("\r\n", newCompilerDiagnostics.Select(d => d.ToString())), document.GetSyntaxRootAsync().Result.ToFullString())); } //check if there are analyzer diagnostics left after the code fix if (!analyzerDiagnostics.Any()) { break; } } //after applying all of the code fixes, compare the resulting string to the inputted one var actual = GetStringFromDocument(document); Assert.AreEqual(newSource, actual); }
public sealed override async Task RegisterCodeFixesAsync(Microsoft.CodeAnalysis.CodeFixes.CodeFixContext context) { var diagnostic = context.Diagnostics.First(); if (!HasValidProperties(diagnostic)) { return; } var success = Enum.TryParse(diagnostic.Properties[ObsoleteFixerAnalyzer.SyntaxKindKey], false, out SyntaxKind syntaxKind); if (!success) { return; } var diagnosticSpan = diagnostic.Location.SourceSpan; var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); // Find the type declaration identified by the diagnostic. var syntax = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().FirstOrDefault(s => s.IsKind(syntaxKind)); if (!IsSupported(syntax)) { return; } var replaceWith = diagnostic.Properties[ObsoleteFixerAnalyzer.ReplaceWithKey]; if (!bool.TryParse(diagnostic.Properties[ObsoleteFixerAnalyzer.IsObsoleteTypeKey], out var isObsoleteTypeKey)) { return; } // Register a code action that will invoke the fix. var title = $"Replace method call with `{replaceWith}`"; context.RegisterCodeFix( CodeAction.Create( title, // todo change to createChangedSolution? c => ReplaceMethodCallsAsync(context.Document, syntax, c, replaceWith, isObsoleteTypeKey), title), diagnostic); }
private async Task<bool> ContainsAnyFixAsync( Document document, DiagnosticData diagnostic, CancellationToken cancellationToken) { var workspaceFixers = ImmutableArray<CodeFixProvider>.Empty; var hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out var fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers); var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out var projectFixers); // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive if (hasAnySharedFixer && document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive) { workspaceFixers = workspaceFixers.WhereAsArray(IsInteractiveCodeFixProvider); hasAnySharedFixer = workspaceFixers.Any(); } var hasConfigurationFixer = _configurationProvidersMap.TryGetValue(document.Project.Language, out var lazyConfigurationProviders) && !lazyConfigurationProviders.Value.IsDefaultOrEmpty; if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasConfigurationFixer) { return false; } var allFixers = ImmutableArray<CodeFixProvider>.Empty; if (hasAnySharedFixer) { allFixers = workspaceFixers; } if (hasAnyProjectFixer) { allFixers = allFixers.AddRange(projectFixers); } var dx = await diagnostic.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false); if (hasConfigurationFixer) { foreach (var lazyConfigurationProvider in lazyConfigurationProviders.Value) { if (lazyConfigurationProvider.IsFixableDiagnostic(dx)) { return true; } } } var fixes = new List<CodeFix>(); var context = new CodeFixContext(document, dx, // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? (action, applicableDiagnostics) => { // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from. lock (fixes) { fixes.Add(new CodeFix(document.Project, action, applicableDiagnostics)); } }, verifyArguments: false, cancellationToken: cancellationToken); var extensionManager = document.Project.Solution.Workspace.Services.GetRequiredService<IExtensionManager>(); // we do have fixer. now let's see whether it actually can fix it foreach (var fixer in allFixers) { await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? Task.CompletedTask).ConfigureAwait(false); foreach (var fix in fixes) { if (!fix.Action.PerformFinalApplicabilityCheck) { return true; } // Have to see if this fix is still applicable. Jump to the foreground thread // to make that check. await ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); var applicable = fix.Action.IsApplicable(document.Project.Solution.Workspace); await TaskScheduler.Default; if (applicable) { return true; } } } return false; }
private async Task <bool> ContainsAnyFix(Document document, DiagnosticData diagnostic, bool considerSuppressionFixes, CancellationToken cancellationToken) { ImmutableArray <CodeFixProvider> workspaceFixers = ImmutableArray <CodeFixProvider> .Empty; List <CodeFixProvider> projectFixers = null; Lazy <ImmutableDictionary <DiagnosticId, ImmutableArray <CodeFixProvider> > > fixerMap; bool hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers); var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out projectFixers); Lazy <ISuppressionFixProvider> lazySuppressionProvider = null; var hasSuppressionFixer = considerSuppressionFixes && _suppressionProvidersMap.TryGetValue(document.Project.Language, out lazySuppressionProvider) && lazySuppressionProvider.Value != null; if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasSuppressionFixer) { return(false); } var allFixers = ImmutableArray <CodeFixProvider> .Empty; if (hasAnySharedFixer) { allFixers = workspaceFixers; } if (hasAnyProjectFixer) { allFixers = allFixers.AddRange(projectFixers); } var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var dx = diagnostic.ToDiagnostic(tree); if (hasSuppressionFixer && lazySuppressionProvider.Value.CanBeSuppressed(dx)) { return(true); } var fixes = new List <CodeFix>(); var context = new CodeFixContext(document, dx, // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? (a, d) => { // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from. lock (fixes) { fixes.Add(new CodeFix(a, d)); } }, verifyArguments: false, cancellationToken: cancellationToken); var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>(); // we do have fixer. now let's see whether it actually can fix it foreach (var fixer in allFixers) { await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false); if (!fixes.Any()) { continue; } return(true); } return(false); }
private async Task <List <CodeFixCollection> > AppendFixesAsync( Document document, TextSpan span, IEnumerable <DiagnosticData> diagnosticDataCollection, List <CodeFixCollection> result, CancellationToken cancellationToken) { Lazy <ImmutableDictionary <DiagnosticId, ImmutableArray <CodeFixProvider> > > fixerMap; bool hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out fixerMap); var projectFixersMap = GetProjectFixers(document.Project); var hasAnyProjectFixer = projectFixersMap.Any(); if (!hasAnySharedFixer && !hasAnyProjectFixer) { return(result); } ImmutableArray <CodeFixProvider> workspaceFixers; List <CodeFixProvider> projectFixers; var allFixers = new List <CodeFixProvider>(); foreach (var diagnosticId in diagnosticDataCollection.Select(d => d.Id).Distinct()) { cancellationToken.ThrowIfCancellationRequested(); if (hasAnySharedFixer && fixerMap.Value.TryGetValue(diagnosticId, out workspaceFixers)) { allFixers.AddRange(workspaceFixers); } if (hasAnyProjectFixer && projectFixersMap.TryGetValue(diagnosticId, out projectFixers)) { allFixers.AddRange(projectFixers); } } var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>(); var diagnostics = diagnosticDataCollection.Select(data => data.ToDiagnostic(tree)).ToImmutableArray(); foreach (var fixer in allFixers.Distinct()) { cancellationToken.ThrowIfCancellationRequested(); Func <Diagnostic, bool> hasFix = (d) => this.GetFixableDiagnosticIds(fixer).Contains(d.Id); Func <ImmutableArray <Diagnostic>, Task <IEnumerable <CodeFix> > > getFixes = async(dxs) => { var fixes = new List <CodeFix>(); var context = new CodeFixContext(document, span, dxs, // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? (a, d) => { // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from. lock (fixes) { fixes.Add(new CodeFix(a, d)); } }, verifyArguments: false, cancellationToken: cancellationToken); var task = fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask; await task.ConfigureAwait(false); return(fixes); }; await AppendFixesOrSuppressionsAsync(document, span, diagnostics, result, fixer, extensionManager, hasFix, getFixes, cancellationToken).ConfigureAwait(false); } return(result); }
private async Task <bool> ContainsAnyFix(Document document, DiagnosticData diagnostic, CancellationToken cancellationToken) { // TODO: We don't return true here if the only available fixes are suppressions. // This is to avoid the problem where lightbulb would show up for every green warning // squiggle in the editor thereby diluting the promise of the light bulb from // "I have a fix" to "I have some action". This is temporary until the editor team exposes // some mechanism (e.g. a faded out lightbulb) that would allow us to say "I have an action // but not a fix". ImmutableArray <CodeFixProvider> workspaceFixers = ImmutableArray <CodeFixProvider> .Empty; List <CodeFixProvider> projectFixers = null; Lazy <ImmutableDictionary <DiagnosticId, ImmutableArray <CodeFixProvider> > > fixerMap; bool hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers); var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out projectFixers); if (!hasAnySharedFixer && !hasAnyProjectFixer) { return(false); } var allFixers = ImmutableArray <CodeFixProvider> .Empty; if (hasAnySharedFixer) { allFixers = workspaceFixers; } if (hasAnyProjectFixer) { allFixers = allFixers.AddRange(projectFixers); } var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var dx = diagnostic.ToDiagnostic(tree); var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>(); var fixes = new List <CodeFix>(); var context = new CodeFixContext(document, dx, // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? (a, d) => { // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from. lock (fixes) { fixes.Add(new CodeFix(a, d)); } }, verifyArguments: false, cancellationToken: cancellationToken); // we do have fixer. now let's see whether it actually can fix it foreach (var fixer in allFixers) { await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false); if (!fixes.Any()) { continue; } return(true); } return(false); }
/// <summary> /// Computes one or more fixes for the specified <see cref="CodeFixContext"/>. /// </summary> public abstract Task RegisterCodeFixesAsync(CodeFixContext context);
private async Task <bool> ContainsAnyFix(Document document, DiagnosticData diagnostic, bool considerSuppressionFixes, CancellationToken cancellationToken) { ImmutableArray <CodeFixProvider> workspaceFixers = ImmutableArray <CodeFixProvider> .Empty; List <CodeFixProvider> projectFixers = null; Lazy <ImmutableDictionary <DiagnosticId, ImmutableArray <CodeFixProvider> > > fixerMap; bool hasAnySharedFixer = _workspaceFixersMap.TryGetValue(document.Project.Language, out fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers); var hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out projectFixers); // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive if (hasAnySharedFixer && document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive) { workspaceFixers = workspaceFixers.WhereAsArray(IsInteractiveCodeFixProvider); hasAnySharedFixer = workspaceFixers.Any(); } Lazy <ISuppressionFixProvider> lazySuppressionProvider = null; var hasSuppressionFixer = considerSuppressionFixes && _suppressionProvidersMap.TryGetValue(document.Project.Language, out lazySuppressionProvider) && lazySuppressionProvider.Value != null; if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasSuppressionFixer) { return(false); } var allFixers = ImmutableArray <CodeFixProvider> .Empty; if (hasAnySharedFixer) { allFixers = workspaceFixers; } if (hasAnyProjectFixer) { allFixers = allFixers.AddRange(projectFixers); } var dx = await diagnostic.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false); if (hasSuppressionFixer && lazySuppressionProvider.Value.CanBeSuppressedOrUnsuppressed(dx)) { return(true); } var fixes = new List <CodeFix>(); var context = new CodeFixContext(document, dx, // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? (action, applicableDiagnostics) => { // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from. lock (fixes) { fixes.Add(new CodeFix(document.Project, action, applicableDiagnostics)); } }, verifyArguments: false, cancellationToken: cancellationToken); var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>(); // we do have fixer. now let's see whether it actually can fix it foreach (var fixer in allFixers) { await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false); foreach (var fix in fixes) { if (!fix.Action.PerformFinalApplicabilityCheck) { return(true); } // Have to see if this fix is still applicable. Jump to the foreground thread // to make that check. var applicable = await Task.Factory.StartNew(() => { this.AssertIsForeground(); return(fix.Action.IsApplicable(document.Project.Solution.Workspace)); }, cancellationToken, TaskCreationOptions.None, this.ForegroundTaskScheduler).ConfigureAwait(false); this.AssertIsBackground(); if (applicable) { return(true); } } } return(false); }