如何调试从未加载的 CodeFixProvider

How do I debug a CodeFixProvider not ever loading

我创建了一个新的 "Analyzer with Code Fix (.NET Standard)" 项目,并更新了分析器来检查我想要的东西,效果很好。现在我已经修改了CodeFixProvider,但是调试的时候一直不显示

我在 getter 中为 FixableDiagnosticIdsGetFixAllProvider()RegisterCodeFixesAsync(CodeFixContext context) 设置了断点,但是当我单击分析器正确标记的行上的 "light bulb"。

关于如何弄清楚为什么它似乎没有被调用的任何想法?

在 "Analyzer with Code Fix (.NET Standard)" 创建的默认项目中,这 3 个地方的断点被正确调用。

我的分析器代码

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace InAnalyzer
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class InAnalyzerAnalyzer : DiagnosticAnalyzer
    {
        public const string CanBeInvokedWithInDiagnosticId = "IN3001";
        public const string DoNotUseInWithParameterDiagnosticId = "IN3002";
        public const string UseInWithParameterDiagnosticId = "IN3003";
        private const string CanBeInvokedWithInCategory = "Performance";
        private const string DoNotUseInWithParameterCategory = "Performance";
        private const string UseInWithParameterCategory = "Performance";

        private static readonly LocalizableString CanBeInvokedWithInTitle = new LocalizableResourceString(nameof(Resources.CanBeInvokedWithInAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString DoNotUseInWithParameterTitle = new LocalizableResourceString( nameof(Resources.DoNotUseInWithParameterAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString UseInWithParameterTitle = new LocalizableResourceString( nameof(Resources.UseInWithParameterAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString CanBeInvokedWithInMessageFormat = new LocalizableResourceString(nameof(Resources.CanBeInvokedWithInAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString DoNotUseInWithParameterMessageFormat = new LocalizableResourceString(nameof(Resources.DoNotUseInWithParameterAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString UseInWithParameterMessageFormat = new LocalizableResourceString(nameof(Resources.UseInWithParameterAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString CanBeInvokedWithInDescription = new LocalizableResourceString(nameof(Resources.CanBeInvokedWithInAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString DoNotUseInWithParameterDescription = new LocalizableResourceString(nameof(Resources.DoNotUseInWithParameterAnalyzerDescription), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString UseInWithParameterDescription = new LocalizableResourceString(nameof(Resources.UseInWithParameterAnalyzerDescription), Resources.ResourceManager, typeof(Resources));

        private static readonly DiagnosticDescriptor CanBeInvokedWithInRule = new DiagnosticDescriptor(
            CanBeInvokedWithInDiagnosticId,
            CanBeInvokedWithInTitle,
            CanBeInvokedWithInMessageFormat,
            CanBeInvokedWithInCategory,
            DiagnosticSeverity.Warning,
            isEnabledByDefault: true,
            CanBeInvokedWithInDescription);

        private static readonly DiagnosticDescriptor DoNotUseInWithParameterRule = new DiagnosticDescriptor(
            DoNotUseInWithParameterDiagnosticId,
            DoNotUseInWithParameterTitle,
            DoNotUseInWithParameterMessageFormat,
            DoNotUseInWithParameterCategory,
            DiagnosticSeverity.Warning,
            isEnabledByDefault: true,
            DoNotUseInWithParameterDescription);

        private static readonly DiagnosticDescriptor UseInWithParameterRule = new DiagnosticDescriptor(
            UseInWithParameterDiagnosticId,
            UseInWithParameterTitle,
            UseInWithParameterMessageFormat,
            UseInWithParameterCategory,
            DiagnosticSeverity.Warning,
            isEnabledByDefault: true,
            UseInWithParameterDescription);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            => ImmutableArray.Create(CanBeInvokedWithInRule, DoNotUseInWithParameterRule, UseInWithParameterRule);

        public override void Initialize(AnalysisContext context)
        {
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
            context.EnableConcurrentExecution();

            context.RegisterSyntaxNodeAction(AnalyzeInvocationExpressionSyntaxNode, SyntaxKind.InvocationExpression);
            context.RegisterSyntaxNodeAction(AnalyzeMethodDeclarationSyntaxNode, SyntaxKind.MethodDeclaration);
        }

        private static void AnalyzeInvocationExpressionSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            var node = (InvocationExpressionSyntax) context.Node;
            var symbol = context.SemanticModel.GetSymbolInfo(node).Symbol ??
                context.SemanticModel.GetDeclaredSymbol(node);
            if (symbol is IMethodSymbol methodSymbol)
            {
                var parametersSymbol = methodSymbol.Parameters;
                var argumentSyntaxList = node?.ArgumentList.Arguments;
                if (argumentSyntaxList != null)
                {
                    var argumentSyntaxes = argumentSyntaxList.Value;
                    for (var index = 0; index < parametersSymbol.Length; index++)
                    {
                        var parameterSymbol = parametersSymbol[index];
                        if (parameterSymbol.RefKind == RefKind.In &&
                            parameterSymbol.Type.IsReadOnly &&
                            parameterSymbol.Type.IsValueType &&
                            index < argumentSyntaxes.Count)
                        {
                            var argumentSyntax = argumentSyntaxes[index];
                            if (argumentSyntax?.RefKindKeyword.IsKind(SyntaxKind.InKeyword) == false)
                            {
                                var diagnostic = Diagnostic.Create(
                                    CanBeInvokedWithInRule,
                                    argumentSyntax.Expression.GetLocation(),
                                    parameterSymbol.Name,
                                    parameterSymbol.Type);

                                context.ReportDiagnostic(diagnostic);
                            }
                        }
                    }
                }
            }
        }

        private static void AnalyzeMethodDeclarationSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            var node = (MethodDeclarationSyntax) context.Node;

            var parameterSyntaxList = node?.ParameterList.Parameters;
            if (parameterSyntaxList != null)
            {
                var parameterSyntaxes = parameterSyntaxList.Value;
                for (var index = 0; index < parameterSyntaxes.Count; index++)
                {
                    var parameterSyntax = parameterSyntaxes[index];
                    if (parameterSyntax != null)
                    {
                        var symbol = context.SemanticModel.GetSymbolInfo(parameterSyntax.Type).Symbol;

                        if (symbol is ITypeSymbol typeSymbol)
                        {
                            if (typeSymbol.IsReadOnly &&
                                typeSymbol.IsValueType)
                            {
                                if (!parameterSyntax.Modifiers.Any(SyntaxKind.InKeyword))
                                {
                                    var diagnostic = Diagnostic.Create(
                                        UseInWithParameterRule,
                                        parameterSyntax.Identifier.GetLocation(),
                                        parameterSyntax.Identifier,
                                        typeSymbol);
                                    context.ReportDiagnostic(diagnostic);
                                }
                            }
                            else
                            {
                                foreach (var modifier in parameterSyntax.Modifiers)
                                {
                                    if (modifier.Kind() == SyntaxKind.InKeyword)
                                    {
                                        var diagnostic = Diagnostic.Create(
                                            DoNotUseInWithParameterRule,
                                            modifier.GetLocation(),
                                            parameterSyntax.Identifier,
                                            typeSymbol);
                                        context.ReportDiagnostic(diagnostic);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

我的CodeFixProvider(可能不完整和不正确;我想调试并让它正常工作,但我什至无法尝试运行):

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

namespace InAnalyzer
{
    [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(InAnalyzerCodeFixProvider)), Shared]
    public class InAnalyzerCodeFixProvider : CodeFixProvider
    {
        private const string AddInModifierTitle = "Add 'in' modifier";
        private const string RemoveInModifierTitle = "Remove 'in' modifier";

        public sealed override ImmutableArray<string> FixableDiagnosticIds
            => ImmutableArray.Create(
                InAnalyzerAnalyzer.CanBeInvokedWithInDiagnosticId,
                InAnalyzerAnalyzer.DoNotUseInWithParameterDiagnosticId,
                InAnalyzerAnalyzer.UseInWithParameterDiagnosticId);

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

        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 node = generator.GetDeclaration(token.Parent);
            if (node == null)
            {
                return;
            }

            foreach (var diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                    case InAnalyzerAnalyzer.CanBeInvokedWithInDiagnosticId:
                    case InAnalyzerAnalyzer.UseInWithParameterDiagnosticId:
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                AddInModifierTitle,
                                c => AddInModifierAsync(context.Document, node, c),
                                AddInModifierTitle),
                            diagnostic);
                        break;
                    case InAnalyzerAnalyzer.DoNotUseInWithParameterDiagnosticId:
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                RemoveInModifierTitle,
                                c => RemoveInModifierAsync(context.Document, node, c),
                                RemoveInModifierTitle),
                            diagnostic);
                        break;
                }
            }
        }

        private async Task<Document> AddInModifierAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            switch (node.Parent)
            {
                case ArgumentSyntax argumentSyntax:
                    editor.ReplaceNode(
                        argumentSyntax,
                        argumentSyntax.WithRefKindKeyword(SyntaxFactory.Token(SyntaxKind.InKeyword)));
                    break;
                case ParameterSyntax parameterSyntax:
                    editor.ReplaceNode(
                        parameterSyntax,
                        parameterSyntax.AddModifiers(SyntaxFactory.Token(SyntaxKind.InKeyword)));
                    break;
            }

            return editor.GetChangedDocument();
        }

        private async Task<Document> RemoveInModifierAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);

            ////switch (node.Parent)
            ////{
            ////    case ArgumentSyntax argumentSyntax:
            ////        editor.ReplaceNode(
            ////            argumentSyntax,
            ////            argumentSyntax.WithRefKindKeyword(SyntaxFactory.Token(SyntaxKind.InKeyword)));
            ////        break;
            ////    case ParameterSyntax parameterSyntax:
            ////        editor.ReplaceNode(
            ////            parameterSyntax,
            ////            parameterSyntax.AddModifiers(SyntaxFactory.Token(SyntaxKind.InKeyword)));
            ////        break;
            ////}

            return editor.GetChangedDocument();
        }
    }
}

找到this, which pointed to the CreateExpInstance tool后,我尝试重置"Roslyn"后缀的实验体。这并没有解决我的问题,但我随后删除了我的 "Roslyn" 后缀的实验实例并再次尝试调试我的 VSIX。这一次,调试我的 VSIX 成功并显示了我的 CodeFixProvider。

rd /s/q "%LOCALAPPDATA%\Microsoft\VisualStudio.0_0f71fe5bRoslyn"

对于其他受此困扰的人,试试这个:

  1. 使用开始搜索菜单找到重置 visual studio 实验实例快捷方式命令
  2. 运行它
  3. 清理你的解决方案
  4. 运行 处于 RELEASE 模式
  5. 请注意,您的内容现在出现在实例中
  6. 关闭它
  7. 切换回 DEBUG 模式
  8. 瞧瞧。黑魔法刚刚发生。问题已解决。