[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang-tools-extra / clang-tidy / bugprone / SuspiciousIncludeCheck.cpp
blob43d53f0b6020aedd1ef8ccec4d81c49af1c3cd91
1 //===--- SuspiciousIncludeCheck.cpp - clang-tidy --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "SuspiciousIncludeCheck.h"
10 #include "../utils/FileExtensionsUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/Lex/Preprocessor.h"
13 #include <optional>
15 namespace clang::tidy::bugprone {
17 namespace {
18 class SuspiciousIncludePPCallbacks : public PPCallbacks {
19 public:
20 explicit SuspiciousIncludePPCallbacks(SuspiciousIncludeCheck &Check,
21 const SourceManager &SM,
22 Preprocessor *PP)
23 : Check(Check), PP(PP) {}
25 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
26 StringRef FileName, bool IsAngled,
27 CharSourceRange FilenameRange,
28 OptionalFileEntryRef File, StringRef SearchPath,
29 StringRef RelativePath, const Module *Imported,
30 SrcMgr::CharacteristicKind FileType) override;
32 private:
33 SuspiciousIncludeCheck &Check;
34 Preprocessor *PP;
36 } // namespace
38 SuspiciousIncludeCheck::SuspiciousIncludeCheck(StringRef Name,
39 ClangTidyContext *Context)
40 : ClangTidyCheck(Name, Context) {
41 std::optional<StringRef> ImplementationFileExtensionsOption =
42 Options.get("ImplementationFileExtensions");
43 RawStringImplementationFileExtensions =
44 ImplementationFileExtensionsOption.value_or(
45 utils::defaultImplementationFileExtensions());
46 if (ImplementationFileExtensionsOption) {
47 if (!utils::parseFileExtensions(RawStringImplementationFileExtensions,
48 ImplementationFileExtensions,
49 utils::defaultFileExtensionDelimiters())) {
50 this->configurationDiag("Invalid implementation file extension: '%0'")
51 << RawStringImplementationFileExtensions;
53 } else
54 ImplementationFileExtensions = Context->getImplementationFileExtensions();
56 std::optional<StringRef> HeaderFileExtensionsOption =
57 Options.get("HeaderFileExtensions");
58 RawStringHeaderFileExtensions =
59 HeaderFileExtensionsOption.value_or(utils::defaultHeaderFileExtensions());
60 if (HeaderFileExtensionsOption) {
61 if (!utils::parseFileExtensions(RawStringHeaderFileExtensions,
62 HeaderFileExtensions,
63 utils::defaultFileExtensionDelimiters())) {
64 this->configurationDiag("Invalid header file extension: '%0'")
65 << RawStringHeaderFileExtensions;
67 } else
68 HeaderFileExtensions = Context->getHeaderFileExtensions();
71 void SuspiciousIncludeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
72 Options.store(Opts, "ImplementationFileExtensions",
73 RawStringImplementationFileExtensions);
74 Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
77 void SuspiciousIncludeCheck::registerPPCallbacks(
78 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
79 PP->addPPCallbacks(
80 ::std::make_unique<SuspiciousIncludePPCallbacks>(*this, SM, PP));
83 void SuspiciousIncludePPCallbacks::InclusionDirective(
84 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
85 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
86 StringRef SearchPath, StringRef RelativePath, const Module *Imported,
87 SrcMgr::CharacteristicKind FileType) {
88 if (IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import)
89 return;
91 SourceLocation DiagLoc = FilenameRange.getBegin().getLocWithOffset(1);
93 const std::optional<StringRef> IFE =
94 utils::getFileExtension(FileName, Check.ImplementationFileExtensions);
95 if (!IFE)
96 return;
98 Check.diag(DiagLoc, "suspicious #%0 of file with '%1' extension")
99 << IncludeTok.getIdentifierInfo()->getName() << *IFE;
101 for (const auto &HFE : Check.HeaderFileExtensions) {
102 SmallString<128> GuessedFileName(FileName);
103 llvm::sys::path::replace_extension(GuessedFileName,
104 (!HFE.empty() ? "." : "") + HFE);
106 OptionalFileEntryRef File =
107 PP->LookupFile(DiagLoc, GuessedFileName, IsAngled, nullptr, nullptr,
108 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
109 if (File) {
110 Check.diag(DiagLoc, "did you mean to include '%0'?", DiagnosticIDs::Note)
111 << GuessedFileName;
116 } // namespace clang::tidy::bugprone