Clang-Tidy, Teil 1: Modernisieren Sie Ihren Quellcode mit C ++ 11 / C ++ 14automatisiertes Refactoring Ihres Quellcodes mit leistungsstarken Open-Source-Tools

16.03.2017 Kevin Funk

FacebookZwitschernLinkedInEmail

In dieser Blogserie wird das clang-tidy-Dienstprogramm aus dem Clang / LLVM-Projekt vorgestellt und gezeigt, wie Sie damit C ++ – Quellcode automatisch umgestalten und in Ihr Build-System integrieren sowie das Tool auf anderen Plattformen als Unices verwenden können.

Motivation: Die Freude an Legacy-Codebasen

C ++ 11 hat eine beträchtliche Anzahl neuer C ++ – Sprachfunktionen hinzugefügt, die bisher noch nicht in vollem Umfang genutzt werden. Die visuellsten sind sicher auto, override, Lambda-Ausdrücke, bereichsbasierte for, einheitliche Initialisierungssyntax, wie Sie es nennen. Während C ++ 11 jetzt schon einige Jahre alt ist, gibt es immer noch viele Codebasen, die keine der neuen Sprachfunktionen verwenden, sei es durch Richtlinien des Managements oder durch reine Faulheit, um den Portierungsaufwand von der Entwicklerseite zu vermeiden. Clang-Tidy aus dem LLVM-Compiler-Infrastrukturprojekt ist hier, um zumindest letzteres zu überwinden und ein automatisches Refactoring Ihres Quellcodes zu ermöglichen, damit die neuen Sprachfunktionen verwendet werden.

Überschreiben verwenden, jemand?

Was passiert nun, wenn Sie bereits eine ziemlich große Codebasis pflegen, die noch im C ++ 03-Modus kompiliert wird, aber Sie möchten in Zukunft C ++ 11 mit all den hilfreichen Funktionen verwenden? Sie werden wahrscheinlich viele, viele ähnliche Codes haben:

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

Bisher haben Sie natürlich immer die richtige Basisklassenmethode neu implementiert, da Sie Ihren Code ausführlich über Komponententests getestet haben! Natürlich hast du das. Der Code ist also in Ordnung, aber Sie möchten jetzt fortfahren. Sie möchten den override -Bezeichner zu jeder einzelnen re-implementierten Methode in Ihrer Codebasis hinzufügen, aber natürlich ohne einen Auszubildenden einzustellen, der den Code Zeile für Zeile durchläuft und manuell hinzufügt.

Nur um zu betonen, dass das Hinzufügen von override tatsächlich einen Zweck erfüllt, haben wir kürzlich einen Fehler in Qt 3D behoben, bei dem wir die richtige Basisklassenmethode nicht überladen haben. Mit dem zuvor hinzugefügten Spezifizierer hätten wir es nach der Neukompilierung sofort bemerkt.

Wir nehmen das missing-override-Beispiel weiter, um die grundlegende Verwendung von clang-tidy zu erklären.

Clang-Tidy zur Rettung!

Clang-Tidy ist ein Clang-basiertes C ++ Linter-Tool, das eine ausführbare Shell namens clang-tidy als Haupteinstiegspunkt bereitstellt. Es ist ein erweiterbares Framework zur Diagnose typischer Programmierfehler oder Stilprobleme — im Allgemeinen alles, was während der statischen Analyse des Codes erkannt werden kann. Der eigentliche Vorteil des Tools besteht darin, dass es zusätzlich ermöglicht, den Quellcode automatisch zu refaktorieren, indem Fixits angewendet werden, die jedes einzelne Problem bereitstellen kann. Es ist stark Plugin-basiert und kommt mit einem nützlichen Satz von Plugins aus der Box, die wir im nächsten Absatz diskutieren werden.

LLVM-Logo - Heimat von clang-tidy

Clang-Tidy ist ein Tool, das von der Clang / LLVM-Community entwickelt und gepflegt wird.

Setup

Unter Linux ist clang-tidy normalerweise einfach über den Paketmanager Ihrer Distribution zu erhalten. Unter Ubuntu Linux ist die Installation beispielsweise so einfach wie das Ausführen der folgenden Befehle:

% sudo apt-get install clang-tidy

Wir werden die Installation des Tools auf anderen Plattformen als Linux in einem der kommenden Blogbeiträge diskutieren.

Hinweis: Wir empfehlen Ihnen, immer die neueste Version zu installieren (zum Zeitpunkt des Schreibens wird die auf Clang / LLVM 3.9 basierende Version empfohlen), da die Anzahl der verfügbaren Plugins / Checker von Version zu Version stark variiert und ständig wächst.

Einführung

Hinweis: In diesem Blogbeitrag wurde clang-tidy-3.9 verwendet

Ein typischer Aufruf des Befehlszeilentools sieht folgendermaßen aus:

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

Wenn Sie es so ausführen, druckt das Tool eine Reihe von Warnungen und Notizen (falls zutreffend), genauso wie Clang / GCC auch Diagnosen bereitstellen.

Clang-Tidy ist ein nützliches statisches Analysetool mit vielen verschiedenen verfügbaren Checkern, dies steht jedoch nicht im Mittelpunkt dieses Blogbeitrags. Wir möchten lieber die leistungsstarken Refactoring-Funktionen des Tools nutzen, um unseren Quellcode zu modernisieren.

Listing available checkers

Wenn Sie das Tool ohne bestimmte Befehlszeilenparameter ausführen, wird der vom Dienstprogramm aktivierte Standardsatz von Checkern ausgeführt. Lassen Sie uns überprüfen, welche anderen Checker es zu bieten hat (indem Sie –checks=’*‘ , um sie alle zu sehen), und speziell grep für diejenigen mit modernize in ihren Namen. Diese Prüfer befürworten die Verwendung moderner Sprachkonstrukte:

$ 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

Beeindruckende Liste von Optionen bereits, nicht wahr? Clang-Tidy liefert in der Tat einige interessante Checkers aus (ab Clang / LLVM 3.9), wobei die Liste von Release zu Release ständig wächst.

Die Namen der Kontrolleure sind ziemlich selbsterklärend (z. B. modernize-use-auto umfasst gegebenenfalls die Verwendung von auto), aber wenn Sie herausfinden möchten, was jeder von ihnen bedeutet, konsultieren Sie bitte die Liste der Kontrolleure auf der clang-tidy-Homepage:

Um zu zeigen, wie das Tool verwendet wird, konzentrieren wir uns auf den modernize-use-override Checker, da er der am besten anwendbare und umstrittenste Checker ist.

Refactoring einer einzelnen Datei

Unser Override-Beispiel wieder:

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

Ausführen von clang-tidy im Beispiel (diesmal mit aktiviertem modernize-use-Override-Checker):

% 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

Okay. Es ist also aufgefallen, dass Derived::reimplementMe(int) eine Basisklassenmethode überschreibt, aber der override -Bezeichner fehlt! Jetzt könnten wir das manuell hinzufügen … oder einfach das Tool es für uns tun lassen, indem wir -fix !

Ausführen im Beispiel (mit modernize-use-override checker & fix-its aktiviert):

% 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 hat das Fix-it angewendet und override nach der Methodendeklaration in Zeile 5 eingefügt. Fertig!

Ein paar Anmerkungen

Es gibt ein paar erwähnenswerte Dinge:

  • Nicht alle Kontrolleure von clang-tidy tragen tatsächlich Fix-its, aber diejenigen, die mit modernize beginnen, tun es alle.
  • Sie können fix-its von mehreren Checkern gleichzeitig verwenden (consider-checks=’modernize-use-override,modernize-use-auto‘ -fix)
  • Das Ausführen von clang-tidy ruft das komplette Clang-Compiler-Frontend auf und benötigt daher einige Zeit, um abzuschließen
  • Die Refactoring-Ergebnisse von clang-tidy sind absolut genau, da sie von einem vollwertigen C ++ – Parser unterstützt werden

Refactoring eines kompletten Projekts (CMake-basiert)

Bisher haben wir clang-tidy nur für eine einzelne eigenständige Datei ausgeführt. Was passiert, wenn Sie ein komplexeres Projekt-Setup mit vielen Dateien und benutzerdefinierten Kompilierungsflags haben? Clang-tidy arbeitet immer mit einer einzigen Datei bzw. Übersetzungseinheit. Wir können dem Tool helfen, die richtigen Kompilierungsflags für jede Übersetzungseinheit herauszufinden, die wir in unserem Projekt kompilieren. Der bequemste Weg, es auszuführen, ist mit einer Kompilierungsbefehlsdatenbank. CMake kann automatisch generieren, und einmal ein compile_commands.json ist vorhanden und eine funktionierende Version von clang-tidy ist in PATH Die gesamte Codebasis kann mit run-clang-tidy analysiert werden.py-Skript (in der Regel als Teil der Installation ausgeliefert). Wenn nicht, können Sie es einfach hier herunterladen.

Hinweis: Es ist sehr zu empfehlen run-clang-tidy.py um clang-tidy für ein ganzes Projekt auszuführen, wird das Tool mehrmals parallel ausgeführt und es wird sichergestellt, dass sich gleichzeitige Ausführungen nicht gegenseitig stören (z. B. indem vermieden wird, einen gemeinsam genutzten Header parallel zu ändern und wiederum fehlerhaften Code zu generieren).

Erzeugen eines compile_commands.json-Datei

Zum Generieren der compile_commands.json-Datei in einem CMake-basierten Projekt, führen Sie einfach:

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

Skript zum Ausführen von clang-tidy verwenden

Um das Tool mit den Standardprüfungen für jede Übersetzungseinheit im Projekt auszuführen, rufen Sie einfach das Skript run-clang-tidy im Verzeichnis mit den compile_commands auf.json-Datei:

% run-clang-tidy.py

Wie bereits erwähnt, wird dies bisher nichts ändern, da wir clang-tidy nur mit aktivierten Standardprüfungen ausgeführt haben. Um beispielsweise die modernize-use-Override-Prüfung für alle Übersetzungseinheiten auszuführen und tatsächlich Ihren gesamten Code umzugestalten, ist dieser Aufruf erforderlich:

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

Das war’s. clang-tidy wird jetzt für jede Übersetzungseinheit in Ihrem Projekt aufgerufen und fügt Überschreibungen hinzu, falls diese fehlen. Der Parameter -header-filter=‘.*‘ stellt sicher, dass clang-tidy Code in den Headern, die in der Übersetzungseinheit verbraucht werden, tatsächlich umgestaltet. Der Parameter checks=‘-*,…‘ stellt sicher, dass alle Standardprüfungen deaktiviert sind.

Beachten Sie, dass die Korrekturen erst angewendet werden, wenn run-clang-tidy abgeschlossen ist! Das Skript zeichnet nur die durchzuführenden Änderungen auf und wendet sie am Ende alle gleichzeitig an.

Ausführen anderer Checker

Auch hier ist das modernize-use-override nur ein Beispiel, clang-tidy hat viele andere Checker, die nützlich sind. Ein weiterer sehr nützlicher ist der modernize-use-nullptr Checker, der 0 oder zB NULL Literale in die moderne C ++ 11 nullptr Version umwandelt. Um alle Verwendungen der Literale im alten Stil in Ihrem Projekt umzugestalten, führen Sie einfach Folgendes aus:

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

Es ist normalerweise eine gute Idee, einen Checker nach dem anderen durchzuführen und Zwischenergebnisse (denken Sie an „Port towards C ++ 11 nullptr“, „Port towards C ++ 11 override“, …) in Ihr Versionskontrollsystem zu übernehmen.

Einige Beispiele aus der Praxis

Ich habe clang-tidy bereits bei vielen verschiedenen Projekten mit positiven Ergebnissen verwendet. Denken Sie daran, dass dieses Tool Ihren Code perfekt kennt (da es tatsächlich das Clang-Compiler-Frontend verwendet) und somit Ihren Code umgestaltet, ohne jemals fehlerhaften Code einzuführen.

Beispiele:

  • Dieser Patch portiert beispielsweise alle KDE-Frameworks-Bibliotheken in Richtung C ++ 11 nullptr, indem er etwa 9000 verschiedene Codestellen berührt
  • Dieser Patch portiert die KDE-Frameworks-Codebasis auf C ++11 Override, indem er etwa 2300 verschiedene Codestellen berührt

Fazit

Clang-Tidy ist ein das macht die Portierung Ihrer Legacy-Codebasis in Richtung C ++ 11 zu einer Frage des Einzeilers. Es kommt mit einem großen Satz von Standard-Checkern und die Liste der zusätzlichen wächst ständig. Mit den Modernize- Checkern können Sie Ihren Quellcode modernisieren / umgestalten, um neue C ++ – Sprachfunktionen zu verwenden.

Im nächsten Teil dieser Serie werden wir diskutieren, wie man clang-tidy projektweit mit anderen Build-Systemen verwendet.

Brauchen Sie Hilfe?

KDAB beschäftigt mehrere Ingenieure, die täglich mit Clang-Werkzeugen arbeiten. Wir helfen Ihnen gerne weiter, falls Sie Probleme mit der Verwendung von Clang-Tools in Ihrem Projekt haben oder das Beste daraus machen möchten: Indem Sie uns projektspezifische Code-Checks implementieren oder automatische Refactoring-Tools auf Ihrer Codebasis ausführen lassen. Wir haben Kunden geholfen, ihre sehr großen Codebasen erfolgreich mit Werkzeugen zu modernisieren – etwas, das für sie kostenmäßig nicht machbar gewesen wäre, wenn sie es manuell gemacht hätten.

Kontaktieren Sie uns

 FacebookZwitschernLinkedInEmail

Kategorien: C ++ / Funktionale Sicherheit / How to / KDAB Blogs / KDAB auf Qt / Werkzeuge

Tags: automatisiertes Refactoring / C ++ / C ++ 11 / C ++14 / Clang / LLVM

Kevin Funk Leitender Softwareentwickler

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.