1 //===--- SuspiciousIncludeCheck.cpp - clang-tidy --------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SuspiciousIncludeCheck.h"
10 #include "../utils/FileExtensionsUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/Lex/Preprocessor.h"
15 namespace clang::tidy::bugprone
{
18 class SuspiciousIncludePPCallbacks
: public PPCallbacks
{
20 explicit SuspiciousIncludePPCallbacks(SuspiciousIncludeCheck
&Check
,
21 const SourceManager
&SM
,
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
*SuggestedModule
,
31 SrcMgr::CharacteristicKind FileType
) override
;
34 SuspiciousIncludeCheck
&Check
;
39 SuspiciousIncludeCheck::SuspiciousIncludeCheck(StringRef Name
,
40 ClangTidyContext
*Context
)
41 : ClangTidyCheck(Name
, Context
),
42 HeaderFileExtensions(Context
->getHeaderFileExtensions()),
43 ImplementationFileExtensions(Context
->getImplementationFileExtensions()) {
46 void SuspiciousIncludeCheck::registerPPCallbacks(
47 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
49 ::std::make_unique
<SuspiciousIncludePPCallbacks
>(*this, SM
, PP
));
52 void 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
)
60 SourceLocation DiagLoc
= FilenameRange
.getBegin().getLocWithOffset(1);
62 const std::optional
<StringRef
> IFE
=
63 utils::getFileExtension(FileName
, Check
.ImplementationFileExtensions
);
67 Check
.diag(DiagLoc
, "suspicious #%0 of file with '%1' extension")
68 << IncludeTok
.getIdentifierInfo()->getName() << *IFE
;
70 for (const auto &HFE
: Check
.HeaderFileExtensions
) {
71 SmallString
<128> GuessedFileName(FileName
);
72 llvm::sys::path::replace_extension(GuessedFileName
,
73 (!HFE
.empty() ? "." : "") + HFE
);
75 OptionalFileEntryRef File
=
76 PP
->LookupFile(DiagLoc
, GuessedFileName
, IsAngled
, nullptr, nullptr,
77 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
79 Check
.diag(DiagLoc
, "did you mean to include '%0'?", DiagnosticIDs::Note
)
85 } // namespace clang::tidy::bugprone