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(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(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        BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
92    StringRef TokenName =
93        Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
94                             Context.getSourceManager(), Context.getLangOpts());
95    size_t Offset = TokenName.find(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(PrevName, SymbolOccurrence::MatchingSymbol,
101                               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(-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>(Decl))
185      return true;
186
187    // DestructorDecl has been handled in Typeloc.
188    if (llvm::isa<CXXDestructorDecl>(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>(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(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({StartLoc, EndLoc,
221                            /*FromDecl=*/nullptr,
222                            /*Context=*/nullptr,
223                            /*Specifier=*/nullptr,
224                            /*IgnorePrefixQualifiers=*/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() && D.getField()) {
232        const FieldDecl *Decl = D.getField();
233        if (isInUSRSet(Decl)) {
234          auto StartLoc = D.getFieldLoc();
235          auto EndLoc = D.getFieldLoc();
236          RenameInfos.push_back({StartLoc, EndLoc,
237                                 /*FromDecl=*/nullptr,
238                                 /*Context=*/nullptr,
239                                 /*Specifier=*/nullptr,
240                                 /*IgnorePrefixQualifiers=*/true});
241        }
242      }
243    }
244    return true;
245  }
246
247  bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
248    // Fix the constructor initializer when renaming class members.
249    for (const auto *Initializer : CD->inits()) {
250      // Ignore implicit initializers.
251      if (!Initializer->isWritten())
252        continue;
253
254      if (const FieldDecl *FD = Initializer->getMember()) {
255        if (isInUSRSet(FD)) {
256          auto Loc = Initializer->getSourceLocation();
257          RenameInfos.push_back({Loc, Loc,
258                                 /*FromDecl=*/nullptr,
259                                 /*Context=*/nullptr,
260                                 /*Specifier=*/nullptr,
261                                 /*IgnorePrefixQualifiers=*/true});
262        }
263      }
264    }
265    return true;
266  }
267
268  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
269    const NamedDecl *Decl = Expr->getFoundDecl();
270    // Get the underlying declaration of the shadow declaration introduced by a
271    // using declaration.
272    if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
273      Decl = UsingShadow->getTargetDecl();
274    }
275
276    auto StartLoc = Expr->getBeginLoc();
277    // For template function call expressions like `foo<int>()`, we want to
278    // restrict the end of location to just before the `<` character.
279    SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
280                                ? Expr->getLAngleLoc().getLocWithOffset(-1)
281                                : Expr->getEndLoc();
282
283    if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
284      if (isInUSRSet(MD)) {
285        // Handle renaming static template class methods, we only rename the
286        // name without prefix qualifiers and restrict the source range to the
287        // name.
288        RenameInfos.push_back({EndLoc, EndLoc,
289                               /*FromDecl=*/nullptr,
290                               /*Context=*/nullptr,
291                               /*Specifier=*/nullptr,
292                               /*IgnorePrefixQualifiers=*/true});
293        return true;
294      }
295    }
296
297    // In case of renaming an enum declaration, we have to explicitly handle
298    // unscoped enum constants referenced in expressions (e.g.
299    // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped
300    // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by
301    // TypeLoc.
302    if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
303      // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`)
304      // when renaming an unscoped enum declaration with a new namespace.
305      if (!Expr->hasQualifier())
306        return true;
307
308      if (const auto *ED =
309              llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
310        if (ED->isScoped())
311          return true;
312        Decl = ED;
313      }
314      // The current fix would qualify "ns1::ns2::Green" as
315      // "ns1::ns2::Color::Green".
316      //
317      // Get the EndLoc of the replacement by moving 1 character backward (
318      // to exclude the last '::').
319      //
320      //    ns1::ns2::Green;
321      //    ^      ^^
322      // BeginLoc  |EndLoc of the qualifier
323      //           new EndLoc
324      EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
325      assert(EndLoc.isValid() &&
326             "The enum constant should have prefix qualifers.");
327    }
328    if (isInUSRSet(Decl) &&
329        IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
330      RenameInfo Info = {StartLoc,
331                         EndLoc,
332                         Decl,
333                         getClosestAncestorDecl(*Expr),
334                         Expr->getQualifier(),
335                         /*IgnorePrefixQualifers=*/false};
336      RenameInfos.push_back(Info);
337    }
338
339    return true;
340  }
341
342  bool VisitUsingDecl(const UsingDecl *Using) {
343    for (const auto *UsingShadow : Using->shadows()) {
344      if (isInUSRSet(UsingShadow->getTargetDecl())) {
345        UsingDecls.push_back(Using);
346        break;
347      }
348    }
349    return true;
350  }
351
352  bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
353    if (!NestedLoc.getNestedNameSpecifier()->getAsType())
354      return true;
355
356    if (const auto *TargetDecl =
357            getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
358      if (isInUSRSet(TargetDecl)) {
359        RenameInfo Info = {NestedLoc.getBeginLoc(),
360                           EndLocationForType(NestedLoc.getTypeLoc()),
361                           TargetDecl,
362                           getClosestAncestorDecl(NestedLoc),
363                           NestedLoc.getNestedNameSpecifier()->getPrefix(),
364                           /*IgnorePrefixQualifers=*/false};
365        RenameInfos.push_back(Info);
366      }
367    }
368    return true;
369  }
370
371  bool VisitTypeLoc(TypeLoc Loc) {
372    auto Parents = Context.getParents(Loc);
373    TypeLoc ParentTypeLoc;
374    if (!Parents.empty()) {
375      // Handle cases of nested name specificier locations.
376      //
377      // The VisitNestedNameSpecifierLoc interface is not impelmented in
378      // RecursiveASTVisitor, we have to handle it explicitly.
379      if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
380        VisitNestedNameSpecifierLocations(*NSL);
381        return true;
382      }
383
384      if (const auto *TL = Parents[0].get<TypeLoc>())
385        ParentTypeLoc = *TL;
386    }
387
388    // Handle the outermost TypeLoc which is directly linked to the interesting
389    // declaration and don't handle nested name specifier locations.
390    if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
391      if (isInUSRSet(TargetDecl)) {
392        // Only handle the outermost typeLoc.
393        //
394        // For a type like "a::Foo", there will be two typeLocs for it.
395        // One ElaboratedType, the other is RecordType:
396        //
397        //   ElaboratedType 0x33b9390 'a::Foo' sugar
398        //   `-RecordType 0x338fef0 'class a::Foo'
399        //     `-CXXRecord 0x338fe58 'Foo'
400        //
401        // Skip if this is an inner typeLoc.
402        if (!ParentTypeLoc.isNull() &&
403            isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
404          return true;
405
406        auto StartLoc = StartLocationForType(Loc);
407        auto EndLoc = EndLocationForType(Loc);
408        if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
409          RenameInfo Info = {StartLoc,
410                             EndLoc,
411                             TargetDecl,
412                             getClosestAncestorDecl(Loc),
413                             GetNestedNameForType(Loc),
414                             /*IgnorePrefixQualifers=*/false};
415          RenameInfos.push_back(Info);
416        }
417        return true;
418      }
419    }
420
421    // Handle specific template class specialiation cases.
422    if (const auto *TemplateSpecType =
423            dyn_cast<TemplateSpecializationType>(Loc.getType())) {
424      TypeLoc TargetLoc = Loc;
425      if (!ParentTypeLoc.isNull()) {
426        if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
427          TargetLoc = ParentTypeLoc;
428      }
429
430      if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
431        TypeLoc TargetLoc = Loc;
432        // FIXME: Find a better way to handle this case.
433        // For the qualified template class specification type like
434        // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
435        // (ElaboratedType) of the TemplateSpecializationType in order to
436        // catch the prefix qualifiers "ns::".
437        if (!ParentTypeLoc.isNull() &&
438            llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
439          TargetLoc = ParentTypeLoc;
440
441        auto StartLoc = StartLocationForType(TargetLoc);
442        auto EndLoc = EndLocationForType(TargetLoc);
443        if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
444          RenameInfo Info = {
445              StartLoc,
446              EndLoc,
447              TemplateSpecType->getTemplateName().getAsTemplateDecl(),
448              getClosestAncestorDecl(DynTypedNode::create(TargetLoc)),
449              GetNestedNameForType(TargetLoc),
450              /*IgnorePrefixQualifers=*/false};
451          RenameInfos.push_back(Info);
452        }
453      }
454    }
455    return true;
456  }
457
458  // Returns a list of RenameInfo.
459  const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
460
461  // Returns a list of using declarations which are needed to update.
462  const std::vector<const UsingDecl *> &getUsingDecls() const {
463    return UsingDecls;
464  }
465
466private:
467  // Get the supported declaration from a given typeLoc. If the declaration type
468  // is not supported, returns nullptr.
469  const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
470    if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>())
471      return TT->getDecl();
472    if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
473      return RD;
474    if (const auto *ED =
475            llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl()))
476      return ED;
477    return nullptr;
478  }
479
480  // Get the closest ancester which is a declaration of a given AST node.
481  template <typename ASTNodeType>
482  const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
483    auto Parents = Context.getParents(Node);
484    // FIXME: figure out how to handle it when there are multiple parents.
485    if (Parents.size() != 1)
486      return nullptr;
487    if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind()))
488      return Parents[0].template get<Decl>();
489    return getClosestAncestorDecl(Parents[0]);
490  }
491
492  // Get the parent typeLoc of a given typeLoc. If there is no such parent,
493  // return nullptr.
494  const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
495    auto Parents = Context.getParents(Loc);
496    // FIXME: figure out how to handle it when there are multiple parents.
497    if (Parents.size() != 1)
498      return nullptr;
499    return Parents[0].get<TypeLoc>();
500  }
501
502  // Check whether the USR of a given Decl is in the USRSet.
503  bool isInUSRSet(const Decl *Decl) const {
504    auto USR = getUSRForDecl(Decl);
505    if (USR.empty())
506      return false;
507    return llvm::is_contained(USRSet, USR);
508  }
509
510  const std::set<std::string> USRSet;
511  ASTContext &Context;
512  std::vector<RenameInfo> RenameInfos;
513  // Record all interested using declarations which contains the using-shadow
514  // declarations of the symbol declarations being renamed.
515  std::vector<const UsingDecl *> UsingDecls;
516};
517
518} // namespace
519
520SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs,
521                                       StringRef PrevName, Decl *Decl) {
522  USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
523  Visitor.TraverseDecl(Decl);
524  return Visitor.takeOccurrences();
525}
526
527std::vector<tooling::AtomicChange>
528createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
529                          llvm::StringRef NewName, Decl *TranslationUnitDecl) {
530  RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
531  Finder.TraverseDecl(TranslationUnitDecl);
532
533  const SourceManager &SM =
534      TranslationUnitDecl->getASTContext().getSourceManager();
535
536  std::vector<tooling::AtomicChange> AtomicChanges;
537  auto Replace = [&](SourceLocation Start, SourceLocation End,
538                     llvm::StringRef Text) {
539    tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
540    llvm::Error Err = ReplaceChange.replace(
541        SM, CharSourceRange::getTokenRange(Start, End), Text);
542    if (Err) {
543      llvm::errs() << "Failed to add replacement to AtomicChange: "
544                   << llvm::toString(std::move(Err)) << "\n";
545      return;
546    }
547    AtomicChanges.push_back(std::move(ReplaceChange));
548  };
549
550  for (const auto &RenameInfo : Finder.getRenameInfos()) {
551    std::string ReplacedName = NewName.str();
552    if (RenameInfo.IgnorePrefixQualifers) {
553      // Get the name without prefix qualifiers from NewName.
554      size_t LastColonPos = NewName.find_last_of(':');
555      if (LastColonPos != std::string::npos)
556        ReplacedName = std::string(NewName.substr(LastColonPos + 1));
557    } else {
558      if (RenameInfo.FromDecl && RenameInfo.Context) {
559        if (!llvm::isa<clang::TranslationUnitDecl>(
560                RenameInfo.Context->getDeclContext())) {
561          ReplacedName = tooling::replaceNestedName(
562              RenameInfo.Specifier, RenameInfo.Begin,
563              RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
564              NewName.startswith("::") ? NewName.str()
565                                       : ("::" + NewName).str());
566        } else {
567          // This fixes the case where type `T` is a parameter inside a function
568          // type (e.g. `std::function<void(T)>`) and the DeclContext of `T`
569          // becomes the translation unit. As a workaround, we simply use
570          // fully-qualified name here for all references whose `DeclContext` is
571          // the translation unit and ignore the possible existence of
572          // using-decls (in the global scope) that can shorten the replaced
573          // name.
574          llvm::StringRef ActualName = Lexer::getSourceText(
575              CharSourceRange::getTokenRange(
576                  SourceRange(RenameInfo.Begin, RenameInfo.End)),
577              SM, TranslationUnitDecl->getASTContext().getLangOpts());
578          // Add the leading "::" back if the name written in the code contains
579          // it.
580          if (ActualName.startswith("::") && !NewName.startswith("::")) {
581            ReplacedName = "::" + NewName.str();
582          }
583        }
584      }
585      // If the NewName contains leading "::", add it back.
586      if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
587        ReplacedName = NewName.str();
588    }
589    Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
590  }
591
592  // Hanlde using declarations explicitly as "using a::Foo" don't trigger
593  // typeLoc for "a::Foo".
594  for (const auto *Using : Finder.getUsingDecls())
595    Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str());
596
597  return AtomicChanges;
598}
599
600} // end namespace tooling
601} // end namespace clang
602