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
9#include "SuspiciousIncludeCheck.h"
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
39SuspiciousIncludeCheck::SuspiciousIncludeCheck(StringRef Name,
40 ClangTidyContext *Context)
41 : ClangTidyCheck(Name, Context),
42 HeaderFileExtensions(Context->getHeaderFileExtensions()),
43 ImplementationFileExtensions(Context->getImplementationFileExtensions()) {
44}
45
46void SuspiciousIncludeCheck::registerPPCallbacks(
47 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
48 PP->addPPCallbacks(
49 C: ::std::make_unique<SuspiciousIncludePPCallbacks>(args&: *this, args: SM, args&: 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(Offset: 1);
61
62 const std::optional<StringRef> IFE =
63 utils::getFileExtension(FileName, FileExtensions: Check.ImplementationFileExtensions);
64 if (!IFE)
65 return;
66
67 Check.diag(Loc: DiagLoc, Description: "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(path&: GuessedFileName,
73 extension: (!HFE.empty() ? "." : "") + HFE);
74
75 OptionalFileEntryRef File =
76 PP->LookupFile(FilenameLoc: DiagLoc, Filename: GuessedFileName, isAngled: IsAngled, FromDir: nullptr, FromFile: nullptr,
77 CurDir: nullptr, SearchPath: nullptr, RelativePath: nullptr, SuggestedModule: nullptr, IsMapped: nullptr, IsFrameworkFound: nullptr);
78 if (File) {
79 Check.diag(Loc: DiagLoc, Description: "did you mean to include '%0'?", Level: DiagnosticIDs::Note)
80 << GuessedFileName;
81 }
82 }
83}
84
85} // namespace clang::tidy::bugprone
86

source code of clang-tools-extra/clang-tidy/bugprone/SuspiciousIncludeCheck.cpp