@@ -226,6 +226,107 @@ llvm::Expected<std::string> qualifyAllDecls(const FunctionDecl *FD) {
226
226
return QualifiedFunc->substr (BodyBegin, BodyEnd - BodyBegin + 1 );
227
227
}
228
228
229
+ // / Generates Replacements for changing template and function parameter names in
230
+ // / \p Dest to be the same as in \p Source.
231
+ llvm::Expected<tooling::Replacements>
232
+ renameParameters (const FunctionDecl *Dest, const FunctionDecl *Source) {
233
+ llvm::DenseMap<const Decl *, std::string> ParamToNewName;
234
+ llvm::DenseMap<const NamedDecl *, std::vector<SourceLocation>> RefLocs;
235
+ auto HandleParam = [&](const NamedDecl *DestParam,
236
+ const NamedDecl *SourceParam) {
237
+ // No need to rename if parameters already have the same name.
238
+ if (DestParam->getName () == SourceParam->getName ())
239
+ return ;
240
+ std::string NewName;
241
+ // Unnamed parameters won't be visited in findExplicitReferences. So add
242
+ // them here.
243
+ if (DestParam->getName ().empty ()) {
244
+ RefLocs[DestParam].push_back (DestParam->getLocation ());
245
+ // If decl is unnamed in destination we pad the new name to avoid gluing
246
+ // with previous token, e.g. foo(int^) shouldn't turn into foo(intx).
247
+ NewName = " " ;
248
+ }
249
+ NewName.append (SourceParam->getName ());
250
+ ParamToNewName[DestParam->getCanonicalDecl ()] = std::move (NewName);
251
+ };
252
+
253
+ // Populate mapping for template parameters.
254
+ auto *DestTempl = Dest->getDescribedFunctionTemplate ();
255
+ auto *SourceTempl = Source->getDescribedFunctionTemplate ();
256
+ assert (bool (DestTempl) == bool (SourceTempl));
257
+ if (DestTempl) {
258
+ const auto *DestTPL = DestTempl->getTemplateParameters ();
259
+ const auto *SourceTPL = SourceTempl->getTemplateParameters ();
260
+ assert (DestTPL->size () == SourceTPL->size ());
261
+
262
+ for (size_t I = 0 , EP = DestTPL->size (); I != EP; ++I)
263
+ HandleParam (DestTPL->getParam (I), SourceTPL->getParam (I));
264
+ }
265
+
266
+ // Populate mapping for function params.
267
+ assert (Dest->param_size () == Source->param_size ());
268
+ for (size_t I = 0 , E = Dest->param_size (); I != E; ++I)
269
+ HandleParam (Dest->getParamDecl (I), Source->getParamDecl (I));
270
+
271
+ const SourceManager &SM = Dest->getASTContext ().getSourceManager ();
272
+ const LangOptions &LangOpts = Dest->getASTContext ().getLangOpts ();
273
+ // Collect other references in function signature, i.e parameter types and
274
+ // default arguments.
275
+ findExplicitReferences (
276
+ // Use function template in case of templated functions to visit template
277
+ // parameters.
278
+ DestTempl ? llvm::dyn_cast<Decl>(DestTempl) : llvm::dyn_cast<Decl>(Dest),
279
+ [&](ReferenceLoc Ref) {
280
+ if (Ref.Targets .size () != 1 )
281
+ return ;
282
+ const auto *Target =
283
+ llvm::cast<NamedDecl>(Ref.Targets .front ()->getCanonicalDecl ());
284
+ auto It = ParamToNewName.find (Target);
285
+ if (It == ParamToNewName.end ())
286
+ return ;
287
+ RefLocs[Target].push_back (Ref.NameLoc );
288
+ });
289
+
290
+ // Now try to generate edits for all the refs.
291
+ tooling::Replacements Replacements;
292
+ for (auto &Entry : RefLocs) {
293
+ const auto *OldDecl = Entry.first ;
294
+ llvm::StringRef OldName = OldDecl->getName ();
295
+ llvm::StringRef NewName = ParamToNewName[OldDecl];
296
+ for (SourceLocation RefLoc : Entry.second ) {
297
+ CharSourceRange ReplaceRange;
298
+ // In case of unnamed parameters, we have an empty char range, whereas we
299
+ // have a tokenrange at RefLoc with named parameters.
300
+ if (OldName.empty ())
301
+ ReplaceRange = CharSourceRange::getCharRange (RefLoc, RefLoc);
302
+ else
303
+ ReplaceRange = CharSourceRange::getTokenRange (RefLoc, RefLoc);
304
+ // If occurence is coming from a macro expansion, try to get back to the
305
+ // file range.
306
+ if (RefLoc.isMacroID ()) {
307
+ ReplaceRange = Lexer::makeFileCharRange (ReplaceRange, SM, LangOpts);
308
+ // Bail out if we need to replace macro bodies.
309
+ if (ReplaceRange.isInvalid ()) {
310
+ auto Err = llvm::createStringError (
311
+ llvm::inconvertibleErrorCode (),
312
+ " Cant rename parameter inside macro body." );
313
+ elog (" define inline: {0}" , Err);
314
+ return std::move (Err);
315
+ }
316
+ }
317
+
318
+ if (auto Err = Replacements.add (
319
+ tooling::Replacement (SM, ReplaceRange, NewName))) {
320
+ elog (" define inline: Couldn't replace parameter name for {0} to {1}: "
321
+ " {2}" ,
322
+ OldName, NewName, Err);
323
+ return std::move (Err);
324
+ }
325
+ }
326
+ }
327
+ return Replacements;
328
+ }
329
+
229
330
// Returns the canonical declaration for the given FunctionDecl. This will
230
331
// usually be the first declaration in current translation unit with the
231
332
// exception of template specialization.
@@ -332,6 +433,10 @@ class DefineInline : public Tweak {
332
433
" Couldn't find semicolon for target declaration." );
333
434
}
334
435
436
+ auto ParamReplacements = renameParameters (Target, Source);
437
+ if (!ParamReplacements)
438
+ return ParamReplacements.takeError ();
439
+
335
440
auto QualifiedBody = qualifyAllDecls (Source);
336
441
if (!QualifiedBody)
337
442
return QualifiedBody.takeError ();
@@ -354,8 +459,9 @@ class DefineInline : public Tweak {
354
459
355
460
llvm::SmallVector<std::pair<std::string, Edit>, 2 > Edits;
356
461
// Edit for Target.
357
- auto FE = Effect::fileEdit (SM, SM.getFileID (*Semicolon),
358
- tooling::Replacements (SemicolonToFuncBody));
462
+ auto FE = Effect::fileEdit (
463
+ SM, SM.getFileID (*Semicolon),
464
+ tooling::Replacements (SemicolonToFuncBody).merge (*ParamReplacements));
359
465
if (!FE)
360
466
return FE.takeError ();
361
467
Edits.push_back (std::move (*FE));
0 commit comments