Clang-Arrumado, parte 1: Modernizar seu código-fonte em C++11/C++14Automated refatoração de código de origem utilizando poderosa fonte aberta de ferramentas

16.03.2017 Kevin Funk

FacebookTwitterLinkedInEmail

Esta série de posts irá apresentar o clang-arrumado utilitário a partir do Clang/LLVM projeto e mostrar como utilizá-lo para automaticamente refatorar código-fonte C++ e integrar com seu sistema de compilação, bem como a forma de usar a ferramenta em outras plataformas de sistemas unix.

Motivation: The joy of legacy code bases

C++11 added a significant amount of new C++ language features which to date still are not used to their full extension. As mais visuais são certamente auto, override, lambda expressions, range-based for, uniform initialization syntax, you name it. Embora o C++11 já tenha vários anos de idade, ainda há muitas bases de código que não usam nenhuma das novas funcionalidades da linguagem, seja por política de gestão, ou por pura preguiça para evitar o esforço de portagem do lado do desenvolvedor. Clang-Tidy do projeto de infra-estrutura de compilador LLVM está aqui para, pelo menos, superar o último, para permitir a refactoração automática do seu código fonte para que ele use os novos recursos da linguagem.Alguém quer usar o comando?

agora, o que acontece se já mantiver uma base de código bastante grande que ainda está compilada no modo C++03, mas deseja abraçar a utilização do C++11 no futuro, com todas as funcionalidades úteis que tem? Você provavelmente terá muitos e muitos códigos semelhantes a este:

struct Base { virtual void reimplementMe(int a) {}};struct Derived : public Base { virtual void reimplementMe(int a) {}};

até agora você, é claro, sempre re-implementou o método de base correta, porque você testou extensivamente o seu código através de testes unitários! Claro que sim. Assim, o código é bom, mas agora você gostaria de seguir em frente. Você gostaria de adicionar o override especificador para cada método re-implementado em sua base de código, mas é claro, sem contratar um estagiário que passa através do Código linha-a-linha e adicioná-los manualmente.

apenas para salientar que a adição de override de fato serve a um propósito, nós acabamos de corrigir um bug no Qt 3D onde não estávamos sobrecarregando o método da classe base correta. Com o especificador adicionado mais cedo, teríamos notado instantaneamente, após a recompilação.

vamos levar o exemplo em falta para explicar o uso básico de clang-tidy.Clang-Tidy to the rescue!

Clang-Tidy é uma ferramenta c++ baseada em clang que fornece um executável de shell chamado clang-tidy como o ponto de entrada principal. É uma estrutura extensível para diagnosticar erros de programação típicos, ou problemas de estilo — geralmente qualquer coisa que pode ser detectada durante a análise estática do Código. O verdadeiro benefício da ferramenta é que ela adicionalmente permite refaturar automaticamente o código fonte, aplicando fixits cada edição individual pode fornecer. É fortemente baseado em plugin e vem com um conjunto útil de plugins fora da caixa, que vamos discutir no próximo parágrafo.

LLVM logo -- home of clang-tidy

Clang-Tidy é uma ferramenta desenvolvida e mantida pela comunidade Clang/LLVM.

configuração

ao executar o Linux, clang-tidy é normalmente fácil de obter através do Gestor de pacotes da sua distribuição. No Ubuntu Linux, por exemplo, instalar é tão fácil como executar os seguintes comandos:

% sudo apt-get install clang-tidy

vamos discutir a instalação da ferramenta em outras plataformas que não o Linux em uma das próximas postagens do blog.

Nota: Recomendamos que você sempre instale a última versão (no momento da escrita, a versão baseada em Clang/LLVM 3.9 é recomendado), como o número de plugins/checkers disponíveis varia muito de versão para versão e cresce constantemente.

Introdução

Nota: neste post do blog, clang-arrumada-3.9 foi usado

Um típico invocação da ferramenta de linha de comando parecido com este:

% clang-tidy test.cpp -- -Imy_project/include -DMY_DEFINES ...

Executar como esta, a ferramenta irá imprimir um monte de avisos e notas (se aplicável), exatamente da mesma maneira Clang/GCC fornecer diagnósticos, também.

Clang-Tidy é uma ferramenta útil de análise estática por si só, com lotes de diferentes checkers disponíveis, este, no entanto, não é o foco deste post no blog. Preferimos aproveitar as poderosas capacidades de refactoring da ferramenta para modernizar o nosso código fonte.

listar códigos de validação disponíveis

executar a ferramenta sem quaisquer parâmetros específicos da linha de comando irá executar o conjunto predefinido de códigos de validação activado pelo utilitário. Vamos verificar o que outros checkers ele tem a oferecer (passando –checks=’*’ para vê-los todos), e especificamente grep para aqueles com modernize em seus nomes. Aqueles checkers defendem o uso de construções de linguagem moderna:

$ clang-tidy --list-checks -checks='*' | grep "modernize" modernize-avoid-bind modernize-deprecated-headers modernize-loop-convert modernize-make-shared modernize-make-unique modernize-pass-by-value modernize-raw-string-literal modernize-redundant-void-arg modernize-replace-auto-ptr modernize-shrink-to-fit modernize-use-auto modernize-use-bool-literals modernize-use-default modernize-use-emplace modernize-use-nullptr modernize-use-override modernize-use-using

já é uma lista impressionante de Opções, não é? Clang-Tidy realmente navega alguns checkers interessantes fora da caixa (a partir de Clang/LLVM 3.9), com a lista crescendo constantemente desde a liberação até a liberação.

os nomes das damas são bastante auto-explicativos (por exemplo, modernize-use-auto irá abraçar usando auto quando aplicável), mas se você quiser explorar o que cada um deles significa, por favor consulte a lista de damas na página clang-tidy:

para mostrar como a ferramenta está sendo usada vamos nos concentrar no verificador modernize-use-override, como é o mais aplicável e mais incontroverso.Refactorar um único ficheiro

o nosso exemplo de anulação outra vez:

struct Base { virtual void reimplementMe(int a) {}};struct Derived : public Base { virtual void reimplementMe(int a) {}};

a executar o clang-tidy no exemplo (desta vez com o verificador modernize-use-override activo):

% clang-tidy-3.9 -checks='modernize-use-override' test.cpp -- -std=c++111 warning generated./home/kfunk/test.cpp:5:18: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' virtual void reimplementMe(int a) {} ^ override

está bem. Então ele percebeu que Derived::reimplementMe(int) substitui um método de classe base, mas está faltando o override especificador! Agora podemos adicionar isso manualmente… ou deixar a ferramenta fazê-lo por nós passando-fix!

executando-o no exemplo (com o verificador modernize-use-override & fix-its activo):

% clang-tidy-3.9 -checks='modernize-use-override' -fix test.cpp -- -std=c++111 warning generated./home/kfunk/test.cpp:5:18: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' virtual void reimplementMe(int a) {} ^ override/home/kfunk/test.cpp:5:5: note: FIX-IT applied suggested code changes virtual void reimplementMe(int a) {} ^/home/kfunk/test.cpp:5:38: note: FIX-IT applied suggested code changes virtual void reimplementMe(int a) {} ^clang-tidy applied 2 of 2 suggested fixes.

Clang-tidy aplicou o fix-it, e inseriu override após a declaração do método na linha 5. Feito!

um par de notas

há algumas coisas que vale a pena mencionar:

  • nem todos os checkers de clang-tidy realmente carregam fix-its, mas os que começam com modernize tudo fazem.
  • Você pode usar a solução fix-its de várias damas, ao mesmo tempo, (considere -verifica=’modernizar-usar-substituir,modernizar-usar-auto’ -fix)
  • Execução de clang-arrumado invoca a completa Clang compilador front-end, portanto, vai precisar de algum tempo para completar
  • Refactoring resultados do clang-arrumado são perfeitamente precisas, devido ao fato de que ele é feito por um completo analisador C++

Refatorando um projeto completo (Alsa-base)

até agora estamos clang-arrumado em um único arquivo autônomo só. O que acontece se você tiver uma configuração de projeto mais complexa, com muitos arquivos, todos com bandeiras de compilação personalizadas? Clang-tidy sempre opera em um único arquivo, ou melhor, unidade de tradução. Nós podemos ajudar a ferramenta para descobrir as bandeiras de compilação corretas para cada unidade de tradução que compilamos em nosso projeto. A maneira mais conveniente de executá-lo é com um banco de dados de comandos compile. O CMake pode gerar automaticamente um, e uma vez um compile_commands.json está no lugar e uma versão de trabalho de clang-tidy está no caminho todo o código base pode ser analisado com o run-clang-tidy.script py (Normalmente enviado como parte da instalação). Se não você pode simplesmente baixá-lo aqui.

Nota: é altamente recomendado o uso de run-clang-tidy.py para executar clang-arrumado em um projeto como um todo, uma vez que ele vai executar a ferramenta várias vezes em paralelo e certifica-se de execuções simultâneas não interferem uns com os outros (por exemplo, evitando modificar um cabeçalho compartilhada em paralelo e gerando código quebrado).

gerando uma composição.JSON file

For generating the compile_commands.ficheiro json num projecto baseado no CMake, apenas executar:

% cd my-cmake-based-project% mkdir build% cd build% cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..

Use script para executar clang-tidy

agora para executar a ferramenta com as verificações por omissão em cada unidade de tradução do projecto, basta invocar o script run-clang-tidy dentro do directório com os compile_commands.ficheiro json:

% run-clang-tidy.py

como visto antes, isso não irá modificar nada até agora, já que nós executamos clang-tidy com apenas as verificações padrão ativadas. Para, por exemplo, executar a verificação modernize-use-override em todas as unidades de traduções e realmente refactor todo o seu código, esta invocação é necessária:

% run-clang-tidy.py -header-filter='.*' -checks='-*,modernize-use-override' -fix

é isso. clang-tidy será agora invocado em cada unidade de tradução do seu projecto e irá adicionar sobreposições onde faltar. The parameter-header-filter=”.* ‘garante clang-tidy realmente refactors código nos cabeçalhos sendo consumidos na unidade de tradução. O parâmetro verifica=’ -*,… ‘ garante que todas as verificações por omissão estão desactivadas.

Note que as correções só são aplicadas quando o run-clang-tidy terminar! O script só gravará as alterações a serem realizadas e aplica – as todas de uma vez no final.

Running other checkers

Again, The modernize-use-override is just an example, clang-tidy has lots of other checkers which are useful. Outro super útil é o checker modernize-use-nullptr, que transforma 0, ou por exemplo NULL literals em versão moderna C++11 nullptr. Para refacturar todos os usos dos literais antigos no seu projecto, basta executar:

% run-clang-tidy.py -header-filter='.*' -checks='-*,modernize-use-nullptr' -fix

geralmente é uma boa ideia realizar um checker após outro, cometendo resultados intermediários (pense em “Port towards C++11 nullptr”, “Port towards C++11 override”,…) no seu sistema de controle de versões.

Some real world examples

i’ve personally used clang-tidy on a lot of different projects already, with positive results. Lembre-se, esta ferramenta tem perfeito conhecimento do seu código (como de fato está usando o compilador Clang frontend) e, assim, irá refaturar o seu código sem nunca introduzir código quebrado.Exemplos:

  • Este patch, por exemplo, as portas de todos KDE Frameworks de bibliotecas para C++11 nullptr, tocando cerca de 9000 de código diferentes localizações
  • Este patch portas do KDE Mármore base de código para C++11 de substituição, tocando em torno de 2300 código diferentes localizações

Conclusão

Clang-Arrumado é uma poderosa ferramenta que faz a portar seu legado base de código para C++11 uma questão de execução de um one-liner. Ele vem com um grande conjunto de damas padrão e a lista de outras cresce constantemente. O modernize-checkers pode ser usado para modernizar/reformular o seu código fonte para usar novas funcionalidades da linguagem C++.

na próxima parte desta série vamos discutir como usar clang-tidy em todo o projeto com outros sistemas de construção.Precisa de Ajuda?

KDAB emprega vários engenheiros que trabalham diariamente com ferramentas em palhetas. Estamos felizes em ajudá-lo no caso de você ter problemas usando ferramentas Clang em seu projeto ou quer tirar o máximo proveito disso: ao deixar-nos implementar verificações de código específicas do projeto ou executar ferramentas de refactoring automático em sua base de código. Nós ajudamos os clientes a modernizar suas bases de código muito grandes com sucesso usando ferramentas-algo que não teria sido viável para eles, em termos de custos, fazê-lo manualmente.

entre em Contato conosco

FacebookTwitterLinkedInEmail

Categorias: C++ / Segurança Funcional / Como / KDAB Blogs / KDAB em Qt / Ferramentas

Tags: automatizada de refatoração / C++ / C++11 / C++14 / Clang / LLVM

Kevin Funk Sênior Engenheiro De Software

Deixe uma resposta

O seu endereço de email não será publicado.