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 *Imported,
36 SrcMgr::CharacteristicKind FileType)
override;
39 std::vector<IncludeMarker> &IncludesToBeProcessed;
41 llvm::StringMap<std::string> CStyledHeaderToCxx;
42 llvm::StringSet<> DeleteHeaders;
43 const SourceManager &SM;
47class ExternCRefutationVisitor
49 std::vector<IncludeMarker> &IncludesToBeProcessed;
50 const SourceManager &SM;
53 ExternCRefutationVisitor(std::vector<IncludeMarker> &IncludesToBeProcessed,
55 : IncludesToBeProcessed(IncludesToBeProcessed), SM(SM) {}
56 bool shouldWalkTypesOfTypeLocs()
const {
return false; }
57 bool shouldVisitLambdaBody()
const {
return false; }
59 bool VisitLinkageSpecDecl(LinkageSpecDecl *LinkSpecDecl)
const {
60 if (LinkSpecDecl->getLanguage() != LinkageSpecDecl::lang_c ||
61 !LinkSpecDecl->hasBraces())
64 auto ExternCBlockBegin = LinkSpecDecl->getBeginLoc();
65 auto ExternCBlockEnd = LinkSpecDecl->getEndLoc();
66 auto IsWrapped = [=, &SM = SM](
const IncludeMarker &Marker) ->
bool {
67 return SM.isBeforeInTranslationUnit(ExternCBlockBegin, Marker.DiagLoc) &&
68 SM.isBeforeInTranslationUnit(Marker.DiagLoc, ExternCBlockEnd);
71 llvm::erase_if(IncludesToBeProcessed, IsWrapped);
80 CheckHeaderFile(Options.get(
"CheckHeaderFile", false)) {}
87 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
88 PP->addPPCallbacks(std::make_unique<IncludeModernizePPCallbacks>(
89 IncludesToBeProcessed,
getLangOpts(), PP->getSourceManager(),
93 ast_matchers::MatchFinder *Finder) {
100 Finder->addMatcher(ast_matchers::translationUnitDecl().bind(
"TU"),
this);
104 IncludesToBeProcessed.clear();
108 const ast_matchers::MatchFinder::MatchResult &Result) {
109 SourceManager &SM = Result.Context->getSourceManager();
112 ExternCRefutationVisitor Visitor(IncludesToBeProcessed, SM);
113 Visitor.TraverseAST(*Result.Context);
117 if (Marker.Replacement.empty()) {
119 "including '%0' has no effect in C++; consider removing it")
121 << FixItHint::CreateRemoval(Marker.ReplacementRange);
123 diag(Marker.DiagLoc,
"inclusion of deprecated C++ header "
124 "'%0'; consider using '%1' instead")
125 << Marker.FileName << Marker.Replacement
126 << FixItHint::CreateReplacement(
127 Marker.ReplacementRange,
128 (llvm::Twine(
"<") + Marker.Replacement +
">").str());
133IncludeModernizePPCallbacks::IncludeModernizePPCallbacks(
134 std::vector<IncludeMarker> &IncludesToBeProcessed, LangOptions LangOpts,
135 const SourceManager &SM,
bool CheckHeaderFile)
136 : IncludesToBeProcessed(IncludesToBeProcessed), LangOpts(LangOpts), SM(SM),
137 CheckHeaderFile(CheckHeaderFile) {
138 for (
const auto &KeyValue :
139 std::vector<std::pair<llvm::StringRef, std::string>>(
140 {{
"assert.h",
"cassert"},
141 {
"complex.h",
"complex"},
142 {
"ctype.h",
"cctype"},
143 {
"errno.h",
"cerrno"},
144 {
"float.h",
"cfloat"},
145 {
"limits.h",
"climits"},
146 {
"locale.h",
"clocale"},
148 {
"setjmp.h",
"csetjmp"},
149 {
"signal.h",
"csignal"},
150 {
"stdarg.h",
"cstdarg"},
151 {
"stddef.h",
"cstddef"},
152 {
"stdio.h",
"cstdio"},
153 {
"stdlib.h",
"cstdlib"},
154 {
"string.h",
"cstring"},
156 {
"wchar.h",
"cwchar"},
157 {
"wctype.h",
"cwctype"}})) {
158 CStyledHeaderToCxx.insert(KeyValue);
161 if (LangOpts.CPlusPlus11) {
162 for (
const auto &KeyValue :
163 std::vector<std::pair<llvm::StringRef, std::string>>(
164 {{
"fenv.h",
"cfenv"},
165 {
"stdint.h",
"cstdint"},
166 {
"inttypes.h",
"cinttypes"},
167 {
"tgmath.h",
"ctgmath"},
168 {
"uchar.h",
"cuchar"}})) {
169 CStyledHeaderToCxx.insert(KeyValue);
172 for (
const auto &Key :
173 std::vector<std::string>({
"stdalign.h",
"stdbool.h",
"iso646.h"})) {
174 DeleteHeaders.insert(Key);
178void IncludeModernizePPCallbacks::InclusionDirective(
179 SourceLocation HashLoc,
const Token &IncludeTok, StringRef
FileName,
180 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
181 StringRef SearchPath, StringRef RelativePath,
const Module *Imported,
182 SrcMgr::CharacteristicKind FileType) {
186 if (!CheckHeaderFile && !SM.isInMainFile(HashLoc))
190 if (SM.isInSystemHeader(HashLoc))
200 SourceLocation DiagLoc = FilenameRange.getBegin();
201 if (CStyledHeaderToCxx.count(
FileName) != 0) {
202 IncludesToBeProcessed.emplace_back(
204 FilenameRange.getAsRange(), DiagLoc});
205 }
else if (DeleteHeaders.count(
FileName) != 0) {
206 IncludesToBeProcessed.emplace_back(
209 SourceRange{HashLoc, FilenameRange.getEnd()}, DiagLoc});
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