clang-tidy
détecte les parties du code qui sont soit bancals, soit pourrait être écrite d'une meilleure façon.
Ne pas utiliser :
readability-static-accessed-through-instance
dans le cas d'un projet Qt
. Dans la déclaration des classes, les champs public : … public slot :
seront considérés comme des doublons car slot
est enlevé lors du preprocessing.S'intègre parfaitement avec CMake.
Il faut commencer par activer l'option set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
.
Puis lancer la génération des Makefile
avec CC="clang" CXX="clang++" cmake -S . -B build
pour générer également le fichier compile_commands.json
. L'utilisation du compilateur clang
n'est pas obligatoire. Elle est simplement là pour vérifier que le code compile bien avec clang
.
L'analyse se lance avec run-clang-tidy
.
Le fichier de config peut se générer via clang-tidy --dump-config > .clang-tidy
. Il est conseillé de générer ce fichier à chaque changement de version de clang, certaines options pouvant être supprimées ou renommées.
Exemple du début du fichier .clang-tidy
:
--- Checks: '*,-llvm-header-guard,-modernize-use-trailing-return-type,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-fuchsia-default-arguments-calls' WarningsAsErrors: '*' HeaderFilterRegex: '' ...
Clang-Tidy, part 1: Modernize your source code using C++11/C++14 Archive du 16/03/2017 le 13/02/2020
Il est aussi possible de filtrer certains dossiers :
run-clang-tidy-12 '^((?!/path1/|/path2/).)*$'
Peut être utile si on souhaite utiliser clang-tidy
pour Android qui est différent de celui du système mais run-clang-tidy
n'est pas fourni dans le SDK Android.
/usr/lib/llvm-14/bin/run-clang-tidy -clang-tidy-binary .../Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin/clang-tidy
Il faut modifier le fichier compile_commands.json
avec une commande perl
qui autorise les regex multilignes.
perl -0777 -i.original -pe 's/,\n\{\n.*\n.*_RCS_FILES\.cpp",\n.*_RCS_FILES\.cpp"\n\}//g' compile_commands.json perl -0777 -i.original -pe 's/\{\n.*\n.*_RCS_FILES\.cpp",\n.*_RCS_FILES\.cpp"\n\},\n//g' compile_commands.json
badcode; // NOLINT // NOLINTNEXTLINE badcode; badcode; // NOLINT(cert-err-58-cpp) // NOLINTBEGIN(google*) Foo(bool param); // NOLINTEND(google*)
Priorité de la convention de nommage:
Voir directement le code source avec les méthodes findStyleKind, findStyleKindForField et findStyleKindForVar.
Ci-dessous, defined(Xxxx)
signifie que XxxxCase
, XxxxPrefix
, XxxxSuffix
, XxxxIgnoredRegex
ou XxxxHungarianPrefix
est dans les règles.
Algo | Exemple |
variable objective-C: si SK_ObjcIvar: SK_ObjcIvar sinon fin | |
typedef: si SK_Typedef: SK_Typedef sinon fin | typedef int INTeGER; |
using: si SK_TypeAlias: SK_TypeAlias sinon fin | using DOUbLE = double; |
namespace: si inline namespace && SK_InlineNamespace: SK_InlineNamespace si SK_Namespace SK_Namespace fin | inline namespace NAMEsPACE {} namespace nAMEPACE {} |
enum: si enum && SK_Enum: SK_Enum fin field in enum: si enum class && SK_ScopedEnumConstant: SK_ScopedEnumConstant si SK_EnumConstant: SK_EnumConstant si SK_Constant: SK_Constant fin | enum eNUM { EnuM_CONST }; enum class eNUM { ENUM_Const }; |
union ou struct ou class: si abstract (une méthode virtuelle pure) && SK_AbstractClass: SK_AbstractClass si struct && SK_Struct: SK_Struct si struct && SK_Class: SK_Class si class && SK_Class: SK_Class si class && SK_Struct: SK_Struct si union && SK_Union: SK_Union si enum && SK_Enum: SK_Enum fin | class ABStract { virtual fOo() = 0; }; struct STRuct {}; class ClAsS {}; union UnIon {}; enum class eNUM {}; |
membre d'une classe: si CheckAnonFieldInParent && struct/union parent est anonyme: Appliquer les règles ci-dessous en considérant le private/protected/public du parent. si const: si SK_ConstantMember: SK_ConstantMember si SK_Constant: SK_Constant si private && SK_PrivateMember: SK_PrivateMember si protected && SK_ProtectedMember: SK_ProtectedMember si public && SK_PublicMember: SK_PublicMember si SK_Member: SK_Member fin | class { const int InT; private: short ShorT; protected: double DoublE; public: float FloaT; } |
paramètre: // Possible en C++ ?!? si constexpr && SK_ConstexprVariable: SK_ConstexprVariable si const: si pointeur && SK_ConstantPointerParameter: SK_ConstantPointerParameter si SK_ConstantParameter: SK_ConstantParameter si SK_Constant: SK_Constant si variadic && SK_ParameterPack: SK_ParameterPack si pointeur && SK_PointerParameter: SK_PointerParameter si SK_Parameter: SK_Parameter fin | template <class... Types> void fOo(const int *IiI, const short &ShorT, int *JjJ, short SsS, Types... arGs); |
variable: si constexpr && SK_ConstexprVariable: SK_ConstexprVariable si const: si static && membre && SK_ClassConstant: SK_ClassConstant si global && pointeur && SK_GlobalConstantPointer: SK_GlobalConstantPointer si global && SK_GlobalConstant: SK_GlobalConstant si local && static && SK_StaticConstant: SK_StaticConstant si local && pointeur && SK_LocalConstantPointer: SK_LocalConstantPointer si local && SK_LocalConstant: SK_LocalConstant // Plus restrictif que la condition précédente ?!? si local && dans le bloc principal de la fonction/méthode && SK_LocalConstant: SK_LocalConstant si SK_Constant: SK_Constant fin si static && membre && SK_ClassMember: SK_ClassMember si global && pointeur && SK_GlobalPointer: SK_GlobalPointer si global && SK_GlobalVariable: SK_GlobalVariable si local && static && SK_StaticVariable: SK_StaticVariable si local && pointeur && SK_LocalPointer: SK_LocalPointer si local && SK_LocalVariable: SK_LocalVariable // Plus restrictif que la condition précédente ?!? si local && dans le bloc principal de la fonction/méthode && SK_LocalVariable: SK_LocalVariable si SK_Variable: SK_Variable fin | constexpr int eE = 150; class Cc { static const int Ee = 150; }; const int *Jj = nullptr; const int jJ = 0; void fOo() { static const int zZZz = 150; const int *ZzzZ = nullptr; { const int ZZzz = 150; } const int ZZzZ = 150; }; class Cc2 { static int Ee2 = 150; }; int *Jj2 = nullptr; int jJ2 = 0; void fOo2() { static int zZZz2 = 150; int *ZzzZ2 = nullptr; { int ZZzz2 = 150; } int ZZzZ2 = 150; }; |
méthode: si override: ignore si constexpr && SK_ConstexprMethod: SK_ConstexprMethod si constexpr && SK_ConstexprFunction: SK_ConstexprFunction si static && SK_ClassMethod: SK_ClassMethod si virtual && SK_VirtualMethod: SK_VirtualMethod si private && SK_PrivateMethod: SK_PrivateMethod si protected && SK_ProtectedMethod: SK_ProtectedMethod si public && SK_PublicMethod: SK_PublicMethod si SK_Method: SK_Method si SK_Function: SK_Function ignore | class A{ public: virtual void fOo()= 0; }; class B:public A{ public: void fOo() override; constexpr int fOo2(); static void fOo3(); virtual void fOo4(); private: void fOo5(); protected: void fOo6(); public: void fOo7(); }; |
fonction: si constexpr && SK_ConstexprFunction: SK_ConstexprFunction // C'est quoi une fonction non globale ? si global && SK_GlobalFunction: SK_GlobalFunction si SK_Function: SK_Function ignore | constexpr void b1r(); void bAr(); |
typename dans template: si SK_TypeTemplateParameter: SK_TypeTemplateParameter si SK_TemplateParameter: SK_TemplateParameter ignore value in template: si SK_ValueTemplateParameter: SK_ValueTemplateParameter si SK_TemplateParameter: SK_TemplateParameter ignore template <typename> class / typename: si SK_TemplateTemplateParameter: SK_TemplateTemplateParameter si SK_TemplateParameter: SK_TemplateParameter ignore | template<typename TypeName, int VaLuE, template<typename> typename TypeTypeName> void FoBa(); |
concept && SK_Concept: SK_Concept | template<class T, class U> concept ConCepT = std::is_base_of<U, T>::value; |
define && SK_MacroDefinition: SK_MacroDefinition | #define MaCrO
|
Writing a basic clang static analysis check Archive du 02/05/2015 le 30/06/2021
Et une version à jour du système de compilation : Tutorial for building tools using LibTooling and LibASTMatchers, Archive du clang 17.0.0 master le 23/05/2023
Getting Involved Archive du clang 17.0.0 master le 24/05/2023
Il faut avoir installé go.
make
CLANG_TIDY_CACHE_BINARY=/usr/bin/clang-tidy-17 CLANG_TIDY_CACHE_DIR=~/.cache/clang-tidy-cache run-clang-tidy-17 -clang-tidy-binary /usr/local/bin/clang-tidy-cache
Il suffit de copier les scripts python clang-tidy
et clang-tidy-cache
dans /usr/local/bin
.
CTCACHE_CLANG_TIDY=/usr/bin/clang-tidy CTCACHE_DIR=~/.cache/clang-tidy-cache run-clang-tidy -clang-tidy-binary /usr/local/bin/clang-tidy