domingo, 26 de janeiro de 2025

Criando um Analisador de Código com Roslyn em C#

O Roslyn é a plataforma de compilação do .NET que permite a criação de ferramentas poderosas para análise e geração de código. Com Roslyn, podemos construir analisadores de código personalizados para detectar padrões específicos, verificar conformidade com boas práticas, ou até mesmo refatorar automaticamente o código. Neste post, vamos explorar como começar a usar Roslyn para construir seu próprio analisador de código em C#.


O que é o Roslyn?

Roslyn é a plataforma de compilação que oferece APIs para análise e geração de código C#. Ao contrário dos compiladores tradicionais, que funcionam como "caixas pretas", o Roslyn fornece acesso completo à árvore de sintaxe, ao fluxo de dados e ao fluxo de controle de programas, permitindo que você interaja com o código de maneira programática.


Por Que Criar um Analisador de Código?

Criar seu próprio analisador de código pode ser útil em diversos cenários:

  • Garantir boas práticas: Detectar padrões problemáticos ou antipatrones (code smells) em tempo de compilação.
  • Automatizar refatoração: Melhorar o código de forma automatizada, substituindo padrões obsoletos por alternativas mais eficientes.
  • Validar convenções de codificação: Forçar que toda a equipe siga os mesmos padrões, como nomenclatura ou estrutura de código.

Passos para Criar um Analisador com Roslyn

1. Criando o Projeto de Analisador

No Visual Studio, você pode criar um Analyzer Project que é especializado na criação de analisadores de código.

  • Abra o Visual Studio e crie um novo projeto do tipo Analyzer with Code Fix.
  • Esse tipo de projeto cria uma solução com dois projetos: um para o analisador de código e outro para corrigir os problemas detectados.

2. Entendendo a Estrutura do Analisador

O principal objetivo do analisador é inspecionar a árvore de sintaxe (Syntax Tree) do código C# para identificar padrões específicos. Para isso, você trabalha com duas classes principais:

  • SyntaxNode: Representa um nó na árvore de sintaxe, como uma expressão, declaração ou bloco de código.
  • SyntaxWalker: Permite percorrer a árvore de sintaxe e inspecionar seus nós.

Aqui está um exemplo básico de um analisador que verifica se uma variável está sendo declarada, mas nunca utilizada:

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class UnusedVariableAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "UV001";
    private static readonly LocalizableString Title = "Unused Variable";
    private static readonly LocalizableString MessageFormat = "The variable '{0}' is declared but never used.";
    private static readonly LocalizableString Description = "Variable is declared but never used in the code.";
    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, "Usage", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.VariableDeclarator);
    }

    private void AnalyzeNode(SyntaxNodeAnalysisContext context)
    {
        var variableDeclarator = (VariableDeclaratorSyntax)context.Node;
        var variableName = variableDeclarator.Identifier.Text;
        
        // Verifique se a variável está sendo usada em algum lugar do código
        // (Este é um exemplo simplificado; normalmente seria necessário fazer mais verificações)
        if (!IsVariableUsed(variableName, context))
        {
            var diagnostic = Diagnostic.Create(Rule, variableDeclarator.GetLocation(), variableName);
            context.ReportDiagnostic(diagnostic);
        }
    }

    private bool IsVariableUsed(string variableName, SyntaxNodeAnalysisContext context)
    {
        // Lógica para verificar se a variável é usada no código
        return false;  // Simplificação para exemplo
    }
}

Este código cria um analisador simples que marca uma variável como "não utilizada" se ela for declarada, mas nunca referenciada em outra parte do código.


3. Registra a Ação do Analisador

O método RegisterSyntaxNodeAction é onde você informa ao Roslyn o tipo de nó que deseja analisar. No exemplo acima, estamos verificando todos os nós do tipo VariableDeclaratorSyntax, que representam as declarações de variáveis.


4. Criando a Correção (Code Fix)

Além de detectar problemas, podemos usar Roslyn para sugerir ou aplicar correções automáticas ao código. Para isso, você precisa criar uma classe que implementa CodeFixProvider. Abaixo está um exemplo simples que sugere a remoção de uma variável não usada:

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UnusedVariableCodeFixProvider)), Shared]
public class UnusedVariableCodeFixProvider : CodeFixProvider
{
    public override async Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var diagnostic = context.Diagnostics.First();
        var diagnosticSpan = diagnostic.Location.SourceSpan;

        // Obtém o nó da variável não utilizada
        var root = await context.Document.GetSyntaxRootAsync();
        var variableDeclarator = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<VariableDeclaratorSyntax>().First();

        // Registra a correção: remover a variável
        context.RegisterCodeFix(
            CodeAction.Create("Remove unused variable", c => RemoveUnusedVariable(context.Document, variableDeclarator, c)),
            diagnostic);
    }

    private async Task<Document> RemoveUnusedVariable(Document document, VariableDeclaratorSyntax variableDeclarator, CancellationToken cancellationToken)
    {
        var root = await document.GetSyntaxRootAsync(cancellationToken);
        var newRoot = root.RemoveNode(variableDeclarator, SyntaxRemoveOptions.KeepNoTrivia);
        return document.WithSyntaxRoot(newRoot);
    }
}

Este exemplo registra uma correção automática para remover a variável não utilizada.


5. Testando o Analisador de Código

Roslyn oferece um modelo de projeto que inclui testes automáticos para seus analisadores e correções. Testar seu analisador é essencial para garantir que ele esteja funcionando corretamente e identificando problemas da maneira que você deseja.


Conclusão

A criação de analisadores de código com Roslyn é uma maneira poderosa de melhorar a qualidade do código, automatizar tarefas repetitivas e garantir a conformidade com boas práticas. Com o exemplo básico de um analisador de variável não utilizada, você pode começar a personalizar suas ferramentas para detectar e corrigir padrões específicos no seu código C#.

Experimente criar seu próprio analisador! Quais padrões você gostaria de verificar no seu código? Deixe nos comentários!

Nenhum comentário:

Postar um comentário