Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -45,6 +45,7 @@ #include "StringIntegerAssignmentCheck.h" #include "StringLiteralWithEmbeddedNulCheck.h" #include "SuspiciousEnumUsageCheck.h" +#include "SuspiciousIncludeCheck.h" #include "SuspiciousMemsetUsageCheck.h" #include "SuspiciousMissingCommaCheck.h" #include "SuspiciousSemicolonCheck.h" @@ -140,6 +141,8 @@ "bugprone-string-literal-with-embedded-nul"); CheckFactories.registerCheck( "bugprone-suspicious-enum-usage"); + CheckFactories.registerCheck( + "bugprone-suspicious-include"); CheckFactories.registerCheck( "bugprone-suspicious-memset-usage"); CheckFactories.registerCheck( Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -37,6 +37,7 @@ StringIntegerAssignmentCheck.cpp StringLiteralWithEmbeddedNulCheck.cpp SuspiciousEnumUsageCheck.cpp + SuspiciousIncludeCheck.cpp SuspiciousMemsetUsageCheck.cpp SuspiciousMissingCommaCheck.cpp SuspiciousSemicolonCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h =================================================================== --- clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h +++ clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DYNAMIC_STATIC_INITIALIZERS_CHECK_H #include "../ClangTidyCheck.h" -#include "../utils/HeaderFileExtensionsUtils.h" +#include "../utils/FileExtensionsUtils.h" namespace clang { namespace tidy { @@ -33,7 +33,7 @@ private: const std::string RawStringHeaderFileExtensions; - utils::HeaderFileExtensionsSet HeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; }; } // namespace bugprone Index: clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp +++ clang-tools-extra/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp @@ -31,8 +31,8 @@ : ClangTidyCheck(Name, Context), RawStringHeaderFileExtensions(Options.getLocalOrGlobal( "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { - if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, - HeaderFileExtensions, ',')) { + if (!utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ',')) { llvm::errs() << "Invalid header file extension: " << RawStringHeaderFileExtensions << "\n"; } Index: clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.h @@ -0,0 +1,57 @@ +//===--- SuspiciousIncludeCheck.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_SUSPICIOUSINCLUDECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSINCLUDECHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/FileExtensionsUtils.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Warns on inclusion of files whose names suggest that they're implementation +/// files, instead of headers. E.g: +/// +/// #include "foo.cpp" // warning +/// #include "bar.c" // warning +/// #include "baz.h" // no diagnostic +/// +/// The check supports these options: +/// - `SuspiciousExtensions`: a comma-separated list of filename extensions of +/// implementation files (The filename extensions should not contain "." +/// prefix) "c,cc,cpp,cxx" by default. +/// +/// - `RecommendedExtensions`: likewise, a comma-separated list of filename +/// extensions of header files. ",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. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-include.html +class SuspiciousIncludeCheck : public ClangTidyCheck { +public: + SuspiciousIncludeCheck(StringRef Name, ClangTidyContext *Context); + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + + utils::FileExtensionsSet SuspiciousExtensions; + utils::FileExtensionsSet RecommendedExtensions; + +private: + const std::string RawStringSuspiciousExtensions; + const std::string RawStringRecommendedExtensions; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSINCLUDECHECK_H Index: clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp @@ -0,0 +1,101 @@ +//===--- SuspiciousIncludeCheck.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 "SuspiciousIncludeCheck.h" +#include "clang/AST/ASTContext.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +namespace { +class SuspiciousIncludePPCallbacks : public PPCallbacks { +public: + explicit SuspiciousIncludePPCallbacks(SuspiciousIncludeCheck &Check, + const SourceManager &SM, + Preprocessor *PP) + : Check(Check), PP(PP) {} + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) override; + +private: + SuspiciousIncludeCheck &Check; + Preprocessor *PP; +}; +} // namespace + +SuspiciousIncludeCheck::SuspiciousIncludeCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RawStringSuspiciousExtensions(Options.getLocalOrGlobal( + "SuspiciousExtensions", + utils::defaultImplementationFileExtensions())), + RawStringRecommendedExtensions(Options.getLocalOrGlobal( + "RecommendedExtensions", utils::defaultHeaderFileExtensions())) { + if (!utils::parseFileExtensions(RawStringSuspiciousExtensions, + SuspiciousExtensions, ',')) { + llvm::errs() << "Invalid implementation file extension: " + << RawStringSuspiciousExtensions << "\n"; + } + + if (!utils::parseFileExtensions(RawStringRecommendedExtensions, + RecommendedExtensions, ',')) { + llvm::errs() << "Invalid header file extension: " + << RawStringRecommendedExtensions << "\n"; + } +} + +void SuspiciousIncludeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "SuspiciousExtensions", RawStringSuspiciousExtensions); + Options.store(Opts, "RecommendedExtensions", RawStringRecommendedExtensions); +} + +void SuspiciousIncludeCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks( + ::std::make_unique(*this, SM, PP)); +} + +void SuspiciousIncludePPCallbacks::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) { + SourceLocation DiagLoc = FilenameRange.getBegin().getLocWithOffset(1); + + const auto SE = utils::getFileExtension(FileName, Check.SuspiciousExtensions); + if (!SE) + return; + + Check.diag(DiagLoc, "suspicious #%0 of file with '%1' extension") + << IncludeTok.getIdentifierInfo()->getName() << *SE; + + for (const auto &RE : Check.RecommendedExtensions) { + SmallString<128> GuessedFileName(FileName); + llvm::sys::path::replace_extension(GuessedFileName, + (RE.size() ? "." : "") + RE); + + const DirectoryLookup *CurDir; + Optional File = + PP->LookupFile(DiagLoc, GuessedFileName, IsAngled, nullptr, nullptr, + CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); + if (File) { + Check.diag(DiagLoc, "did you mean to include '%0'?", DiagnosticIDs::Note) + << GuessedFileName; + } + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h =================================================================== --- clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h +++ clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H #include "../ClangTidyCheck.h" -#include "../utils/HeaderFileExtensionsUtils.h" +#include "../utils/FileExtensionsUtils.h" namespace clang { namespace tidy { @@ -35,7 +35,7 @@ private: const std::string RawStringHeaderFileExtensions; - utils::HeaderFileExtensionsSet HeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; }; } // namespace readability Index: clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp +++ clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp @@ -24,8 +24,8 @@ : ClangTidyCheck(Name, Context), RawStringHeaderFileExtensions(Options.getLocalOrGlobal( "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { - if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, - HeaderFileExtensions, ',')) { + if (!utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ',')) { llvm::errs() << "Invalid header file extension: " << RawStringHeaderFileExtensions << "\n"; } Index: clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h =================================================================== --- clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h +++ clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H #include "../ClangTidyCheck.h" -#include "../utils/HeaderFileExtensionsUtils.h" +#include "../utils/FileExtensionsUtils.h" namespace clang { namespace tidy { @@ -38,7 +38,7 @@ private: const std::string RawStringHeaderFileExtensions; - utils::HeaderFileExtensionsSet HeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; }; } // namespace build Index: clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp +++ clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp @@ -23,8 +23,8 @@ : ClangTidyCheck(Name, Context), RawStringHeaderFileExtensions(Options.getLocalOrGlobal( "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { - if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, - HeaderFileExtensions, ',')) { + if (!utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ',')) { llvm::errs() << "Invalid header file extension: " << RawStringHeaderFileExtensions << "\n"; } Index: clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h =================================================================== --- clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h +++ clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEFINITIONS_IN_HEADERS_H #include "../ClangTidyCheck.h" -#include "../utils/HeaderFileExtensionsUtils.h" +#include "../utils/FileExtensionsUtils.h" namespace clang { namespace tidy { @@ -40,7 +40,7 @@ private: const bool UseHeaderFileExtension; const std::string RawStringHeaderFileExtensions; - utils::HeaderFileExtensionsSet HeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; }; } // namespace misc Index: clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp +++ clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp @@ -18,8 +18,8 @@ namespace { -AST_MATCHER_P(NamedDecl, usesHeaderFileExtension, - utils::HeaderFileExtensionsSet, HeaderFileExtensions) { +AST_MATCHER_P(NamedDecl, usesHeaderFileExtension, utils::FileExtensionsSet, + HeaderFileExtensions) { return utils::isExpansionLocInHeaderFile( Node.getBeginLoc(), Finder->getASTContext().getSourceManager(), HeaderFileExtensions); @@ -33,8 +33,8 @@ UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)), RawStringHeaderFileExtensions(Options.getLocalOrGlobal( "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { - if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, - HeaderFileExtensions, ',')) { + if (!utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ',')) { // FIXME: Find a more suitable way to handle invalid configuration // options. llvm::errs() << "Invalid header file extension: " Index: clang-tools-extra/clang-tidy/utils/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/utils/CMakeLists.txt +++ clang-tools-extra/clang-tidy/utils/CMakeLists.txt @@ -5,8 +5,8 @@ DeclRefExprUtils.cpp ExceptionAnalyzer.cpp ExprSequence.cpp + FileExtensionsUtils.cpp FixItHintUtils.cpp - HeaderFileExtensionsUtils.cpp HeaderGuard.cpp IncludeInserter.cpp IncludeSorter.cpp Index: clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.h @@ -0,0 +1,63 @@ +//===--- FileExtensionsUtils.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_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace tidy { +namespace utils { + +typedef llvm::SmallSet FileExtensionsSet; + +/// Checks whether expansion location of \p Loc is in header file. +bool isExpansionLocInHeaderFile(SourceLocation Loc, const SourceManager &SM, + const FileExtensionsSet &HeaderFileExtensions); + +/// Checks whether presumed location of \p Loc is in header file. +bool isPresumedLocInHeaderFile(SourceLocation Loc, SourceManager &SM, + const FileExtensionsSet &HeaderFileExtensions); + +/// Checks whether spelling location of \p Loc is in header file. +bool isSpellingLocInHeaderFile(SourceLocation Loc, SourceManager &SM, + const FileExtensionsSet &HeaderFileExtensions); + +/// Returns recommended default value for the list of header file +/// extensions. +inline StringRef defaultHeaderFileExtensions() { return ",h,hh,hpp,hxx"; } + +/// Returns recommended default value for the list of implementaiton file +/// extensions. +inline StringRef defaultImplementationFileExtensions() { + return "c,cc,cpp,cxx"; +} + +/// Parses header file extensions from a semicolon-separated list. +bool parseFileExtensions(StringRef AllFileExtensions, + FileExtensionsSet &FileExtensions, char delimiter); + +/// Decides whether a file has a header file extension. +/// Returns the file extension, if included in the provided set. +llvm::Optional +getFileExtension(StringRef FileName, const FileExtensionsSet &FileExtensions); + +/// Decides whether a file has one of the specified file extensions. +bool isFileExtension(StringRef FileName, + const FileExtensionsSet &FileExtensions); + +} // namespace utils +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H Index: clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/utils/FileExtensionsUtils.cpp @@ -0,0 +1,70 @@ +//===--- FileExtensionsUtils.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#include "FileExtensionsUtils.h" +#include "clang/Basic/CharInfo.h" +#include "llvm/Support/Path.h" + +namespace clang { +namespace tidy { +namespace utils { + +bool isExpansionLocInHeaderFile(SourceLocation Loc, const SourceManager &SM, + const FileExtensionsSet &HeaderFileExtensions) { + SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); + return isFileExtension(SM.getFilename(ExpansionLoc), HeaderFileExtensions); +} + +bool isPresumedLocInHeaderFile(SourceLocation Loc, SourceManager &SM, + const FileExtensionsSet &HeaderFileExtensions) { + PresumedLoc PresumedLocation = SM.getPresumedLoc(Loc); + return isFileExtension(PresumedLocation.getFilename(), HeaderFileExtensions); +} + +bool isSpellingLocInHeaderFile(SourceLocation Loc, SourceManager &SM, + const FileExtensionsSet &HeaderFileExtensions) { + SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); + return isFileExtension(SM.getFilename(SpellingLoc), HeaderFileExtensions); +} + +bool parseFileExtensions(StringRef AllFileExtensions, + FileExtensionsSet &FileExtensions, char delimiter) { + SmallVector Suffixes; + AllFileExtensions.split(Suffixes, delimiter); + FileExtensions.clear(); + for (StringRef Suffix : Suffixes) { + StringRef Extension = Suffix.trim(); + for (StringRef::const_iterator it = Extension.begin(); + it != Extension.end(); ++it) { + if (!isAlphanumeric(*it)) + return false; + } + FileExtensions.insert(Extension); + } + return true; +} + +llvm::Optional +getFileExtension(StringRef FileName, const FileExtensionsSet &FileExtensions) { + StringRef extension = llvm::sys::path::extension(FileName); + if (extension.empty()) + return llvm::None; + // Skip "." prefix. + if (!FileExtensions.count(extension.substr(1))) + return llvm::None; + return extension; +} + +bool isFileExtension(StringRef FileName, + const FileExtensionsSet &FileExtensions) { + return getFileExtension(FileName, FileExtensions).hasValue(); +} + +} // namespace utils +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.h =================================================================== --- clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.h +++ /dev/null @@ -1,55 +0,0 @@ -//===--- HeaderFileExtensionsUtils.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_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H - -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/StringRef.h" - -namespace clang { -namespace tidy { -namespace utils { - -typedef llvm::SmallSet HeaderFileExtensionsSet; - -/// Checks whether expansion location of \p Loc is in header file. -bool isExpansionLocInHeaderFile( - SourceLocation Loc, const SourceManager &SM, - const HeaderFileExtensionsSet &HeaderFileExtensions); - -/// Checks whether presumed location of \p Loc is in header file. -bool isPresumedLocInHeaderFile( - SourceLocation Loc, SourceManager &SM, - const HeaderFileExtensionsSet &HeaderFileExtensions); - -/// Checks whether spelling location of \p Loc is in header file. -bool isSpellingLocInHeaderFile( - SourceLocation Loc, SourceManager &SM, - const HeaderFileExtensionsSet &HeaderFileExtensions); - -/// Returns recommended default value for the list of header file -/// extensions. -inline StringRef defaultHeaderFileExtensions() { return ",h,hh,hpp,hxx"; } - -/// Parses header file extensions from a semicolon-separated list. -bool parseHeaderFileExtensions(StringRef AllHeaderFileExtensions, - HeaderFileExtensionsSet &HeaderFileExtensions, - char delimiter); - -/// Decides whether a file has a header file extension. -bool isHeaderFileExtension(StringRef FileName, - const HeaderFileExtensionsSet &HeaderFileExtensions); - -} // namespace utils -} // namespace tidy -} // namespace clang - -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H Index: clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.cpp =================================================================== --- clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===--- HeaderFileExtensionsUtils.cpp - 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 -// -//===----------------------------------------------------------------------===// - -#include "HeaderFileExtensionsUtils.h" -#include "clang/Basic/CharInfo.h" -#include "llvm/Support/Path.h" - -namespace clang { -namespace tidy { -namespace utils { - -bool isExpansionLocInHeaderFile( - SourceLocation Loc, const SourceManager &SM, - const HeaderFileExtensionsSet &HeaderFileExtensions) { - SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); - return isHeaderFileExtension(SM.getFilename(ExpansionLoc), - HeaderFileExtensions); -} - -bool isPresumedLocInHeaderFile( - SourceLocation Loc, SourceManager &SM, - const HeaderFileExtensionsSet &HeaderFileExtensions) { - PresumedLoc PresumedLocation = SM.getPresumedLoc(Loc); - return isHeaderFileExtension(PresumedLocation.getFilename(), - HeaderFileExtensions); -} - -bool isSpellingLocInHeaderFile( - SourceLocation Loc, SourceManager &SM, - const HeaderFileExtensionsSet &HeaderFileExtensions) { - SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); - return isHeaderFileExtension(SM.getFilename(SpellingLoc), - HeaderFileExtensions); -} - -bool parseHeaderFileExtensions(StringRef AllHeaderFileExtensions, - HeaderFileExtensionsSet &HeaderFileExtensions, - char delimiter) { - SmallVector Suffixes; - AllHeaderFileExtensions.split(Suffixes, delimiter); - HeaderFileExtensions.clear(); - for (StringRef Suffix : Suffixes) { - StringRef Extension = Suffix.trim(); - for (StringRef::const_iterator it = Extension.begin(); - it != Extension.end(); ++it) { - if (!isAlphanumeric(*it)) - return false; - } - HeaderFileExtensions.insert(Extension); - } - return true; -} - -bool isHeaderFileExtension( - StringRef FileName, const HeaderFileExtensionsSet &HeaderFileExtensions) { - StringRef extension = llvm::sys::path::extension(FileName); - if (extension.empty()) - return false; - // Skip "." prefix. - return HeaderFileExtensions.count(extension.substr(1)) > 0; -} - -} // namespace utils -} // namespace tidy -} // namespace clang Index: clang-tools-extra/clang-tidy/utils/HeaderGuard.h =================================================================== --- clang-tools-extra/clang-tidy/utils/HeaderGuard.h +++ clang-tools-extra/clang-tidy/utils/HeaderGuard.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADERGUARD_H #include "../ClangTidy.h" -#include "../utils/HeaderFileExtensionsUtils.h" +#include "../utils/FileExtensionsUtils.h" namespace clang { namespace tidy { @@ -29,8 +29,8 @@ : ClangTidyCheck(Name, Context), RawStringHeaderFileExtensions(Options.getLocalOrGlobal( "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { - utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, - HeaderFileExtensions, ','); + utils::parseFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ','); } void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override; @@ -54,7 +54,7 @@ private: std::string RawStringHeaderFileExtensions; - utils::HeaderFileExtensionsSet HeaderFileExtensions; + utils::FileExtensionsSet HeaderFileExtensions; }; } // namespace utils Index: clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp =================================================================== --- clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp +++ clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp @@ -273,13 +273,13 @@ } bool HeaderGuardCheck::shouldSuggestEndifComment(StringRef FileName) { - return utils::isHeaderFileExtension(FileName, HeaderFileExtensions); + return utils::isFileExtension(FileName, HeaderFileExtensions); } bool HeaderGuardCheck::shouldFixHeaderGuard(StringRef FileName) { return true; } bool HeaderGuardCheck::shouldSuggestToAddHeaderGuard(StringRef FileName) { - return utils::isHeaderFileExtension(FileName, HeaderFileExtensions); + return utils::isFileExtension(FileName, HeaderFileExtensions); } std::string HeaderGuardCheck::formatEndIf(StringRef HeaderGuard) { Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-include.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-include.cpp @@ -0,0 +1,21 @@ +// RUN: %check_clang_tidy %s bugprone-suspicious-include %t -- -- -isystem %S/Inputs/Headers -fmodules + +// CHECK-MESSAGES: [[@LINE+4]]:11: warning: suspicious #include of file with '.cpp' extension +// CHECK-MESSAGES: [[@LINE+3]]:11: note: did you mean to include 'a'? +// CHECK-MESSAGES: [[@LINE+2]]:11: note: did you mean to include 'a.h'? +// CHECK-MESSAGES: [[@LINE+1]]:11: note: did you mean to include 'a.hpp'? +#include "a.cpp" + +#include "b.h" + +// CHECK-MESSAGES: [[@LINE+1]]:10: warning: suspicious #import of file with '.c' extension +#import "c.c" + +// CHECK-MESSAGES: [[@LINE+1]]:16: warning: suspicious #include_next of file with '.c' extension +#include_next + +// CHECK-MESSAGES: [[@LINE+1]]:13: warning: suspicious #include of file with '.cc' extension +# include + +// CHECK-MESSAGES: [[@LINE+1]]:14: warning: suspicious #include of file with '.cxx' extension +# include