clang-tools 23.0.0git
SuspiciousIncludeCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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//===----------------------------------------------------------------------===//
8
11#include "clang/AST/ASTContext.h"
12#include "clang/Lex/Preprocessor.h"
13#include <optional>
14
15namespace clang::tidy::bugprone {
16
17namespace {
18class SuspiciousIncludePPCallbacks : public PPCallbacks {
19public:
20 explicit SuspiciousIncludePPCallbacks(SuspiciousIncludeCheck &Check,
21 const SourceManager &SM,
22 Preprocessor *PP)
23 : Check(Check), PP(PP) {}
24
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 *SuggestedModule,
30 bool ModuleImported,
31 SrcMgr::CharacteristicKind FileType) override;
32
33private:
34 SuspiciousIncludeCheck &Check;
35 Preprocessor *PP;
36};
37} // namespace
38
40 ClangTidyContext *Context)
41 : ClangTidyCheck(Name, Context),
42 IgnoredRegexString(Options.get("IgnoredRegex").value_or(StringRef{})),
44
46 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
47 PP->addPPCallbacks(
48 std::make_unique<SuspiciousIncludePPCallbacks>(*this, SM, PP));
49}
50
52 if (!IgnoredRegexString.empty())
53 Options.store(Opts, "IgnoredRegex", IgnoredRegexString);
54}
55
56void SuspiciousIncludePPCallbacks::InclusionDirective(
57 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
58 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
59 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
60 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
61 if (IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import)
62 return;
63
64 if (!Check.IgnoredRegexString.empty() && Check.IgnoredRegex.match(FileName))
65 return;
66
67 const SourceLocation DiagLoc = FilenameRange.getBegin().getLocWithOffset(1);
68
69 const std::optional<StringRef> IFE = utils::getFileExtension(
70 FileName, Check.getImplementationFileExtensions());
71 if (!IFE)
72 return;
73
74 Check.diag(DiagLoc, "suspicious #%0 of file with '%1' extension")
75 << IncludeTok.getIdentifierInfo()->getName() << *IFE;
76
77 for (const auto &HFE : Check.getHeaderFileExtensions()) {
78 SmallString<128> GuessedFileName(FileName);
79 llvm::sys::path::replace_extension(GuessedFileName,
80 (!HFE.empty() ? "." : "") + HFE);
81
82 const OptionalFileEntryRef File =
83 PP->LookupFile(DiagLoc, GuessedFileName, IsAngled, nullptr, nullptr,
84 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
85 if (File) {
86 Check.diag(DiagLoc, "did you mean to include '%0'?", DiagnosticIDs::Note)
87 << GuessedFileName;
88 }
89 }
90}
91
92} // namespace clang::tidy::bugprone
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
SuspiciousIncludeCheck(StringRef Name, ClangTidyContext *Context)
std::optional< StringRef > getFileExtension(StringRef FileName, const FileExtensionsSet &FileExtensions)
Decides whether a file has a header file extension.
llvm::StringMap< ClangTidyValue > OptionMap