@@ -48,6 +48,10 @@ class AddUsing : public Tweak {
48
48
NestedNameSpecifierLoc QualifierToRemove;
49
49
// The name following QualifierToRemove.
50
50
llvm::StringRef Name;
51
+ // If valid, the insertion point for "using" statement must come after this.
52
+ // This is relevant when the type is defined in the main file, to make sure
53
+ // the type/function is already defined at the point where "using" is added.
54
+ SourceLocation MustInsertAfterLoc;
51
55
};
52
56
REGISTER_TWEAK (AddUsing)
53
57
@@ -120,7 +124,8 @@ struct InsertionPointData {
120
124
llvm::Expected<InsertionPointData>
121
125
findInsertionPoint (const Tweak::Selection &Inputs,
122
126
const NestedNameSpecifierLoc &QualifierToRemove,
123
- const llvm::StringRef Name) {
127
+ const llvm::StringRef Name,
128
+ const SourceLocation MustInsertAfterLoc) {
124
129
auto &SM = Inputs.AST ->getSourceManager ();
125
130
126
131
// Search for all using decls that affect this point in file. We need this for
@@ -132,6 +137,11 @@ findInsertionPoint(const Tweak::Selection &Inputs,
132
137
SM)
133
138
.TraverseAST (Inputs.AST ->getASTContext ());
134
139
140
+ auto IsValidPoint = [&](const SourceLocation Loc) {
141
+ return MustInsertAfterLoc.isInvalid () ||
142
+ SM.isBeforeInTranslationUnit (MustInsertAfterLoc, Loc);
143
+ };
144
+
135
145
bool AlwaysFullyQualify = true ;
136
146
for (auto &U : Usings) {
137
147
// Only "upgrade" to fully qualified is all relevant using decls are fully
@@ -149,12 +159,13 @@ findInsertionPoint(const Tweak::Selection &Inputs,
149
159
U->getName () == Name) {
150
160
return InsertionPointData ();
151
161
}
162
+
152
163
// Insertion point will be before last UsingDecl that affects cursor
153
164
// position. For most cases this should stick with the local convention of
154
165
// add using inside or outside namespace.
155
166
LastUsingLoc = U->getUsingLoc ();
156
167
}
157
- if (LastUsingLoc.isValid ()) {
168
+ if (LastUsingLoc.isValid () && IsValidPoint (LastUsingLoc) ) {
158
169
InsertionPointData Out;
159
170
Out.Loc = LastUsingLoc;
160
171
Out.AlwaysFullyQualify = AlwaysFullyQualify;
@@ -175,23 +186,25 @@ findInsertionPoint(const Tweak::Selection &Inputs,
175
186
if (Tok == Toks.end () || Tok->endLocation ().isInvalid ()) {
176
187
return error (" Namespace with no {" );
177
188
}
178
- if (!Tok->endLocation ().isMacroID ()) {
189
+ if (!Tok->endLocation ().isMacroID () && IsValidPoint (Tok-> endLocation ()) ) {
179
190
InsertionPointData Out;
180
191
Out.Loc = Tok->endLocation ();
181
192
Out.Suffix = " \n " ;
182
193
return Out;
183
194
}
184
195
}
185
196
// No using, no namespace, no idea where to insert. Try above the first
186
- // top level decl.
197
+ // top level decl after MustInsertAfterLoc .
187
198
auto TLDs = Inputs.AST ->getLocalTopLevelDecls ();
188
- if (TLDs.empty ()) {
189
- return error (" Cannot find place to insert \" using\" " );
199
+ for (const auto &TLD : TLDs) {
200
+ if (!IsValidPoint (TLD->getBeginLoc ()))
201
+ continue ;
202
+ InsertionPointData Out;
203
+ Out.Loc = SM.getExpansionLoc (TLD->getBeginLoc ());
204
+ Out.Suffix = " \n\n " ;
205
+ return Out;
190
206
}
191
- InsertionPointData Out;
192
- Out.Loc = SM.getExpansionLoc (TLDs[0 ]->getBeginLoc ());
193
- Out.Suffix = " \n\n " ;
194
- return Out;
207
+ return error (" Cannot find place to insert \" using\" " );
195
208
}
196
209
197
210
bool isNamespaceForbidden (const Tweak::Selection &Inputs,
@@ -254,6 +267,7 @@ bool AddUsing::prepare(const Selection &Inputs) {
254
267
if (auto *II = D->getDecl ()->getIdentifier ()) {
255
268
QualifierToRemove = D->getQualifierLoc ();
256
269
Name = II->getName ();
270
+ MustInsertAfterLoc = D->getDecl ()->getBeginLoc ();
257
271
}
258
272
} else if (auto *T = Node->ASTNode .get <TypeLoc>()) {
259
273
if (auto E = T->getAs <ElaboratedTypeLoc>()) {
@@ -271,6 +285,15 @@ bool AddUsing::prepare(const Selection &Inputs) {
271
285
QualifierToRemove, Inputs.AST ->getASTContext ().getPrintingPolicy ());
272
286
if (!Name.consume_front (QualifierToRemoveStr))
273
287
return false ; // What's spelled doesn't match the qualifier.
288
+
289
+ if (const auto *ET = E.getTypePtr ()) {
290
+ if (const auto *TDT =
291
+ dyn_cast<TypedefType>(ET->getNamedType ().getTypePtr ())) {
292
+ MustInsertAfterLoc = TDT->getDecl ()->getBeginLoc ();
293
+ } else if (auto *TD = ET->getAsTagDecl ()) {
294
+ MustInsertAfterLoc = TD->getBeginLoc ();
295
+ }
296
+ }
274
297
}
275
298
}
276
299
@@ -312,7 +335,8 @@ Expected<Tweak::Effect> AddUsing::apply(const Selection &Inputs) {
312
335
return std::move (Err);
313
336
}
314
337
315
- auto InsertionPoint = findInsertionPoint (Inputs, QualifierToRemove, Name);
338
+ auto InsertionPoint =
339
+ findInsertionPoint (Inputs, QualifierToRemove, Name, MustInsertAfterLoc);
316
340
if (!InsertionPoint) {
317
341
return InsertionPoint.takeError ();
318
342
}
0 commit comments