Validando regras de estilo de código no .NET em tempo de compilação
Qualidade de código no .NET - Parte 2
Introdução
A análise estática de código é uma ótima ferramenta para detectar alguns tipos de erros no seu código, como por exemplo, não liberar objetos que implementam IDisposable. Além disso, ela ajuda a validar se o código escrito está seguindo um padrão definido, por exemplo, utilizando PascalCase para nomes de classes e camelCase para nomes de parâmetros.
Nesse post eu vou mostrar como usar os Roslyn Analyzers com C# para validar alguns padrões de qualidade e estilo de código, exibindo erros em tempo de compilação caso alguma das regras não seja respeitada, não permitindo que as alterações cheguem às branches protegidas do repositório.
Roslyn Analyzers
Roslyn é o compilador do .NET. Roslyn Analyzers são ferramentas de análise estática para o Roslyn. Eles inspecionam o código para estilo, qualidade, e práticas que possivelmente causam bugs. Eles funcionam de acordo com regras definidas e severidades que são configuradas no arquivo EditorConfig
.
O .NET 5 e versões superiores possuem os analisadores habilitados por padrão. Para habilitar em versões anteriores do .NET, você pode configurar a propriedade EnableNETAnalyzers
como true
em projetos que utilizam um project SDK ou instalá-los através de um pacote nuget:
Configurando EnableNETAnalyzers no arquivo do projeto
|
|
Instalando através de um pacote nuget
Install-Package Microsoft.CodeAnalysis.NetAnalyzers
Habilitando mais analisadores
Por padrão, apenas algumas regras são habilitadas, mas podemos configurar isso com a propriedade AnalysisMode
no arquivo de projeto:
|
|
Os valores da propriedade AnalysisMode
são diferentes entre os SDKs do .NET 6 e .NET 5. Detalhes aqui.
Como habilitar os analisadores .NET no VS Code
Os analisadores .NET funcionam por padrão no Visual Studio, mas precisam ser habilitados no VS Code.
1 - Acesse File > Preferences > Settings
.
2 - Navegue até Extensions > C# configuration
ou pesquise por omnisharp.enableRoslynAnalyzers
.
3 - Selecione a opção Omnisharp: Enable Roslyn Analyzers
.
4 - Navegue até Extensions > C# configuration
ou pesquise por omnisharp.enableEditorConfigSupport
.
5 - Selecione a opção Omnisharp: Enable Editor Config Support
.
6 - Reinicie a extensão C#/Omnisharp ou o VS Code.
Tipos de regras
Os analisadores .NET estão divididos em várias categorias, mas aqui listo algumas apenas para explicar como elas interagem com as funcionalidades do Visual Studio.
Formatação padrão: Opções padrões do Editorconfig, como tamanho da indentação e utilização de tabs ou espaços;
Estilo de código - Formatação .NET: Indentação específica da linguagem, espaços em branco, e wrapping. Por exemplo, usar espaços antes de parênteses nas definições de métodos.
Estilo de código - Linguagens .NET: Regras específicas do C# e Visual Basic. Exemplos: usar
var
em vez de um tipo explícito, preferir propriedades automáticas em vez de backing fields.Estilo de código - Convenções de nomenclatura: Regras sobre nomenclatura de elementos, como forçar PascalCase para nomes de classes e a palavra Async no final do nome de métodos assíncronos.
Estilo de código - Código desnecessário: Regras para código que nunca é executado como variáveis não utilizadas.
Qualidade de código: Regras para melhorar a qualidade do código. Essas regras ajudam a identificar código que podem causar bugs ou problemas de segurança. Exemplos: Não declarar membros estáticos em tipos genéricos, e Enums que não contenham um valor para zero.
A tabela abaixo mostra como as funcionalidades do Visual Studio aplicam as correções para cada um desses tipos de regras.
Correções aplicadas para | 🖹 Formatação | 🧹 Code Cleanup | 💡 Code Fix |
---|---|---|---|
Formatação padrão | ✔️ | ✔️ | ✔️ |
Formatação .NET | ✔️ | ✔️ | ✔️ |
Linguagens .NET | ✔️ | ✔️ | |
Convenções de nomenclatura | ✔️ | ||
Código desnecessário | ❗ | ✔️ | |
Qualidade de código | ❗ |
❗ Apenas algumas regras são aplicadas.
💡 No post anterior desta série, eu explico como configurar o Visual Studio para aplicar essas regras no Code Cleanup e como executar automaticamente o Code Cleanup ao salvar os arquivos.
Validando regras no nosso código
As regras dos analisadores são configuradas no arquivo EditorConfig (que eu expliquei na Parte 1 dessa série) e as severidades podem ser definidas em três níveis. Os conflitos nas regras são resolvidos na seguinte ordem:
- Regras específicas
- Categorias de regras
- Todas as regras
No exemplo abaixo, Violação de regras de nomenclatura (IDE1006
) serão consideradas como Warning
, porque estão definidas no nível da regra específica:
|
|
1. Crie um arquivo EditorConfig pelo Visual Studio
Primeiro, precisamos criar um arquivo EditorConfig com a configuração das regras que usaremos como padrão.
O Visual Studio possui uma ferramenta para ajudar a configurar as regras de estilo de código do seu EditorConfig, mostrando snippets de código de como a regra funciona.
- Acesse Tools > Options > Text Editor > C# > Code Style;
- Configure suas preferências de estilo de código nos menus General, Formatting e Naming. ⚠️ Não se preocupe em configurar as severidades aqui; algumas delas são respeitadas apenas pelo Visual Studio e não são validadas na compilação e em outras IDEs;
- De volta ao menu General, clique em
Generate .editoconfig file from settings
e salve o arquivo na pasta onde a solução do seu projeto (.sln
) está.
⚠️ Se você não estiver usando Visual Studio, você pode usar um exemplo e alterar para suas preferências, como esse do Roslyn.
2. Configure todos os projetos para usar os analisadores .NET Analyzers recomendados
Em seguida, configuramos a propriedade AnalysisMode em todos os projetos da nossa solução.
Para o SDK do .NET 6 e superiores, configure como Recommended
ou All
.
|
|
3. Configure a severidade de todos os analisadores como Error
No nosso EditorConfig, inclua a linha abaixo para configurar a severidade de todas as regras como error
.
# Configura a severidade como error para todos os analisadores
dotnet_analyzer_diagnostic.severity = error
4. Corrija os erro e sobrescreva as regras que não deseja utilizar
Se você está habilitando os analisadores em um projeto existente, muitos erros vão ser mostrados. Corrija-os e sobrescreva as severidades das regras que não se aplicam ou que serão corrigidas em outro momento.
💡 No post anterior desta série, eu explico como adicionar fixers ao Code Cleanup do Visual Studio. Você pode personalizar ele para corrigir algumas das violações de regras.
Configurando a severidade das regras diretamente no arquivo EditorConfig
|
|
Configurando a severidade das regras pela lista de erros do Visual Studio
Para erros sendo mostrados na lista de erros, você pode clicar com botão direito na mensagem e selecionar Set severity > Choose a severity
. A severidade será adicionada ao arquivo EditorConfig.
Configurando a severidade das regras pelo Solution Explorer do Visual Studio
Pelo Solution Explorer, abra Dependencies > Analyzers
abaixo do projeto, depois clique com o botão direito na regra e selecione Set severity > Choose a severity
. A severidade será adicionada ao arquivo EditorConfig.
5. Validando as regras na compilação
Habilitar os analisadores apenas mostrará as mensagens na sua IDE. Para realmente validar se as regras estão sendo cumpridas, precisamos informar o compilador para falhar em caso de violações das regras, bloqueando as alterações de subirem para as branches protegidas do repositório.
Para isso, precisamos configurar a propriedade EnforceCodeStyleInBuild
como true
em todos os projetos da nossa solução.
|
|
Exemplos das regras sendo validadas
Regras sendo validadas no Visual Studio
Regras sendo validadas no VS Code
Regras sendo validadas na linha de comando com dotnet build
Criando convenções de nomenclatura adicionais
Abaixo temos algumas convenções de nomenclatura do C#:
Símbolo | Convenção | Exemplo |
---|---|---|
classes/records/structs | PascalCase | PhysicalAddress |
interfaces | “I”+PascalCase | IWorkerQueue |
membros públicos | PascalCase | StartEventProcessing |
campos privados/internos | “_"+camelCase | _workerQueue |
campos estáticos | “s_"+camelCase | s_workerQueue |
variáveis locais *️ | camelCase | isValid |
parâmetros | camelCase | name |
métodos assíncronos | PascalCase+“Async” | GetStringAsync |
Mais detalhes aqui.
Por padrão, o Visual Studio não cria convenções de nomenclatura para campos estáticos, variáveis locais, parâmetros e métodos async. Se quisermos usá-las, temos que criar as convenções manualmente, como mostro abaixo.
*️ Não especificado na documentação, mas o Roslyn usa essa convenção.
Criando convenções de nomenclatura para métodos async
|
|
Criando convenções de nomenclatura para variáveis locais e parâmetros
|
|
Como ignorar a regra CA1707 (Identifiers should not contain underscores) em projetos de testes
Algumas convenções para nomenclatura de testes utilizam underscore. Se esse for o seu caso, você vai receber uma violação da regra CA1707.
Para desabilitar essa regra apenas nos projetos de testes, crie um arquivo com o nome GlobalSuppressions.cs
na raiz do seu projeto de testes com o conteúdo abaixo.
|
|
Analisadores de terceiros
Existem analisadores de terceiros que podem ter regras adicionais que podem ser úteis. Aqui estão alguns: