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