10#include "clang/AST/RecursiveASTVisitor.h"
11#include "clang/Frontend/CompilerInstance.h"
12#include "clang/Lex/PPCallbacks.h"
13#include "clang/Lex/Preprocessor.h"
14#include "llvm/ADT/StringMap.h"
15#include "llvm/ADT/StringSet.h"
25class IncludeModernizePPCallbacks :
public PPCallbacks {
27 explicit IncludeModernizePPCallbacks(
28 std::vector<IncludeMarker> &IncludesToBeProcessed, LangOptions LangOpts,
29 const SourceManager &SM,
bool CheckHeaderFile);
31 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
33 CharSourceRange FilenameRange,
34 OptionalFileEntryRef File, StringRef SearchPath,
35 StringRef RelativePath,
const Module *SuggestedModule,
37 SrcMgr::CharacteristicKind FileType)
override;
40 std::vector<IncludeMarker> &IncludesToBeProcessed;
42 llvm::StringMap<std::string> CStyledHeaderToCxx;
43 llvm::StringSet<> DeleteHeaders;
44 const SourceManager &SM;
48class ExternCRefutationVisitor
50 std::vector<IncludeMarker> &IncludesToBeProcessed;
51 const SourceManager &SM;
54 ExternCRefutationVisitor(std::vector<IncludeMarker> &IncludesToBeProcessed,
56 : IncludesToBeProcessed(IncludesToBeProcessed), SM(SM) {}
57 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
58 bool shouldVisitLambdaBody()
const {
return false; }
60 bool VisitLinkageSpecDecl(LinkageSpecDecl *LinkSpecDecl)
const {
61 if (LinkSpecDecl->getLanguage() != LinkageSpecLanguageIDs::C ||
62 !LinkSpecDecl->hasBraces())
65 auto ExternCBlockBegin = LinkSpecDecl->getBeginLoc();
66 auto ExternCBlockEnd = LinkSpecDecl->getEndLoc();
67 auto IsWrapped = [=, &SM = SM](
const IncludeMarker &Marker) ->
bool {
68 return SM.isBeforeInTranslationUnit(ExternCBlockBegin, Marker.DiagLoc) &&
69 SM.isBeforeInTranslationUnit(Marker.DiagLoc, ExternCBlockEnd);
72 llvm::erase_if(IncludesToBeProcessed, IsWrapped);
81 CheckHeaderFile(Options.get(
"CheckHeaderFile", false)) {}
88 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
89 PP->addPPCallbacks(std::make_unique<IncludeModernizePPCallbacks>(
90 IncludesToBeProcessed,
getLangOpts(), PP->getSourceManager(),
94 ast_matchers::MatchFinder *Finder) {
101 Finder->addMatcher(ast_matchers::translationUnitDecl().bind(
"TU"),
this);
105 IncludesToBeProcessed.clear();
109 const ast_matchers::MatchFinder::MatchResult &Result) {
110 SourceManager &SM = Result.Context->getSourceManager();
113 ExternCRefutationVisitor Visitor(IncludesToBeProcessed, SM);
114 Visitor.TraverseAST(*Result.Context);
118 if (Marker.Replacement.empty()) {
120 "including '%0' has no effect in C++; consider removing it")
122 << FixItHint::CreateRemoval(Marker.ReplacementRange);
124 diag(Marker.DiagLoc,
"inclusion of deprecated C++ header "
125 "'%0'; consider using '%1' instead")
126 << Marker.FileName << Marker.Replacement
127 << FixItHint::CreateReplacement(
128 Marker.ReplacementRange,
129 (llvm::Twine(
"<") + Marker.Replacement +
">").str());
134IncludeModernizePPCallbacks::IncludeModernizePPCallbacks(
135 std::vector<IncludeMarker> &IncludesToBeProcessed, LangOptions LangOpts,
136 const SourceManager &SM,
bool CheckHeaderFile)
137 : IncludesToBeProcessed(IncludesToBeProcessed), LangOpts(LangOpts), SM(SM),
138 CheckHeaderFile(CheckHeaderFile) {
139 for (
const auto &KeyValue :
140 std::vector<std::pair<llvm::StringRef, std::string>>(
141 {{
"assert.h",
"cassert"},
142 {
"complex.h",
"complex"},
143 {
"ctype.h",
"cctype"},
144 {
"errno.h",
"cerrno"},
145 {
"float.h",
"cfloat"},
146 {
"limits.h",
"climits"},
147 {
"locale.h",
"clocale"},
149 {
"setjmp.h",
"csetjmp"},
150 {
"signal.h",
"csignal"},
151 {
"stdarg.h",
"cstdarg"},
152 {
"stddef.h",
"cstddef"},
153 {
"stdio.h",
"cstdio"},
154 {
"stdlib.h",
"cstdlib"},
155 {
"string.h",
"cstring"},
157 {
"wchar.h",
"cwchar"},
158 {
"wctype.h",
"cwctype"}})) {
159 CStyledHeaderToCxx.insert(KeyValue);
162 if (LangOpts.CPlusPlus11) {
163 for (
const auto &KeyValue :
164 std::vector<std::pair<llvm::StringRef, std::string>>(
165 {{
"fenv.h",
"cfenv"},
166 {
"stdint.h",
"cstdint"},
167 {
"inttypes.h",
"cinttypes"},
168 {
"tgmath.h",
"ctgmath"},
169 {
"uchar.h",
"cuchar"}})) {
170 CStyledHeaderToCxx.insert(KeyValue);
173 for (
const auto &Key :
174 std::vector<std::string>({
"stdalign.h",
"stdbool.h",
"iso646.h"})) {
175 DeleteHeaders.insert(Key);
179void IncludeModernizePPCallbacks::InclusionDirective(
180 SourceLocation HashLoc,
const Token &IncludeTok, StringRef
FileName,
181 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
182 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
183 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
187 if (!CheckHeaderFile && !SM.isInMainFile(HashLoc))
191 if (SM.isInSystemHeader(HashLoc))
201 SourceLocation DiagLoc = FilenameRange.getBegin();
202 if (CStyledHeaderToCxx.count(
FileName) != 0) {
203 IncludesToBeProcessed.emplace_back(
205 FilenameRange.getAsRange(), DiagLoc});
206 }
else if (DeleteHeaders.count(
FileName) != 0) {
207 IncludesToBeProcessed.emplace_back(
210 SourceRange{HashLoc, FilenameRange.getEnd()}, DiagLoc});
llvm::SmallString< 256U > Name
bool IsAngled
true if this was an include with angle brackets
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::StringMap< ClangTidyValue > OptionMap