1 //===--- USRLocFinder.cpp - Clang refactoring library ---------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Methods for finding all instances of a USR. Our strategy is very
12 /// simple; we just compare the USR at every relevant AST node with the one
13 /// provided.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
18 #include "clang/AST/ASTContext.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/Core/Lookup.h"
25 #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.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 // \brief This visitor recursively searches for all instances of a USR in a
42 // translation unit and stores them for later usage.
43 class USRLocFindingASTVisitor
44     : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
45 public:
46   explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs,
47                                    StringRef PrevName,
48                                    const ASTContext &Context)
49       : RecursiveSymbolVisitor(Context.getSourceManager(),
50                                Context.getLangOpts()),
51         USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
52   }
53 
54   bool visitSymbolOccurrence(const NamedDecl *ND,
55                              ArrayRef<SourceRange> NameRanges) {
56     if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) {
57       assert(NameRanges.size() == 1 &&
58              "Multiple name pieces are not supported yet!");
59       SourceLocation Loc = NameRanges[0].getBegin();
60       const SourceManager &SM = Context.getSourceManager();
61       // TODO: Deal with macro occurrences correctly.
62       if (Loc.isMacroID())
63         Loc = SM.getSpellingLoc(Loc);
64       checkAndAddLocation(Loc);
65     }
66     return true;
67   }
68 
69   // Non-visitors:
70 
71   // \brief Returns a list of unique locations. Duplicate or overlapping
72   // locations are erroneous and should be reported!
73   const std::vector<clang::SourceLocation> &getLocationsFound() const {
74     return LocationsFound;
75   }
76 
77 private:
78   void checkAndAddLocation(SourceLocation Loc) {
79     const SourceLocation BeginLoc = Loc;
80     const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
81         BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
82     StringRef TokenName =
83         Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
84                              Context.getSourceManager(), Context.getLangOpts());
85     size_t Offset = TokenName.find(PrevName);
86 
87     // The token of the source location we find actually has the old
88     // name.
89     if (Offset != StringRef::npos)
90       LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset));
91   }
92 
93   const std::set<std::string> USRSet;
94   const std::string PrevName;
95   std::vector<clang::SourceLocation> LocationsFound;
96   const ASTContext &Context;
97 };
98 
99 SourceLocation StartLocationForType(TypeLoc TL) {
100   // For elaborated types (e.g. `struct a::A`) we want the portion after the
101   // `struct` but including the namespace qualifier, `a::`.
102   if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) {
103     NestedNameSpecifierLoc NestedNameSpecifier =
104         ElaboratedTypeLoc.getQualifierLoc();
105     if (NestedNameSpecifier.getNestedNameSpecifier())
106       return NestedNameSpecifier.getBeginLoc();
107     TL = TL.getNextTypeLoc();
108   }
109   return TL.getLocStart();
110 }
111 
112 SourceLocation EndLocationForType(TypeLoc TL) {
113   // Dig past any namespace or keyword qualifications.
114   while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
115          TL.getTypeLocClass() == TypeLoc::Qualified)
116     TL = TL.getNextTypeLoc();
117 
118   // The location for template specializations (e.g. Foo<int>) includes the
119   // templated types in its location range.  We want to restrict this to just
120   // before the `<` character.
121   if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
122     return TL.castAs<TemplateSpecializationTypeLoc>()
123         .getLAngleLoc()
124         .getLocWithOffset(-1);
125   }
126   return TL.getEndLoc();
127 }
128 
129 NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
130   // Dig past any keyword qualifications.
131   while (TL.getTypeLocClass() == TypeLoc::Qualified)
132     TL = TL.getNextTypeLoc();
133 
134   // For elaborated types (e.g. `struct a::A`) we want the portion after the
135   // `struct` but including the namespace qualifier, `a::`.
136   if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>())
137     return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
138   return nullptr;
139 }
140 
141 // Find all locations identified by the given USRs for rename.
142 //
143 // This class will traverse the AST and find every AST node whose USR is in the
144 // given USRs' set.
145 class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
146 public:
147   RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
148       : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
149 
150   // A structure records all information of a symbol reference being renamed.
151   // We try to add as few prefix qualifiers as possible.
152   struct RenameInfo {
153     // The begin location of a symbol being renamed.
154     SourceLocation Begin;
155     // The end location of a symbol being renamed.
156     SourceLocation End;
157     // The declaration of a symbol being renamed (can be nullptr).
158     const NamedDecl *FromDecl;
159     // The declaration in which the nested name is contained (can be nullptr).
160     const Decl *Context;
161     // The nested name being replaced (can be nullptr).
162     const NestedNameSpecifier *Specifier;
163   };
164 
165   // FIXME: Currently, prefix qualifiers will be added to the renamed symbol
166   // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming
167   // "a::Foo" to "b::Bar").
168   // For renaming declarations/definitions, prefix qualifiers should be filtered
169   // out.
170   bool VisitNamedDecl(const NamedDecl *Decl) {
171     // UsingDecl has been handled in other place.
172     if (llvm::isa<UsingDecl>(Decl))
173       return true;
174 
175     // DestructorDecl has been handled in Typeloc.
176     if (llvm::isa<CXXDestructorDecl>(Decl))
177       return true;
178 
179     if (Decl->isImplicit())
180       return true;
181 
182     if (isInUSRSet(Decl)) {
183       RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr,
184                          nullptr, nullptr};
185       RenameInfos.push_back(Info);
186     }
187     return true;
188   }
189 
190   bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
191     const NamedDecl *Decl = Expr->getFoundDecl();
192     if (isInUSRSet(Decl)) {
193       RenameInfo Info = {Expr->getSourceRange().getBegin(),
194                          Expr->getSourceRange().getEnd(), Decl,
195                          getClosestAncestorDecl(*Expr), Expr->getQualifier()};
196       RenameInfos.push_back(Info);
197     }
198 
199     return true;
200   }
201 
202   bool VisitUsingDecl(const UsingDecl *Using) {
203     for (const auto *UsingShadow : Using->shadows()) {
204       if (isInUSRSet(UsingShadow->getTargetDecl())) {
205         UsingDecls.push_back(Using);
206         break;
207       }
208     }
209     return true;
210   }
211 
212   bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
213     if (!NestedLoc.getNestedNameSpecifier()->getAsType())
214       return true;
215     if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc()))
216       return true;
217 
218     if (const auto *TargetDecl =
219             getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
220       if (isInUSRSet(TargetDecl)) {
221         RenameInfo Info = {NestedLoc.getBeginLoc(),
222                            EndLocationForType(NestedLoc.getTypeLoc()),
223                            TargetDecl, getClosestAncestorDecl(NestedLoc),
224                            NestedLoc.getNestedNameSpecifier()->getPrefix()};
225         RenameInfos.push_back(Info);
226       }
227     }
228     return true;
229   }
230 
231   bool VisitTypeLoc(TypeLoc Loc) {
232     if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc))
233       return true;
234 
235     auto Parents = Context.getParents(Loc);
236     TypeLoc ParentTypeLoc;
237     if (!Parents.empty()) {
238       // Handle cases of nested name specificier locations.
239       //
240       // The VisitNestedNameSpecifierLoc interface is not impelmented in
241       // RecursiveASTVisitor, we have to handle it explicitly.
242       if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
243         VisitNestedNameSpecifierLocations(*NSL);
244         return true;
245       }
246 
247       if (const auto *TL = Parents[0].get<TypeLoc>())
248         ParentTypeLoc = *TL;
249     }
250 
251     // Handle the outermost TypeLoc which is directly linked to the interesting
252     // declaration and don't handle nested name specifier locations.
253     if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
254       if (isInUSRSet(TargetDecl)) {
255         // Only handle the outermost typeLoc.
256         //
257         // For a type like "a::Foo", there will be two typeLocs for it.
258         // One ElaboratedType, the other is RecordType:
259         //
260         //   ElaboratedType 0x33b9390 'a::Foo' sugar
261         //   `-RecordType 0x338fef0 'class a::Foo'
262         //     `-CXXRecord 0x338fe58 'Foo'
263         //
264         // Skip if this is an inner typeLoc.
265         if (!ParentTypeLoc.isNull() &&
266             isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
267           return true;
268         RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc),
269                            TargetDecl, getClosestAncestorDecl(Loc),
270                            GetNestedNameForType(Loc)};
271         RenameInfos.push_back(Info);
272         return true;
273       }
274     }
275 
276     // Handle specific template class specialiation cases.
277     if (const auto *TemplateSpecType =
278             dyn_cast<TemplateSpecializationType>(Loc.getType())) {
279       TypeLoc TargetLoc = Loc;
280       if (!ParentTypeLoc.isNull()) {
281         if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
282           TargetLoc = ParentTypeLoc;
283       }
284 
285       if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
286         TypeLoc TargetLoc = Loc;
287         // FIXME: Find a better way to handle this case.
288         // For the qualified template class specification type like
289         // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc
290         // (ElaboratedType) of the TemplateSpecializationType in order to
291         // catch the prefix qualifiers "ns::".
292         if (!ParentTypeLoc.isNull() &&
293             llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
294           TargetLoc = ParentTypeLoc;
295         RenameInfo Info = {
296             StartLocationForType(TargetLoc), EndLocationForType(TargetLoc),
297             TemplateSpecType->getTemplateName().getAsTemplateDecl(),
298             getClosestAncestorDecl(
299                 ast_type_traits::DynTypedNode::create(TargetLoc)),
300             GetNestedNameForType(TargetLoc)};
301         RenameInfos.push_back(Info);
302       }
303     }
304     return true;
305   }
306 
307   // Returns a list of RenameInfo.
308   const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
309 
310   // Returns a list of using declarations which are needed to update.
311   const std::vector<const UsingDecl *> &getUsingDecls() const {
312     return UsingDecls;
313   }
314 
315 private:
316   // FIXME: This method may not be suitable for renaming other types like alias
317   // types. Need to figure out a way to handle it.
318   bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const {
319     while (!TL.isNull()) {
320       // SubstTemplateTypeParm is the TypeLocation class for a substituted type
321       // inside a template expansion so we ignore these.  For example:
322       //
323       // template<typename T> struct S {
324       //   T t;  // <-- this T becomes a TypeLoc(int) with class
325       //         //     SubstTemplateTypeParm when S<int> is instantiated
326       // }
327       if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
328         return true;
329 
330       // Typedef is the TypeLocation class for a type which is a typedef to the
331       // type we want to replace.  We ignore the use of the typedef as we will
332       // replace the definition of it.  For example:
333       //
334       // typedef int T;
335       // T a;  // <---  This T is a TypeLoc(int) with class Typedef.
336       if (TL.getTypeLocClass() == TypeLoc::Typedef)
337         return true;
338       TL = TL.getNextTypeLoc();
339     }
340     return false;
341   }
342 
343   // Get the supported declaration from a given typeLoc. If the declaration type
344   // is not supported, returns nullptr.
345   //
346   // FIXME: support more types, e.g. enum, type alias.
347   const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
348     if (const auto *RD = Loc.getType()->getAsCXXRecordDecl())
349       return RD;
350     return nullptr;
351   }
352 
353   // Get the closest ancester which is a declaration of a given AST node.
354   template <typename ASTNodeType>
355   const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
356     auto Parents = Context.getParents(Node);
357     // FIXME: figure out how to handle it when there are multiple parents.
358     if (Parents.size() != 1)
359       return nullptr;
360     if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
361             Parents[0].getNodeKind()))
362       return Parents[0].template get<Decl>();
363     return getClosestAncestorDecl(Parents[0]);
364   }
365 
366   // Get the parent typeLoc of a given typeLoc. If there is no such parent,
367   // return nullptr.
368   const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
369     auto Parents = Context.getParents(Loc);
370     // FIXME: figure out how to handle it when there are multiple parents.
371     if (Parents.size() != 1)
372       return nullptr;
373     return Parents[0].get<TypeLoc>();
374   }
375 
376   // Check whether the USR of a given Decl is in the USRSet.
377   bool isInUSRSet(const Decl *Decl) const {
378     auto USR = getUSRForDecl(Decl);
379     if (USR.empty())
380       return false;
381     return llvm::is_contained(USRSet, USR);
382   }
383 
384   const std::set<std::string> USRSet;
385   ASTContext &Context;
386   std::vector<RenameInfo> RenameInfos;
387   // Record all interested using declarations which contains the using-shadow
388   // declarations of the symbol declarations being renamed.
389   std::vector<const UsingDecl *> UsingDecls;
390 };
391 
392 } // namespace
393 
394 std::vector<SourceLocation>
395 getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName,
396                    Decl *Decl) {
397   USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
398   Visitor.TraverseDecl(Decl);
399   return Visitor.getLocationsFound();
400 }
401 
402 std::vector<tooling::AtomicChange>
403 createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs,
404                           llvm::StringRef NewName, Decl *TranslationUnitDecl) {
405   RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
406   Finder.TraverseDecl(TranslationUnitDecl);
407 
408   const SourceManager &SM =
409       TranslationUnitDecl->getASTContext().getSourceManager();
410 
411   std::vector<tooling::AtomicChange> AtomicChanges;
412   auto Replace = [&](SourceLocation Start, SourceLocation End,
413                      llvm::StringRef Text) {
414     tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
415     llvm::Error Err = ReplaceChange.replace(
416         SM, CharSourceRange::getTokenRange(Start, End), Text);
417     if (Err) {
418       llvm::errs() << "Faile to add replacement to AtomicChange: "
419                    << llvm::toString(std::move(Err)) << "\n";
420       return;
421     }
422     AtomicChanges.push_back(std::move(ReplaceChange));
423   };
424 
425   for (const auto &RenameInfo : Finder.getRenameInfos()) {
426     std::string ReplacedName = NewName.str();
427     if (RenameInfo.FromDecl && RenameInfo.Context) {
428       if (!llvm::isa<clang::TranslationUnitDecl>(
429               RenameInfo.Context->getDeclContext())) {
430         ReplacedName = tooling::replaceNestedName(
431             RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
432             RenameInfo.FromDecl,
433             NewName.startswith("::") ? NewName.str() : ("::" + NewName).str());
434       }
435     }
436     // If the NewName contains leading "::", add it back.
437     if (NewName.startswith("::") && NewName.substr(2) == ReplacedName)
438       ReplacedName = NewName.str();
439     Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
440   }
441 
442   // Hanlde using declarations explicitly as "using a::Foo" don't trigger
443   // typeLoc for "a::Foo".
444   for (const auto *Using : Finder.getUsingDecls())
445     Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str());
446 
447   return AtomicChanges;
448 }
449 
450 } // end namespace tooling
451 } // end namespace clang
452