1//===--- DeprecatedHeadersCheck.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 "DeprecatedHeadersCheck.h"
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"
16
17#include <vector>
18
19using IncludeMarker =
20 clang::tidy::modernize::DeprecatedHeadersCheck::IncludeMarker;
21namespace clang::tidy::modernize {
22namespace {
23
24class IncludeModernizePPCallbacks : public PPCallbacks {
25public:
26 explicit IncludeModernizePPCallbacks(
27 std::vector<IncludeMarker> &IncludesToBeProcessed, LangOptions LangOpts,
28 const SourceManager &SM, bool CheckHeaderFile);
29
30 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
31 StringRef FileName, bool IsAngled,
32 CharSourceRange FilenameRange,
33 OptionalFileEntryRef File, StringRef SearchPath,
34 StringRef RelativePath, const Module *SuggestedModule,
35 bool ModuleImported,
36 SrcMgr::CharacteristicKind FileType) override;
37
38private:
39 std::vector<IncludeMarker> &IncludesToBeProcessed;
40 LangOptions LangOpts;
41 llvm::StringMap<std::string> CStyledHeaderToCxx;
42 llvm::StringSet<> DeleteHeaders;
43 const SourceManager &SM;
44 bool CheckHeaderFile;
45};
46
47class ExternCRefutationVisitor
48 : public RecursiveASTVisitor<ExternCRefutationVisitor> {
49 std::vector<IncludeMarker> &IncludesToBeProcessed;
50 const SourceManager &SM;
51
52public:
53 ExternCRefutationVisitor(std::vector<IncludeMarker> &IncludesToBeProcessed,
54 SourceManager &SM)
55 : IncludesToBeProcessed(IncludesToBeProcessed), SM(SM) {}
56 bool shouldWalkTypesOfTypeLocs() const { return false; }
57 bool shouldVisitLambdaBody() const { return false; }
58
59 bool VisitLinkageSpecDecl(LinkageSpecDecl *LinkSpecDecl) const {
60 if (LinkSpecDecl->getLanguage() != LinkageSpecLanguageIDs::C ||
61 !LinkSpecDecl->hasBraces())
62 return true;
63
64 auto ExternCBlockBegin = LinkSpecDecl->getBeginLoc();
65 auto ExternCBlockEnd = LinkSpecDecl->getEndLoc();
66 auto IsWrapped = [=, &SM = SM](const IncludeMarker &Marker) -> bool {
67 return SM.isBeforeInTranslationUnit(LHS: ExternCBlockBegin, RHS: Marker.DiagLoc) &&
68 SM.isBeforeInTranslationUnit(LHS: Marker.DiagLoc, RHS: ExternCBlockEnd);
69 };
70
71 llvm::erase_if(C&: IncludesToBeProcessed, P: IsWrapped);
72 return true;
73 }
74};
75} // namespace
76
77DeprecatedHeadersCheck::DeprecatedHeadersCheck(StringRef Name,
78 ClangTidyContext *Context)
79 : ClangTidyCheck(Name, Context),
80 CheckHeaderFile(Options.get(LocalName: "CheckHeaderFile", Default: false)) {}
81
82void DeprecatedHeadersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
83 Options.store(Options&: Opts, LocalName: "CheckHeaderFile", Value: CheckHeaderFile);
84}
85
86void DeprecatedHeadersCheck::registerPPCallbacks(
87 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
88 PP->addPPCallbacks(C: std::make_unique<IncludeModernizePPCallbacks>(
89 args&: IncludesToBeProcessed, args: getLangOpts(), args&: PP->getSourceManager(),
90 args&: CheckHeaderFile));
91}
92void DeprecatedHeadersCheck::registerMatchers(
93 ast_matchers::MatchFinder *Finder) {
94 // Even though the checker operates on a "preprocessor" level, we still need
95 // to act on a "TranslationUnit" to acquire the AST where we can walk each
96 // Decl and look for `extern "C"` blocks where we will suppress the report we
97 // collected during the preprocessing phase.
98 // The `onStartOfTranslationUnit()` won't suffice, since we need some handle
99 // to the `ASTContext`.
100 Finder->addMatcher(NodeMatch: ast_matchers::translationUnitDecl().bind(ID: "TU"), Action: this);
101}
102
103void DeprecatedHeadersCheck::onEndOfTranslationUnit() {
104 IncludesToBeProcessed.clear();
105}
106
107void DeprecatedHeadersCheck::check(
108 const ast_matchers::MatchFinder::MatchResult &Result) {
109 SourceManager &SM = Result.Context->getSourceManager();
110
111 // Suppress includes wrapped by `extern "C" { ... }` blocks.
112 ExternCRefutationVisitor Visitor(IncludesToBeProcessed, SM);
113 Visitor.TraverseAST(AST&: *Result.Context);
114
115 // Emit all the remaining reports.
116 for (const IncludeMarker &Marker : IncludesToBeProcessed) {
117 if (Marker.Replacement.empty()) {
118 diag(Loc: Marker.DiagLoc,
119 Description: "including '%0' has no effect in C++; consider removing it")
120 << Marker.FileName
121 << FixItHint::CreateRemoval(RemoveRange: Marker.ReplacementRange);
122 } else {
123 diag(Loc: Marker.DiagLoc, Description: "inclusion of deprecated C++ header "
124 "'%0'; consider using '%1' instead")
125 << Marker.FileName << Marker.Replacement
126 << FixItHint::CreateReplacement(
127 RemoveRange: Marker.ReplacementRange,
128 Code: (llvm::Twine("<") + Marker.Replacement + ">").str());
129 }
130 }
131}
132
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"},
147 {"math.h", "cmath"},
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"},
155 {"time.h", "ctime"},
156 {"wchar.h", "cwchar"},
157 {"wctype.h", "cwctype"}})) {
158 CStyledHeaderToCxx.insert(KV: KeyValue);
159 }
160 // Add C++11 headers.
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(KV: KeyValue);
170 }
171 }
172 for (const auto &Key :
173 std::vector<std::string>({"stdalign.h", "stdbool.h", "iso646.h"})) {
174 DeleteHeaders.insert(key: Key);
175 }
176}
177
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 *SuggestedModule,
182 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
183
184 // If we don't want to warn for non-main file reports and this is one, skip
185 // it.
186 if (!CheckHeaderFile && !SM.isInMainFile(Loc: HashLoc))
187 return;
188
189 // Ignore system headers.
190 if (SM.isInSystemHeader(Loc: HashLoc))
191 return;
192
193 // FIXME: Take care of library symbols from the global namespace.
194 //
195 // Reasonable options for the check:
196 //
197 // 1. Insert std prefix for every such symbol occurrence.
198 // 2. Insert `using namespace std;` to the beginning of TU.
199 // 3. Do nothing and let the user deal with the migration himself.
200 SourceLocation DiagLoc = FilenameRange.getBegin();
201 if (auto It = CStyledHeaderToCxx.find(Key: FileName);
202 It != CStyledHeaderToCxx.end()) {
203 IncludesToBeProcessed.emplace_back(args: IncludeMarker{
204 .Replacement: It->second, .FileName: FileName, .ReplacementRange: FilenameRange.getAsRange(), .DiagLoc: DiagLoc});
205 } else if (DeleteHeaders.count(Key: FileName) != 0) {
206 IncludesToBeProcessed.emplace_back(
207 // NOLINTNEXTLINE(modernize-use-emplace) - false-positive
208 args: IncludeMarker{.Replacement: std::string{}, .FileName: FileName,
209 .ReplacementRange: SourceRange{HashLoc, FilenameRange.getEnd()}, .DiagLoc: DiagLoc});
210 }
211}
212
213} // namespace clang::tidy::modernize
214

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp