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
19.05k stars 4.04k forks source link

Conversion from Analyzer with Code Fix to Stand-alone code Analysis Tool #33003

Open MichaelWay89 opened 5 years ago

MichaelWay89 commented 5 years ago

I'm recently converting an analyzer which is extension of Visual Studio (already coded) to a stand-alone analyzer. What I did so far: I copied the methods of analysis from extension to stand-alone in the following way:

Extension

context.RegisterSyntaxNodeAction(ClassAnalyzer, SyntaxKind.ClassDeclaration); //Class analysis

...

private void ClassAnalyzer(SyntaxNodeAnalysisContext obj)
{
    var Name = ((ClassDeclarationSyntax)obj.Node).Identifier.Value.ToString();
    if (!InPascal(Name)) //Class should be in pascal case
    {
        var diagnostic = Diagnostic.Create(Rule1, ((ClassDeclarationSyntax)obj.Node).Identifier.GetLocation(), Name);
        obj.ReportDiagnostic(diagnostic);
    }
    if (HasUndescore(Name)) //Shouldn't have underscores
    {
        var diagnostic = Diagnostic.Create(Rule9, ((ClassDeclarationSyntax)obj.Node).Identifier.GetLocation(), Name);
        obj.ReportDiagnostic(diagnostic);
    }
}

Stand-Alone

Program p = new Program(); //Because main method is static
...
Console.WriteLine($"Finished loading solution '{solutionPath}'");
//Starts analysis
var proj = solution.Projects.Single();
var compilation = proj.GetCompilationAsync().Result;
foreach (var tree in compilation.SyntaxTrees)
{
    var class = tree.GetRoot().DescendantNodesAndSelf().Where(x => x.IsKind(SyntaxKind.ClassDeclaration));
    foreach (var c in class)
    {
        p.ClassAnalyzer(c);
    }

...

private void ClassAnalyzer(SyntaxNode obj)
{
    var Name = ((ClassDeclarationSyntax)obj).Identifier.Value.ToString();
    if (!InPascal(Name)) //Class should be in pascal case
    {
        Console.WriteLine(Name + " is not in Pascal Case");
    }
    if (HasUndescore(Name)) //Shouldn't have underscores
    {
        Console.WriteLine(Name + " shouldn't have underscores");
    }
}

So far so good. It turns out that I have other methods of analysis that need adaptation that is not presenting itself so simple.

I have methods that are triggered with the following conditions:

Methods that are triggered by this triggers are not changeable to work through SyntaxNode because they require information that is not available in this structure. Somehow I need to continue triggering these methods with these (or similar) parameters in order to access the same information. I searched everywhere and do not know how to find these structures to "trigger" those methods.

What i want to do:

Extension

context.RegisterOperationAction(LocalVariableAnalyzer, OperationKind.VariableDeclarator); //Local Variable analysis

...

private void LocalVariableAnalyzer(OperationAnalysisContext obj)
{
    //Code that depends on the structure OperationAnalysisContext
}

And somehow this becomes something like:

Stand-Alone

Program p = new Program(); //Because main method is static
...
Console.WriteLine($"Finished loading solution '{solutionPath}'");
//Starts analysis
var proj = solution.Projects.Single();
var compilation = proj.GetCompilationAsync().Result;
foreach (var tree in compilation.SyntaxTrees)
{
    var locvars = tree.GetRoot().DescendantNodesAndSelf().Where(x => x.IsKind(OperationKind.VariableDeclarator));
    foreach (var c in locvars)
    {
        p.LocalVariableAnalyzer(c);
    }

...

private void LocalVariableAnalyzer(OperationAnalysisContext obj)
{
    //Same code that depends on the structure OperationAnalysisContext or slightly adapted
}

Just to remember, i don't need access only to OperationAnalysis, but to SymbolKind too.

Thanks in advance.

jinujoseph commented 5 years ago

cc @mavasani

mavasani commented 5 years ago

@MichaelWay89 Can you please clarify what is your use case for doing such a conversion?

MichaelWay89 commented 5 years ago

I've implemented a Visual Studio extension for programmers to use on their computers, but I need to deploy the analyser in the CI build in Team Foundation Server to collect the same analysis and open bugs. Even though the extension was running with the compiler on the build server, our version is outdated and the extension is not compatible. I need the same rules to be executed in the build and some of them are triggered only in those methods (Operation or Symbol). The way I found it was to do a command line analyzer and run it on a build task, that's why I need conversion.