7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " UseUsingCheck.h"
10
- #include " clang/AST/ASTContext .h"
10
+ #include " ../utils/LexerUtils .h"
11
11
#include " clang/AST/DeclGroup.h"
12
+ #include " clang/Basic/LangOptions.h"
13
+ #include " clang/Basic/SourceLocation.h"
14
+ #include " clang/Basic/SourceManager.h"
15
+ #include " clang/Basic/TokenKinds.h"
12
16
#include " clang/Lex/Lexer.h"
17
+ #include < string>
13
18
14
19
using namespace clang ::ast_matchers;
15
20
namespace {
@@ -83,6 +88,9 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
83
88
if (!ParentDecl)
84
89
return ;
85
90
91
+ const SourceManager &SM = *Result.SourceManager ;
92
+ const LangOptions &LO = getLangOpts ();
93
+
86
94
// Match CXXRecordDecl only to store the range of the last non-implicit full
87
95
// declaration, to later check whether it's within the typdef itself.
88
96
const auto *MatchedTagDecl = Result.Nodes .getNodeAs <TagDecl>(TagDeclName);
@@ -119,14 +127,51 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
119
127
return ;
120
128
}
121
129
122
- PrintingPolicy PrintPolicy (getLangOpts ());
123
- PrintPolicy.SuppressScope = true ;
124
- PrintPolicy.ConstantArraySizeAsWritten = true ;
125
- PrintPolicy.UseVoidForZeroParams = false ;
126
- PrintPolicy.PrintInjectedClassNameWithArguments = false ;
130
+ const TypeLoc TL = MatchedDecl->getTypeSourceInfo ()->getTypeLoc ();
131
+
132
+ auto [Type, QualifierStr] = [MatchedDecl, this , &TL, &SM,
133
+ &LO]() -> std::pair<std::string, std::string> {
134
+ SourceRange TypeRange = TL.getSourceRange ();
135
+
136
+ // Function pointer case, get the left and right side of the identifier
137
+ // without the identifier.
138
+ if (TypeRange.fullyContains (MatchedDecl->getLocation ())) {
139
+ const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange (
140
+ TypeRange.getBegin (), MatchedDecl->getLocation ());
141
+ const auto RangeRightOfIdentifier = CharSourceRange::getCharRange (
142
+ Lexer::getLocForEndOfToken (MatchedDecl->getLocation (), 0 , SM, LO),
143
+ Lexer::getLocForEndOfToken (TypeRange.getEnd (), 0 , SM, LO));
144
+ const std::string VerbatimType =
145
+ (Lexer::getSourceText (RangeLeftOfIdentifier, SM, LO) +
146
+ Lexer::getSourceText (RangeRightOfIdentifier, SM, LO))
147
+ .str ();
148
+ return {VerbatimType, " " };
149
+ }
150
+
151
+ StringRef ExtraReference = " " ;
152
+ if (MainTypeEndLoc.isValid () && TypeRange.fullyContains (MainTypeEndLoc)) {
153
+ // Each type introduced in a typedef can specify being a reference or
154
+ // pointer type seperately, so we need to sigure out if the new using-decl
155
+ // needs to be to a reference or pointer as well.
156
+ const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind (
157
+ MatchedDecl->getLocation (), SM, LO, tok::TokenKind::star,
158
+ tok::TokenKind::amp, tok::TokenKind::comma,
159
+ tok::TokenKind::kw_typedef);
160
+
161
+ ExtraReference = Lexer::getSourceText (
162
+ CharSourceRange::getCharRange (Tok, Tok.getLocWithOffset (1 )), SM, LO);
127
163
128
- std::string Type = MatchedDecl->getUnderlyingType ().getAsString (PrintPolicy);
129
- std::string Name = MatchedDecl->getNameAsString ();
164
+ if (ExtraReference != " *" && ExtraReference != " &" )
165
+ ExtraReference = " " ;
166
+
167
+ TypeRange.setEnd (MainTypeEndLoc);
168
+ }
169
+ return {
170
+ Lexer::getSourceText (CharSourceRange::getTokenRange (TypeRange), SM, LO)
171
+ .str (),
172
+ ExtraReference.str ()};
173
+ }();
174
+ StringRef Name = MatchedDecl->getName ();
130
175
SourceRange ReplaceRange = MatchedDecl->getSourceRange ();
131
176
132
177
// typedefs with multiple comma-separated definitions produce multiple
@@ -143,7 +188,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
143
188
// This is the first (and possibly the only) TypedefDecl in a typedef. Save
144
189
// Type and Name in case we find subsequent TypedefDecl's in this typedef.
145
190
FirstTypedefType = Type;
146
- FirstTypedefName = Name;
191
+ FirstTypedefName = Name.str ();
192
+ MainTypeEndLoc = TL.getEndLoc ();
147
193
} else {
148
194
// This is additional TypedefDecl in a comma-separated typedef declaration.
149
195
// Start replacement *after* prior replacement and separate with semicolon.
@@ -153,10 +199,10 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
153
199
// If this additional TypedefDecl's Type starts with the first TypedefDecl's
154
200
// type, make this using statement refer back to the first type, e.g. make
155
201
// "typedef int Foo, *Foo_p;" -> "using Foo = int;\nusing Foo_p = Foo*;"
156
- if (Type.size () > FirstTypedefType.size () &&
157
- Type.substr (0 , FirstTypedefType.size ()) == FirstTypedefType)
158
- Type = FirstTypedefName + Type.substr (FirstTypedefType.size () + 1 );
202
+ if (Type == FirstTypedefType && !QualifierStr.empty ())
203
+ Type = FirstTypedefName;
159
204
}
205
+
160
206
if (!ReplaceRange.getEnd ().isMacroID ()) {
161
207
const SourceLocation::IntTy Offset =
162
208
MatchedDecl->getFunctionType () ? 0 : Name.size ();
@@ -171,13 +217,12 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
171
217
LastTagDeclRange->second .isValid () &&
172
218
ReplaceRange.fullyContains (LastTagDeclRange->second )) {
173
219
Type = std::string (Lexer::getSourceText (
174
- CharSourceRange::getTokenRange (LastTagDeclRange->second ),
175
- *Result.SourceManager , getLangOpts ()));
220
+ CharSourceRange::getTokenRange (LastTagDeclRange->second ), SM, LO));
176
221
if (Type.empty ())
177
222
return ;
178
223
}
179
224
180
- std::string Replacement = Using + Name + " = " + Type;
225
+ std::string Replacement = ( Using + Name + " = " + Type + QualifierStr). str () ;
181
226
Diag << FixItHint::CreateReplacement (ReplaceRange, Replacement);
182
227
}
183
228
} // namespace clang::tidy::modernize
0 commit comments