Featured image of post Validando regras de estilo de código no .NET em tempo de compilação

Validando regras de estilo de código no .NET em tempo de compilação

Qualidade de código no .NET - Parte 2

Follow me
Esse post é parte de uma série:
Parte  2  -  Validando regras de estilo de código no .NET em tempo de compilação

Introdução Link to this section

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 Link to this section

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 Link to this section

1
2
3
<PropertyGroup>
  <EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>

Instalando através de um pacote nuget Link to this section

Install-Package Microsoft.CodeAnalysis.NetAnalyzers

Habilitando mais analisadores Link to this section

Por padrão, apenas algumas regras são habilitadas, mas podemos configurar isso com a propriedade AnalysisMode no arquivo de projeto:

1
2
3
<PropertyGroup>
  <AnalysisMode>Recommended</AnalysisMode>
</PropertyGroup>

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 Link to this section

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 Link to this section

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 Link to this section

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:

  1. Regras específicas
  2. Categorias de regras
  3. 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
2
3
4
5
6
# Defines that all analyzers rules are suggestions
dotnet_analyzer_diagnostic.severity = suggestion
# Defines that all Code Style analyzers rules are errors
dotnet_analyzer_diagnostic.category-Style.severity = error
# Defines that the rule IDE1006 is a warning
dotnet_diagnostic.IDE1006.severity = warning

1. Crie um arquivo EditorConfig pelo Visual Studio Link to this section

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.

  1. Acesse Tools > Options > Text Editor > C# > Code Style;
  2. 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;
  3. 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á.

Configurando regras de estilo do código no EditorConfig

⚠️ 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 Link to this section

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.

1
2
3
<PropertyGroup>
  <AnalysisMode>Recommended</AnalysisMode>
</PropertyGroup>

3. Configure a severidade de todos os analisadores como Error Link to this section

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 Link to this section

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 Link to this section

1
2
3
4
5
6
7
# Outras regras ...

# Configura a severity como none para as regras que não se aplicam
dotnet_diagnostic.IDE0075.severity = none

# Configura a severity como warning para as regras que serão resolvidas no futuro
dotnet_diagnostic.IDE0047.severity = warning

Configurando a severidade das regras pela lista de erros do Visual Studio Link to this section

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 de uma regra

Configurando a severidade das regras pelo Solution Explorer do Visual Studio Link to this section

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.

Configurando a severidade de uma regra

5. Validando as regras na compilação Link to this section

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.

1
2
3
<PropertyGroup>
  <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>

Exemplos das regras sendo validadas Link to this section

Regras sendo validadas no Visual Studio Link to this section

Regras sendo validadas no VS Code Link to this section

Regras sendo validadas na linha de comando com dotnet build Link to this section

Criando convenções de nomenclatura adicionais Link to this section

Abaixo temos algumas convenções de nomenclatura do C#:

SímboloConvençãoExemplo
classes/records/structsPascalCasePhysicalAddress
interfaces“I”+PascalCaseIWorkerQueue
membros públicosPascalCaseStartEventProcessing
campos privados/internos“_"+camelCase_workerQueue
campos estáticos“s_"+camelCases_workerQueue
variáveis locais *️camelCaseisValid
parâmetroscamelCasename
métodos assíncronosPascalCase+“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 Link to this section

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
dotnet_naming_rule.async_methods_should_be_pascalcase_async.severity = error
dotnet_naming_rule.async_methods_should_be_pascalcase_async.symbols = async_methods
dotnet_naming_rule.async_methods_should_be_pascalcase_async.style = pascalcase_async

dotnet_naming_symbols.async_methods.applicable_kinds = method
dotnet_naming_symbols.async_methods.applicable_accessibilities = *
dotnet_naming_symbols.async_methods.required_modifiers = async

dotnet_naming_style.pascalcase_async.required_suffix = Async
dotnet_naming_style.pascalcase_async.capitalization = pascal_case

Criando convenções de nomenclatura para variáveis locais e parâmetros Link to this section

1
2
3
4
5
6
7
dotnet_naming_rule.locals_and_parameters_should_be_pascal_case.severity = error
dotnet_naming_rule.locals_and_parameters_should_be_pascal_case.symbols = locals_and_parameters
dotnet_naming_rule.locals_and_parameters_should_be_pascal_case.style = camel_case

dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local

dotnet_naming_style.camel_case.capitalization = camel_case

Como ignorar a regra CA1707 (Identifiers should not contain underscores) em projetos de testes Link to this section

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.

1
2
3
using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Not applicable for test names", Scope = "module")]

Analisadores de terceiros Link to this section

Existem analisadores de terceiros que podem ter regras adicionais que podem ser úteis. Aqui estão alguns:

Feedly
RSS
LinkedIn
Mastodon
Ko-fi
GitHub Sponsor
Licensed under CC BY-NC-SA 4.0
Criado com Hugo
Tema Stack desenvolvido por Jimmy