clang-tools 22.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 HeaderFileExtensions(Context->getHeaderFileExtensions()),
43 ImplementationFileExtensions(Context->getImplementationFileExtensions()),
44 IgnoredRegexString(Options.get("IgnoredRegex").value_or(StringRef{})),
46
48 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
49 PP->addPPCallbacks(
50 ::std::make_unique<SuspiciousIncludePPCallbacks>(*this, SM, PP));
51}
52
54 if (!IgnoredRegexString.empty())
55 Options.store(Opts, "IgnoredRegex", IgnoredRegexString);
56}
57
58void SuspiciousIncludePPCallbacks::InclusionDirective(
59 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
60 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
61 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
62 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
63 if (IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import)
64 return;
65
66 if (!Check.IgnoredRegexString.empty() && Check.IgnoredRegex.match(FileName))
67 return;
68
69 SourceLocation DiagLoc = FilenameRange.getBegin().getLocWithOffset(1);
70
71 const std::optional<StringRef> IFE =
73 if (!IFE)
74 return;
75
76 Check.diag(DiagLoc, "suspicious #%0 of file with '%1' extension")
77 << IncludeTok.getIdentifierInfo()->getName() << *IFE;
78
79 for (const auto &HFE : Check.HeaderFileExtensions) {
80 SmallString<128> GuessedFileName(FileName);
81 llvm::sys::path::replace_extension(GuessedFileName,
82 (!HFE.empty() ? "." : "") + HFE);
83
84 OptionalFileEntryRef File =
85 PP->LookupFile(DiagLoc, GuessedFileName, IsAngled, nullptr, nullptr,
86 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
87 if (File) {
88 Check.diag(DiagLoc, "did you mean to include '%0'?", DiagnosticIDs::Note)
89 << GuessedFileName;
90 }
91 }
92}
93
94} // 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