Search code examples
c#roslynroslyn-code-analysiscodefixprovider

Roslyn CodeFixProvider isn't loading or running in the Visual Studio IDE. What am I missing?


I first wrote a DiagnosticAnalyzer and then battled to get it to load until I listed its project as an Asset in the VSIX manifest.

Now I also added a CodeFixProvider to the same project as the analyzer, but it doesn't load.

What am I missing?

I tried the following:

  1. Added the SharedAttribute.
  2. Changed its namespace to the same namespace as the analyzer.
  3. Made sure the DiagnosticId is pointing to the same DiagnosticId used by the Analyzer.
  4. Deleted the "C:\Users\cp321831\AppData\Local\Microsoft\VisualStudio\15.0_c657f3ebRoslyn\ComponentModelCache" directory
  5. Deleted the "C:\Users\cp321831\AppData\Local\Microsoft\VisualStudio\15.0_c657f3ebExp\ComponentModelCache" directory
  6. Deleted the completed "15.0_c657f3ebRoslyn" and "15.0_c657f3ebExp" directories
  7. I made sure the name ends with CodeFixProvider.

A breakpoint in the type constructor as well as the instance constructor and any of the methods reveal that nothing in the code fixer is loaded and nothing gets hit.

Here is the code for the code fixer:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Capitec.CodeAnalysis.Diagnostics
{
    [ExportCodeFixProvider(LanguageNames.CSharp), Shared]
    public sealed class UserInteractionCodeFixProvider : CodeFixProvider
    {
        private const string Title = "Invoke mapped function instead";

        static UserInteractionCodeFixProvider()
        {
        }

        public UserInteractionCodeFixProvider()
        {
        }

        public override ImmutableArray<string> FixableDiagnosticIds => 
            ImmutableArray.Create(
                AutomationScriptAnalyzerOfReplacableUserInteractions.DiagnosticId);

        public override FixAllProvider GetFixAllProvider()
        {
            return WellKnownFixAllProviders.BatchFixer;
        }

        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                                .ConfigureAwait(false);
            var diagnostic = context.Diagnostics.First();
            var span = diagnostic.Location.SourceSpan;
            var invocation = ResolveInvocation(root, span);
            context.RegisterCodeFix(
                CodeAction.Create(
                    Title,
                    ct => InvokeFunctionInstead(context.Document, invocation, ct),
                    equivalenceKey: Title),
                    diagnostic);
        }

        private InvocationExpressionSyntax ResolveInvocation(SyntaxNode root, TextSpan span)
        {
            return root
                    .FindToken(span.Start)
                    .Parent
                    .AncestorsAndSelf()
                    .OfType<InvocationExpressionSyntax>()
                    .First();
        }

        private Task<Document> InvokeFunctionInstead(
            Document document, 
            InvocationExpressionSyntax invocation, 
            CancellationToken cancellationToken)
        {
            return Task.FromResult(document);
        }
    }
}

Any help would be appreciated.

Thanks.


Solution

  • You are missing entry in your vsixmanifest which tells Visual Studio that your project contains MEF component. MEF (Managed extensibility framework) is used inside Visual Studio to discover, register and retrieve different components. ExportCodeProviderAttribute actually extends ExportAttribute which is used by MEF as marker that this is MEF component. However you have to specify that your project contains MEF components for extensions, otherwise discovery does not happen. This is why your code fix provider was not discovered and could not be used.

    Example how your assets tab in vsixmanifest should look like: enter image description here

    Also for creating analyzers and code fix providers, you should start with template that is available in Visual Studio under Visual C# -> Extensibility -> Analyzer with Code Fix (NuGet + VSIX). All necessary infrastructure code and settings will be already set up for you.