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"
24class IncludeModernizePPCallbacks :
public PPCallbacks {
26 explicit IncludeModernizePPCallbacks(
27 std::vector<IncludeMarker> &IncludesToBeProcessed,
28 const LangOptions &LangOpts,
const SourceManager &SM,
29 bool CheckHeaderFile);
31 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
32 StringRef FileName,
bool IsAngled,
33 CharSourceRange FilenameRange,
34 OptionalFileEntryRef File, StringRef SearchPath,
35 StringRef RelativePath,
const Module *SuggestedModule,
37 SrcMgr::CharacteristicKind FileType)
override;
40 std::vector<IncludeMarker> &IncludesToBeProcessed;
41 llvm::StringMap<StringRef> 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() != LinkageSpecLanguageIDs::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)) {}
83 Options.store(Opts,
"CheckHeaderFile", CheckHeaderFile);
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,
135 const LangOptions &LangOpts,
const SourceManager &SM,
bool CheckHeaderFile)
136 : IncludesToBeProcessed(IncludesToBeProcessed), SM(SM),
137 CheckHeaderFile(CheckHeaderFile) {
139 static constexpr std::pair<StringRef, StringRef> CXX98Headers[] = {
140 {
"assert.h",
"cassert"}, {
"complex.h",
"complex"},
141 {
"ctype.h",
"cctype"}, {
"errno.h",
"cerrno"},
142 {
"float.h",
"cfloat"}, {
"limits.h",
"climits"},
143 {
"locale.h",
"clocale"}, {
"math.h",
"cmath"},
144 {
"setjmp.h",
"csetjmp"}, {
"signal.h",
"csignal"},
145 {
"stdarg.h",
"cstdarg"}, {
"stddef.h",
"cstddef"},
146 {
"stdio.h",
"cstdio"}, {
"stdlib.h",
"cstdlib"},
147 {
"string.h",
"cstring"}, {
"time.h",
"ctime"},
148 {
"wchar.h",
"cwchar"}, {
"wctype.h",
"cwctype"},
150 CStyledHeaderToCxx.insert(std::begin(CXX98Headers), std::end(CXX98Headers));
152 static constexpr std::pair<StringRef, StringRef> CXX11Headers[] = {
153 {
"fenv.h",
"cfenv"}, {
"stdint.h",
"cstdint"},
154 {
"inttypes.h",
"cinttypes"}, {
"tgmath.h",
"ctgmath"},
155 {
"uchar.h",
"cuchar"},
157 if (LangOpts.CPlusPlus11)
158 CStyledHeaderToCxx.insert(std::begin(CXX11Headers), std::end(CXX11Headers));
160 static constexpr StringRef HeadersToDelete[] = {
"stdalign.h",
"stdbool.h",
162 DeleteHeaders.insert_range(HeadersToDelete);
165void IncludeModernizePPCallbacks::InclusionDirective(
166 SourceLocation HashLoc,
const Token &IncludeTok, StringRef FileName,
167 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
168 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
169 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
173 if (!CheckHeaderFile && !SM.isInMainFile(HashLoc))
177 if (SM.isInSystemHeader(HashLoc))
187 SourceLocation DiagLoc = FilenameRange.getBegin();
188 if (
auto It = CStyledHeaderToCxx.find(FileName);
189 It != CStyledHeaderToCxx.end()) {
191 It->second, FileName, FilenameRange.getAsRange(), DiagLoc});
192 }
else if (DeleteHeaders.contains(FileName)) {
193 IncludesToBeProcessed.emplace_back(
196 SourceRange{HashLoc, FilenameRange.getEnd()}, DiagLoc});
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::StringMap< ClangTidyValue > OptionMap