''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.
=====CMake=====
S'intègre parfaitement avec [[prog:cmake|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'':
---
Checks: '*,-llvm-header-guard,-modernize-use-trailing-return-type,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-fuchsia-default-arguments-calls'
WarningsAsErrors: '*'
HeaderFilterRegex: ''
...
[[https://www.kdab.com/clang-tidy-part-1-modernize-source-code-using-c11c14/|Clang-Tidy, part 1: Modernize your source code using C++11/C++14]] {{ :prog:clang:clang-tidy_part_1_modernize_your_source_code_using_c_11_c_14_-_kdab_2020-02-13_22_45_54_.html |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 [[https://github.com/llvm/llvm-project/blob/2c739dfd53fde0995f91c8a2c11ec803041bac86/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp#L1122|findStyleKind]], [[https://github.com/llvm/llvm-project/blob/2c739dfd53fde0995f91c8a2c11ec803041bac86/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp#L1475|findStyleKindForField]] et [[https://github.com/llvm/llvm-project/blob/2c739dfd53fde0995f91c8a2c11ec803041bac86/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp#L1501C34-L1501C53|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
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 class / typename:
si SK_TemplateTemplateParameter:
SK_TemplateTemplateParameter
si SK_TemplateParameter:
SK_TemplateParameter
ignore
|
template typename TypeTypeName>
void FoBa();
|
|
concept && SK_Concept:
SK_Concept
|
template
concept ConCepT = std::is_base_of::value;
|
|
define && SK_MacroDefinition:
SK_MacroDefinition
|
#define MaCrO
|
=====Extensions=====
[[http://bbannier.github.io/blog/2015/05/02/Writing-a-basic-clang-static-analysis-check.html|Writing a basic clang static analysis check]] {{ :prog:clang:writing_a_basic_clang_static_analysis_check_2021-06-30_06_21_21_.html |Archive du 02/05/2015 le 30/06/2021}}
Et une version à jour du système de compilation : [[https://clang.llvm.org/docs/LibASTMatchersTutorial.html|Tutorial for building tools using LibTooling and LibASTMatchers]], {{ :prog:clang:tutorial_for_building_tools_using_libtooling_and_libastmatchers_clang_17.0.0git_documentation_23_05_2023_08_35_52_.html |Archive du clang 17.0.0 master le 23/05/2023}}
[[https://clang.llvm.org/extra/clang-tidy/Contributing.html|Getting Involved]] {{ :prog:clang:getting_involved_extra_clang_tools_17.0.0git_documentation_24_05_2023_09_20_28_.html |Archive du clang 17.0.0 master le 24/05/2023}}
=====Cache=====
====kokulshan/clang-tidy-cache====
[[https://github.com/kokulshan/clang-tidy-cache|Site web]]
* 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====
[[https://github.com/matus-chochlik/ctcache|Site web]]
* 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