clang  10.0.0svn
USRLocFinder.cpp
Go to the documentation of this file.
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 
17 #include "clang/AST/ASTContext.h"
19 #include "clang/Basic/LLVM.h"
22 #include "clang/Lex/Lexer.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".
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(
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 
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>
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
std::vector< tooling::AtomicChange > createRenameAtomicChanges(llvm::ArrayRef< std::string > USRs, llvm::StringRef NewName, Decl *TranslationUnitDecl)
Create atomic changes for renaming all symbol references which are identified by the USRs set to a gi...
Defines the clang::ASTContext interface.
llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range, llvm::StringRef ReplacementText)
Adds a replacement that replaces the given Range with ReplacementText.
bool IgnorePrefixQualifers
std::string replaceNestedName(const NestedNameSpecifier *Use, SourceLocation UseLoc, const DeclContext *UseContext, const NamedDecl *FromDecl, StringRef ReplacementString)
Emulate a lookup to replace one nested name specifier with another using as few additional namespace ...
Definition: Lookup.cpp:183
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
Definition: Dominators.h:30
std::vector< AtomicChange > AtomicChanges
Definition: AtomicChange.h:140
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
const NestedNameSpecifier * Specifier
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol...
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Methods for determining the USR of a symbol at a location in source code.
unsigned Offset
Definition: Format.cpp:1758
Provides functionality for finding all instances of a USR in a given AST.
SourceLocation End
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
SourceLocation Begin
const SourceManager & SM
Definition: Format.cpp:1616
const NamedDecl * FromDecl
Encodes a location in the source.
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:134
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:377
ast_type_traits::DynTypedNode Node
Dataflow Directional Tag Classes.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
SourceManager & getSourceManager()
Definition: ASTContext.h:675
std::vector< SymbolOccurrence > SymbolOccurrences
Defines the clang::SourceLocation class and associated facilities.
SymbolOccurrences getOccurrencesOfUSRs(ArrayRef< std::string > USRs, StringRef PrevName, Decl *Decl)
Finds the symbol occurrences for the symbol that&#39;s identified by the given USR set.
A SourceLocation and its associated SourceManager.
The top declaration context.
Definition: Decl.h:107
An atomic change is used to create and group a set of source edits, e.g.
Definition: AtomicChange.h:36
StringRef Text
Definition: Format.cpp:1757
A trivial tuple used to represent a source range.
const LangOptions & getLangOpts() const
Definition: ASTContext.h:720
This class handles loading and caching of source files into memory.