clang 22.0.0git
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
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
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 auto FileIdAndOffset = 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.
54class USRLocFindingASTVisitor
55 : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
56public:
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
86private:
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 =
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
109SourceLocation StartLocationForType(TypeLoc TL) {
110 if (auto QTL = TL.getAs<QualifiedTypeLoc>())
111 TL = QTL.getUnqualifiedLoc();
112
113 // For elaborated types (e.g. `struct a::A`) we want the portion after the
114 // `struct`, including the namespace qualifier, `a::`.
115 switch (TL.getTypeLocClass()) {
116 case TypeLoc::Record:
117 case TypeLoc::InjectedClassName:
118 case TypeLoc::Enum: {
119 auto TTL = TL.castAs<TagTypeLoc>();
120 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
121 return QualifierLoc.getBeginLoc();
122 return TTL.getNameLoc();
123 }
124 case TypeLoc::Typedef: {
125 auto TTL = TL.castAs<TypedefTypeLoc>();
126 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
127 return QualifierLoc.getBeginLoc();
128 return TTL.getNameLoc();
129 }
130 case TypeLoc::UnresolvedUsing: {
131 auto TTL = TL.castAs<UnresolvedUsingTypeLoc>();
132 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
133 return QualifierLoc.getBeginLoc();
134 return TTL.getNameLoc();
135 }
136 case TypeLoc::Using: {
137 auto TTL = TL.castAs<UsingTypeLoc>();
138 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
139 return QualifierLoc.getBeginLoc();
140 return TTL.getNameLoc();
141 }
142 case TypeLoc::TemplateSpecialization: {
143 auto TTL = TL.castAs<TemplateSpecializationTypeLoc>();
144 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
145 return QualifierLoc.getBeginLoc();
146 return TTL.getTemplateNameLoc();
147 }
148 case TypeLoc::DeducedTemplateSpecialization: {
149 auto DTL = TL.castAs<clang::DeducedTemplateSpecializationTypeLoc>();
150 if (NestedNameSpecifierLoc QualifierLoc = DTL.getQualifierLoc())
151 return QualifierLoc.getBeginLoc();
152 return DTL.getTemplateNameLoc();
153 }
154 case TypeLoc::DependentName: {
155 auto TTL = TL.castAs<DependentNameTypeLoc>();
156 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
157 return QualifierLoc.getBeginLoc();
158 return TTL.getNameLoc();
159 }
160 case TypeLoc::DependentTemplateSpecialization: {
161 auto TTL = TL.castAs<DependentTemplateSpecializationTypeLoc>();
162 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
163 return QualifierLoc.getBeginLoc();
164 return TTL.getTemplateNameLoc();
165 }
166 default:
167 llvm_unreachable("unhandled TypeLoc class");
168 }
169}
170
171SourceLocation EndLocationForType(TypeLoc TL) {
172 if (auto QTL = TL.getAs<QualifiedTypeLoc>())
173 TL = QTL.getUnqualifiedLoc();
174
175 // The location for template specializations (e.g. Foo<int>) includes the
176 // templated types in its location range. We want to restrict this to just
177 // before the `<` character.
178 if (auto TTL = TL.getAs<TemplateSpecializationTypeLoc>())
179 return TTL.getLAngleLoc().getLocWithOffset(-1);
180 return TL.getEndLoc();
181}
182
183NestedNameSpecifier GetNestedNameForType(TypeLoc TL) {
184 if (auto QTL = TL.getAs<QualifiedTypeLoc>())
185 TL = QTL.getUnqualifiedLoc();
186 return TL.getPrefix().getNestedNameSpecifier();
187}
188
189// Find all locations identified by the given USRs for rename.
190//
191// This class will traverse the AST and find every AST node whose USR is in the
192// given USRs' set.
193class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> {
194public:
195 RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context)
196 : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
197
198 // A structure records all information of a symbol reference being renamed.
199 // We try to add as few prefix qualifiers as possible.
200 struct RenameInfo {
201 // The begin location of a symbol being renamed.
202 SourceLocation Begin;
203 // The end location of a symbol being renamed.
204 SourceLocation End;
205 // The declaration of a symbol being renamed (can be nullptr).
206 const NamedDecl *FromDecl;
207 // The declaration in which the nested name is contained (can be nullptr).
208 const Decl *Context;
209 // The nested name being replaced.
210 NestedNameSpecifier Specifier;
211 // Determine whether the prefix qualifiers of the NewName should be ignored.
212 // Normally, we set it to true for the symbol declaration and definition to
213 // avoid adding prefix qualifiers.
214 // For example, if it is true and NewName is "a::b::foo", then the symbol
215 // occurrence which the RenameInfo points to will be renamed to "foo".
217 };
218
219 bool VisitNamedDecl(const NamedDecl *Decl) {
220 // UsingDecl has been handled in other place.
221 if (llvm::isa<UsingDecl>(Decl))
222 return true;
223
224 // DestructorDecl has been handled in Typeloc.
225 if (llvm::isa<CXXDestructorDecl>(Decl))
226 return true;
227
228 if (Decl->isImplicit())
229 return true;
230
231 if (isInUSRSet(Decl)) {
232 // For the case of renaming an alias template, we actually rename the
233 // underlying alias declaration of the template.
234 if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl))
235 Decl = TAT->getTemplatedDecl();
236
237 auto StartLoc = Decl->getLocation();
238 auto EndLoc = StartLoc;
239 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
240 RenameInfo Info = {StartLoc,
241 EndLoc,
242 /*FromDecl=*/nullptr,
243 /*Context=*/nullptr,
244 /*Specifier=*/std::nullopt,
245 /*IgnorePrefixQualifiers=*/true};
246 RenameInfos.push_back(Info);
247 }
248 }
249 return true;
250 }
251
252 bool VisitMemberExpr(const MemberExpr *Expr) {
253 const NamedDecl *Decl = Expr->getFoundDecl();
254 auto StartLoc = Expr->getMemberLoc();
255 auto EndLoc = Expr->getMemberLoc();
256 if (isInUSRSet(Decl)) {
257 RenameInfos.push_back({StartLoc, EndLoc,
258 /*FromDecl=*/nullptr,
259 /*Context=*/nullptr,
260 /*Specifier=*/std::nullopt,
261 /*IgnorePrefixQualifiers=*/true});
262 }
263 return true;
264 }
265
266 bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
267 for (const DesignatedInitExpr::Designator &D : E->designators()) {
268 if (D.isFieldDesignator()) {
269 if (const FieldDecl *Decl = D.getFieldDecl()) {
270 if (isInUSRSet(Decl)) {
271 auto StartLoc = D.getFieldLoc();
272 auto EndLoc = D.getFieldLoc();
273 RenameInfos.push_back({StartLoc, EndLoc,
274 /*FromDecl=*/nullptr,
275 /*Context=*/nullptr,
276 /*Specifier=*/std::nullopt,
277 /*IgnorePrefixQualifiers=*/true});
278 }
279 }
280 }
281 }
282 return true;
283 }
284
285 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {
286 // Fix the constructor initializer when renaming class members.
287 for (const auto *Initializer : CD->inits()) {
288 // Ignore implicit initializers.
289 if (!Initializer->isWritten())
290 continue;
291
292 if (const FieldDecl *FD = Initializer->getMember()) {
293 if (isInUSRSet(FD)) {
294 auto Loc = Initializer->getSourceLocation();
295 RenameInfos.push_back({Loc, Loc,
296 /*FromDecl=*/nullptr,
297 /*Context=*/nullptr,
298 /*Specifier=*/std::nullopt,
299 /*IgnorePrefixQualifiers=*/true});
300 }
301 }
302 }
303 return true;
304 }
305
306 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
307 const NamedDecl *Decl = Expr->getFoundDecl();
308 // Get the underlying declaration of the shadow declaration introduced by a
309 // using declaration.
310 if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
311 Decl = UsingShadow->getTargetDecl();
312 }
313
314 auto StartLoc = Expr->getBeginLoc();
315 // For template function call expressions like `foo<int>()`, we want to
316 // restrict the end of location to just before the `<` character.
317 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
318 ? Expr->getLAngleLoc().getLocWithOffset(-1)
319 : Expr->getEndLoc();
320
321 if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
322 if (isInUSRSet(MD)) {
323 // Handle renaming static template class methods, we only rename the
324 // name without prefix qualifiers and restrict the source range to the
325 // name.
326 RenameInfos.push_back({EndLoc, EndLoc,
327 /*FromDecl=*/nullptr,
328 /*Context=*/nullptr,
329 /*Specifier=*/std::nullopt,
330 /*IgnorePrefixQualifiers=*/true});
331 return true;
332 }
333 }
334
335 // In case of renaming an enum declaration, we have to explicitly handle
336 // unscoped enum constants referenced in expressions (e.g.
337 // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped
338 // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by
339 // TypeLoc.
340 if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
341 // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`)
342 // when renaming an unscoped enum declaration with a new namespace.
343 if (!Expr->hasQualifier())
344 return true;
345
346 if (const auto *ED =
347 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
348 if (ED->isScoped())
349 return true;
350 Decl = ED;
351 }
352 // The current fix would qualify "ns1::ns2::Green" as
353 // "ns1::ns2::Color::Green".
354 //
355 // Get the EndLoc of the replacement by moving 1 character backward (
356 // to exclude the last '::').
357 //
358 // ns1::ns2::Green;
359 // ^ ^^
360 // BeginLoc |EndLoc of the qualifier
361 // new EndLoc
362 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
363 assert(EndLoc.isValid() &&
364 "The enum constant should have prefix qualifers.");
365 }
366 if (isInUSRSet(Decl) &&
367 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
368 RenameInfo Info = {StartLoc,
369 EndLoc,
370 Decl,
371 getClosestAncestorDecl(*Expr),
372 Expr->getQualifier(),
373 /*IgnorePrefixQualifiers=*/false};
374 RenameInfos.push_back(Info);
375 }
376
377 return true;
378 }
379
380 bool VisitUsingDecl(const UsingDecl *Using) {
381 for (const auto *UsingShadow : Using->shadows()) {
382 if (isInUSRSet(UsingShadow->getTargetDecl())) {
383 UsingDecls.push_back(Using);
384 break;
385 }
386 }
387 return true;
388 }
389
390 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
391 TypeLoc TL = NestedLoc.getAsTypeLoc();
392 if (!TL)
393 return true;
394
395 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(TL)) {
396 if (isInUSRSet(TargetDecl)) {
397 RenameInfo Info = {NestedLoc.getBeginLoc(),
398 EndLocationForType(TL),
399 TargetDecl,
400 getClosestAncestorDecl(NestedLoc),
401 /*Specifier=*/std::nullopt,
402 /*IgnorePrefixQualifiers=*/false};
403 RenameInfos.push_back(Info);
404 }
405 }
406 return true;
407 }
408
409 bool VisitTypeLoc(TypeLoc Loc) {
410 auto Parents = Context.getParents(Loc);
411 TypeLoc ParentTypeLoc;
412 if (!Parents.empty()) {
413 // Handle cases of nested name specificier locations.
414 //
415 // The VisitNestedNameSpecifierLoc interface is not impelmented in
416 // RecursiveASTVisitor, we have to handle it explicitly.
417 if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
418 VisitNestedNameSpecifierLocations(*NSL);
419 return true;
420 }
421
422 if (const auto *TL = Parents[0].get<TypeLoc>())
423 ParentTypeLoc = *TL;
424 }
425
426 // Handle the outermost TypeLoc which is directly linked to the interesting
427 // declaration and don't handle nested name specifier locations.
428 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
429 if (isInUSRSet(TargetDecl)) {
430 // Only handle the outermost typeLoc.
431 //
432 // For a type like "a::Foo", there will be two typeLocs for it.
433 // One ElaboratedType, the other is RecordType:
434 //
435 // ElaboratedType 0x33b9390 'a::Foo' sugar
436 // `-RecordType 0x338fef0 'class a::Foo'
437 // `-CXXRecord 0x338fe58 'Foo'
438 //
439 // Skip if this is an inner typeLoc.
440 if (!ParentTypeLoc.isNull() &&
441 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
442 return true;
443
444 auto StartLoc = StartLocationForType(Loc);
445 auto EndLoc = EndLocationForType(Loc);
446 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
447 RenameInfo Info = {StartLoc,
448 EndLoc,
449 TargetDecl,
450 getClosestAncestorDecl(Loc),
451 GetNestedNameForType(Loc),
452 /*IgnorePrefixQualifiers=*/false};
453 RenameInfos.push_back(Info);
454 }
455 return true;
456 }
457 }
458
459 // Handle specific template class specialiation cases.
460 if (const auto *TemplateSpecType =
461 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
462 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
463 auto StartLoc = StartLocationForType(Loc);
464 auto EndLoc = EndLocationForType(Loc);
465 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
466 RenameInfo Info = {
467 StartLoc,
468 EndLoc,
469 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
470 getClosestAncestorDecl(DynTypedNode::create(Loc)),
471 GetNestedNameForType(Loc),
472 /*IgnorePrefixQualifiers=*/false};
473 RenameInfos.push_back(Info);
474 }
475 }
476 }
477 return true;
478 }
479
480 // Returns a list of RenameInfo.
481 const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; }
482
483 // Returns a list of using declarations which are needed to update.
484 const std::vector<const UsingDecl *> &getUsingDecls() const {
485 return UsingDecls;
486 }
487
488private:
489 // Get the supported declaration from a given typeLoc. If the declaration type
490 // is not supported, returns nullptr.
491 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
492 if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>())
493 return TT->getDecl();
494 return Loc.getType()->getAsTagDecl();
495 }
496
497 // Get the closest ancester which is a declaration of a given AST node.
498 template <typename ASTNodeType>
499 const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {
500 auto Parents = Context.getParents(Node);
501 // FIXME: figure out how to handle it when there are multiple parents.
502 if (Parents.size() != 1)
503 return nullptr;
504 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind()))
505 return Parents[0].template get<Decl>();
506 return getClosestAncestorDecl(Parents[0]);
507 }
508
509 // Get the parent typeLoc of a given typeLoc. If there is no such parent,
510 // return nullptr.
511 const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {
512 auto Parents = Context.getParents(Loc);
513 // FIXME: figure out how to handle it when there are multiple parents.
514 if (Parents.size() != 1)
515 return nullptr;
516 return Parents[0].get<TypeLoc>();
517 }
518
519 // Check whether the USR of a given Decl is in the USRSet.
520 bool isInUSRSet(const Decl *Decl) const {
521 auto USR = getUSRForDecl(Decl);
522 if (USR.empty())
523 return false;
524 return llvm::is_contained(USRSet, USR);
525 }
526
527 const std::set<std::string> USRSet;
528 ASTContext &Context;
529 std::vector<RenameInfo> RenameInfos;
530 // Record all interested using declarations which contains the using-shadow
531 // declarations of the symbol declarations being renamed.
532 std::vector<const UsingDecl *> UsingDecls;
533};
534
535} // namespace
536
538 StringRef PrevName, Decl *Decl) {
539 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());
540 Visitor.TraverseDecl(Decl);
541 return Visitor.takeOccurrences();
542}
543
544std::vector<tooling::AtomicChange>
546 llvm::StringRef NewName, Decl *TranslationUnitDecl) {
547 RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext());
548 Finder.TraverseDecl(TranslationUnitDecl);
549
550 const SourceManager &SM =
552
553 std::vector<tooling::AtomicChange> AtomicChanges;
554 auto Replace = [&](SourceLocation Start, SourceLocation End,
555 llvm::StringRef Text) {
556 tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start);
557 llvm::Error Err = ReplaceChange.replace(
559 if (Err) {
560 llvm::errs() << "Failed to add replacement to AtomicChange: "
561 << llvm::toString(std::move(Err)) << "\n";
562 return;
563 }
564 AtomicChanges.push_back(std::move(ReplaceChange));
565 };
566
567 for (const auto &RenameInfo : Finder.getRenameInfos()) {
568 std::string ReplacedName = NewName.str();
569 if (RenameInfo.IgnorePrefixQualifiers) {
570 // Get the name without prefix qualifiers from NewName.
571 size_t LastColonPos = NewName.find_last_of(':');
572 if (LastColonPos != std::string::npos)
573 ReplacedName = std::string(NewName.substr(LastColonPos + 1));
574 } else {
575 if (RenameInfo.FromDecl && RenameInfo.Context) {
576 if (!llvm::isa<clang::TranslationUnitDecl>(
577 RenameInfo.Context->getDeclContext())) {
578 ReplacedName = tooling::replaceNestedName(
579 RenameInfo.Specifier, RenameInfo.Begin,
580 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
581 NewName.starts_with("::") ? NewName.str()
582 : ("::" + NewName).str());
583 } else {
584 // This fixes the case where type `T` is a parameter inside a function
585 // type (e.g. `std::function<void(T)>`) and the DeclContext of `T`
586 // becomes the translation unit. As a workaround, we simply use
587 // fully-qualified name here for all references whose `DeclContext` is
588 // the translation unit and ignore the possible existence of
589 // using-decls (in the global scope) that can shorten the replaced
590 // name.
591 llvm::StringRef ActualName = Lexer::getSourceText(
593 SourceRange(RenameInfo.Begin, RenameInfo.End)),
595 // Add the leading "::" back if the name written in the code contains
596 // it.
597 if (ActualName.starts_with("::") && !NewName.starts_with("::")) {
598 ReplacedName = "::" + NewName.str();
599 }
600 }
601 }
602 // If the NewName contains leading "::", add it back.
603 if (NewName.starts_with("::") && NewName.substr(2) == ReplacedName)
604 ReplacedName = NewName.str();
605 }
606 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
607 }
608
609 // Hanlde using declarations explicitly as "using a::Foo" don't trigger
610 // typeLoc for "a::Foo".
611 for (const auto *Using : Finder.getUsingDecls())
612 Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str());
613
614 return AtomicChanges;
615}
616
617} // end namespace tooling
618} // end namespace clang
Defines the clang::ASTContext interface.
DynTypedNode Node
const Decl * D
Expr * E
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
#define SM(sm)
Definition: OffloadArch.cpp:16
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol.
SourceLocation Loc
Definition: SemaObjC.cpp:754
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Methods for determining the USR of a symbol at a location in source code.
const NamedDecl * FromDecl
bool IgnorePrefixQualifiers
SourceLocation Begin
Provides functionality for finding all instances of a USR in a given AST.
SourceManager & getSourceManager()
Definition: ASTContext.h:801
const LangOptions & getLangOpts() const
Definition: ASTContext.h:894
static CharSourceRange getTokenRange(SourceRange R)
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:524
static DynTypedNode create(const T &Node)
Creates a DynTypedNode from Node.
A SourceLocation and its associated SourceManager.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Definition: Lexer.cpp:1020
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
Definition: Lexer.cpp:848
Encodes a location in the source.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
The top declaration context.
Definition: Decl.h:104
ASTContext & getASTContext() const
Definition: Decl.h:140
SourceLocation getBeginLoc() const
Get the begin source location.
Definition: TypeLoc.cpp:193
An atomic change is used to create and group a set of source edits, e.g.
Definition: AtomicChange.h:37
llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range, llvm::StringRef ReplacementText)
Adds a replacement that replaces the given Range with ReplacementText.
@ MatchingSymbol
This occurrence is an exact match and can be renamed automatically.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
Definition: ModuleMapFile.h:36
SymbolOccurrences getOccurrencesOfUSRs(ArrayRef< std::string > USRs, StringRef PrevName, Decl *Decl)
Finds the symbol occurrences for the symbol that's identified by the given USR set.
std::vector< AtomicChange > AtomicChanges
Definition: AtomicChange.h:154
std::vector< SymbolOccurrence > SymbolOccurrences
std::string getUSRForDecl(const Decl *Decl)
Definition: USRFinder.cpp:133
std::string replaceNestedName(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:175
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...
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30