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