Index: clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tidy/bugprone/BugproneTidyModule.cpp @@ -20,6 +20,7 @@ #include "FoldInitTypeCheck.h" #include "ForwardDeclarationNamespaceCheck.h" #include "ForwardingReferenceOverloadCheck.h" +#include "HeaderGuardCheck.h" #include "InaccurateEraseCheck.h" #include "IncorrectRoundingsCheck.h" #include "IntegerDivisionCheck.h" @@ -80,6 +81,8 @@ "bugprone-forward-declaration-namespace"); CheckFactories.registerCheck( "bugprone-forwarding-reference-overload"); + CheckFactories.registerCheck( + "bugprone-header-guard"); CheckFactories.registerCheck( "bugprone-inaccurate-erase"); CheckFactories.registerCheck( Index: clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tidy/bugprone/CMakeLists.txt +++ clang-tidy/bugprone/CMakeLists.txt @@ -12,6 +12,7 @@ FoldInitTypeCheck.cpp ForwardDeclarationNamespaceCheck.cpp ForwardingReferenceOverloadCheck.cpp + HeaderGuardCheck.cpp InaccurateEraseCheck.cpp IncorrectRoundingsCheck.cpp IntegerDivisionCheck.cpp Index: clang-tidy/bugprone/HeaderGuardCheck.h =================================================================== --- /dev/null +++ clang-tidy/bugprone/HeaderGuardCheck.h @@ -0,0 +1,39 @@ +//===--- HeaderGuardCheck.h - clang-tidy ------------------------*- C++ -*-===// +// +// 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_BUGPRONE_HEADERGUARDCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_HEADERGUARDCHECK_H + +#include "../utils/HeaderGuard.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds and fixes missing header guards and does not enforce any style. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-header-guard.html +class BugproneHeaderGuardCheck : public utils::HeaderGuardCheck { +public: + BugproneHeaderGuardCheck(StringRef Name, ClangTidyContext *Context); + bool shouldSuggestToAddHeaderGuard(StringRef Filename) override; + bool shouldSuggestEndifComment(StringRef Filename) override { return false; } + std::string getHeaderGuard(StringRef Filename, StringRef OldGuard) override; + + enum GuardStyle { GS_Unsupported = 0, GS_Minimal, GS_LLVM }; + +private: + const enum GuardStyle Style; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_HEADERGUARDCHECK_H Index: clang-tidy/bugprone/HeaderGuardCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/bugprone/HeaderGuardCheck.cpp @@ -0,0 +1,77 @@ +//===--- HeaderGuardCheck.cpp - clang-tidy --------------------------------===// +// +// 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" + +namespace clang { +namespace tidy { +namespace bugprone { + +BugproneHeaderGuardCheck::BugproneHeaderGuardCheck(StringRef Name, + ClangTidyContext *Context) + : HeaderGuardCheck(Name, Context), + Style(llvm::StringSwitch(Options.get("GuardStyle", "minimal")) + .Case("llvm", GS_LLVM) + .Case("minimal", GS_Minimal) + .Default(GS_Unsupported)) {} + +bool BugproneHeaderGuardCheck::shouldSuggestToAddHeaderGuard( + StringRef Filename) { + if (Style == GS_Unsupported) + return false; + + return HeaderGuardCheck::shouldSuggestToAddHeaderGuard(Filename); +} + +std::string BugproneHeaderGuardCheck::getHeaderGuard(StringRef Filename, + StringRef OldGuard) { + std::string Guard; + if (Style == GS_LLVM) { + Guard = tooling::getAbsolutePath(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. + size_t PosInclude = Guard.rfind("include/"); + if (PosInclude != StringRef::npos) + Guard = Guard.substr(PosInclude + std::strlen("include/")); + + // For clang we drop the _TOOLS_. + size_t PosToolsClang = Guard.rfind("tools/clang/"); + if (PosToolsClang != StringRef::npos) + Guard = Guard.substr(PosToolsClang + std::strlen("tools/")); + + // The remainder is LLVM_FULL_PATH_TO_HEADER_H + size_t PosLLVM = Guard.rfind("llvm/"); + if (PosLLVM != StringRef::npos) + Guard = Guard.substr(PosLLVM); + + std::replace(Guard.begin(), Guard.end(), '/', '_'); + + // The prevalent style in clang is LLVM_CLANG_FOO_BAR_H + if (StringRef(Guard).startswith("clang")) + Guard = "LLVM_" + Guard; + + } else if (Style == GS_Minimal) { + if (OldGuard.size()) + return OldGuard; + Guard = llvm::sys::path::filename(Filename); + } else { + // Called without a recognized style. + // Do not suggest any changes. + return OldGuard; + } + std::replace(Guard.begin(), Guard.end(), '.', '_'); + std::replace(Guard.begin(), Guard.end(), '-', '_'); + return StringRef(Guard).upper(); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tidy/llvm/CMakeLists.txt =================================================================== --- clang-tidy/llvm/CMakeLists.txt +++ clang-tidy/llvm/CMakeLists.txt @@ -1,7 +1,6 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyLLVMModule - HeaderGuardCheck.cpp IncludeOrderCheck.cpp LLVMTidyModule.cpp PreferIsaOrDynCastInConditionalsCheck.cpp Index: clang-tidy/llvm/HeaderGuardCheck.h =================================================================== --- clang-tidy/llvm/HeaderGuardCheck.h +++ /dev/null @@ -1,39 +0,0 @@ -//===--- HeaderGuardCheck.h - clang-tidy ------------------------*- C++ -*-===// -// -// 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_LLVM_HEADERGUARDCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADERGUARDCHECK_H - -#include "../utils/HeaderGuard.h" - -namespace clang { -namespace tidy { -namespace llvm_check { - -/// Finds and fixes header guards that do not adhere to LLVM style. -/// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/llvm-header-guard.html -/// The check supports these options: -/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of -/// header files (The filename extension should not contain "." prefix). -/// ",h,hh,hpp,hxx" by default. -/// For extension-less header files, using an empty string or leaving an -/// empty string between "," if there are other filename extensions. -class LLVMHeaderGuardCheck : public utils::HeaderGuardCheck { -public: - LLVMHeaderGuardCheck(StringRef Name, ClangTidyContext *Context); - - bool shouldSuggestEndifComment(StringRef Filename) override { return false; } - std::string getHeaderGuard(StringRef Filename, StringRef OldGuard) override; -}; - -} // namespace llvm_check -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADERGUARDCHECK_H Index: clang-tidy/llvm/HeaderGuardCheck.cpp =================================================================== --- clang-tidy/llvm/HeaderGuardCheck.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===--- HeaderGuardCheck.cpp - clang-tidy --------------------------------===// -// -// 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" - -namespace clang { -namespace tidy { -namespace llvm_check { - -LLVMHeaderGuardCheck::LLVMHeaderGuardCheck(StringRef Name, - ClangTidyContext *Context) - : HeaderGuardCheck(Name, Context) {} - -std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename, - StringRef OldGuard) { - std::string Guard = tooling::getAbsolutePath(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. - size_t PosInclude = Guard.rfind("include/"); - if (PosInclude != StringRef::npos) - Guard = Guard.substr(PosInclude + std::strlen("include/")); - - // For clang we drop the _TOOLS_. - size_t PosToolsClang = Guard.rfind("tools/clang/"); - if (PosToolsClang != StringRef::npos) - Guard = Guard.substr(PosToolsClang + std::strlen("tools/")); - - // The remainder is LLVM_FULL_PATH_TO_HEADER_H - size_t PosLLVM = Guard.rfind("llvm/"); - if (PosLLVM != StringRef::npos) - Guard = Guard.substr(PosLLVM); - - std::replace(Guard.begin(), Guard.end(), '/', '_'); - std::replace(Guard.begin(), Guard.end(), '.', '_'); - std::replace(Guard.begin(), Guard.end(), '-', '_'); - - // The prevalent style in clang is LLVM_CLANG_FOO_BAR_H - if (StringRef(Guard).startswith("clang")) - Guard = "LLVM_" + Guard; - - return StringRef(Guard).upper(); -} - -} // namespace llvm_check -} // namespace tidy -} // namespace clang Index: clang-tidy/llvm/LLVMTidyModule.cpp =================================================================== --- clang-tidy/llvm/LLVMTidyModule.cpp +++ clang-tidy/llvm/LLVMTidyModule.cpp @@ -10,7 +10,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "../readability/NamespaceCommentCheck.h" -#include "HeaderGuardCheck.h" +#include "../bugprone/HeaderGuardCheck.h" #include "IncludeOrderCheck.h" #include "PreferIsaOrDynCastInConditionalsCheck.h" #include "TwineLocalCheck.h" @@ -22,7 +22,8 @@ class LLVMModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck("llvm-header-guard"); + CheckFactories.registerCheck( + "llvm-header-guard"); CheckFactories.registerCheck("llvm-include-order"); CheckFactories.registerCheck( "llvm-namespace-comment"); @@ -30,6 +31,16 @@ "llvm-prefer-isa-or-dyn-cast-in-conditionals"); CheckFactories.registerCheck("llvm-twine-local"); } + + ClangTidyOptions getModuleOptions() override { + ClangTidyOptions Options; + ClangTidyOptions::OptionMap &Opts = Options.CheckOptions; + + Opts["llvm-header-guard.GuardStyle"] = "llvm"; + + return Options; + } + }; // Register the LLVMTidyModule using this statically initialized variable. Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -122,6 +122,11 @@ Checks whether there are underscores in googletest test and test case names in test macros, which is prohibited by the Googletest FAQ. +- New :doc:`bugprone-header-guard + ` check. + + Finds and fixes missing header guards and does not enforce any style. + - New :doc:`objc-super-self ` check. Finds invocations of ``-self`` on super instances in initializers of Index: docs/clang-tidy/checks/bugprone-header-guard.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/bugprone-header-guard.rst @@ -0,0 +1,31 @@ +.. title:: clang-tidy - bugprone-header-guard + +bugprone-header-guard +===================== + +Finds and fixes missing header guards and does not enforce any style. + +Options +------- + +.. option:: HeaderFileExtensions + + A comma-separated list of filename extensions of header files (the filename + extensions should not include "." prefix). Default is `h,hh,hpp,hxx`. + For header files without an extension, use an empty string (if there are no + other desired extensions) or leave an empty element in the list. e.g., + `h,hh,hpp,hxx,` (note the trailing comma). + +.. option:: GuardStyle + + The style to use for the header guard. The values are + + .. option:: minimal + + If a guard is missing, use the uppercased filename as the guard. This is + the default. + + .. option:: llvm + + Finds and fixes header guards that do not adhere to LLVM style. Used by + the `llvm-header-guard `_ checker. Index: docs/clang-tidy/checks/google-build-namespaces.rst =================================================================== --- docs/clang-tidy/checks/google-build-namespaces.rst +++ docs/clang-tidy/checks/google-build-namespaces.rst @@ -18,7 +18,7 @@ .. option:: HeaderFileExtensions A comma-separated list of filename extensions of header files (the filename - extensions should not include "." prefix). Default is "h,hh,hpp,hxx". + extensions should not include "." prefix). Default is `h,hh,hpp,hxx`. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., - "h,hh,hpp,hxx," (note the trailing comma). + `h,hh,hpp,hxx,` (note the trailing comma). Index: docs/clang-tidy/checks/google-global-names-in-headers.rst =================================================================== --- docs/clang-tidy/checks/google-global-names-in-headers.rst +++ docs/clang-tidy/checks/google-global-names-in-headers.rst @@ -15,7 +15,7 @@ .. option:: HeaderFileExtensions A comma-separated list of filename extensions of header files (the filename - extensions should not contain "." prefix). Default is "h". + extensions should not include "." prefix). Default is `h,hh,hpp,hxx`. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., - "h,hh,hpp,hxx," (note the trailing comma). + `h,hh,hpp,hxx,` (note the trailing comma). Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -45,6 +45,7 @@ bugprone-fold-init-type bugprone-forward-declaration-namespace bugprone-forwarding-reference-overload + bugprone-header-guard bugprone-inaccurate-erase bugprone-incorrect-roundings bugprone-integer-division Index: docs/clang-tidy/checks/llvm-header-guard.rst =================================================================== --- docs/clang-tidy/checks/llvm-header-guard.rst +++ docs/clang-tidy/checks/llvm-header-guard.rst @@ -3,15 +3,6 @@ llvm-header-guard ================= -Finds and fixes header guards that do not adhere to LLVM style. +The llvm-header-guard check is an alias, please see +`bugprone-header-guard `_ for more information. -Options -------- - -.. option:: HeaderFileExtensions - - A comma-separated list of filename extensions of header files (the filename - extensions should not include "." prefix). Default is "h,hh,hpp,hxx". - For header files without an extension, use an empty string (if there are no - other desired extensions) or leave an empty element in the list. e.g., - "h,hh,hpp,hxx," (note the trailing comma). Index: docs/clang-tidy/checks/misc-definitions-in-headers.rst =================================================================== --- docs/clang-tidy/checks/misc-definitions-in-headers.rst +++ docs/clang-tidy/checks/misc-definitions-in-headers.rst @@ -89,10 +89,10 @@ .. option:: HeaderFileExtensions A comma-separated list of filename extensions of header files (the filename - extensions should not include "." prefix). Default is "h,hh,hpp,hxx". + extensions should not include "." prefix). Default is `h,hh,hpp,hxx`. For header files without an extension, use an empty string (if there are no other desired extensions) or leave an empty element in the list. e.g., - "h,hh,hpp,hxx," (note the trailing comma). + `h,hh,hpp,hxx,` (note the trailing comma). .. option:: UseHeaderFileExtension Index: test/clang-tidy/bugprone-header-guard.cpp =================================================================== --- /dev/null +++ test/clang-tidy/bugprone-header-guard.cpp @@ -0,0 +1,21 @@ +// GuardStyle=default (minimal), HeaderFileExtension=cpp +// RUN: %check_clang_tidy %s bugprone-header-guard %t -- -config="{CheckOptions: [{key: bugprone-header-guard.HeaderFileExtensions, value: 'cpp'}]}" -header-filter=.* -- +// GuardStyle=llvm, HeaderFileExtension=cpp +// RUN: %check_clang_tidy -check-suffix=LLVM %s bugprone-header-guard %t -- -config="{CheckOptions: [{key: bugprone-header-guard.HeaderFileExtensions, value: 'cpp'}, {key: bugprone-header-guard.GuardStyle, value: 'llvm'}]}" -header-filter=.* -- +// GuardStyle=minimal, HeaderFileExtension=cpp +// RUN: %check_clang_tidy -check-suffix=MINIMAL %s bugprone-header-guard %t -- -config="{CheckOptions: [{key: bugprone-header-guard.HeaderFileExtensions, value: 'cpp'}, {key: bugprone-header-guard.GuardStyle, value: 'minimal'}]}" -header-filter=.* -- + +// CHECK-MESSAGES: 1:1: warning: header is missing header guard +// CHECK-FIXES: #ifndef BUGPRONE_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES-NEXT: #define BUGPRONE_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES: #endif + +// CHECK-MESSAGES-LLVM: 1:1: warning: header is missing header guard +// CHECK-FIXES-LLVM: #ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_OUTPUT_BUGPRONE_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES-NEXT-LLVM: #define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_OUTPUT_BUGPRONE_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES-LLVM: #endif + +// CHECK-MESSAGES-MINIMAL: 1:1: warning: header is missing header guard +// CHECK-FIXES-MINIMAL: #ifndef BUGPRONE_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES-NEXT-MINIMAL: #define BUGPRONE_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES-MINIMAL: #endif Index: test/clang-tidy/llvm-header-guard.cpp =================================================================== --- /dev/null +++ test/clang-tidy/llvm-header-guard.cpp @@ -0,0 +1,9 @@ +// RUN: %check_clang_tidy %s llvm-header-guard %t -- \ +// RUN: -config="{CheckOptions: [{key: llvm-header-guard.HeaderFileExtensions, value: 'cpp'}]}" \ +// RUN: -header-filter=.* -- + +// CHECK-MESSAGES: 1:1: warning: header is missing header guard + +// CHECK-FIXES: #ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_OUTPUT_LLVM_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES-NEXT: #define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_OUTPUT_LLVM_HEADER_GUARD_CPP_TMP_CPP +// CHECK-FIXES: #endif Index: unittests/clang-tidy/CMakeLists.txt =================================================================== --- unittests/clang-tidy/CMakeLists.txt +++ unittests/clang-tidy/CMakeLists.txt @@ -29,6 +29,7 @@ clangSerialization clangTidy clangTidyAndroidModule + clangTidyBugproneModule clangTidyGoogleModule clangTidyLLVMModule clangTidyObjCModule Index: unittests/clang-tidy/LLVMModuleTest.cpp =================================================================== --- unittests/clang-tidy/LLVMModuleTest.cpp +++ unittests/clang-tidy/LLVMModuleTest.cpp @@ -1,9 +1,10 @@ #include "ClangTidyTest.h" -#include "llvm/HeaderGuardCheck.h" +#include "bugprone/HeaderGuardCheck.h" #include "llvm/IncludeOrderCheck.h" #include "gtest/gtest.h" using namespace clang::tidy::llvm_check; +using namespace clang::tidy::bugprone; namespace clang { namespace tidy { @@ -14,8 +15,10 @@ static std::string runHeaderGuardCheck(StringRef Code, const Twine &Filename, Optional ExpectedWarning) { std::vector Errors; - std::string Result = test::runCheckOnCode( - Code, &Errors, Filename, std::string("-xc++-header")); + ClangTidyOptions Options; + Options.CheckOptions["test-check-0.GuardStyle"] = "llvm"; + std::string Result = test::runCheckOnCode( + Code, &Errors, Filename, std::string("-xc++-header"), Options); if (Errors.size() != (size_t)ExpectedWarning.hasValue()) return "invalid error count"; if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message) @@ -25,9 +28,9 @@ } namespace { -struct WithEndifComment : public LLVMHeaderGuardCheck { +struct WithEndifComment : public BugproneHeaderGuardCheck { WithEndifComment(StringRef Name, ClangTidyContext *Context) - : LLVMHeaderGuardCheck(Name, Context) {} + : BugproneHeaderGuardCheck(Name, Context) {} bool shouldSuggestEndifComment(StringRef Filename) override { return true; } }; } // namespace @@ -36,8 +39,10 @@ runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename, Optional ExpectedWarning) { std::vector Errors; + ClangTidyOptions Options; + Options.CheckOptions["test-check-0.GuardStyle"] = "llvm"; std::string Result = test::runCheckOnCode( - Code, &Errors, Filename, std::string("-xc++-header")); + Code, &Errors, Filename, std::string("-xc++-header"), Options); if (Errors.size() != (size_t)ExpectedWarning.hasValue()) return "invalid error count"; if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message)