1//===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//
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/// \file
10/// Methods for finding all instances of a USR. Our strategy is very
11/// simple; we just compare the USR at every relevant AST node with the one
12/// provided.
13///
14//===----------------------------------------------------------------------===//
15
16#include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
17#include "clang/AST/ASTContext.h"
18#include "clang/AST/ParentMapContext.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/Basic/LLVM.h"
21#include "clang/Basic/SourceLocation.h"
22#include "clang/Basic/SourceManager.h"
23#include "clang/Lex/Lexer.h"
24#include "clang/Tooling/Refactoring/Lookup.h"
25#include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h"
26#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
27#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/Support/Casting.h"
30#include <cstddef>
31#include <set>
32#include <string>
33#include <vector>
34
35using namespace llvm;
36
37namespace clang {
38namespace tooling {
39
40namespace {
41
42// Returns true if the given Loc is valid for edit. We don't edit the
43// SourceLocations that are valid or in temporary buffer.
44bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) {
45 if (Loc.isInvalid())
46 return false;
47 const clang::FullSourceLoc FullLoc(Loc, SM);
48 std::pair<clang::FileID, unsigned> FileIdAndOffset =
49 FullLoc.getSpellingLoc().getDecomposedLoc();
50 return SM.getFileEntryForID(FID: FileIdAndOffset.first) != nullptr;
51}
52
53// This visitor recursively searches for all instances of a USR in a
54// translation unit and stores them for later usage.
55class USRLocFindingASTVisitor
56 : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
57public:
58 explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
59 StringRef PrevName,
60 const ASTContext &Context)
61 : RecursiveSymbolVisitor(Context.getSourceManager(),
62 Context.getLangOpts()),
63 USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
64 }
65
66 bool visitSymbolOccurrence(const NamedDecl *ND,
67 ArrayRef<SourceRange> NameRanges) {
68 if (USRSet.find(x: getUSRForDecl(ND)) != USRSet.end()) {
69 assert(NameRanges.size() == 1 &&
70 "Multiple name pieces are not supported yet!");
71 SourceLocation Loc = NameRanges[0].getBegin();
72 const SourceManager &SM = Context.getSourceManager();
73 // TODO: Deal with macro occurrences correctly.
74 if (Loc.isMacroID())
75 Loc = SM.getSpellingLoc(Loc);
76 checkAndAddLocation(Loc);
77 }
78 return true;
79 }
80
81 // Non-visitors:
82
83 /// Returns a set of unique symbol occurrences. Duplicate or
84 /// overlapping occurrences are erroneous and should be reported!
85 SymbolOccurrences takeOccurrences() { return std::move(Occurrences); }
86
87private:
88 void checkAndAddLocation(SourceLocation Loc) {
89 const SourceLocation BeginLoc = Loc;
90 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
91 Loc: BeginLoc, Offset: 0, SM: Context.getSourceManager(), LangOpts: Context.getLangOpts());
92 StringRef TokenName =
93 Lexer::getSourceText(Range: CharSourceRange::getTokenRange(B: BeginLoc, E: EndLoc),
94 SM: Context.getSourceManager(), LangOpts: Context.getLangOpts());
95 size_t Offset = TokenName.find(Str: PrevName.getNamePieces()[0]);
96
97 // The token of the source location we find actually has the old
98 // name.
99 if (Offset != StringRef::npos)
100 Occurrences.emplace_back(args: PrevName, args: SymbolOccurrence::MatchingSymbol,
101 args: BeginLoc.getLocWithOffset(Offset));
102 }
103
104 const std::set<std::string> USRSet;
105 const SymbolName PrevName;
106 SymbolOccurrences Occurrences;
107 const ASTContext &Context;
108};
109
110SourceLocation StartLocationForType(TypeLoc TL) {
111 // For elaborated types (e.g. `struct a::A`) we want the portion after the
112 // `struct` but including the namespace qualifier, `a::`.
113 if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
114 NestedNameSpecifierLoc NestedNameSpecifier =
115 ElaboratedTypeLoc.getQualifierLoc();
116 if (NestedNameSpecifier.getNestedNameSpecifier())
117 return NestedNameSpecifier.getBeginLoc();
118 TL = TL.getNextTypeLoc();
119 }
120 return TL.getBeginLoc();
121}
122
123SourceLocation EndLocationForType(TypeLoc TL) {
124 // Dig past any namespace or keyword qualifications.
125 while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
126 TL.getTypeLocClass() == TypeLoc::Qualified)
127 TL = TL.getNextTypeLoc();
128
129 // The location for template specializations (e.g. Foo<int>) includes the
130 // templated types in its location range. We want to restrict this to just
131 // before the `<` character.
132 if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
133 return TL.castAs<TemplateSpecializationTypeLoc>()
134 .getLAngleLoc()
135 .getLocWithOffset(Offset: -1);
136 }
137 return TL.getEndLoc();
138}
139
140NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
141 // Dig past any keyword qualifications.
142 while (TL.getTypeLocClass() == TypeLoc::Qualified)
143 TL = TL.getNextTypeLoc();
144
145 // For elaborated types (e.g. `struct a::A`) we want the portion after the
146 // `struct` but including the namespace qualifier, `a::`.
147 if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
148 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
149 return nullptr;
150}
151
152// Find all locations identified by the given USRs for rename.
153//
154// This class will traverse the AST and find every AST node whose USR is in the
155// given USRs' set.
156class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
157public:
158 RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
159 : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
160
161 // A structure records all information of a symbol reference being renamed.
162 // We try to add as few prefix qualifiers as possible.
163 struct RenameInfo {
164 // The begin location of a symbol being renamed.
165 SourceLocation Begin;
166 // The end location of a symbol being renamed.
167 SourceLocation End;
168 // The declaration of a symbol being renamed (can be nullptr).
169 const NamedDecl *FromDecl;
170 // The declaration in which the nested name is contained (can be nullptr).
171 const Decl *Context;
172 // The nested name being replaced (can be nullptr).
173 const NestedNameSpecifier *Specifier;
174 // Determine whether the prefix qualifiers of the NewName should be ignored.
175 // Normally, we set it to true for the symbol declaration and definition to
176 // avoid adding prefix qualifiers.
177 // For example, if it is true and NewName is "a::b::foo", then the symbol
178 // occurrence which the RenameInfo points to will be renamed to "foo".
179 bool IgnorePrefixQualifers;
180 };
181
182 bool VisitNamedDecl(const NamedDecl *Decl) {
183 // UsingDecl has been handled in other place.
184 if (llvm::isa<UsingDecl>(Val: Decl))
185 return true;
186
187 // DestructorDecl has been handled in Typeloc.
188 if (llvm::isa<CXXDestructorDecl>(Val: Decl))
189 return true;
190
191 if (Decl->isImplicit())
192 return true;
193
194 if (isInUSRSet(Decl)) {
195 // For the case of renaming an alias template, we actually rename the
196 // underlying alias declaration of the template.
197 if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Val: Decl))
198 Decl = TAT->getTemplatedDecl();
199
200 auto StartLoc = Decl->getLocation();
201 auto EndLoc = StartLoc;
202 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
203 RenameInfo Info = {StartLoc,
204 EndLoc,
205 /*FromDecl=*/nullptr,
206 /*Context=*/nullptr,
207 /*Specifier=*/nullptr,
208 /*IgnorePrefixQualifers=*/true};
209 RenameInfos.push_back(x: Info);
210 }
211 }
212 return true;
213 }
214
215 bool VisitMemberExpr(const MemberExpr *Expr) {
216 const NamedDecl *Decl = Expr->getFoundDecl();
217 auto StartLoc = Expr->getMemberLoc();
218 auto EndLoc = Expr->getMemberLoc();
219 if (isInUSRSet(Decl)) {
220 RenameInfos.push_back(x: {.Begin: StartLoc, .End: EndLoc,
221 /*FromDecl=*/nullptr,
222 /*Context=*/nullptr,
223 /*Specifier=*/nullptr,
224 /*IgnorePrefixQualifiers=*/.IgnorePrefixQualifers: true});
225 }
226 return true;
227 }
228
229 bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
230 for (const DesignatedInitExpr::Designator &D : E->designators()) {
231 if (D.isFieldDesignator()) {
232 if (const FieldDecl *Decl = D.getFieldDecl()) {
233 if (isInUSRSet(Decl)) {
234 auto StartLoc = D.getFieldLoc();
235 auto EndLoc = D.getFieldLoc();
236 RenameInfos.push_back(x: {.Begin: StartLoc, .End: EndLoc,
237 /*FromDecl=*/nullptr,
238 /*Context=*/nullptr,
239 /*Specifier=*/nullptr,
240 /*IgnorePrefixQualifiers=*/.IgnorePrefixQualifers: true});
241 }
242 }
243 }
244 }
245 return true;
246 }
247
248 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
249 // Fix the constructor initializer when renaming class members.
250 for (const auto *Initializer : CD->inits()) {
251 // Ignore implicit initializers.
252 if (!Initializer->isWritten())
253 continue;
254
255 if (const FieldDecl *FD = Initializer->getMember()) {
256 if (isInUSRSet(FD)) {
257 auto Loc = Initializer->getSourceLocation();
258 RenameInfos.push_back(x: {.Begin: Loc, .End: Loc,
259 /*FromDecl=*/nullptr,
260 /*Context=*/nullptr,
261 /*Specifier=*/nullptr,
262 /*IgnorePrefixQualifiers=*/.IgnorePrefixQualifers: true});
263 }
264 }
265 }
266 return true;
267 }
268
269 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
270 const NamedDecl *Decl = Expr->getFoundDecl();
271 // Get the underlying declaration of the shadow declaration introduced by a
272 // using declaration.
273 if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Val: Decl)) {
274 Decl = UsingShadow->getTargetDecl();
275 }
276
277 auto StartLoc = Expr->getBeginLoc();
278 // For template function call expressions like `foo<int>()`, we want to
279 // restrict the end of location to just before the `<` character.
280 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
281 ? Expr->getLAngleLoc().getLocWithOffset(Offset: -1)
282 : Expr->getEndLoc();
283
284 if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Val: Decl)) {
285 if (isInUSRSet(MD)) {
286 // Handle renaming static template class methods, we only rename the
287 // name without prefix qualifiers and restrict the source range to the
288 // name.
289 RenameInfos.push_back(x: {.Begin: EndLoc, .End: EndLoc,
290 /*FromDecl=*/nullptr,
291 /*Context=*/nullptr,
292 /*Specifier=*/nullptr,
293 /*IgnorePrefixQualifiers=*/.IgnorePrefixQualifers: true});
294 return true;
295 }
296 }
297
298 // In case of renaming an enum declaration, we have to explicitly handle
299 // unscoped enum constants referenced in expressions (e.g.
300 // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped
301 // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by
302 // TypeLoc.
303 if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Val: Decl)) {
304 // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`)
305 // when renaming an unscoped enum declaration with a new namespace.
306 if (!Expr->hasQualifier())
307 return true;
308
309 if (const auto *ED =
310 llvm::dyn_cast_or_null<EnumDecl>(Val: getClosestAncestorDecl(Node: *T))) {
311 if (ED->isScoped())
312 return true;
313 Decl = ED;
314 }
315 // The current fix would qualify "ns1::ns2::Green" as
316 // "ns1::ns2::Color::Green".
317 //
318 // Get the EndLoc of the replacement by moving 1 character backward (
319 // to exclude the last '::').
320 //
321 // ns1::ns2::Green;
322 // ^ ^^
323 // BeginLoc |EndLoc of the qualifier
324 // new EndLoc
325 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(Offset: -1);
326 assert(EndLoc.isValid() &&
327 "The enum constant should have prefix qualifers.");
328 }
329 if (isInUSRSet(Decl) &&
330 IsValidEditLoc(SM: Context.getSourceManager(), Loc: StartLoc)) {
331 RenameInfo Info = {.Begin: StartLoc,
332 .End: EndLoc,
333 .FromDecl: Decl,
334 .Context: getClosestAncestorDecl(Node: *Expr),
335 .Specifier: Expr->getQualifier(),
336 /*IgnorePrefixQualifers=*/false};
337 RenameInfos.push_back(x: Info);
338 }
339
340 return true;
341 }
342
343 bool VisitUsingDecl(const UsingDecl *Using) {
344 for (const auto *UsingShadow : Using->shadows()) {
345 if (isInUSRSet(UsingShadow->getTargetDecl())) {
346 UsingDecls.push_back(Using);
347 break;
348 }
349 }
350 return true;
351 }
352
353 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
354 if (!NestedLoc.getNestedNameSpecifier()->getAsType())
355 return true;
356
357 if (const auto *TargetDecl =
358 getSupportedDeclFromTypeLoc(Loc: NestedLoc.getTypeLoc())) {
359 if (isInUSRSet(TargetDecl)) {
360 RenameInfo Info = {.Begin: NestedLoc.getBeginLoc(),
361 .End: EndLocationForType(TL: NestedLoc.getTypeLoc()),
362 .FromDecl: TargetDecl,
363 .Context: getClosestAncestorDecl(Node: NestedLoc),
364 .Specifier: NestedLoc.getNestedNameSpecifier()->getPrefix(),
365 /*IgnorePrefixQualifers=*/false};
366 RenameInfos.push_back(x: Info);
367 }
368 }
369 return true;
370 }
371
372 bool VisitTypeLoc(TypeLoc Loc) {
373 auto Parents = Context.getParents(Node: Loc);
374 TypeLoc ParentTypeLoc;
375 if (!Parents.empty()) {
376 // Handle cases of nested name specificier locations.
377 //
378 // The VisitNestedNameSpecifierLoc interface is not impelmented in
379 // RecursiveASTVisitor, we have to handle it explicitly.
380 if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
381 VisitNestedNameSpecifierLocations(NestedLoc: *NSL);
382 return true;
383 }
384
385 if (const auto *TL = Parents[0].get<TypeLoc>())
386 ParentTypeLoc = *TL;
387 }
388
389 // Handle the outermost TypeLoc which is directly linked to the interesting
390 // declaration and don't handle nested name specifier locations.
391 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
392 if (isInUSRSet(TargetDecl)) {
393 // Only handle the outermost typeLoc.
394 //
395 // For a type like "a::Foo", there will be two typeLocs for it.
396 // One ElaboratedType, the other is RecordType:
397 //
398 // ElaboratedType 0x33b9390 'a::Foo' sugar
399 // `-RecordType 0x338fef0 'class a::Foo'
400 // `-CXXRecord 0x338fe58 'Foo'
401 //
402 // Skip if this is an inner typeLoc.
403 if (!ParentTypeLoc.isNull() &&
404 isInUSRSet(getSupportedDeclFromTypeLoc(Loc: ParentTypeLoc)))
405 return true;
406
407 auto StartLoc = StartLocationForType(TL: Loc);
408 auto EndLoc = EndLocationForType(TL: Loc);
409 if (IsValidEditLoc(SM: Context.getSourceManager(), Loc: StartLoc)) {
410 RenameInfo Info = {.Begin: StartLoc,
411 .End: EndLoc,
412 .FromDecl: TargetDecl,
413 .Context: getClosestAncestorDecl(Node: Loc),
414 .Specifier: GetNestedNameForType(TL: Loc),
415 /*IgnorePrefixQualifers=*/false};
416 RenameInfos.push_back(x: Info);
417 }
418 return true;
419 }
420 }
421
422 // Handle specific template class specialiation cases.
423 if (const auto *TemplateSpecType =
424 dyn_cast<TemplateSpecializationType>(Val: Loc.getType())) {
425 TypeLoc TargetLoc = Loc;
426 if (!ParentTypeLoc.isNull()) {
427 if (llvm::isa<ElaboratedType>(Val: ParentTypeLoc.getType()))
428 TargetLoc = ParentTypeLoc;
429 }
430
431 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
432 TypeLoc TargetLoc = Loc;
433 // FIXME: Find a better way to handle this case.
434 // For the qualified template class specification type like
435 // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
436 // (ElaboratedType) of the TemplateSpecializationType in order to
437 // catch the prefix qualifiers "ns::".
438 if (!ParentTypeLoc.isNull() &&
439 llvm::isa<ElaboratedType>(Val: ParentTypeLoc.getType()))
440 TargetLoc = ParentTypeLoc;
441
442 auto StartLoc = StartLocationForType(TL: TargetLoc);
443 auto EndLoc = EndLocationForType(TL: TargetLoc);
444 if (IsValidEditLoc(SM: Context.getSourceManager(), Loc: StartLoc)) {
445 RenameInfo Info = {
446 .Begin: StartLoc,
447 .End: EndLoc,
448 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
449 .Context: getClosestAncestorDecl(Node: DynTypedNode::create(Node: TargetLoc)),
450 .Specifier: GetNestedNameForType(TL: TargetLoc),
451 /*IgnorePrefixQualifers=*/false};
452 RenameInfos.push_back(x: Info);
453 }
454 }
455 }
456 return true;
457 }
458
459 // Returns a list of RenameInfo.
460 const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
461
462 // Returns a list of using declarations which are needed to update.
463 const std::vector<const UsingDecl *> &getUsingDecls() const {
464 return UsingDecls;
465 }
466
467private:
468 // Get the supported declaration from a given typeLoc. If the declaration type
469 // is not supported, returns nullptr.
470 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
471 if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>())
472 return TT->getDecl();
473 if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
474 return RD;
475 if (const auto *ED =
476 llvm::dyn_cast_or_null<EnumDecl>(Val: Loc.getType()->getAsTagDecl()))
477 return ED;
478 return nullptr;
479 }
480
481 // Get the closest ancester which is a declaration of a given AST node.
482 template <typename ASTNodeType>
483 const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
484 auto Parents = Context.getParents(Node);
485 // FIXME: figure out how to handle it when there are multiple parents.
486 if (Parents.size() != 1)
487 return nullptr;
488 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind()))
489 return Parents[0].template get<Decl>();
490 return getClosestAncestorDecl(Parents[0]);
491 }
492
493 // Get the parent typeLoc of a given typeLoc. If there is no such parent,
494 // return nullptr.
495 const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
496 auto Parents = Context.getParents(Node: Loc);
497 // FIXME: figure out how to handle it when there are multiple parents.
498 if (Parents.size() != 1)
499 return nullptr;
500 return Parents[0].get<TypeLoc>();
501 }
502
503 // Check whether the USR of a given Decl is in the USRSet.
504 bool isInUSRSet(const Decl *Decl) const {
505 auto USR = getUSRForDecl(Decl);
506 if (USR.empty())
507 return false;
508 return llvm::is_contained(Range: USRSet, Element: USR);
509 }
510
511 const std::set<std::string> USRSet;
512 ASTContext &Context;
513 std::vector<RenameInfo> RenameInfos;
514 // Record all interested using declarations which contains the using-shadow
515 // declarations of the symbol declarations being renamed.
516 std::vector<const UsingDecl *> UsingDecls;
517};
518
519} // namespace
520
521SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs,
522 StringRef PrevName, Decl *Decl) {
523 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
524 Visitor.TraverseDecl(D: Decl);
525 return Visitor.takeOccurrences();
526}
527
528std::vector<tooling::AtomicChange>
529createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
530 llvm::StringRef NewName, Decl *TranslationUnitDecl) {
531 RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
532 Finder.TraverseDecl(D: TranslationUnitDecl);
533
534 const SourceManager &SM =
535 TranslationUnitDecl->getASTContext().getSourceManager();
536
537 std::vector<tooling::AtomicChange> AtomicChanges;
538 auto Replace = [&](SourceLocation Start, SourceLocation End,
539 llvm::StringRef Text) {
540 tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
541 llvm::Error Err = ReplaceChange.replace(
542 SM, Range: CharSourceRange::getTokenRange(B: Start, E: End), ReplacementText: Text);
543 if (Err) {
544 llvm::errs() << "Failed to add replacement to AtomicChange: "
545 << llvm::toString(E: std::move(Err)) << "\n";
546 return;
547 }
548 AtomicChanges.push_back(x: std::move(ReplaceChange));
549 };
550
551 for (const auto &RenameInfo : Finder.getRenameInfos()) {
552 std::string ReplacedName = NewName.str();
553 if (RenameInfo.IgnorePrefixQualifers) {
554 // Get the name without prefix qualifiers from NewName.
555 size_t LastColonPos = NewName.find_last_of(C: ':');
556 if (LastColonPos != std::string::npos)
557 ReplacedName = std::string(NewName.substr(Start: LastColonPos + 1));
558 } else {
559 if (RenameInfo.FromDecl && RenameInfo.Context) {
560 if (!llvm::isa<clang::TranslationUnitDecl>(
561 Val: RenameInfo.Context->getDeclContext())) {
562 ReplacedName = tooling::replaceNestedName(
563 Use: RenameInfo.Specifier, UseLoc: RenameInfo.Begin,
564 UseContext: RenameInfo.Context->getDeclContext(), FromDecl: RenameInfo.FromDecl,
565 ReplacementString: NewName.starts_with(Prefix: "::") ? NewName.str()
566 : ("::" + NewName).str());
567 } else {
568 // This fixes the case where type `T` is a parameter inside a function
569 // type (e.g. `std::function<void(T)>`) and the DeclContext of `T`
570 // becomes the translation unit. As a workaround, we simply use
571 // fully-qualified name here for all references whose `DeclContext` is
572 // the translation unit and ignore the possible existence of
573 // using-decls (in the global scope) that can shorten the replaced
574 // name.
575 llvm::StringRef ActualName = Lexer::getSourceText(
576 Range: CharSourceRange::getTokenRange(
577 R: SourceRange(RenameInfo.Begin, RenameInfo.End)),
578 SM, LangOpts: TranslationUnitDecl->getASTContext().getLangOpts());
579 // Add the leading "::" back if the name written in the code contains
580 // it.
581 if (ActualName.starts_with(Prefix: "::") && !NewName.starts_with(Prefix: "::")) {
582 ReplacedName = "::" + NewName.str();
583 }
584 }
585 }
586 // If the NewName contains leading "::", add it back.
587 if (NewName.starts_with(Prefix: "::") && NewName.substr(Start: 2) == ReplacedName)
588 ReplacedName = NewName.str();
589 }
590 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
591 }
592
593 // Hanlde using declarations explicitly as "using a::Foo" don't trigger
594 // typeLoc for "a::Foo".
595 for (const auto *Using : Finder.getUsingDecls())
596 Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str());
597
598 return AtomicChanges;
599}
600
601} // end namespace tooling
602} // end namespace clang
603

source code of clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp