diff --git a/clang-tools-extra/clang-tidy/utils/HeaderGuard.h b/clang-tools-extra/clang-tidy/utils/HeaderGuard.h --- a/clang-tools-extra/clang-tidy/utils/HeaderGuard.h +++ b/clang-tools-extra/clang-tidy/utils/HeaderGuard.h @@ -38,6 +38,9 @@ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override; + /// Ensure that the provided header guard is a non-reserved identifier. + std::string sanitizeHeaderGuard(StringRef Guard); + /// Returns ``true`` if the check should suggest inserting a trailing comment /// on the ``#endif`` of the header guard. It will use the same name as /// returned by ``HeaderGuardCheck::getHeaderGuard``. diff --git a/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp b/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp --- a/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp +++ b/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp @@ -164,9 +164,10 @@ StringRef CurHeaderGuard, std::vector &FixIts) { std::string CPPVar = Check->getHeaderGuard(FileName, CurHeaderGuard); + CPPVar = Check->sanitizeHeaderGuard(CPPVar); std::string CPPVarUnder = CPPVar + '_'; - // Allow a trailing underscore iff we don't have to change the endif comment + // Allow a trailing underscore if we don't have to change the endif comment // too. if (Ifndef.isValid() && CurHeaderGuard != CPPVar && (CurHeaderGuard != CPPVarUnder || @@ -216,6 +217,7 @@ continue; std::string CPPVar = Check->getHeaderGuard(FileName); + CPPVar = Check->sanitizeHeaderGuard(CPPVar); std::string CPPVarUnder = CPPVar + '_'; // Allow a trailing underscore. // If there's a macro with a name that follows the header guard convention // but was not recognized by the preprocessor as a header guard there must @@ -278,6 +280,11 @@ PP->addPPCallbacks(std::make_unique(PP, this)); } +std::string HeaderGuardCheck::sanitizeHeaderGuard(StringRef Guard) { + // Only reserved identifiers are allowed to start with an '_'. + return Guard.drop_while([](char C) { return C == '_'; }).str(); +} + bool HeaderGuardCheck::shouldSuggestEndifComment(StringRef FileName) { return utils::isFileExtension(FileName, HeaderFileExtensions); } diff --git a/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp b/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp --- a/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp @@ -219,6 +219,16 @@ "", "/llvm-project/clang-tools-extra/clangd/foo.h", StringRef("header is missing header guard"))); + // Substitution of characters should not result in a header guard starting + // with "_". + EXPECT_EQ("#ifndef BAR_H\n" + "#define BAR_H\n" + "\n" + "\n" + "#endif\n", + runHeaderGuardCheck("", "include/--bar.h", + StringRef("header is missing header guard"))); + #ifdef WIN32 // Check interaction with Windows-style path separators (\). EXPECT_EQ(