Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -49,6 +49,13 @@ /// \p Default. std::string get(StringRef LocalName, std::string Default) const; + /// \brief Read a named option from the \c Context. + /// + /// Reads the option with the check-local name \p LocalName from local or + /// global \c CheckOptions. If the option is not present in both options, + /// returns Default. + std::string getLocalOrGlobal(StringRef LocalName, std::string Default) const; + /// \brief Read a named option from the \c Context and parse it as an integral /// type \c T. /// Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -341,6 +341,18 @@ return Default; } +std::string OptionsView::getLocalOrGlobal( + StringRef LocalName, std::string Default) const { + std::vector Names = { NamePrefix + LocalName.str(), + LocalName.str() }; + for (const auto &Name : Names) { + auto Iter = CheckOptions.find(Name); + if (Iter != CheckOptions.end()) + return Iter->second; + } + return Default; +} + void OptionsView::store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const { Options[NamePrefix + LocalName.str()] = Value; Index: clang-tidy/ClangTidyOptions.h =================================================================== --- clang-tidy/ClangTidyOptions.h +++ clang-tidy/ClangTidyOptions.h @@ -211,6 +211,11 @@ std::error_code parseLineFilter(llvm::StringRef LineFilter, ClangTidyGlobalOptions &Options); +/// \brief Checks whether file extension of Filename ends with +/// HeaderFileExtensions. +bool endWithHeaderFileExtensions(llvm::StringRef FileName, + llvm::StringRef HeaderFileExtensions); + /// \brief Parses configuration from JSON and returns \c ClangTidyOptions or an /// error. llvm::ErrorOr parseConfiguration(llvm::StringRef Config); Index: clang-tidy/ClangTidyOptions.cpp =================================================================== --- clang-tidy/ClangTidyOptions.cpp +++ clang-tidy/ClangTidyOptions.cpp @@ -263,6 +263,19 @@ return Input.error(); } +bool endWithHeaderFileExtensions(llvm::StringRef Filename, + llvm::StringRef HeaderFileExtensions) { + SmallVector Suffixes; + HeaderFileExtensions.split(Suffixes, ','); + for (const auto& Suffix : Suffixes) { + if (Suffix.empty() && llvm::sys::path::extension(Filename).empty()) + return true; + if (Filename.endswith(Suffix)) + return true; + } + return false; +} + llvm::ErrorOr parseConfiguration(StringRef Config) { llvm::yaml::Input Input(Config); ClangTidyOptions Options; Index: clang-tidy/google/GlobalNamesInHeadersCheck.h =================================================================== --- clang-tidy/google/GlobalNamesInHeadersCheck.h +++ clang-tidy/google/GlobalNamesInHeadersCheck.h @@ -17,14 +17,20 @@ namespace google { namespace readability { -// Flag global namespace pollution in header files. -// Right now it only triggers on using declarations and directives. +/// Flag global namespace pollution in header files. +/// Right now it only triggers on using declarations and directives. +/// +/// There is one option: +/// - `HeaderFileExtensions`: the file extensions that regard as header file. +/// ".h" by default. class GlobalNamesInHeadersCheck : public ClangTidyCheck { public: - GlobalNamesInHeadersCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + GlobalNamesInHeadersCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +private: + const std::string HeaderFileExtensions; }; } // namespace readability Index: clang-tidy/google/GlobalNamesInHeadersCheck.cpp =================================================================== --- clang-tidy/google/GlobalNamesInHeadersCheck.cpp +++ clang-tidy/google/GlobalNamesInHeadersCheck.cpp @@ -20,6 +20,17 @@ namespace google { namespace readability { +GlobalNamesInHeadersCheck::GlobalNamesInHeadersCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + HeaderFileExtensions(Options.getLocalOrGlobal("HeaderFileExtensions", + ".h")) {} + +void GlobalNamesInHeadersCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderFileExtensions", HeaderFileExtensions); +} + void GlobalNamesInHeadersCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { Finder->addMatcher( @@ -41,7 +52,7 @@ StringRef Filename = Result.SourceManager->getFilename( Result.SourceManager->getSpellingLoc(D->getLocStart())); - if (!Filename.endswith(".h")) + if (!endWithHeaderFileExtensions(Filename, HeaderFileExtensions)) return; } Index: clang-tidy/google/UnnamedNamespaceInHeaderCheck.h =================================================================== --- clang-tidy/google/UnnamedNamespaceInHeaderCheck.h +++ clang-tidy/google/UnnamedNamespaceInHeaderCheck.h @@ -19,15 +19,21 @@ /// Finds anonymous namespaces in headers. /// +/// There is one option: +/// - `HeaderFileExtensions`: the file extensions that regard as header file. +/// ".h,.hh,.hpp,.hxx" by default. +/// /// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Namespaces#Namespaces /// /// Corresponding cpplint.py check name: 'build/namespaces'. class UnnamedNamespaceInHeaderCheck : public ClangTidyCheck { public: - UnnamedNamespaceInHeaderCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + UnnamedNamespaceInHeaderCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +private: + const std::string HeaderFileExtensions; }; } // namespace build Index: clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp =================================================================== --- clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp +++ clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp @@ -19,6 +19,17 @@ namespace google { namespace build { +UnnamedNamespaceInHeaderCheck::UnnamedNamespaceInHeaderCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + HeaderFileExtensions(Options.getLocalOrGlobal("HeaderFileExtensions", + ".h,.hh,.hpp,.hxx")) {} + +void UnnamedNamespaceInHeaderCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderFileExtensions", HeaderFileExtensions); +} + void UnnamedNamespaceInHeaderCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not @@ -36,11 +47,8 @@ if (!Loc.isValid()) return; - // Look if we're inside a header, check for common suffixes only. - // TODO: Allow configuring the set of file extensions. StringRef FileName = SM->getPresumedLoc(Loc).getFilename(); - if (FileName.endswith(".h") || FileName.endswith(".hh") || - FileName.endswith(".hpp") || FileName.endswith(".hxx")) + if (endWithHeaderFileExtensions(FileName, HeaderFileExtensions)) diag(Loc, "do not use unnamed namespaces in header files"); } Index: clang-tidy/misc/DefinitionsInHeadersCheck.h =================================================================== --- clang-tidy/misc/DefinitionsInHeadersCheck.h +++ clang-tidy/misc/DefinitionsInHeadersCheck.h @@ -22,6 +22,8 @@ // There is one option: // - `UseHeaderFileExtension`: Whether to use file extension (h, hh, hpp, hxx) // to distinguish header files. True by default. +// - `HeaderFileExtensions`: the file extensions that regard as header file. +// ",.h,.hh,.hpp,.hxx" by default. // // For the user-facing documentation see: // http://clang.llvm.org/extra/clang-tidy/checks/misc-definitions-in-headers.html @@ -34,6 +36,7 @@ private: const bool UseHeaderFileExtension; + const std::string HeaderFileExtensions; }; } // namespace misc Index: clang-tidy/misc/DefinitionsInHeadersCheck.cpp =================================================================== --- clang-tidy/misc/DefinitionsInHeadersCheck.cpp +++ clang-tidy/misc/DefinitionsInHeadersCheck.cpp @@ -19,13 +19,12 @@ namespace { -AST_MATCHER(NamedDecl, isHeaderFileExtension) { +AST_MATCHER_P(NamedDecl, useHeaderFileExtension, + StringRef, HeaderFileExtensions) { SourceManager& SM = Finder->getASTContext().getSourceManager(); SourceLocation ExpansionLoc = SM.getExpansionLoc(Node.getLocStart()); StringRef Filename = SM.getFilename(ExpansionLoc); - return Filename.endswith(".h") || Filename.endswith(".hh") || - Filename.endswith(".hpp") || Filename.endswith(".hxx") || - llvm::sys::path::extension(Filename).empty(); + return endWithHeaderFileExtensions(Filename, HeaderFileExtensions); } } // namespace @@ -33,24 +32,29 @@ DefinitionsInHeadersCheck::DefinitionsInHeadersCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), - UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)) {} + UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)), + HeaderFileExtensions(Options.getLocalOrGlobal("HeaderFileExtensions", + ",.h,.hh,.hpp,.hxx")) {} void DefinitionsInHeadersCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "UseHeaderFileExtension", UseHeaderFileExtension); + Options.store(Opts, "HeaderFileExtensions", HeaderFileExtensions); } void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) { if (UseHeaderFileExtension) { Finder->addMatcher( namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())), - isHeaderFileExtension()).bind("name-decl"), + useHeaderFileExtension(HeaderFileExtensions)) + .bind("name-decl"), this); } else { Finder->addMatcher( namedDecl(anyOf(functionDecl(isDefinition()), varDecl(isDefinition())), - anyOf(isHeaderFileExtension(), - unless(isExpansionInMainFile()))).bind("name-decl"), + anyOf(useHeaderFileExtension(HeaderFileExtensions), + unless(isExpansionInMainFile()))) + .bind("name-decl"), this); } } Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -74,6 +74,14 @@ ".clang-tidy file."), cl::init(""), cl::cat(ClangTidyCategory)); +static cl::opt +HeaderFileExtensions("header-file-extensions", + cl::desc("File extensions that regard as header file.\n" + "The format is a comma-list of file extensions\n" + "with '.' prefix:\n" + " '.h,.hh,.hpp,.hxx'\n"), + cl::init(".h,.hh,.hpp,.hxx"), cl::cat(ClangTidyCategory)); + static cl::opt SystemHeaders("system-headers", cl::desc("Display the errors from system headers."), @@ -244,6 +252,8 @@ OverrideOptions.SystemHeaders = SystemHeaders; if (AnalyzeTemporaryDtors.getNumOccurrences() > 0) OverrideOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors; + if (HeaderFileExtensions.getNumOccurrences() > 0) + OverrideOptions.CheckOptions["HeaderFileExtensions"] = HeaderFileExtensions; if (!Config.empty()) { if (llvm::ErrorOr ParsedConfig =