dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.96k stars 4.03k forks source link

RegisterAdditionalFileAction doesn't seem to fire when such a file is frontmost #73179

Open chucker opened 5 months ago

chucker commented 5 months ago

Version Used: C# Tools 4.10.0-3.24211.4+e482b6e

Steps to Reproduce:

  1. Make a fresh analyzer with the template
  2. Upgrade all NuGet packages; the template doesn't know context.RegisterAdditionalFileAction yet
  3. Make a new class that inherits from DiagnosticAnalyzer, like so:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

using System;
using System.Collections.Immutable;
using System.IO;
using System.Runtime.CompilerServices;

namespace Analyzer1
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class AdditionalFileActionAnalyzer : DiagnosticAnalyzer
    {
        public const string DiagnosticId = "Analyzer1";

        // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
        // See https://github.com/dotnet/roslyn/blob/main/docs/analyzers/Localizing%20Analyzers.md for more on localization
        private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
        private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
        private const string Category = "Naming";

        private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }

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

            Logger.Log("hello");

            context.RegisterAdditionalFileAction(AnalyzeAdditionalFile);
        }

        private static void AnalyzeAdditionalFile(AdditionalFileAnalysisContext context)
        {
            Logger.Log("AnalyzeAdditionalFile");
        }
    }

    internal class Logger
    {
        public static void Log(string text, [CallerFilePath] string filePath = null,
           [CallerMemberName] string memberName = null)
        {
            File.AppendAllText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @"analyzer.log"),
                $"{Path.GetFileNameWithoutExtension(filePath)}|{memberName}|{DateTime.Now:yyyy-MM-dd HH:mm:ss}|{text}\n");
        }
    }
}
  1. Use the template's VSIX project to launch a debugged VS instance. Open a project where <AdditionalFiles> includes a file, or a file is implicitly in it for another reason.

Diagnostic Id:

n/a

Expected Behavior:

AnalyzeAdditionalFile should be logged on occasion when such a file is frontmost, and being edited. I.e., the analyzer should be usable during design time.

Actual Behavior:

AnalyzeAdditionalFile seems to only ever get logged when explicitly building the project.

I'm unsure if this is by design. (The docs don't seem to imply as much.) It's not the behavior I observe with RegisterSymbolAction, where I can simply make a C# file frontmost, and the analyzer will run. If it is by design that RegisterAdditionalFileAction only takes place at build, what's the guidance on running an analyzer on a non-C# file (in my case, a .cshtml, but .xaml and others would be of use as well) as the users view/edit code?

genlu commented 5 months ago

AnalyzeAdditionalFile seems to only ever get logged when explicitly building the project.

@sharwell I think this is expected behavior, could you pls confirm?

what's the guidance on running an analyzer on a non-C# file (in my case, a .cshtml, but .xaml and others would be of use as well) as the users view/edit code?

@davidwengier Any suggestions here?

davidwengier commented 5 months ago

I don't think this will work right now, in the IDE at least. Roslyn doesn't register for diagnostic requests for additional files at the moment, and Razor won't run Roslyn diagnostics. I expect this to change in future with our cohosting effort, but that doesn't help now. Depending on the type of analysis being performed, analyzing and reporting diagnostics on the generated C# file that is compiled for a .cshtml should work fine, and Razor tooling will translate diagnostics reported in those files, to the appropriate position in the .cshtml file itself.