Clang-Tidy, část 1: modernizujte zdrojový kód pomocí C++11 / C++14automatizované refaktorování zdrojového kódu pomocí výkonných nástrojů s otevřeným zdrojovým kódem

16.03.2017 Kevin Funk

 Facebook TwitterLinkedIn Email

tato série blogů představí nástroj clang-tidy z projektu Clang/LLVM a ukáže, jak jej použít k automatickému refaktoru zdrojového kódu C++ a integraci s vaším systémem sestavení, a jak tento nástroj používat na jiných platformách než Unices.

motivace: radost ze starších kódových základen

C++11 přidala značné množství nových jazykových funkcí C++, které dosud nejsou plně využívány. Nejvíce vizuální jsou určitě auto, override, Lambda výrazy, rozsah založený na for, jednotná Inicializační syntaxe, pojmenujete to. Zatímco C++11 je již několik let starý, stále existuje spousta kódových základen, které nepoužívají žádné nové jazykové funkce, ať už je to politika ze strany správy nebo čistá lenost, aby se zabránilo Portování ze strany vývojáře. Clang-Tidy z projektu LLVM compiler infrastructure je tu, aby alespoň překonal ten druhý, aby umožnil automatické refaktorování zdrojového kódu, takže používá nové jazykové funkce.

použít přepsat, někdo?

co se stane, pokud již udržujete poměrně velkou kódovou základnu, která se stále kompiluje v režimu C++03, ale chcete v budoucnu používat C++11 se všemi užitečnými funkcemi, které má? Pravděpodobně budete mít spoustu a spoustu kódu podobného tomuto:

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

zatím jste samozřejmě vždy znovu implementovali správnou metodu základní třídy, protože jste svůj kód rozsáhle testovali pomocí jednotkových testů! Samozřejmě, že ano. Kód je tedy v pořádku, ale nyní byste chtěli jít dál. Chtěli byste přidat specifikátor override ke každé znovu implementované metodě ve vaší kódové základně, ale samozřejmě bez najímání praktikanta, který prochází kódovým řádkem po řádku a přidává je ručně.

abychom zdůraznili, že přidání override skutečně slouží účelu, nedávno jsme opravili chybu v Qt 3D, kde jsme nepřetěžovali správnou metodu základní třídy. S dříve přidaným specifikátorem bychom si všimli okamžitě po rekompilaci.

vezmeme příklad chybějícího přepisu, abychom vysvětlili základní použití clang-tidy.

Clang-uklizené na záchranu!

Clang-Tidy je Clang-based C++ linter nástroj, který poskytuje Shell spustitelný soubor s názvem clang-tidy jako hlavní vstupní bod. Jedná se o rozšiřitelný rámec pro diagnostiku typických programovacích chyb nebo problémů se stylem-obecně cokoli, co lze zjistit během statické analýzy kódu. Skutečnou výhodou tohoto nástroje je, že navíc umožňuje automaticky refaktor zdrojový kód použitím fixits každý jednotlivý problém může poskytnout. Je silně založen na pluginech a přichází s užitečnou sadou pluginů po vybalení z krabice, o které budeme diskutovat v dalším odstavci.

LLVM logo - domov clang-tidy

Clang-Tidy je nástroj vyvinutý a udržovaný komunitou Clang/LLVM.

nastavení

při spuštění Linuxu se clang-tidy obvykle snadno dostanete prostřednictvím správce balíčků vaší distribuce. Například v Ubuntu Linux je instalace stejně snadná jako spuštění následujících příkazů:

% sudo apt-get install clang-tidy

budeme diskutovat o instalaci nástroje na jiné platformy než Linux V jednom z nadcházejících blogových příspěvků.

Poznámka: Doporučujeme vám vždy nainstalovat nejnovější verzi (v době psaní se doporučuje verze založená na Clang/LLVM 3.9), protože počet dostupných pluginů/dám se v jednotlivých verzích velmi liší a neustále roste.

Úvod

Poznámka: V tomto blogu byl použit clang-tidy-3.9

typické vyvolání nástroje příkazového řádku vypadá takto:

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

tímto způsobem nástroj vytiskne spoustu varování a poznámek (pokud je to možné), přesně stejným způsobem Clang/GCC poskytuje diagnostiku.

Clang-Tidy je užitečný statický analytický nástroj sám o sobě se spoustou různých dostupných dám, to však není předmětem tohoto blogu. Raději bychom chtěli využít výkonné refaktorovací schopnosti nástroje k modernizaci našeho zdrojového kódu.

Výpis dostupných dám

spuštění nástroje bez konkrétních parametrů příkazového řádku spustí výchozí sadu dám povolených nástrojem. Podívejme se, jaké další dámy nabízí (předáním-checks=’*‘, abychom je viděli všechny), a konkrétně grep pro ty, kteří mají modernizovat ve svých jménech. Tyto dámy obhajují používání moderních jazykových konstrukcí:

$ 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

působivý seznam možností, že? Clang-Tidy skutečně dodává některé zajímavé dámy z krabice (od Clang / LLVM 3.9), přičemž seznam neustále roste od vydání k vydání.

názvy dám jsou do značné míry samovysvětlující (např. modernizovat-use-auto bude zahrnovat použití auto tam, kde je to možné), ale pokud chcete prozkoumat, co každý z nich znamená, prostudujte si seznam dám na domovské stránce clang-tidy:

Chcete-li ukázat, jak se nástroj používá, Zaměřme se na kontrolu modernizace-použití-přepsání, protože je to nejpoužívanější a nejkontroverznější kontrola.

refaktorování jednoho souboru

náš příklad přepsání znovu:

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

spuštění clang-tidy na příkladu (tentokrát s povolenou kontrolou modernize-use-override):

% 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

dobře. Takže si všiml, že Derived::reimplementMe(int) přepíše metodu základní třídy, ale chybí specifikátor override! Nyní bychom mohli přidat, že ručně … nebo jen nechat nástroj udělat pro nás tím, že projde-fix!

spuštění na příkladu (s 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 použil fix-it a vložil override za prohlášení o metodě v řádku 5. Hotovo!

pár poznámek

za zmínku stojí několik věcí:

  • ne všechny dámy clang-tidy ve skutečnosti nesou fix-its, ale ty, které začínají modernizovat všechny.
  • můžete použít fix-its z více dáma ve stejnou dobu (zvážit-kontroly=’modernizovat-use-override,modernizovat-use-auto‘ -fix)
  • Běh clang-tidy vyvolá kompletní Clang kompilátor frontend, tedy bude potřebovat nějaký čas k dokončení
  • refaktoring výsledky z clang-tidy jsou naprosto přesné, vzhledem k tomu, že je podpořen plnohodnotným C++ parser

refaktorování kompletního projektu (CMake-based)

zatím jsme spustili Clang-tidy pouze na jednom samostatném souboru. Co se stane, pokud máte složitější nastavení projektu, se spoustou souborů, vše s vlastními kompilačními vlajkami? Clang-tidy vždy pracuje na jednom souboru, nebo spíše na Překladové jednotce. Můžeme pomoci nástroji zjistit správné příznaky kompilace pro každou překladovou jednotku, kterou kompilujeme v našem projektu. Nejpohodlnější způsob, jak jej spustit, je databáze příkazů kompilace. CMake může automaticky generovat jeden, a jednou compile_commands.json je na svém místě a pracovní verze clang-tidy je v cestě celá kódová základna může být analyzována pomocí run-clang-tidy.PY skript (obvykle dodáván jako součást instalace). Pokud ne, můžete si jej jednoduše stáhnout zde.

Poznámka: důrazně se doporučuje používat run-clang-tidy.py spustit clang-tidy na celém projektu, protože bude spouštět nástroj vícekrát paralelně a zajistí, že souběžné spuštění nebudou vzájemně rušit (např. tím, že se vyhnete paralelní úpravě sdílené hlavičky a generujete nefunkční kód).

generování compile_commands.json soubor

pro generování compile_commands.soubor json v projektu založeném na CMake, stačí spustit:

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

použijte skript ke spuštění Clang-tidy

nyní pro spuštění nástroje s výchozími kontrolami na každé Překladové jednotce v projektu jednoduše vyvolejte skript run-clang-tidy uvnitř adresáře s compile_commands.json soubor:

% run-clang-tidy.py

jak bylo vidět dříve, zatím to nic nezmění, protože jsme spustili clang-tidy pouze s povolenými výchozími kontrolami. Chcete-li například spustit kontrolu modernizovat-use-override na všech překladových jednotkách a skutečně refaktorovat celý kód, je toto vyvolání nutné:

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

to je ono. clang-tidy bude nyní vyvolán na každé Překladové jednotce ve vašem projektu a přidá přepisy, pokud chybí. Parametr-header-filter=‘.* ‚zajišťuje, že clang-tidy skutečně refactors kód v hlavičkách spotřebovaných v Překladové jednotce. Parametr checks=‘ -*,… ‚ zajistí, že všechny výchozí kontroly jsou zakázány.

Všimněte si, že opravy se použijí pouze po dokončení run-clang-tidy! Skript bude zaznamenávat pouze změny, které mají být provedeny, a použije je všechny najednou na konci.

spuštění dalších dám

Opět platí, že modernizovat-use-override je jen příklad, clang-tidy má spoustu dalších dám, které jsou užitečné. Dalším velmi užitečným je kontrola modernize-use-nullptr, která transformuje 0 nebo např. NULL literály na moderní verzi C++11 nullptr. Chcete-li refaktorovat všechna použití starých literálů ve vašem projektu, jednoduše spusťte:

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

obvykle je vhodné provést jednu kontrolu za druhou a odevzdat průběžné výsledky (přemýšlejte o“ Port towards C++11 nullptr“,“ Port towards C++11 override“,…) do vašeho systému řízení verzí.

některé příklady reálného světa

osobně jsem použil clang-tidy na mnoha různých projektech již s pozitivními výsledky. Nezapomeňte, že tento nástroj má dokonalou znalost vašeho kódu (jak je to ve skutečnosti pomocí frontendu kompilátoru Clang), a tak refaktoruje váš kód, aniž by kdy zavedl zlomený kód.

příklady:

  • tato oprava například portuje všechny knihovny rámců KDE směrem k C++11 nullptr, dotykem kolem 9000 různých umístění kódu
  • Tato oprava porty kde Marble kódovou základnu na C++11 přepsat, dotykem kolem 2300 různých umístění kódu

závěr

Clang-Tidy je mocný nástroj, který umožňuje Portování vaší starší kódové základny směrem k C++11 otázkou spuštění jedné vložky. Dodává se s velkou sadou výchozích dám a seznam dalších neustále roste. Modernizovat-dáma může být použit k modernizaci / refaktor zdrojový kód používat nové funkce jazyka C++.

v další části této série budeme diskutovat o tom, jak používat clang-tidy project-wide s jinými systémy sestavení.

potřebujete pomoc?

KDAB zaměstnává několik inženýrů, kteří denně pracují s nástroji Clang. Rádi vám pomůžeme v případě, že máte problémy s používáním nástrojů Clang ve vašem projektu nebo chcete z toho vytěžit maximum: tím, že nám umožníte implementovat kontroly kódu specifické pro projekt nebo spustit automatické refaktorovací nástroje na základně kódu. Pomohli jsme klientům úspěšně modernizovat jejich velmi velké kódové základny pomocí nástrojů-něco, co by pro ně nebylo nákladově proveditelné, dělat to ručně.

kontaktujte nás

FacebookTwitterLinkedIn Email

kategorie: C++ / funkční bezpečnost / Jak / Kdab blogy / KDAB na Qt / nástroje

tagy: automatické refaktorování / C++ / C++11 / C++14 / Clang / LLVM

Kevin Funk Senior softwarový inženýr

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.