Clang-Tidy, osa 1: modernisoi lähdekoodisi käyttämällä C++11/c++14-lähdekoodin automaattista refaktorointia tehokkaalla avoimen lähdekoodin työkalulla

16.03.2017 Kevin Funk

 Facebook Twitter LinkedIn Sähköposti

tässä blogisarjassa esitellään clang-tidy-apuohjelma Clang / LLVM-projektista ja näytetään, miten sitä käytetään automaattisesti palauttamaan C++ – lähdekoodi ja integroimaan build-järjestelmään sekä miten työkalua käytetään muilla alustoilla kuin Unices.

Motivation: the joy of legacy code bases

C++11 lisäsi siihen huomattavan määrän uusia C++ – kielen ominaisuuksia, joita ei toistaiseksi vielä käytetä täysin. Visuaalisimmat ovat varmuudella auto, override, Lambda-lausekkeet, kantamallipohjaiset for, yhtenäinen alustussyntaksi, you name it. Vaikka C++11 on jo useita vuosia vanha, siellä on vielä paljon koodipohjia, jotka eivät käytä mitään uuden kielen ominaisuuksia, olipa se politiikan johdon, tai puhdas laiskuus välttää siirtämistä vaivaa kehittäjäpuolelta. Clang-Tidy alkaen LLVM compiler infrastructure project on täällä ainakin voittaa jälkimmäinen, jotta automaattinen refactoring Oman lähdekoodin joten se käyttää uutta kieltä ominaisuuksia.

Käytätkö ohitusta?

nyt, mitä tapahtuu, jos sinulla on jo ennestään melko suuri koodikanta, joka vielä koostetaan C++03-tilassa, mutta haluat kuitenkin omaksua C++11: n käytön tulevaisuudessa, kaikkine hyödyllisine ominaisuuksineen? Sinulla todennäköisesti on paljon ja paljon koodia samanlainen kuin tämä:

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

tähän mennessä olet tietenkin aina uudelleen käyttöön oikea perusluokan menetelmä, koska olet laajasti testannut koodin kautta yksikkö testit! Tietenkin. Joten koodi on hyvä, mutta haluat nyt siirtyä eteenpäin. Haluat lisätä override specifierin jokaiseen uudelleen toteutettuun menetelmään koodikannassasi, mutta tietenkin palkkaamatta harjoittelijaa, joka käy koodin rivi riviltä läpi ja lisää ne käsin.

korostaakseni, että override lisääminen todellakin palvelee tarkoitusta, olemme juuri äskettäin korjanneet vian Qt 3D: ssä, jossa emme ylikuormittaneet oikeaa perusluokan menetelmää. Kun specifier olisi lisätty aiemmin, olisimme huomanneet heti, kun recompilation.

otamme puuttuvan ohitusesimerkin tarkemmin selittämään clang-tidyn peruskäyttöä.

Clang-Tidy to the rescue!

Clang-Tidy on clang-pohjainen C++ linter-työkalu, joka tarjoaa pääsyöttöpisteeksi clang-tidy-nimisen shell-suoritustiedoston. Se on laajennettavissa oleva kehys tyypillisten ohjelmointivirheiden tai tyyliongelmien diagnosointiin-yleensä mitä tahansa, mikä voidaan havaita koodin staattisen analyysin aikana. Todellinen hyöty työkalu on, että se lisäksi mahdollistaa automaattisesti refactor lähdekoodi soveltamalla fixits kunkin yksittäisen ongelman voi tarjota. Se on voimakkaasti plugin-pohjainen ja mukana hyödyllinen joukko plugins Out of the box, jonka aiomme keskustella seuraavassa kappaleessa.

LLVM logo -- koti clang-tidy

Clang-Tidy on clang/LLVM-yhteisön kehittämä ja ylläpitämä työkalu.

Setup

Linuxia ajettaessa clang-tidy on yleensä helppo saada oman jakelun paketinhallinnan kautta. Esimerkiksi Ubuntu Linuxissa sen asentaminen on yhtä helppoa kuin seuraavien komentojen suorittaminen:

% sudo apt-get install clang-tidy

keskustelemme työkalun asentamisesta muille alustoille kuin Linuxille yhdessä tulevista blogikirjoituksista.

Huom.: Suosittelemme aina asentaa uusimman version (kirjoitushetkellä, versio perustuu Clang/LLVM 3.9 suositellaan), koska määrä saatavilla plugins/Tammi vaihtelee suuresti versiosta toiseen ja kasvaa jatkuvasti.

Johdanto

huomaa: tässä blogikirjoituksessa käytettiin clang-tidy – 3.9: ää

tyypillinen komentorivityökalun kutsu näyttää tältä:

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

sen suorittaminen näin, työkalu tulostaa joukon varoituksia ja muistiinpanoja (tarvittaessa), täsmälleen samalla tavalla Clang/GCC tarjoavat diagnostiikka, liian.

Clang-Tidy on sinänsä hyödyllinen staattinen analyysityökalu, jossa on paljon erilaisia käytettävissä olevia nappuloita, mutta tämä ei kuitenkaan ole tämän blogikirjoituksen painopiste. Haluamme mieluummin hyödyntää työkalun tehokkaita refaktorointiominaisuuksia modernisoidaksemme lähdekoodiamme.

listaus käytettävissä olevista tarkistimista

työkalun ajaminen ilman erityisiä komentoriviparametreja ajaa apuohjelman mahdollistamien tarkistimien oletusjoukon. Katsotaanpa tarkistaa, mitä muita nappuloita se on tarjota (passing –tarkastukset=’*’ nähdä ne kaikki), ja erityisesti grep niille, joilla modernisoida niiden nimissä. Nämä Tammi puoltaa käyttö modernin kielen konstruktioita:

$ 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

vaikuttava lista vaihtoehtoja jo, eikö? Clang-Tidy todellakin aluksia joitakin mielenkiintoisia nappuloita kättelyssä (kuten Clang / LLVM 3.9), jossa luettelo kasvaa jatkuvasti julkaisusta julkaisuun.

nappuloiden nimet ovat melko itsestään selviä (esim. modernize-use-auto omaksuu tarvittaessa automaattisen käytön), mutta jos haluat tutkia, mitä kukin niistä tarkoittaa, tutustu nappuloiden listaan clang-tidy-kotisivulla:

näyttääksemme kuinka työkalua käytetään keskitytään modernisoida-käyttää-ohittaa-tarkistimeen, koska se on sovellettavin ja kiistattomin tarkistin.

Refactoring a single file

our override example again:

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

käynnissä clang-tidy esimerkissä (tällä kertaa modernize-use-override checker käytössä):

% 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

hyvä on. Niinpä se huomasi, että Derived::reimplementMe(int) ohittaa perusluokkamenetelmän, mutta siitä puuttuu override specifier! Nyt voisimme lisätä, että manuaalisesti… tai vain anna työkalun tehdä sen meille syöttämällä-fix!

ajaa sitä esimerkillä (modernize-use-override checker & fix – its enabled):

% 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 sovelsi fix-it: tä ja lisäsi override menetelmän ilmoituksen jälkeen riville 5. Sovittu!

pari säveltä

on muutama mainitsemisen arvoinen asia:

  • ei kaikki nappuloita clang-siisti todella kuljettaa fix-its, mutta ne, jotka alkavat modernisoida kaikki eivät.
  • voit käyttää fix-its-ohjelmaa usealta tarkistajalta samaan aikaan (consider-checks= ”modernize-use-override,modernize-use-auto” -fix)
  • Running clang-tidy laskuttaa koko Clang-kääntäjän frontendin, joten tarvitset jonkin aikaa
  • Refactoring tulokset clang-tidystä ovat täysin tarkkoja, koska sen takana on täysimittainen C++ jäsennin

refactoring a complete project (cmake-based)

so far we’ve run clang-tidy on a single, Standalone File only. Mitä tapahtuu, jos sinulla on monimutkaisempi projektiasetus, jossa on paljon tiedostoja, joissa kaikissa on omat compile-liput? Clang-tidy toimii aina yhdellä tiedostolla tai pikemminkin käännösyksiköllä. Voimme auttaa työkalu selvittää oikea kääntää liput kunkin käännösyksikkö kokoamme meidän projekti. Kätevin tapa suorittaa se on compile komentotietokanta. CMake voi automaattisesti luoda yhden, ja kerran compile_commands.json on paikallaan ja toimiva versio clang-tidy on polku koko koodin pohja voidaan analysoida run-clang-tidy.py script (yleensä toimitetaan osana asennusta). Jos ei voit ladata sen täältä.

Huom: on erittäin suositeltavaa käyttää run-clang-tidy.py voit suorittaa clang-tidyn koko projektissa, koska se ajaa työkalun useita kertoja rinnakkain ja varmistaa, että samanaikaiset suoritukset eivät häiritse toisiaan (esim.välttämällä jaetun otsakkeen muokkaamista rinnakkain ja luo puolestaan rikkinäistä koodia).

generoidaan compile_commands.JSON file

for generating the compile_commands.JSON-tiedosto CMake-pohjaisessa projektissa, suorita vain:

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

käytä komentosarjaa clang-tidyn ajamiseen

nyt, kun haluat suorittaa työkalun projektin jokaisen käännösyksikön oletustarkistuksilla, käytä komentosarjaa kansiossa compile_commands-komennolla.json-tiedosto:

% run-clang-tidy.py

kuten aiemmin on nähty, tämä ei muuta mitään toistaiseksi, koska olemme ajaneet clang-tidy vain oletustarkistukset käytössä. Voit esimerkiksi suorittaa modernize-use-override-tarkistuksen kaikille käännösyksiköille ja palauttaa kaikki koodisi, tätä kutsumista tarvitaan:

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

juuri noin. clang-tidy otetaan nyt käyttöön jokaisessa projektisi käännösyksikössä ja lisätään ohitukset, jos ne puuttuvat. The parameter-header-filter=”.* ”varmistaa, että clang-tidy todella refactors koodi otsikot kulutetaan käännösyksikkö. Parametri checks=’ -*,… ’ varmistaa, että kaikki oletustarkistukset on poistettu käytöstä.

huomaa, että korjauksia tehdään vain kerran ajettaessa-clang-tidy on valmis! Skripti tallentaa vain suoritettavat muutokset ja soveltaa ne kaikki kerralla lopussa.

muiden nappuloiden ajaminen

taas modernisoitu-käytä-ohitus on vain esimerkki, clang-tidyssä on paljon muitakin nappuloita, jotka ovat hyödyllisiä. Toinen superhyödyllinen on modernize-use-nullptr-tarkistin, joka muuntaa 0: n eli esimerkiksi NULL literals: n nykyaikaiseksi C++11 nullptr versioksi. Refactor kaikki käyttötarkoitukset vanhan tyylin literals projektissasi, yksinkertaisesti ajaa:

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

on yleensä hyvä idea suorittaa tarkistin toisensa jälkeen, toimittaen välituloksia (ajattele ”portti kohti c++11 nullptr”, ”portti kohti c++11 ohitus”,…) versionhallintajärjestelmääsi.

joitakin reaalimaailman esimerkkejä

olen itse käyttänyt clang-tidyä jo monissa eri projekteissa, positiivisin tuloksin. Muista, tämä työkalu on täydellinen tieto koodin (koska se on itse asiassa käyttäen Clang kääntäjä frontend) ja siten refactor koodin ilman koskaan käyttöön rikki koodi.

esimerkkejä:

  • tämä korjaus esimerkiksi porttaa kaikki KDE: n Frameworks-kirjastot C++11 nullptr: ään koskettamalla noin 9000 eri koodipaikkaa
  • tämä paikkaus porttaa KDE: n Marmorikoodipohjan C++11: een ohittaen noin 2300 eri koodipaikkaa

johtopäätös

Clang-Tidy on tehokas työkalu, joka tekee vanhan koodikannan siirtämisestä kohti c++11: tä yhden linerin ajamisesta. Sen mukana tulee suuri joukko oletustarkistimia ja luettelo muista kasvaa jatkuvasti. Modernize-nappulaa voidaan käyttää lähdekoodin modernisointiin/refaktoriin uusien C++ – kielen ominaisuuksien käyttämiseksi.

sarjan seuraavassa osassa keskustellaan siitä, miten clang-tidy-projektia voidaan käyttää muiden rakennusjärjestelmien kanssa.

Tarvitsetko apua?

KDAB työllistää useita insinöörejä, jotka työskentelevät päivittäin Clang-työkalujen parissa. Olemme iloisia voidessamme auttaa sinua, jos sinulla on ongelmia Clang-työkalujen käytössä projektissasi tai haluat saada siitä kaiken irti: antamalla meidän toteuttaa projektikohtaisia kooditarkistuksia tai ajaa automaattisia refactoring-työkaluja koodikantaasi. Olemme auttaneet asiakkaita modernisoimalla heidän erittäin suuri koodi emäkset onnistuneesti työkaluilla-jotain, joka ei olisi ollut mahdollista heille kustannustehokkaasti tehdä se manuaalisesti.

ota yhteyttä

FacebookTwitter LinkedIn  Sähköposti

Kategoriat: C++ / Toimintaturvallisuus / miten / Kdab blogit / KDAB Qt / Työkalut

tunnisteet: automaattinen refaktorointi / C++ / C++11 / c++14 / Clang / LLVM

Kevin Funk vanhempi ohjelmistoinsinööri

Vastaa

Sähköpostiosoitettasi ei julkaista.