clang-tools 19.0.0git
SuspiciousIncludeCheck.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
8
10#include "../utils/FileExtensionsUtils.h"
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}
45
47 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
48 PP->addPPCallbacks(
49 ::std::make_unique<SuspiciousIncludePPCallbacks>(*this, SM, PP));
50}
51
52void SuspiciousIncludePPCallbacks::InclusionDirective(
53 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
54 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
55 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
56 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
57 if (IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import)
58 return;
59
60 SourceLocation DiagLoc = FilenameRange.getBegin().getLocWithOffset(1);
61
62 const std::optional<StringRef> IFE =
63 utils::getFileExtension(FileName, Check.ImplementationFileExtensions);
64 if (!IFE)
65 return;
66
67 Check.diag(DiagLoc, "suspicious #%0 of file with '%1' extension")
68 << IncludeTok.getIdentifierInfo()->getName() << *IFE;
69
70 for (const auto &HFE : Check.HeaderFileExtensions) {
71 SmallString<128> GuessedFileName(FileName);
72 llvm::sys::path::replace_extension(GuessedFileName,
73 (!HFE.empty() ? "." : "") + HFE);
74
75 OptionalFileEntryRef File =
76 PP->LookupFile(DiagLoc, GuessedFileName, IsAngled, nullptr, nullptr,
77 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
78 if (File) {
79 Check.diag(DiagLoc, "did you mean to include '%0'?", DiagnosticIDs::Note)
80 << GuessedFileName;
81 }
82 }
83}
84
85} // namespace clang::tidy::bugprone
llvm::SmallString< 256U > Name
bool IsAngled
true if this was an include with angle brackets
StringRef FileName
Base class for all clang-tidy checks.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
SuspiciousIncludeCheck(StringRef Name, ClangTidyContext *Context)
std::optional< StringRef > getFileExtension(StringRef FileName, const FileExtensionsSet &FileExtensions)
Decides whether a file has a header file extension.