Clang-Tidy, partea 1: modernizați codul sursă utilizând C++11 / C++14refactorizarea automată a codului sursă utilizând instrumente puternice open-source

16.03.2017 Kevin Funk

 Facebook  Twitter  LinkedIn  e-mail

această serie de bloguri va introduce utilitarul clang-tidy din proiectul Clang/LLVM și va arăta cum să îl utilizați pentru a refactoriza automat codul sursă C++ și pentru a vă integra cu sistemul dvs. de construire, precum și modul de utilizare a instrumentului pe alte platforme decât Unices.

motivație: bucuria bazelor de cod moștenite

C++11 a adăugat o cantitate semnificativă de noi caracteristici de limbaj C++ care până în prezent încă nu sunt utilizate în măsura lor deplină. Cele mai vizuale sunt cu siguranță auto, override, expresii Lambda, bazate pe gamă for, sintaxă de inițializare uniformă, o numiți. În timp ce C++11 are acum câțiva ani deja, există încă o mulțime de baze de cod care nu utilizează niciuna dintre noile caracteristici lingvistice, fie prin politica conducerii, fie prin lenea pură pentru a evita efortul de portare din partea dezvoltatorului. Clang-Tidy din proiectul de infrastructură compilator LLVM este aici pentru a depăși cel puțin acesta din urmă, pentru a permite refactorizarea automată a codului sursă, astfel încât să utilizeze noile caracteristici lingvistice.

folosește cineva suprascrierea?

acum, ce se întâmplă dacă mențineți deja o bază de cod destul de mare, care este încă compilată în modul C++03, dar doriți să îmbrățișați utilizarea C++11 în viitor, cu toate caracteristicile utile pe care le are? Veți avea probabil o mulțime și o mulțime de cod similar cu aceasta:

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

până în prezent, desigur, ați re-implementat întotdeauna metoda corectă a clasei de bază, deoarece ați testat extensiv codul dvs. prin teste unitare! Bineînțeles că ai făcut-o. Astfel, codul este bine, dar acum doriți să mergeți mai departe. Doriți să adăugați specificatorul override la fiecare metodă reimplementată din Baza de cod, dar, desigur, fără a angaja un stagiar care trece prin codul linie cu linie și le adaugă manual.

doar pentru a sublinia faptul că adăugarea override servește într-adevăr unui scop, tocmai am rezolvat recent o eroare în Qt 3D în care nu supraîncărcam metoda corectă a clasei de bază. Cu specificatorul adăugat mai devreme, am fi observat instantaneu, după recompilare.

vom lua exemplul lipsă-suprascrie în continuare pentru a explica utilizarea de bază a zăngănit-tidy.

zăngănit-ordonat la salvare!

Clang-Tidy este un instrument linter bazat pe clang C++ care oferă un executabil shell numit clang-tidy ca punct principal de intrare. Este un cadru extensibil pentru diagnosticarea erorilor tipice de programare sau a problemelor de stil — în general orice poate fi detectat în timpul analizei statice a codului. Beneficiul real al instrumentului este că permite în plus să refactor automat codul sursă prin aplicarea fixits fiecare problemă individuală poate oferi. Este puternic bazat pe plugin-uri și vine cu un set util de plugin-uri din cutie, pe care le vom discuta în paragraful următor.

LLVM logo-casa de zăngănit-tidy

zăngănit-Tidy este un instrument dezvoltat și întreținut de comunitatea zăngănit/LLVM.

configurare

când rulați Linux, clang-tidy este de obicei ușor de obținut prin managerul de pachete al distribuției. Pe Ubuntu Linux, de exemplu, instalarea acestuia este la fel de ușoară ca rularea următoarelor comenzi:

% sudo apt-get install clang-tidy

vom discuta despre instalarea instrumentului pe alte platforme decât Linux într-una din postările viitoare de pe blog.

notă: Vă recomandăm să instalați întotdeauna cea mai recentă versiune (la momentul scrierii, se recomandă versiunea bazată pe Clang/LLVM 3.9), deoarece numărul de pluginuri/Dame disponibile variază foarte mult de la versiune la versiune și crește constant.

Introducere

Notă: În această postare pe blog, zăngănit-tidy-3.9 A fost folosit

o invocare tipică a instrumentului de linie de comandă arată astfel:

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

executându-l astfel, instrumentul va imprima o grămadă de avertismente și note (dacă este cazul), exact în același mod în care Clang/GCC oferă și diagnostice.

zăngănit-Tidy este un instrument util de analiză statică pe cont propriu, cu o mulțime de diferite Dame disponibile, acest lucru, cu toate acestea, nu este punctul central al acestui post pe blog. Am prefera să folosim capacitățile puternice de refactorizare ale instrumentului pentru a ne moderniza codul sursă.

listarea Dame disponibile

rularea instrumentului fără parametri specifici de linie de comandă va rula setul implicit de dame activat de utilitate. Să verificăm ce alte dame are de oferit (prin trecere –controale=’*’ pentru a le vedea pe toate), și în mod specific grep pentru cei cu modernizarea în numele lor. Aceste dame pledează pentru utilizarea construcțiilor limbajului modern:

$ 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

o listă impresionantă de opțiuni deja, nu-i așa? Clang-Tidy livrează într-adevăr niște dame interesante din cutie (începând cu Clang/LLVM 3.9), lista crescând constant de la lansare la lansare.

numele de dame sunt destul de mult auto-explicative (de exemplu, modernize-use-auto va îmbrățișa folosind auto acolo unde este cazul), dar dacă doriți să explorați ce înseamnă fiecare dintre ele, vă rugăm să consultați lista de dame de pe pagina de start zăngănit-tidy:

pentru a arăta modul în care instrumentul este utilizat, să ne concentrăm pe verificatorul modernize-use-override, deoarece este cel mai aplicabil și cel mai necontroversat verificator.

refactorizarea unui singur fișier

exemplul nostru de suprascriere din nou:

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

rularea clang-tidy pe exemplu (de data aceasta cu verificatorul modernize-use-override activat):

% 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

bine. Deci, a observat că Derived::reimplementMe(int) suprascrie o metodă de clasă de bază, dar lipsește specificatorul override! Acum am putea adăuga asta manual … sau pur și simplu lăsați instrumentul să o facă pentru noi trecând-fix!

rulează-l pe exemplul (cu modernize-use-override checker & fix-sa activat):

% 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 a aplicat fix-it-ul și a introdus override după declarația metodei din linia 5. Gata!

câteva note

există câteva lucruri care merită menționate:

  • nu toate dame de zăngănit-tidy transporta de fapt fix-its, dar cele care încep cu modernizarea toate fac.
  • puteți utiliza fix-its De la mai multe dame în același timp (luați în considerare-checkers=’modernize-use-override,modernize-use-auto’ -fix)
  • rularea clang-tidy invocă interfața completă a compilatorului Clang, astfel va avea nevoie de ceva timp pentru a finaliza
  • rezultatele Refactorizării din clang-tidy sunt perfect exacte, datorită faptului că este susținută de un parser c++ complet 6122>

refactorizarea unui proiect complet (bazat pe CMake)

până acum am rulat zăngănit-ordonat pe un singur fișier, independent numai. Ce se întâmplă dacă aveți o configurare mai complexă a proiectului, cu o mulțime de fișiere, toate cu steaguri de compilare personalizate? Clang-tidy funcționează întotdeauna pe un singur fișier, sau mai degrabă, unitate de traducere. Putem ajuta instrumentul să dau seama corect compila steaguri pentru fiecare unitate de traducere vom compila în proiectul nostru. Cel mai convenabil mod de a rula este cu o bază de date de comandă compilare. CMake poate genera automat unul, și o dată pe compile_commands.json este în loc și o versiune de lucru a clang-tidy este în cale întreaga bază de cod poate fi analizată cu run-clang-tidy.script py (de obicei livrat ca parte a instalării). Dacă nu, îl puteți descărca pur și simplu aici.

Notă: este foarte recomandat să utilizați run-clang-tidy.py pentru a rula clang-tidy pe un întreg proiect, deoarece va rula instrumentul de mai multe ori în paralel și se asigură că execuțiile concurente nu interferează unele cu altele (de exemplu, evitând modificarea unui antet partajat în paralel și, la rândul său, generând Cod rupt).

generarea unui compile_commands.fișier json

pentru generarea compile_commands.fișier json într-un proiect bazat pe CMake, trebuie doar să rulați:

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

utilizați scriptul pentru a rula clang-tidy

acum, pentru a rula instrumentul cu verificările implicite pe fiecare unitate de traducere din proiect, pur și simplu invocați scriptul run-clang-tidy din Directorul cu compile_commands.fișier json:

% run-clang-tidy.py

așa cum am văzut anterior, acest lucru nu va modifica nimic până acum, deoarece am rulat clang-tidy cu doar verificările implicite activate. Pentru a rula, de exemplu, verificarea moderniza-utilizare-suprascrie pe toate unitățile de traduceri și de fapt refactor tot codul, este nevoie de această invocare:

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

asta e. clang-tidy va fi acum invocată pe fiecare unitate de traducere în proiectul dumneavoastră și va adăuga suprascrie în cazul în care lipsesc. Parametrul-antet-filtru=’.* ‘face sigur zăngănit-tidy refactors de fapt cod în anteturile consumate în unitatea de traducere. Parametrul checks=’ -*,… ‘ se asigură că toate verificările implicite sunt dezactivate.

rețineți că remedierile sunt aplicate numai după ce run-clang-tidy a terminat! Scriptul va înregistra doar modificările care urmează să fie efectuate și le va aplica simultan la sfârșit.

rularea altor Dame

din nou, modernizarea-utilizare-suprascrie este doar un exemplu, zăngănit-tidy are o mulțime de alte dame care sunt utile. Un alt super util este modernize-use-nullptr checker, care transformă 0 sau, de exemplu, NULL literali în versiunea modernă C++11 nullptr. Pentru a refactor toate utilizările literali stil vechi în proiectul dumneavoastră, pur și simplu a alerga:

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

de obicei, este o idee bună să efectuați un verificator după altul, comitând rezultate intermediare (gândiți-vă la „Port către C++11 nullptr”, „Port către C++11 override”,…) în sistemul dvs. de control al versiunii.

câteva exemple din lumea reală

am folosit personal zăngănit pe o mulțime de proiecte diferite deja, cu rezultate pozitive. Amintiți-vă, acest instrument are cunoștințe perfecte de codul dvs. (așa cum este, de fapt, folosind zăngănit compilator frontend) și, astfel, va refactor codul fără a introduce vreodată Cod rupt.

Exemple:

  • acest patch, de exemplu, portează toate bibliotecile cadrelor KDE către C++11 nullptr, atingând aproximativ 9000 de locații de cod diferite
  • acest patch portează baza codului de marmură KDE la C++11 suprascrie, atingând aproximativ 2300 de locații de cod diferite

concluzie

zăngănit este un instrument puternic ceea ce face ca portarea bazei de cod vechi către C++11 să fie o chestiune de rulare a unui singur liner. Vine cu un set excelent de dame implicite, iar lista celor suplimentare crește constant. Modernize-Dame poate fi folosit pentru a moderniza/refactor codul sursă pentru a utiliza noi caracteristici de limbaj c++.

în următoarea parte a acestei serii vom discuta despre cum să folosim clang-tidy la nivel de proiect cu alte sisteme de construire.

aveți nevoie de ajutor?

KDAB angajează mai mulți ingineri care lucrează cu zăngănit Scule pe o bază de zi cu zi. Suntem bucuroși să vă ajute în cazul în care aveți probleme cu ajutorul zăngăni scule în proiectul dumneavoastră sau doriți să obțineți cele mai multe din ea: permițându-ne să pună în aplicare controale de cod specifice proiectului sau rula instrumente automate refactoring pe baza de cod. Am ajutat clienții să – și modernizeze bazele de cod foarte mari folosind cu succes scule-ceva care nu ar fi fost fezabil pentru ei, făcând-o manual din punct de vedere al costurilor.

Contacteaza-ne

Facebook Twitter  LinkedIn  Email

Categorii: c++ / siguranță funcțională / cum să / bloguri KDAB / KDAB pe Qt / Scule

etichete: refactorizare automată / C++ / C++11 / C++14 / zăngănit / LLVM

Kevin Funk Senior inginer Software

Lasă un răspuns

Adresa ta de email nu va fi publicată.