https://github.com/thorsten-klein updated https://github.com/llvm/llvm-project/pull/177315
>From e71df3859650e1e6a49177fab36db261a69d4aa8 Mon Sep 17 00:00:00 2001 From: Thorsten Klein <[email protected]> Date: Fri, 24 Jul 2026 10:33:23 +0200 Subject: [PATCH] [clang-tidy] Add a new check `misc-header-guard` Find and fix header guards It respects option `misc-header-guard.HeaderDirs`, which contains a list of one or more header directory names. --- .clang-tidy | 1 + .../clang-tidy/misc/CMakeLists.txt | 1 + .../clang-tidy/misc/HeaderGuardCheck.cpp | 115 ++++++++ .../clang-tidy/misc/HeaderGuardCheck.h | 53 ++++ .../clang-tidy/misc/MiscTidyModule.cpp | 2 + .../portability/AvoidPragmaOnceCheck.cpp | 10 +- .../clang-tidy/utils/HeaderGuard.cpp | 15 +- .../clang-tidy/utils/HeaderGuard.h | 6 + .../clang-tidy/utils/LexerUtils.cpp | 11 + .../clang-tidy/utils/LexerUtils.h | 3 + clang-tools-extra/docs/ReleaseNotes.md | 6 + .../docs/clang-tidy/checks/list.md | 1 + .../clang-tidy/checks/misc/header-guard.md | 95 +++++++ .../misc/header-guard-pragma-once-leak.cpp | 16 ++ .../clang-tidy/checkers/misc/header-guard.cpp | 252 ++++++++++++++++++ .../misc/header-guard/include/correct.hpp | 6 + .../misc/header-guard/include/missing.hpp | 3 + .../header-guard/include/other/correct.hpp | 6 + .../header-guard/include/other/missing.hpp | 3 + .../misc/header-guard/include/other/wrong.hpp | 7 + .../include/pragma-once-leak-a.hpp | 8 + .../include/pragma-once-leak-b.hpp | 8 + .../misc/header-guard/include/pragma-once.hpp | 10 + .../misc/header-guard/include/wrong.hpp | 7 + 24 files changed, 636 insertions(+), 9 deletions(-) create mode 100644 clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/misc/header-guard.md create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard-pragma-once-leak.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/correct.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/missing.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/correct.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/missing.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/wrong.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-a.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-b.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once.hpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/wrong.hpp diff --git a/.clang-tidy b/.clang-tidy index 2cda1b81de808..bb404c291cd13 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,7 @@ Checks: > clang-diagnostic-*, llvm-*, misc-*, + -misc-header-guard, -misc-const-correctness, -misc-include-cleaner, -misc-no-recursion, diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index 68faf77fa1d5f..5453e48333b0f 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_library(clangTidyMiscModule STATIC CoroutineHostileRAIICheck.cpp DefinitionsInHeadersCheck.cpp ExplicitConstructorCheck.cpp + HeaderGuardCheck.cpp HeaderIncludeCycleCheck.cpp IncludeCleanerCheck.cpp MiscTidyModule.cpp diff --git a/clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.cpp b/clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.cpp new file mode 100644 index 0000000000000..8a66edda5ffa5 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "HeaderGuardCheck.h" +#include "../utils/LexerUtils.h" +#include "../utils/OptionsUtils.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/Path.h" + +namespace clang::tidy::misc { + +/// Canonicalize a path by removing ./ and ../ components, matching the +/// format of the ``Filename`` passed to the ``HeaderGuardCheck`` virtuals. +static std::string cleanPath(StringRef Path) { + SmallString<256> Result = Path; + llvm::sys::path::remove_dots(Result, true); + return std::string(Result); +} + +HeaderGuardCheck::HeaderGuardCheck(StringRef Name, ClangTidyContext *Context) + : clang::tidy::utils::HeaderGuardCheck(Name, Context), + AllowPragmaOnce(Options.get("AllowPragmaOnce", false)), + HeaderDirs(utils::options::parseStringList( + Options.get("HeaderDirs", "include"))), + EndifComment(Options.get("EndifComment", false)), + Prefix(Options.get("Prefix", "")) {} + +std::string HeaderGuardCheck::getHeaderGuard(StringRef Filename, + StringRef /*OldGuard*/) { + // When running under Windows, need to convert the path separators from + // `\` to `/`. + std::string AbsPath = + llvm::sys::path::convert_to_slash(tooling::getAbsolutePath(Filename)); + + // consider all directories from HeaderDirs option. Stop at first found. + for (const StringRef HeaderDir : HeaderDirs) { + const size_t PosHeaderDir = AbsPath.rfind("/" + HeaderDir.str() + "/"); + if (PosHeaderDir != StringRef::npos) { + // We don't want the header dir in our guards, i.e. _INCLUDE_ + AbsPath = AbsPath.substr(PosHeaderDir + HeaderDir.size() + 2); + break; // stop at first found + } + } + + std::string Guard = AbsPath; + llvm::replace(Guard, '/', '_'); + llvm::replace(Guard, '.', '_'); + llvm::replace(Guard, '-', '_'); + Guard = Prefix.str() + Guard; + + return StringRef(Guard).upper(); +} + +bool HeaderGuardCheck::shouldSuggestEndifComment(StringRef /*Filename*/) { + return EndifComment; +} + +bool HeaderGuardCheck::shouldSuggestToAddHeaderGuard(StringRef Filename) { + if (AllowPragmaOnce && PragmaOnceLocs.contains(Filename)) + return false; + return utils::HeaderGuardCheck::shouldSuggestToAddHeaderGuard(Filename); +} + +SourceLocation HeaderGuardCheck::getPragmaOnceLoc(StringRef Filename) const { + const auto It = PragmaOnceLocs.find(Filename); + return It == PragmaOnceLocs.end() ? SourceLocation() : It->second; +} + +void HeaderGuardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "AllowPragmaOnce", AllowPragmaOnce); + Options.store(Opts, "EndifComment", EndifComment); + Options.store(Opts, "HeaderDirs", + utils::options::serializeStringList(HeaderDirs)); + Options.store(Opts, "Prefix", Prefix); +} + +namespace { + +class HeaderGuardCallbacks : public PPCallbacks { +public: + HeaderGuardCallbacks(HeaderGuardCheck *Check, const SourceManager &SM) + : Check(Check), SM(SM) {} + void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind /*Introducer*/) override { + if (!utils::lexer::isPragmaOnce(Loc, SM)) + return; + if (OptionalFileEntryRef FE = SM.getFileEntryRefForID(SM.getFileID(Loc))) + Check->PragmaOnceLocs[cleanPath(FE->getName())] = Loc; + if (!Check->AllowPragmaOnce) + Check->diag(Loc, "use include guards instead of 'pragma once'"); + } + +private: + HeaderGuardCheck *Check; + const SourceManager &SM; +}; + +} // namespace + +void HeaderGuardCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + utils::HeaderGuardCheck::registerPPCallbacks(SM, PP, ModuleExpanderPP); + PP->addPPCallbacks(std::make_unique<HeaderGuardCallbacks>(this, SM)); +} + +} // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.h b/clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.h new file mode 100644 index 0000000000000..a8d58e4a7b9c6 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/HeaderGuardCheck.h @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_HEADERGUARDCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_HEADERGUARDCHECK_H + +#include "../utils/HeaderGuard.h" +#include "llvm/ADT/StringMap.h" + +namespace clang::tidy::misc { + +/// Finds and fixes header guards. +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/misc/header-guard.html +class HeaderGuardCheck : public utils::HeaderGuardCheck { +public: + HeaderGuardCheck(StringRef Name, ClangTidyContext *Context); + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus || LangOpts.C99; + } + + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + + bool shouldSuggestEndifComment(StringRef Filename) override; + bool shouldSuggestToAddHeaderGuard(StringRef Filename) override; + SourceLocation getPragmaOnceLoc(StringRef Filename) const override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + std::string getHeaderGuard(StringRef Filename, StringRef OldGuard) override; + + const bool AllowPragmaOnce; + + /// Records, per file, the location of a ``#pragma once`` directive found + /// while preprocessing. Tracked per file (rather than as a single flag for + /// the whole translation unit) so that a pragma in one header does not + /// affect the diagnostic for a different header included in the same TU. + llvm::StringMap<SourceLocation> PragmaOnceLocs; + +private: + const std::vector<StringRef> HeaderDirs; + const bool EndifComment; + const StringRef Prefix; +}; + +} // namespace clang::tidy::misc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_HEADERGUARDCHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index 52d3b4297ba26..e9e57d4d6f4e2 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -14,6 +14,7 @@ #include "CoroutineHostileRAIICheck.h" #include "DefinitionsInHeadersCheck.h" #include "ExplicitConstructorCheck.h" +#include "HeaderGuardCheck.h" #include "HeaderIncludeCycleCheck.h" #include "IncludeCleanerCheck.h" #include "MisleadingBidirectionalCheck.h" @@ -57,6 +58,7 @@ class MiscModule : public ClangTidyModule { "misc-definitions-in-headers"); CheckFactories.registerCheck<ExplicitConstructorCheck>( "misc-explicit-constructor"); + CheckFactories.registerCheck<HeaderGuardCheck>("misc-header-guard"); CheckFactories.registerCheck<HeaderIncludeCycleCheck>( "misc-header-include-cycle"); CheckFactories.registerCheck<IncludeCleanerCheck>("misc-include-cleaner"); diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp index bfcc52d3c8c3f..16a21aa714c94 100644 --- a/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp +++ b/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp @@ -8,6 +8,7 @@ #include "AvoidPragmaOnceCheck.h" +#include "../utils/LexerUtils.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" @@ -23,14 +24,7 @@ class PragmaOnceCallbacks : public PPCallbacks { : Check(Check), SM(SM) {} void PragmaDirective(SourceLocation Loc, PragmaIntroducerKind Introducer) override { - auto Str = StringRef(SM.getCharacterData(Loc)); - if (!Str.consume_front("#")) - return; - Str = Str.trim(); - if (!Str.consume_front("pragma")) - return; - Str = Str.trim(); - if (Str.starts_with("once")) + if (utils::lexer::isPragmaOnce(Loc, SM)) Check->diag(Loc, "avoid 'pragma once' directive; use include guards instead"); } diff --git a/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp b/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp index 84dbc695a3de4..44676cc4ff3b1 100644 --- a/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp +++ b/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp @@ -241,7 +241,8 @@ class HeaderGuardPPCallbacks : public PPCallbacks { const StringRef LineEnding = SM.getBufferData(FID).detectEOL(); - Check->diag(StartLoc, "header is missing header guard") + auto Diag = + Check->diag(StartLoc, "header is missing header guard") << FixItHint::CreateInsertion( StartLoc, (Twine("#ifndef ") + CPPVar + LineEnding + "#define " + CPPVar + LineEnding + LineEnding) @@ -254,6 +255,18 @@ class HeaderGuardPPCallbacks : public PPCallbacks { : "endif") + LineEnding) .str()); + + // Remove a pre-existing `#pragma once` so we don't end up with both a + // pragma and a header guard protecting the same file. + const SourceLocation PragmaOnceLoc = Check->getPragmaOnceLoc(FileName); + if (PragmaOnceLoc.isValid()) { + const char *Data = SM.getCharacterData(PragmaOnceLoc); + size_t Len = std::strcspn(Data, "\r\n"); + while (Data[Len] == '\r' || Data[Len] == '\n') + ++Len; + Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + PragmaOnceLoc, PragmaOnceLoc.getLocWithOffset(Len))); + } } } diff --git a/clang-tools-extra/clang-tidy/utils/HeaderGuard.h b/clang-tools-extra/clang-tidy/utils/HeaderGuard.h index 8ef1a1879d8a2..9101de760c790 100644 --- a/clang-tools-extra/clang-tidy/utils/HeaderGuard.h +++ b/clang-tools-extra/clang-tidy/utils/HeaderGuard.h @@ -35,6 +35,12 @@ class HeaderGuardCheck : public ClangTidyCheck { /// Returns ``true`` if the check should add a header guard to the file /// if it has none. virtual bool shouldSuggestToAddHeaderGuard(StringRef Filename); + /// Returns the location of an existing ``#pragma once`` directive in the + /// file \p Filename, so that it can be removed when a header guard is + /// inserted in its place. Returns an invalid location if there is none. + virtual SourceLocation getPragmaOnceLoc(StringRef Filename) const { + return {}; + } /// Returns a replacement for the ``#endif`` line with a comment mentioning /// \p HeaderGuard. The replacement should start with ``endif``. virtual std::string formatEndIf(StringRef HeaderGuard); diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp index d83713f06b800..9a5d89bb90cd4 100644 --- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp +++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp @@ -371,4 +371,15 @@ SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl, return {}; } +bool isPragmaOnce(SourceLocation Loc, const SourceManager &SM) { + auto Str = StringRef(SM.getCharacterData(Loc)); + if (!Str.consume_front("#")) + return false; + Str = Str.trim(); + if (!Str.consume_front("pragma")) + return false; + Str = Str.trim(); + return Str.starts_with("once"); +} + } // namespace clang::tidy::utils::lexer diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h index 9b2daf74965e4..eace1f6e58a54 100644 --- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h +++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h @@ -160,6 +160,9 @@ SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM, SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl, const SourceManager &SM); +/// Returns ``true`` if the pragma directive at \p Loc is a ``#pragma once``. +bool isPragmaOnce(SourceLocation Loc, const SourceManager &SM); + } // namespace tidy::utils::lexer } // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index 29de9aef9e4b6..9816ce6fa6808 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -100,6 +100,12 @@ infrastructure are described first, followed by tool-specific sections. #### New checks +- New {doc}`misc-header-guard + <clang-tidy/checks/misc/header-guard>` check. + + Finds and fixes header guards that do not conform to the configured style + options. + - New {doc}`performance-expensive-value-or <clang-tidy/checks/performance/expensive-value-or>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md index 77c9eafa7835c..89df31093fe13 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.md +++ b/clang-tools-extra/docs/clang-tidy/checks/list.md @@ -265,6 +265,7 @@ readability/* | {doc}`misc-coroutine-hostile-raii <misc/coroutine-hostile-raii>` | | | {doc}`misc-definitions-in-headers <misc/definitions-in-headers>` | Yes | | {doc}`misc-explicit-constructor <misc/explicit-constructor>` | Yes | +| {doc}`misc-header-guard <misc/header-guard>` | Yes | | {doc}`misc-header-include-cycle <misc/header-include-cycle>` | | | {doc}`misc-include-cleaner <misc/include-cleaner>` | Yes | | {doc}`misc-misleading-bidirectional <misc/misleading-bidirectional>` | | diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/header-guard.md b/clang-tools-extra/docs/clang-tidy/checks/misc/header-guard.md new file mode 100644 index 0000000000000..f419b9e90288b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/header-guard.md @@ -0,0 +1,95 @@ +```{title} clang-tidy - misc-header-guard +``` + +# misc-header-guard + +Finds and fixes header guards that do not conform to the configured style +options. + +All following examples consider header file +`/path/to/include/component/header.hpp` + +By default, the check ensures following header guard: + +```cpp +#ifndef COMPONENT_HEADER_HPP +#define COMPONENT_HEADER_HPP +... +#endif +``` + +## Options + +````{option} HeaderDirs + +A semicolon-separated list of one or more header directory names. Header +directories may contain `/` as path separator. The list is searched for the +first matching string. The header guard will start from this path +component. Default is `include`. + +E.g. {option}`HeaderDirs` is set to one of the following values: + +* `component` +* `include/component` +* `component;include` + +It results in the same following header guard: + +```cpp +#ifndef HEADER_HPP +#define HEADER_HPP +... +#endif +``` + +:::{warning} +The {option}`HeaderDirs` list is searched until first directory name +matches the header file path. E.g. if {option}`HeaderDirs` is set to +`include;component`, the check will result in default behavior (since +`include` is found first). +::: +```` + +````{option} Prefix + +A string specifying an optional prefix that is applied to each header guard. +Default is an empty string. + +E.g. {option}`Prefix` is set to `MY_OWN_PREFIX_`: + +```cpp +#ifndef MY_OWN_PREFIX_COMPONENT_HEADER_HPP +#define MY_OWN_PREFIX_COMPONENT_HEADER_HPP +... +#endif +``` +```` + +````{option} EndifComment + +A Boolean that controls whether the `#endif` comment is suggested. +Default is `false`. + +E.g. {option}`EndifComment` is set to `true`: + +```cpp +#ifndef COMPONENT_HEADER_HPP +#define COMPONENT_HEADER_HPP +... +#endif // COMPONENT_HEADER_HPP +``` +```` + +````{option} AllowPragmaOnce + +A Boolean that controls whether `#pragma once` directive is allowed. +Default is `false`. + +E.g. with option {option}`AllowPragmaOnce` set to `true`, `#pragma once` +is allowed as header guard: + +```cpp +#pragma once +... +``` +```` diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard-pragma-once-leak.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard-pragma-once-leak.cpp new file mode 100644 index 0000000000000..14c0bfc865d57 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard-pragma-once-leak.cpp @@ -0,0 +1,16 @@ +// Regression test: pragma-once state must be tracked per file, not once for +// the whole translation unit. Otherwise a `#pragma once` in one header +// (allowed via AllowPragmaOnce) would suppress the "missing header guard" +// diagnostic for an unrelated header included later in the same TU. +#include "header-guard/include/pragma-once-leak-a.hpp" +#include "header-guard/include/pragma-once-leak-b.hpp" + +// RUN: %check_clang_tidy %s misc-header-guard %t -export-fixes=%t.yaml \ +// RUN: --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.AllowPragmaOnce: true, \ +// RUN: }}' -- -I%S > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s + +// CHECK-MSG-NOT: pragma-once-leak-a.hpp{{.*}}warning: +// CHECK-MSG: pragma-once-leak-b.hpp:1:1: warning: header is missing header guard [misc-header-guard] diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard.cpp new file mode 100644 index 0000000000000..18efcab015744 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard.cpp @@ -0,0 +1,252 @@ +#include "header-guard/include/correct.hpp" +#include "header-guard/include/missing.hpp" +#include "header-guard/include/wrong.hpp" + +#include "header-guard/include/other/correct.hpp" +#include "header-guard/include/other/missing.hpp" +#include "header-guard/include/other/wrong.hpp" + +// --------------------------------------- +// TEST 1: Use no config options (default) +// --------------------------------------- +// RUN: %check_clang_tidy %s misc-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: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES1: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES1: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES1: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-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" +// CHECK-YAML1: ReplacementText: "\n#endif\n" + +// CHECK-YAML1: Message: header is missing header guard +// CHECK-YAML1: FilePath: '{{.*header-guard.include.other.}}missing.hpp' +// CHECK-YAML1: ReplacementText: "#ifndef OTHER_MISSING_HPP\n#define OTHER_MISSING_HPP\n\n" +// CHECK-YAML1: ReplacementText: "\n#endif\n" + +// CHECK-YAML1: Message: header guard does not follow preferred style +// CHECK-YAML1: FilePath: '{{.*header-guard.include.other.}}wrong.hpp' +// CHECK-YAML1: ReplacementText: OTHER_WRONG_HPP + +// CHECK-YAML1: Message: header guard does not follow preferred style +// CHECK-YAML1: FilePath: '{{.*header-guard.include.}}wrong.hpp' +// CHECK-YAML1: ReplacementText: WRONG_HPP + + +// --------------------------------------- +// TEST 2: Set option HeaderDirs=other +// --------------------------------------- +// RUN: %check_clang_tidy %s misc-header-guard %t -export-fixes=%t.2.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-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: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES2: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES2: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES2: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES2: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES2: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] + +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*header-guard.include.}}correct.hpp' +// CHECK-YAML2: ReplacementText: {{.*}}CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_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 {{.*}}CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_MISSING_HPP\n#define {{.*}}CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_MISSING_HPP\n\n" +// CHECK-YAML2: ReplacementText: "\n#endif\n" + +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*header-guard.include.other.}}correct.hpp' +// CHECK-YAML2: ReplacementText: CORRECT_HPP + +// CHECK-YAML2: Message: header is missing header guard +// CHECK-YAML2: FilePath: '{{.*header-guard.include.other.}}missing.hpp' +// CHECK-YAML2: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n" +// CHECK-YAML2: ReplacementText: "\n#endif\n" + +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*header-guard.include.other.}}wrong.hpp' +// CHECK-YAML2: ReplacementText: WRONG_HPP + +// CHECK-YAML2: Message: header guard does not follow preferred style +// CHECK-YAML2: FilePath: '{{.*header-guard.include.}}wrong.hpp' +// CHECK-YAML2: ReplacementText: {{.*}}CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_WRONG_HPP + + +// --------------------------------------- +// TEST 3: Set option HeaderDirs=other;include +// --------------------------------------- +// RUN: %check_clang_tidy %s misc-header-guard %t -export-fixes=%t.3.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.HeaderDirs: other;include, \ +// 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: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES3: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES3: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES3: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES3: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES3: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-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" +// CHECK-YAML3: ReplacementText: "\n#endif\n" + +// CHECK-YAML3: Message: header guard does not follow preferred style +// CHECK-YAML3: FilePath: '{{.*header-guard.include.other.}}correct.hpp' +// CHECK-YAML3: ReplacementText: CORRECT_HPP + +// CHECK-YAML3: Message: header is missing header guard +// CHECK-YAML3: FilePath: '{{.*header-guard.include.other.}}missing.hpp' +// CHECK-YAML3: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n" +// CHECK-YAML3: ReplacementText: "\n#endif\n" + +// CHECK-YAML3: Message: header guard does not follow preferred style +// CHECK-YAML3: FilePath: '{{.*header-guard.include.other.}}wrong.hpp' +// CHECK-YAML3: ReplacementText: WRONG_HPP + +// CHECK-YAML3: Message: header guard does not follow preferred style +// CHECK-YAML3: FilePath: '{{.*header-guard.include.}}wrong.hpp' +// CHECK-YAML3: ReplacementText: WRONG_HPP + + +// ------------------------------------------------------------------- +// TEST 4: Set option HeaderDirs=other;include and Prefix=SOME_PREFIX_ +// ------------------------------------------------------------------- +// RUN: %check_clang_tidy %s misc-header-guard %t -export-fixes=%t.4.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.Prefix: SOME_PREFIX_, \ +// RUN: }}' -- -I%S > %t.4.msg 2>&1 +// RUN: FileCheck -input-file=%t.4.msg -check-prefix=CHECK-MESSAGES4 %s +// RUN: FileCheck -input-file=%t.4.yaml -check-prefix=CHECK-YAML4 %s + +// CHECK-MESSAGES4: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES4: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES4: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES4: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES4: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES4: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] + +// CHECK-YAML4: Message: header guard does not follow preferred style +// CHECK-YAML4: FilePath: '{{.*header-guard.include.}}correct.hpp' +// CHECK-YAML4: ReplacementText: SOME_PREFIX_CORRECT_HPP + +// CHECK-YAML4: Message: header is missing header guard +// CHECK-YAML4: FilePath: '{{.*header-guard.include.}}missing.hpp' +// CHECK-YAML4: ReplacementText: "#ifndef SOME_PREFIX_MISSING_HPP\n#define SOME_PREFIX_MISSING_HPP\n\n" +// CHECK-YAML4: ReplacementText: "\n#endif\n" + +// CHECK-YAML4: Message: header guard does not follow preferred style +// CHECK-YAML4: FilePath: '{{.*header-guard.include.other.}}correct.hpp' +// CHECK-YAML4: ReplacementText: SOME_PREFIX_OTHER_CORRECT_HPP + +// CHECK-YAML4: Message: header is missing header guard +// CHECK-YAML4: FilePath: '{{.*header-guard.include.other.}}missing.hpp' +// CHECK-YAML4: ReplacementText: "#ifndef SOME_PREFIX_OTHER_MISSING_HPP\n#define SOME_PREFIX_OTHER_MISSING_HPP\n\n" +// CHECK-YAML4: ReplacementText: "\n#endif\n" + +// CHECK-YAML4: Message: header guard does not follow preferred style +// CHECK-YAML4: FilePath: '{{.*header-guard.include.other.}}wrong.hpp' +// CHECK-YAML4: ReplacementText: SOME_PREFIX_OTHER_WRONG_HPP + +// CHECK-YAML4: Message: header guard does not follow preferred style +// CHECK-YAML4: FilePath: '{{.*header-guard.include.}}wrong.hpp' +// CHECK-YAML4: ReplacementText: SOME_PREFIX_WRONG_HPP + + + +// ------------------------------------------------------------------- +// TEST 5: Set option EndifComment=true +// ------------------------------------------------------------------- +// RUN: %check_clang_tidy %s misc-header-guard %t -export-fixes=%t.5.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.EndifComment: true, \ +// RUN: }}' -- -I%S > %t.5.msg 2>&1 +// RUN: FileCheck -input-file=%t.5.msg -check-prefix=CHECK-MESSAGES5 %s +// RUN: FileCheck -input-file=%t.5.yaml -check-prefix=CHECK-YAML5 %s + +// CHECK-MESSAGES5: correct.hpp:6:2: warning: #endif for a header guard should reference the guard macro in a comment [misc-header-guard] +// CHECK-MESSAGES5: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES5: other{{.}}correct.hpp:6:2: warning: #endif for a header guard should reference the guard macro in a comment [misc-header-guard] +// CHECK-MESSAGES5: other{{.}}missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES5: other{{.}}wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES5: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] + +// CHECK-YAML5: Message: '#endif for a header guard should reference the guard macro in a comment' +// CHECK-YAML5: FilePath: '{{.*header-guard.include.}}correct.hpp' +// CHECK-YAML5: ReplacementText: 'endif // CORRECT_HPP' + +// CHECK-YAML5: Message: header is missing header guard +// CHECK-YAML5: FilePath: '{{.*header-guard.include.}}missing.hpp' +// CHECK-YAML5: ReplacementText: "#ifndef MISSING_HPP\n#define MISSING_HPP\n\n" +// CHECK-YAML5: ReplacementText: "\n#endif // MISSING_HPP\n" + +// CHECK-YAML5: Message: '#endif for a header guard should reference the guard macro in a comment' +// CHECK-YAML5: FilePath: '{{.*header-guard.include.other.}}correct.hpp' +// CHECK-YAML5: ReplacementText: 'endif // OTHER_CORRECT_HPP' + +// CHECK-YAML5: Message: header is missing header guard +// CHECK-YAML5: FilePath: '{{.*header-guard.include.other.}}missing.hpp' +// CHECK-YAML5: ReplacementText: "#ifndef OTHER_MISSING_HPP\n#define OTHER_MISSING_HPP\n\n" +// CHECK-YAML5: ReplacementText: "\n#endif // OTHER_MISSING_HPP\n" + +// CHECK-YAML5: Message: header guard does not follow preferred style +// CHECK-YAML5: FilePath: '{{.*header-guard.include.other.}}wrong.hpp' +// CHECK-YAML5: ReplacementText: OTHER_WRONG_HPP + +// CHECK-YAML5: Message: header guard does not follow preferred style +// CHECK-YAML5: FilePath: '{{.*header-guard.include.}}wrong.hpp' +// CHECK-YAML5: ReplacementText: WRONG_HPP + +// ------------------------------------------------------------------- +// TEST 6: Set option HeaderDirs=path/to/non-matching-dir +// ------------------------------------------------------------------- +// RUN: %check_clang_tidy %s misc-header-guard %t -export-fixes=%t.6.yaml --header-filter=.* \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.HeaderDirs: path/to/non-matching-dir, \ +// RUN: }}' -- -I%S > %t.6.msg 2>&1 +// RUN: FileCheck -input-file=%t.6.msg -check-prefix=CHECK-MESSAGES6 %s +// RUN: FileCheck -input-file=%t.6.yaml -check-prefix=CHECK-YAML6 %s + +// CHECK-MESSAGES6: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES6: correct.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES6: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES6: missing.hpp:1:1: warning: header is missing header guard [misc-header-guard] +// CHECK-MESSAGES6: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] +// CHECK-MESSAGES6: wrong.hpp:1:9: warning: header guard does not follow preferred style [misc-header-guard] + +// CHECK-YAML6: Message: header guard does not follow preferred style +// CHECK-YAML6: FilePath: '{{.*header-guard.include.}}correct.hpp' +// CHECK-YAML6: ReplacementText: {{.*}}_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_CORRECT_HPP + +// CHECK-YAML6: Message: header is missing header guard +// CHECK-YAML6: FilePath: '{{.*header-guard.include.}}missing.hpp' +// CHECK-YAML6: ReplacementText: "#ifndef {{.*}}_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_MISSING_HPP + +// CHECK-YAML6: Message: header guard does not follow preferred style +// CHECK-YAML6: FilePath: '{{.*header-guard.include.other.}}correct.hpp' +// CHECK-YAML6: ReplacementText: {{.*}}_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_OTHER_CORRECT_HPP + +// CHECK-YAML6: Message: header is missing header guard +// CHECK-YAML6: FilePath: '{{.*header-guard.include.other.}}missing.hpp' +// CHECK-YAML6: ReplacementText: "#ifndef {{.*}}_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_OTHER_MISSING_HPP + +// CHECK-YAML6: Message: header guard does not follow preferred style +// CHECK-YAML6: FilePath: '{{.*header-guard.include.other.}}wrong.hpp' +// CHECK-YAML6: ReplacementText: {{.*}}_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_OTHER_WRONG_HPP + +// CHECK-YAML6: Message: header guard does not follow preferred style +// CHECK-YAML6: FilePath: '{{.*header-guard.include.}}wrong.hpp' +// CHECK-YAML6: ReplacementText: {{.*}}_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_MISC_HEADER_GUARD_INCLUDE_WRONG_HPP + diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/correct.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/correct.hpp new file mode 100644 index 0000000000000..14117bae35153 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/correct.hpp @@ -0,0 +1,6 @@ +#ifndef CORRECT_HPP +#define CORRECT_HPP +// RUN: %check_clang_tidy %s misc-header-guard correct -export-fixes=%t.yaml > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG-NOT: warning: +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/missing.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/missing.hpp new file mode 100644 index 0000000000000..4a5a3a495a2b1 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/missing.hpp @@ -0,0 +1,3 @@ +// RUN: %check_clang_tidy %s misc-header-guard missing -export-fixes=%t.yaml > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG: :1:1: warning: header is missing header guard [misc-header-guard] diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/correct.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/correct.hpp new file mode 100644 index 0000000000000..63cda116d3f3e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/correct.hpp @@ -0,0 +1,6 @@ +#ifndef OTHER_CORRECT_HPP +#define OTHER_CORRECT_HPP +// RUN: %check_clang_tidy %s misc-header-guard correct -export-fixes=%t.yaml > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG-NOT: warning: +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/missing.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/missing.hpp new file mode 100644 index 0000000000000..4a5a3a495a2b1 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/missing.hpp @@ -0,0 +1,3 @@ +// RUN: %check_clang_tidy %s misc-header-guard missing -export-fixes=%t.yaml > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG: :1:1: warning: header is missing header guard [misc-header-guard] diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/wrong.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/wrong.hpp new file mode 100644 index 0000000000000..a9afba832a10a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/other/wrong.hpp @@ -0,0 +1,7 @@ +#ifndef SOME_WRONG_HEADER_GUARD_HPP +#define SOME_WRONG_HEADER_GUARD_HPP +#endif + +// RUN: %check_clang_tidy %s misc-header-guard wrong -export-fixes=%t.yaml > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG: warning: header guard does not follow preferred style [misc-header-guard] diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-a.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-a.hpp new file mode 100644 index 0000000000000..dbb3171b079ce --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-a.hpp @@ -0,0 +1,8 @@ +#pragma once + +// RUN: %check_clang_tidy %s misc-header-guard pragma-once-leak-a -export-fixes=%t.yaml \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.AllowPragmaOnce: true, \ +// RUN: }}' > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG-NOT: warning: diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-b.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-b.hpp new file mode 100644 index 0000000000000..f7afb382629dd --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once-leak-b.hpp @@ -0,0 +1,8 @@ +// No header guard, no pragma once. + +// RUN: %check_clang_tidy %s misc-header-guard pragma-once-leak-b -export-fixes=%t.yaml \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.AllowPragmaOnce: true, \ +// RUN: }}' > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG: :1:1: warning: header is missing header guard [misc-header-guard] diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once.hpp new file mode 100644 index 0000000000000..be4a9341966e0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/pragma-once.hpp @@ -0,0 +1,10 @@ +#pragma once + +// RUN: %check_clang_tidy %s misc-header-guard pragma-once -export-fixes=%t.1.yaml > %t.1.msg 2>&1 +// RUN: FileCheck -input-file=%t.1.msg -check-prefix=CHECK-MSG1 %s +// CHECK-MSG1: pragma-once.hpp:1:1: warning: use include guards instead of 'pragma once' [misc-header-guard] + +// RUN: %check_clang_tidy %s misc-header-guard pragma-once \ +// RUN: --config='{CheckOptions: { \ +// RUN: misc-header-guard.AllowPragmaOnce: true, \ +// RUN: }}' > %t.2.msg 2>&1 diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/wrong.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/wrong.hpp new file mode 100644 index 0000000000000..e5ca81da6a680 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-guard/include/wrong.hpp @@ -0,0 +1,7 @@ +#ifndef HERE_IS_SOMETHING_WRONG_HPP +#define HERE_IS_SOMETHING_WRONG_HPP +#endif + +// RUN: %check_clang_tidy %s misc-header-guard wrong -export-fixes=%t.yaml > %t.msg 2>&1 +// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MSG %s +// CHECK-MSG: warning: header guard does not follow preferred style [misc-header-guard] _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
