7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " DeprecatedHeadersCheck.h"
10
- #include " clang/AST/RecursiveASTVisitor.h"
11
10
#include " clang/Frontend/CompilerInstance.h"
12
11
#include " clang/Lex/PPCallbacks.h"
13
12
#include " clang/Lex/Preprocessor.h"
14
13
#include " llvm/ADT/StringMap.h"
15
14
#include " llvm/ADT/StringSet.h"
16
15
17
- #include < algorithm>
18
16
#include < vector>
19
17
20
18
namespace clang {
21
19
namespace tidy {
22
20
namespace modernize {
23
- namespace detail {
24
- bool operator <(const IncludeMarker &LHS, const IncludeMarker &RHS) {
25
- return LHS.DecomposedDiagLoc < RHS.DecomposedDiagLoc ;
26
- }
27
- bool operator <(const IncludeMarker &LHS,
28
- const std::pair<FileID, unsigned > &RHS) {
29
- return LHS.DecomposedDiagLoc < RHS;
30
- }
31
- bool operator <(const std::pair<FileID, unsigned > &LHS,
32
- const IncludeMarker &RHS) {
33
- return LHS < RHS.DecomposedDiagLoc ;
34
- }
35
21
22
+ namespace {
36
23
class IncludeModernizePPCallbacks : public PPCallbacks {
37
24
public:
38
- explicit IncludeModernizePPCallbacks (DeprecatedHeadersCheck &Check,
39
- LangOptions LangOpts,
40
- const SourceManager &SM);
25
+ explicit IncludeModernizePPCallbacks (ClangTidyCheck &Check,
26
+ LangOptions LangOpts);
41
27
42
28
void InclusionDirective (SourceLocation HashLoc, const Token &IncludeTok,
43
29
StringRef FileName, bool IsAngled,
@@ -47,98 +33,22 @@ class IncludeModernizePPCallbacks : public PPCallbacks {
47
33
SrcMgr::CharacteristicKind FileType) override ;
48
34
49
35
private:
50
- DeprecatedHeadersCheck &Check;
36
+ ClangTidyCheck &Check;
51
37
LangOptions LangOpts;
52
38
llvm::StringMap<std::string> CStyledHeaderToCxx;
53
39
llvm::StringSet<> DeleteHeaders;
54
- const SourceManager &SM;
55
- };
56
-
57
- class ExternCRefutationVisitor
58
- : public RecursiveASTVisitor<ExternCRefutationVisitor> {
59
- std::vector<IncludeMarker> &IncludesToBeProcessed;
60
- const SourceManager &SM;
61
-
62
- public:
63
- ExternCRefutationVisitor (std::vector<IncludeMarker> &IncludesToBeProcessed,
64
- SourceManager &SM)
65
- : IncludesToBeProcessed(IncludesToBeProcessed), SM(SM) {}
66
- bool shouldWalkTypesOfTypeLocs () const { return false ; }
67
- bool shouldVisitLambdaBody () const { return false ; }
68
-
69
- bool VisitLinkageSpecDecl (LinkageSpecDecl *LinkSpecDecl) const {
70
- if (LinkSpecDecl->getLanguage () != LinkageSpecDecl::lang_c ||
71
- !LinkSpecDecl->hasBraces ())
72
- return true ;
73
-
74
- auto ExternCBlockBegin =
75
- SM.getDecomposedExpansionLoc (LinkSpecDecl->getBeginLoc ());
76
- auto ExternCBlockEnd =
77
- SM.getDecomposedExpansionLoc (LinkSpecDecl->getEndLoc ());
78
-
79
- auto Begin = IncludesToBeProcessed.begin ();
80
- auto End = IncludesToBeProcessed.end ();
81
- auto Low = std::lower_bound (Begin, End, ExternCBlockBegin);
82
- auto Up = std::upper_bound (Low, End, ExternCBlockEnd);
83
- IncludesToBeProcessed.erase (Low, Up);
84
- return true ;
85
- }
86
40
};
87
- } // namespace detail
41
+ } // namespace
88
42
89
43
void DeprecatedHeadersCheck::registerPPCallbacks (
90
44
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
91
- PP->addPPCallbacks (::std::make_unique<detail::IncludeModernizePPCallbacks>(
92
- *this , getLangOpts (), PP->getSourceManager ()));
93
- }
94
- void DeprecatedHeadersCheck::registerMatchers (
95
- ast_matchers::MatchFinder *Finder) {
96
- // Even though the checker operates on a "preprocessor" level, we still need
97
- // to act on a "TranslationUnit" to acquire the AST where we can walk each
98
- // Decl and look for `extern "C"` blocks where we will suppress the report we
99
- // collected during the preprocessing phase.
100
- // The `onStartOfTranslationUnit()` won't suffice, since we need some handle
101
- // to the `ASTContext`.
102
- Finder->addMatcher (ast_matchers::translationUnitDecl ().bind (" TU" ), this );
103
- }
104
-
105
- void DeprecatedHeadersCheck::onEndOfTranslationUnit () {
106
- IncludesToBeProcessed.clear ();
107
- }
108
-
109
- void DeprecatedHeadersCheck::check (
110
- const ast_matchers::MatchFinder::MatchResult &Result) {
111
- SourceManager &SM = Result.Context ->getSourceManager ();
112
- using detail::IncludeMarker;
113
-
114
- llvm::sort (IncludesToBeProcessed);
115
-
116
- // Suppress includes wrapped by `extern "C" { ... }` blocks.
117
- detail::ExternCRefutationVisitor Visitor (IncludesToBeProcessed, SM);
118
- Visitor.TraverseAST (*Result.Context );
119
-
120
- // Emit all the remaining reports.
121
- for (const IncludeMarker &Entry : IncludesToBeProcessed) {
122
- SourceLocation DiagLoc = SM.getComposedLoc (Entry.DecomposedDiagLoc .first ,
123
- Entry.DecomposedDiagLoc .second );
124
- if (Entry.Replacement .empty ()) {
125
- diag (DiagLoc, " including '%0' has no effect in C++; consider removing it" )
126
- << Entry.FileName << FixItHint::CreateRemoval (Entry.ReplacementRange );
127
- } else {
128
- diag (DiagLoc, " inclusion of deprecated C++ header "
129
- " '%0'; consider using '%1' instead" )
130
- << Entry.FileName << Entry.Replacement
131
- << FixItHint::CreateReplacement (
132
- Entry.ReplacementRange ,
133
- (llvm::Twine (" <" ) + Entry.Replacement + " >" ).str ());
134
- }
135
- }
45
+ PP->addPPCallbacks (
46
+ ::std::make_unique<IncludeModernizePPCallbacks>(*this , getLangOpts ()));
136
47
}
137
48
138
- detail::IncludeModernizePPCallbacks::IncludeModernizePPCallbacks (
139
- DeprecatedHeadersCheck &Check, LangOptions LangOpts,
140
- const SourceManager &SM)
141
- : Check(Check), LangOpts(LangOpts), SM(SM) {
49
+ IncludeModernizePPCallbacks::IncludeModernizePPCallbacks (ClangTidyCheck &Check,
50
+ LangOptions LangOpts)
51
+ : Check(Check), LangOpts(LangOpts) {
142
52
for (const auto &KeyValue :
143
53
std::vector<std::pair<llvm::StringRef, std::string>>(
144
54
{{" assert.h" , " cassert" },
@@ -179,7 +89,7 @@ detail::IncludeModernizePPCallbacks::IncludeModernizePPCallbacks(
179
89
}
180
90
}
181
91
182
- void detail:: IncludeModernizePPCallbacks::InclusionDirective (
92
+ void IncludeModernizePPCallbacks::InclusionDirective (
183
93
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
184
94
bool IsAngled, CharSourceRange FilenameRange, Optional<FileEntryRef> File,
185
95
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
@@ -191,16 +101,19 @@ void detail::IncludeModernizePPCallbacks::InclusionDirective(
191
101
// 1. Insert std prefix for every such symbol occurrence.
192
102
// 2. Insert `using namespace std;` to the beginning of TU.
193
103
// 3. Do nothing and let the user deal with the migration himself.
194
- std::pair<FileID, unsigned > DiagLoc =
195
- SM.getDecomposedExpansionLoc (FilenameRange.getBegin ());
196
104
if (CStyledHeaderToCxx.count (FileName) != 0 ) {
197
- Check.IncludesToBeProcessed .push_back (
198
- IncludeMarker{CStyledHeaderToCxx[FileName], FileName,
199
- FilenameRange.getAsRange (), DiagLoc});
105
+ std::string Replacement =
106
+ (llvm::Twine (" <" ) + CStyledHeaderToCxx[FileName] + " >" ).str ();
107
+ Check.diag (FilenameRange.getBegin (), " inclusion of deprecated C++ header "
108
+ " '%0'; consider using '%1' instead" )
109
+ << FileName << CStyledHeaderToCxx[FileName]
110
+ << FixItHint::CreateReplacement (FilenameRange.getAsRange (),
111
+ Replacement);
200
112
} else if (DeleteHeaders.count (FileName) != 0 ) {
201
- Check.IncludesToBeProcessed .push_back (
202
- IncludeMarker{std::string{}, FileName,
203
- SourceRange{HashLoc, FilenameRange.getEnd ()}, DiagLoc});
113
+ Check.diag (FilenameRange.getBegin (),
114
+ " including '%0' has no effect in C++; consider removing it" )
115
+ << FileName << FixItHint::CreateRemoval (
116
+ SourceRange (HashLoc, FilenameRange.getEnd ()));
204
117
}
205
118
}
206
119
0 commit comments