Clang-Tidy, del 1: Moderniser kildekoden din Ved Hjelp Av C++11 / C++14automatisert refactoring av kildekoden din ved hjelp av kraftig åpen kildekode-verktøy

16.03.2017 Kevin Funk

 Facebook  Twitter  LinkedIn  E-Post

denne bloggserien vil introdusere clang-tidy-verktøyet Fra Clang / LLVM-prosjektet og vise hvordan du bruker det til å automatisk refactor C++ kildekode og integrere med ditt byggesystem, samt hvordan du bruker verktøyet på Andre plattformer enn Unices.

Motivasjon: the joy of legacy – kodebaser

C++11 la til en betydelig mengde Nye C++ – språkfunksjoner som hittil fortsatt ikke er brukt i sin fulle grad. De mest visuelle er sikkert auto, override, Lambda-uttrykk ,rekkeviddebasert for, uniform initialiseringssyntaks, du heter det. Mens C++11 er nå flere år allerede, er det fortsatt mange kodebaser som ikke bruker noen av de nye språkfunksjonene, det være seg ved politikk fra ledelsen, eller ved ren latskap for å unngå porting innsats fra utviklersiden. Clang-Tidy FRA LLVM compiler infrastructure-prosjektet er her for å i det minste overvinne sistnevnte, for å tillate automatisk refactoring av kildekoden din, slik at den bruker de nye språkfunksjonene.

Bruk overstyring, noen?

nå, hva skjer Hvis du allerede opprettholder en ganske stor kodebase som fortsatt kompilerer Under c++03-modus, men du vil omfavne Å bruke C++11 i fremtiden, med alle de nyttige funksjonene den har? Du vil sannsynligvis ha mye og mye kode som ligner på dette:

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

Så langt har du selvfølgelig alltid re-implementert riktig base-klasse metode, fordi du har grundig testet koden din via enhetstester! Selvfølgelig gjorde du det. Dermed er koden bra, men du vil nå fortsette. Du vil legge til override specifier til hver enkelt re-implementerte metode i kodebasen, men selvfølgelig uten å ansette en trainee som går gjennom koden linje for linje og legger dem manuelt.

Bare for å understreke at å legge til override faktisk tjener en hensikt, har vi nylig løst En feil I Qt 3D der vi ikke overbelastet riktig grunnklassemetode. Med specifier lagt til tidligere, ville vi ha lagt merke til umiddelbart, etter rekompilering.

Vi tar det manglende overstyringseksemplet videre for å forklare grunnleggende bruk av clang-tidy.

Clang-Tidy til unnsetning!

Clang-Tidy Er en clang-basert c++ linter verktøy som gir et skall kjørbar kalt clang-tidy som hoved inngangspunkt. Det er et utvidbart rammeverk for å diagnostisere typiske programmeringsfeil eller stilproblemer-generelt alt som kan oppdages under statisk analyse av koden. Den virkelige fordelen med verktøyet er at det i tillegg gjør det mulig å automatisk refactor kildekoden ved å bruke fixits hver enkelt sak kan gi. Det er tungt plugin-basert og kommer med et nyttig sett med plugins ut av boksen, som vi skal diskutere i neste avsnitt.

LLVM logo -- home of clang-tidy

Clang-Tidy er et verktøy utviklet og vedlikeholdt Av clang/LLVM samfunnet.

Oppsett

når du kjører Linux, er clang-tidy vanligvis lett å få via distribusjonens pakkebehandling. På Ubuntu Linux for eksempel er det like enkelt å installere det som å kjøre følgende kommandoer:

% sudo apt-get install clang-tidy

vi diskuterer installering av verktøyet på Andre plattformer Enn Linux i et av de kommende blogginnleggene.

Notat: Vi anbefaler at du alltid installerer den nyeste versjonen (i skrivende stund anbefales versjonen basert På Clang / LLVM 3.9), da antall tilgjengelige plugins / brikker varierer sterkt fra versjon til versjon og vokser hele tiden.

Innledning

Merk: i dette blogginnlegget ble clang-tidy-3.9 brukt

en typisk påkalling av kommandolinjeverktøyet ser slik ut:

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

Utfører det slik, vil verktøyet skrive ut en rekke advarsler og notater (hvis aktuelt), på nøyaktig samme måte Som Clang / GCC gir diagnostikk også.

Clang-Tidy er et nyttig statisk analyseverktøy på egen hånd med mange forskjellige tilgjengelige brikker, dette er imidlertid ikke fokus for dette blogginnlegget. Vi ønsker heller å utnytte verktøyets kraftige refactoring evner til å modernisere vår kildekode.

Oppføring av tilgjengelige brikker

Kjøring av verktøyet uten noen spesifikke kommandolinjeparametere vil kjøre standard sett med brikker aktivert av verktøyet. La oss sjekke hva andre brikker den har å tilby (ved å sende –sjekker=’*’ for å se dem alle), og spesielt grep for de med modernisere i deres navn. Disse brikkene fortaler bruk av moderne språkkonstruksjoner:

$ 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

Imponerende liste over alternativer allerede, er det ikke? Clang-Tidy sender faktisk noen interessante brikker ut av esken (fra Clang/LLVM 3.9), med listen som vokser hele tiden fra utgivelse til utgivelse.Modernize-use-auto vil omfavne bruk av auto der det er aktuelt), men hvis du vil utforske hva hver av dem betyr, vennligst se listen over brikker på clang-tidy hjemmeside:

for å vise hvordan verktøyet blir brukt, la oss fokusere på modernize-use-override checker, da det er den mest anvendelige og mest ukontroversielle checker.

Refactoring en enkelt fil

vårt overstyreeksempel igjen:

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

Running clang-tidy på eksemplet (denne gangen med modernize-use-override checker aktivert):

% 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

Ok. Så det la merke til at Derived::reimplementMe(int) overstyrer en grunnklassemetode, men mangler override specifier! Nå kan vi legge til det manuelt … eller bare la verktøyet gjøre det for oss ved å passere-fix!

Kjører det på eksemplet (med modernize-use-override checker & fix – its aktivert):

% 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 brukte fix-it, og satt inn override etter metodedeklarasjonen i linje 5. Ferdig!

et par notater

Det er noen ting verdt å nevne:

  • Ikke alle brikker av clang-ryddig faktisk bære fix-its, men de som starter med modernisere alle gjør.
  • du kan bruke fix-its fra flere brikker samtidig (vurder-checks=’modernize-use-override,modernize-use-auto’ -fix)
  • Running clang-tidy påkaller den komplette clang-kompilatoren frontend, og vil derfor trenge litt tid til å fullføre
  • Refactoring resultater fra clang-tidy er helt nøyaktige, fordi det støttes av en fullverdig C++ parser

refactoring et komplett prosjekt (cmake-basert)

så langt har vi kjørt clang-tidy på en enkelt, frittstående fil. Hva skjer hvis du har et mer komplekst prosjektoppsett, med mange filer, alle med tilpassede kompileringsflagg? Clang-tidy opererer alltid på en enkelt fil, eller rettere, oversettelsesenhet. Vi kan hjelpe verktøyet til å finne ut de riktige kompileringsflaggene for hver oversettelsesenhet vi kompilerer i vårt prosjekt. Den mest praktiske måten å kjøre den på er med en kompilere kommandodatabase. CMake kan automatisk generere en, og en gang en compile_commands.json er på plass og en fungerende versjon av clang-tidy er I BANE hele kodebasen kan analyseres med run-clang-tidy.py script (vanligvis sendt som en del av installasjonen). Hvis ikke kan du bare laste den ned her.

Merk: Det anbefales sterkt å bruke run-clang-tidy.py å kjøre clang-tidy på et helt prosjekt, siden det vil kjøre verktøyet flere ganger parallelt og sørger for at samtidige henrettelser ikke forstyrrer hverandre(f. eks.

Genererer en compile_commands.json-fil

for generering av compile_commands.json-fil i Et CMake-basert prosjekt, bare kjør:

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

Bruk skript til å kjøre clang-tidy

Nå for å kjøre verktøyet med standardkontrollene på hver oversettelsesenhet i prosjektet, bare påkall run-clang-tidy skriptet inne i katalogen med compile_commands.json fil:

% run-clang-tidy.py

Som sett før, vil dette ikke endre noe så langt, da vi har kjørt clang-tidy med bare standardkontrollene aktivert. Å f. eks kjøre modernize-use-override sjekk på alle oversettelser enheter og faktisk refactor all koden din, er dette påkalling nødvendig:

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

Sånn ja. clang-tidy vil nå påberopes på hver oversettelse enhet i prosjektet og vil legge overstyringer der mangler. Parameteren-header-filter=’.* ‘sørger for at clang-tidy faktisk refactors kode i overskriftene blir konsumert i oversettelsesenheten. Parameteren checks=’ -*,… ‘ sørger for at alle standardkontroller er deaktivert.

Merk at reparasjonene bare brukes i en gang run-clang-tidy er ferdig! Skriptet registrerer bare endringene som skal utføres og bruker dem alle samtidig på slutten.

Kjører andre brikker

igjen, moderniser-bruk-overstyringen er bare et eksempel, clang-tidy har mange andre brikker som er nyttige. En annen super nyttig er modernize-use-nullptr checker ,som forvandler 0, eller f. eks NULL bokstaver i moderne c++11 nullptr versjon. Å refactor all bruk av de gamle stil literals i prosjektet, bare kjøre:

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

det er vanligvis en god ide å utføre en kontroller etter hverandre, og begå mellomresultater (tenk på «Port mot C++11 nullptr», «Port mot C++11 override», …) i versjonskontrollsystemet.

noen virkelige eksempler

jeg har personlig brukt clang-tidy på mange forskjellige prosjekter allerede, med positive resultater. Husk at dette verktøyet har perfekt kunnskap om koden din (som det faktisk bruker clang compiler frontend) og dermed vil refactor koden din uten å innføre ødelagt kode.

Eksempler:

  • denne oppdateringen for eksempel porter ALLE KDE Rammer biblioteker mot C++11 nullptr, ved å berøre rundt 9000 forskjellige kode steder
  • denne oppdateringen porter Kde Marmor kodebasen Til C++11 overstyre, ved å berøre rundt 2300 forskjellige kode steder

Konklusjon

Clang-Tidy er en kraftig verktøy som gjør porting din arv kodebase mot c++11 et spørsmål Om Å Kjøre en one-liner. Den leveres med et stort sett med standard brikker og listen over flere som vokser stadig. Modernize-checkers kan brukes til å modernisere / refactor kildekoden til å bruke nye C++ språkfunksjoner.

i neste del av denne serien vil vi diskutere hvordan man bruker clang-tidy prosjektomfattende med andre byggesystemer.

Trenger du hjelp?

KDAB sysselsetter flere ingeniører som jobber med Klangverktøy på daglig basis. Vi er glade for å hjelpe deg i tilfelle du har problemer med Å bruke Clang Tooling i prosjektet eller ønsker å få mest mulig ut av det: ved å la oss implementere prosjektspesifikke kodesjekker eller kjøre automatiske refactoring verktøy på kodebasen. Vi har hjulpet kunder med å modernisere sine svært store kodebaser med å bruke verktøy-noe som ikke ville vært mulig for dem å gjøre det manuelt.

Kontakt oss

Facebook  Twitter  LinkedIn  E-Post

Kategorier: C++ / Funksjonell Sikkerhet / Hvordan / Kdab Blogger / KDAB På Qt / Verktøy

Tags: automatisert refactoring / C++ / C++11 / C++14 / Clang / LLVM

Kevin Funk Senior Programvareingeniør

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.