https://github.com/thorsten-klein created https://github.com/llvm/llvm-project/pull/176940
new option `HeaderDirs` for `llvm-header-guard` is added. Defaults to `include`. When checking header guards, the header file path is searched for the first matching directory in this list. All parent path components preceding that directory are discarded, so the generated header guard starts at the matched include directory. Ref: #71732 >From 54fe622d73bf90007dfcb7342f720d1390026e7d Mon Sep 17 00:00:00 2001 From: Thorsten Klein <[email protected]> Date: Mon, 19 Jan 2026 15:43:14 +0100 Subject: [PATCH] added option `llvm-header-guard.HeaderDirs` new option HeaderDirs for llvm-header-guard is added. Defaults to `include`. When checking header guards, the header file path is searched for the first matching directory in this list. All parent path components preceding that directory are discarded, so the generated header guard starts at the matched include directory. --- .../clang-tidy/llvm/HeaderGuardCheck.cpp | 23 +++- .../clang-tidy/llvm/HeaderGuardCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 8 ++ .../clang-tidy/checks/llvm/header-guard.rst | 8 ++ .../clang-tidy/checkers/llvm/header-guard.cpp | 104 ++++++++++++++++++ .../llvm/header-guard/include/correct.hpp | 6 + .../llvm/header-guard/include/missing.hpp | 0 .../llvm/header-guard/include/wrong.hpp | 6 + .../llvm/header-guard/other/correct.hpp | 11 ++ .../llvm/header-guard/other/missing.hpp | 0 .../llvm/header-guard/other/wrong.hpp | 6 + 11 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/correct.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/missing.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/wrong.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/correct.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/missing.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/wrong.hpp diff --git a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp index ef8b6b1dfb8f7..36e837e203a89 100644 --- a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "HeaderGuardCheck.h" +#include "../utils/OptionsUtils.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/Path.h" @@ -14,7 +15,9 @@ namespace clang::tidy::llvm_check { LLVMHeaderGuardCheck::LLVMHeaderGuardCheck(StringRef Name, ClangTidyContext *Context) - : HeaderGuardCheck(Name, Context) {} + : HeaderGuardCheck(Name, Context), + HeaderDirs(utils::options::parseStringList( + Options.get("HeaderDirs", "include"))) {} std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename, StringRef OldGuard) { @@ -27,10 +30,15 @@ std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename, // Sanitize the path. There are some rules for compatibility with the historic // style in include/llvm and include/clang which we want to preserve. - // We don't want _INCLUDE_ in our guards. - const size_t PosInclude = Guard.rfind("include/"); - if (PosInclude != StringRef::npos) - Guard = Guard.substr(PosInclude + std::strlen("include/")); + // consider all directories from HeaderDirs option. Stop at first found. + for (StringRef HeaderDir : HeaderDirs) { + size_t PosHeaderDir = Guard.rfind(HeaderDir.str() + "/"); + if (PosHeaderDir != StringRef::npos) { + // We don't want the header dir in our guards, i.e. _INCLUDE_ + Guard = Guard.substr(PosHeaderDir + HeaderDir.size() + 1); + break; // stop at first found + } + } // For clang we drop the _TOOLS_. const size_t PosToolsClang = Guard.rfind("tools/clang/"); @@ -64,4 +72,9 @@ std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename, return StringRef(Guard).upper(); } +void LLVMHeaderGuardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderDirs", + utils::options::serializeStringList(HeaderDirs)); +} + } // namespace clang::tidy::llvm_check diff --git a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h index cfc920bb85e23..a7447a5c8863d 100644 --- a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h +++ b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h @@ -21,7 +21,11 @@ class LLVMHeaderGuardCheck : public utils::HeaderGuardCheck { LLVMHeaderGuardCheck(StringRef Name, ClangTidyContext *Context); bool shouldSuggestEndifComment(StringRef Filename) override { return false; } + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; std::string getHeaderGuard(StringRef Filename, StringRef OldGuard) override; + +private: + const std::vector<StringRef> HeaderDirs; }; } // namespace clang::tidy::llvm_check diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 94a11b1acb73a..61889d8b90210 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -113,6 +113,14 @@ Changes in existing checks <clang-tidy/checks/performance/move-const-arg>` check by avoiding false positives on trivially copyable types with a non-public copy constructor. +- Improved :doc:`llvm-header-guard + <clang-tidy/checks/llvm/header-guard>` check by adding the option + `HeaderDirs` which is a list of one or more include directory names. + Defaults to `include`. When checking header guards, the header file path is + searched for the first matching directory in this list. All parent path + components preceding that directory are discarded, so the generated header + guard starts at the matched include directory. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst index 74eb10ba6fcf9..f65bea01421f0 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst @@ -4,3 +4,11 @@ llvm-header-guard ================= Finds and fixes header guards that do not adhere to LLVM style. + +Options +------- + +.. option:: HeaderDirs + + A list of directories where the include guard string will start. + defaults to `include`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard.cpp new file mode 100644 index 0000000000000..8cc3ea8f26581 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard.cpp @@ -0,0 +1,104 @@ +#include "header-guard/include/correct.hpp" +#include "header-guard/include/missing.hpp" +#include "header-guard/include/wrong.hpp" + +#include "header-guard/other/correct.hpp" +#include "header-guard/other/missing.hpp" +#include "header-guard/other/wrong.hpp" + +// --------------------------------------- +// TEST 1: Use no config options (default) +// --------------------------------------- +// RUN: %check_clang_tidy %s llvm-header-guard %t -export-fixes=%t.1.yaml --header-filter=.* -- -I%S > %t.1.msg 2>&1 +// RUN: FileCheck -input-file=%t.1.msg -check-prefix=CHECK-MESSAGES1 %s +// RUN: FileCheck -input-file=%t.1.yaml -check-prefix=CHECK-YAML1 %s + +// CHECK-MESSAGES1: header-guard/include/missing.hpp:1:1: warning: header is missing header guard [llvm-header-guard] +// CHECK-MESSAGES1: header-guard/other/missing.hpp:1:1: warning: header is missing header guard [llvm-header-guard] +// CHECK-MESSAGES1: header-guard/include/wrong.hpp:1:9: warning: header guard does not follow preferred style [llvm-header-guard] +// CHECK-MESSAGES1: header-guard/other/wrong.hpp:1:9: warning: header guard does not follow preferred style [llvm-header-guard] + +// CHECK-YAML1: Message: header is missing header guard +// CHECK-YAML1: FilePath: '{{.*}}/header-guard/include/missing.hpp' +// CHECK-YAML1: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n\n#endif\n" +// CHECK-YAML1: Message: header guard does not follow preferred style +// CHECK-YAML1: FilePath: '{{.*}}/header-guard/include/wrong.hpp' +// CHECK-YAML1: ReplacementText: WRONG_HPP + +// CHECK-YAML1: Message: header is missing header guard +// CHECK-YAML1: FilePath: '{{.*}}/header-guard/other/missing.hpp' +// CHECK-YAML1: ReplacementText: "#ifndef LLVM_HEADER_GUARD_OTHER_MISSING_HPP\n#define LLVM_HEADER_GUARD_OTHER_MISSING_HPP\n\n\n#endif\n" +// CHECK-YAML1: Message: header guard does not follow preferred style +// CHECK-YAML1: FilePath: '{{.*}}/header-guard/other/wrong.hpp' +// CHECK-YAML1: ReplacementText: LLVM_HEADER_GUARD_OTHER_WRONG_HPP + +// --------------------------------------- +// TEST 2: Set option HeaderDirs=other +// --------------------------------------- +// RUN: %check_clang_tidy %s llvm-header-guard %t -export-fixes=%t.2.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: llvm-header-guard.HeaderDirs: other, \ +// RUN: }}' -- -I%S > %t.2.msg 2>&1 +// RUN: FileCheck -input-file=%t.2.msg -check-prefix=CHECK-MESSAGES2 %s +// RUN: FileCheck -input-file=%t.2.yaml -check-prefix=CHECK-YAML2 %s + +// CHECK-MESSAGES2: header-guard/include/missing.hpp:1:1: warning: header is missing header guard [llvm-header-guard] +// CHECK-MESSAGES2: header-guard/other/missing.hpp:1:1: warning: header is missing header guard [llvm-header-guard] +// CHECK-MESSAGES2: header-guard/include/wrong.hpp:1:9: warning: header guard does not follow preferred style [llvm-header-guard] +// CHECK-MESSAGES2: header-guard/other/wrong.hpp:1:9: warning: header guard does not follow preferred style [llvm-header-guard] + +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*}}/header-guard/include/correct.hpp' +// CHECK-YAML2: ReplacementText: LLVM_HEADER_GUARD_INCLUDE_CORRECT_HPP +// CHECK-YAML2: Message: header is missing header guard +// CHECK-YAML2: FilePath: '{{.*}}/header-guard/include/missing.hpp' +// CHECK-YAML2: ReplacementText: "#ifndef LLVM_HEADER_GUARD_INCLUDE_MISSING_HPP\n#define LLVM_HEADER_GUARD_INCLUDE_MISSING_HPP\n\n\n#endif\n" +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*}}/header-guard/include/wrong.hpp' +// CHECK-YAML2: ReplacementText: LLVM_HEADER_GUARD_INCLUDE_WRONG_HPP + +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*}}/header-guard/other/correct.hpp' +// CHECK-YAML2: ReplacementText: CORRECT_HPP +// CHECK-YAML2: Message: header is missing header guard +// CHECK-YAML2: FilePath: '{{.*}}/header-guard/other/missing.hpp' +// CHECK-YAML2: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n\n#endif\n" +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*}}/header-guard/other/wrong.hpp' +// CHECK-YAML2: ReplacementText: WRONG_HPP + + +// --------------------------------------- +// TEST 3: Set option HeaderDirs=include;other +// --------------------------------------- +// RUN: %check_clang_tidy %s llvm-header-guard %t -export-fixes=%t.3.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: llvm-header-guard.HeaderDirs: include;other, \ +// RUN: }}' -- -I%S > %t.3.msg 2>&1 +// RUN: FileCheck -input-file=%t.3.msg -check-prefix=CHECK-MESSAGES3 %s +// RUN: FileCheck -input-file=%t.3.yaml -check-prefix=CHECK-YAML3 %s + +// CHECK-MESSAGES3: header-guard/include/missing.hpp:1:1: warning: header is missing header guard [llvm-header-guard] +// CHECK-MESSAGES3: header-guard/other/missing.hpp:1:1: warning: header is missing header guard [llvm-header-guard] +// CHECK-MESSAGES3: header-guard/include/wrong.hpp:1:9: warning: header guard does not follow preferred style [llvm-header-guard] +// CHECK-MESSAGES3: header-guard/other/wrong.hpp:1:9: warning: header guard does not follow preferred style [llvm-header-guard] + +// CHECK-YAML3: Message: header is missing header guard +// CHECK-YAML3: FilePath: '{{.*}}/header-guard/include/missing.hpp' +// CHECK-YAML3: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n\n#endif\n" +// CHECK-YAML3: Message: header guard does not follow preferred style +// CHECK-YAML3: FilePath: '{{.*}}/header-guard/include/wrong.hpp' +// CHECK-YAML3: ReplacementText: WRONG_HPP + +// CHECK-YAML3: Message: header guard does not follow preferred style +// CHECK-YAML3: FilePath: '{{.*}}/header-guard/other/correct.hpp' +// CHECK-YAML3: ReplacementText: CORRECT_HPP +// CHECK-YAML3: Message: header is missing header guard +// CHECK-YAML3: FilePath: '{{.*}}/header-guard/other/missing.hpp' +// CHECK-YAML3: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n\n#endif\n" +// CHECK-YAML3: Message: header guard does not follow preferred style +// CHECK-YAML3: FilePath: '{{.*}}/header-guard/other/wrong.hpp' +// CHECK-YAML3: ReplacementText: WRONG_HPP + + + diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/correct.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/correct.hpp new file mode 100644 index 0000000000000..19f3347459a7a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/correct.hpp @@ -0,0 +1,6 @@ +#ifndef CORRECT_HPP +#define CORRECT_HPP + +// do anything + +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/missing.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/missing.hpp new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/wrong.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/wrong.hpp new file mode 100644 index 0000000000000..bc58b550aca09 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/wrong.hpp @@ -0,0 +1,6 @@ +#ifndef HERE_IS_SOMETHING_WRONG_HPP +#define HERE_IS_SOMETHING_WRONG_HPP + +// do anything + +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/correct.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/correct.hpp new file mode 100644 index 0000000000000..f3da7919d5853 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/correct.hpp @@ -0,0 +1,11 @@ +#ifndef LLVM_HEADER_GUARD_OTHER_CORRECT_HPP +#define LLVM_HEADER_GUARD_OTHER_CORRECT_HPP + +#ifndef CORRECT_HPP +#define CORRECT_HPP + +// do anything + +#endif + +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/missing.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/missing.hpp new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/wrong.hpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/wrong.hpp new file mode 100644 index 0000000000000..7b8abb25cf951 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/wrong.hpp @@ -0,0 +1,6 @@ +#ifndef SOME_WRONG_HEADER_GUARD_HPP +#define SOME_WRONG_HEADER_GUARD_HPP + +// do anything + +#endif _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
