Table des matières
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-instancedans le cas d'un projetQt. Dans la déclaration des classes, les champspublic : … public slot :seront considérés comme des doublons carslotest enlevé lors du preprocessing.
CMake
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.
Options
- Configuration des règles
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:
- .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
- Analyse uniquement certains dossiers
Il est aussi possible de filtrer certains dossiers :
run-clang-tidy-12 '^((?!/path1/|/path2/).)*$'
- Spécifier la localisation de clang-tidy
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
- Exclure certains fichiers
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
Gestion les erreurs
- Ignorer la vérification sur des lignes de code spécifiques
badcode; // NOLINT // NOLINTNEXTLINE badcode; badcode; // NOLINT(cert-err-58-cpp) // NOLINTBEGIN(google*) Foo(bool param); // NOLINTEND(google*)
Détail des règles
readability-identifier-naming
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
|
Extensions
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
Cache
kokulshan/clang-tidy-cache
- Installation
Il faut avoir installé go.
make
- Exécution
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
matus-chochlik/ctcache
- Installation
Il suffit de copier les scripts python clang-tidy et clang-tidy-cache dans /usr/local/bin.
- Execution
CTCACHE_CLANG_TIDY=/usr/bin/clang-tidy CTCACHE_DIR=~/.cache/clang-tidy-cache run-clang-tidy -clang-tidy-binary /usr/local/bin/clang-tidy
