[clang-tools-extra] added option `llvm-header-guard.HeaderDirs` (PR #176940)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 20 07:21:58 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
@llvm/pr-subscribers-clang-tools-extra
Author: Thorsten Klein (thorsten-klein)
<details>
<summary>Changes</summary>
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 `HeaderDirs` list. All parent path components preceding that directory are discarded, so the generated header guard starts at the matched include directory.
Ref: #<!-- -->71732
---
Full diff: https://github.com/llvm/llvm-project/pull/176940.diff
11 Files Affected:
- (modified) clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp (+18-5)
- (modified) clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h (+4)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+8)
- (modified) clang-tools-extra/docs/clang-tidy/checks/llvm/header-guard.rst (+8)
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard.cpp (+104)
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/correct.hpp (+6)
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/missing.hpp ()
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/include/wrong.hpp (+6)
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/correct.hpp (+11)
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/missing.hpp ()
- (added) clang-tools-extra/test/clang-tidy/checkers/llvm/header-guard/other/wrong.hpp (+6)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/176940
More information about the cfe-commits
mailing list