28#include "llvm/ADT/StringRef.h"
29#include "llvm/Support/Casting.h"
48 auto FileIdAndOffset = FullLoc.getSpellingLoc().getDecomposedLoc();
49 return SM.getFileEntryForID(FileIdAndOffset.first) !=
nullptr;
54class USRLocFindingASTVisitor
55 :
public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
57 explicit USRLocFindingASTVisitor(
const std::vector<std::string> &USRs,
59 const ASTContext &Context)
60 : RecursiveSymbolVisitor(Context.getSourceManager(),
61 Context.getLangOpts()),
62 USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
65 bool visitSymbolOccurrence(
const NamedDecl *ND,
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();
75 checkAndAddLocation(
Loc);
87 void checkAndAddLocation(SourceLocation
Loc) {
88 const SourceLocation BeginLoc =
Loc;
90 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
93 Context.getSourceManager(), Context.getLangOpts());
94 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);
98 if (Offset != StringRef::npos)
100 BeginLoc.getLocWithOffset(Offset));
103 const std::set<std::string> USRSet;
104 const SymbolName PrevName;
106 const ASTContext &Context;
109SourceLocation StartLocationForType(TypeLoc TL) {
110 if (
auto QTL = TL.getAs<QualifiedTypeLoc>())
111 TL = QTL.getUnqualifiedLoc();
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();
124 case TypeLoc::Typedef: {
125 auto TTL = TL.castAs<TypedefTypeLoc>();
126 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
127 return QualifierLoc.getBeginLoc();
128 return TTL.getNameLoc();
130 case TypeLoc::UnresolvedUsing: {
131 auto TTL = TL.castAs<UnresolvedUsingTypeLoc>();
132 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
133 return QualifierLoc.getBeginLoc();
134 return TTL.getNameLoc();
136 case TypeLoc::Using: {
137 auto TTL = TL.castAs<UsingTypeLoc>();
138 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
139 return QualifierLoc.getBeginLoc();
140 return TTL.getNameLoc();
142 case TypeLoc::TemplateSpecialization: {
143 auto TTL = TL.castAs<TemplateSpecializationTypeLoc>();
144 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
145 return QualifierLoc.getBeginLoc();
146 return TTL.getTemplateNameLoc();
148 case TypeLoc::DeducedTemplateSpecialization: {
150 if (NestedNameSpecifierLoc QualifierLoc = DTL.getQualifierLoc())
152 return DTL.getTemplateNameLoc();
154 case TypeLoc::DependentName: {
155 auto TTL = TL.castAs<DependentNameTypeLoc>();
156 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
157 return QualifierLoc.getBeginLoc();
158 return TTL.getNameLoc();
160 case TypeLoc::DependentTemplateSpecialization: {
161 auto TTL = TL.castAs<DependentTemplateSpecializationTypeLoc>();
162 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())
163 return QualifierLoc.getBeginLoc();
164 return TTL.getTemplateNameLoc();
167 llvm_unreachable(
"unhandled TypeLoc class");
171SourceLocation EndLocationForType(TypeLoc TL) {
172 if (
auto QTL = TL.getAs<QualifiedTypeLoc>())
173 TL = QTL.getUnqualifiedLoc();
178 if (
auto TTL = TL.getAs<TemplateSpecializationTypeLoc>())
179 return TTL.getLAngleLoc().getLocWithOffset(-1);
180 return TL.getEndLoc();
183NestedNameSpecifier GetNestedNameForType(TypeLoc TL) {
184 if (
auto QTL = TL.getAs<QualifiedTypeLoc>())
185 TL = QTL.getUnqualifiedLoc();
186 return TL.getPrefix().getNestedNameSpecifier();
193class RenameLocFinder :
public RecursiveASTVisitor<RenameLocFinder> {
196 : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
210 NestedNameSpecifier Specifier;
219 bool VisitNamedDecl(
const NamedDecl *Decl) {
221 if (llvm::isa<UsingDecl>(
Decl))
225 if (llvm::isa<CXXDestructorDecl>(
Decl))
228 if (
Decl->isImplicit())
231 if (isInUSRSet(
Decl)) {
234 if (
const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(
Decl))
235 Decl = TAT->getTemplatedDecl();
237 auto StartLoc =
Decl->getLocation();
238 auto EndLoc = StartLoc;
239 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
240 RenameInfo Info = {StartLoc,
246 RenameInfos.push_back(Info);
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,
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,
285 bool VisitCXXConstructorDecl(
const CXXConstructorDecl *CD) {
292 if (
const FieldDecl *FD =
Initializer->getMember()) {
293 if (isInUSRSet(FD)) {
295 RenameInfos.push_back({
Loc,
Loc,
306 bool VisitDeclRefExpr(
const DeclRefExpr *Expr) {
307 const NamedDecl *
Decl = Expr->getFoundDecl();
310 if (
auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
311 Decl = UsingShadow->getTargetDecl();
314 auto StartLoc = Expr->getBeginLoc();
317 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
318 ? Expr->getLAngleLoc().getLocWithOffset(-1)
321 if (
const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
322 if (isInUSRSet(MD)) {
326 RenameInfos.push_back({EndLoc, EndLoc,
340 if (
const auto *
T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
343 if (!Expr->hasQualifier())
347 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*
T))) {
362 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
363 assert(EndLoc.isValid() &&
364 "The enum constant should have prefix qualifers.");
366 if (isInUSRSet(Decl) &&
367 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
368 RenameInfo Info = {StartLoc,
371 getClosestAncestorDecl(*Expr),
372 Expr->getQualifier(),
374 RenameInfos.push_back(Info);
380 bool VisitUsingDecl(
const UsingDecl *Using) {
381 for (
const auto *UsingShadow :
Using->shadows()) {
382 if (isInUSRSet(UsingShadow->getTargetDecl())) {
383 UsingDecls.push_back(Using);
390 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
391 TypeLoc TL = NestedLoc.getAsTypeLoc();
395 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(TL)) {
396 if (isInUSRSet(TargetDecl)) {
397 RenameInfo Info = {NestedLoc.getBeginLoc(),
398 EndLocationForType(TL),
400 getClosestAncestorDecl(NestedLoc),
403 RenameInfos.push_back(Info);
409 bool VisitTypeLoc(TypeLoc
Loc) {
410 auto Parents = Context.getParents(
Loc);
411 TypeLoc ParentTypeLoc;
412 if (!Parents.empty()) {
417 if (
const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
418 VisitNestedNameSpecifierLocations(*NSL);
422 if (
const auto *TL = Parents[0].get<TypeLoc>())
428 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(
Loc)) {
429 if (isInUSRSet(TargetDecl)) {
440 if (!ParentTypeLoc.isNull() &&
441 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
444 auto StartLoc = StartLocationForType(
Loc);
445 auto EndLoc = EndLocationForType(
Loc);
446 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
447 RenameInfo Info = {StartLoc,
450 getClosestAncestorDecl(
Loc),
451 GetNestedNameForType(
Loc),
453 RenameInfos.push_back(Info);
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)) {
469 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
471 GetNestedNameForType(
Loc),
473 RenameInfos.push_back(Info);
481 const std::vector<RenameInfo> &getRenameInfos()
const {
return RenameInfos; }
484 const std::vector<const UsingDecl *> &getUsingDecls()
const {
491 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc
Loc) {
493 return TT->getDecl();
494 return Loc.getType()->getAsTagDecl();
498 template <
typename ASTNodeType>
499 const Decl *getClosestAncestorDecl(
const ASTNodeType &
Node) {
500 auto Parents = Context.getParents(
Node);
502 if (Parents.size() != 1)
504 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind()))
505 return Parents[0].template get<Decl>();
506 return getClosestAncestorDecl(Parents[0]);
511 const TypeLoc *getParentTypeLoc(TypeLoc
Loc)
const {
512 auto Parents = Context.getParents(
Loc);
514 if (Parents.size() != 1)
516 return Parents[0].get<TypeLoc>();
520 bool isInUSRSet(
const Decl *Decl)
const {
524 return llvm::is_contained(USRSet, USR);
527 const std::set<std::string> USRSet;
529 std::vector<RenameInfo> RenameInfos;
532 std::vector<const UsingDecl *> UsingDecls;
540 Visitor.TraverseDecl(
Decl);
541 return Visitor.takeOccurrences();
544std::vector<tooling::AtomicChange>
555 llvm::StringRef
Text) {
557 llvm::Error Err = ReplaceChange.
replace(
560 llvm::errs() <<
"Failed to add replacement to AtomicChange: "
561 << llvm::toString(std::move(Err)) <<
"\n";
567 for (
const auto &RenameInfo : Finder.getRenameInfos()) {
568 std::string ReplacedName = NewName.str();
569 if (RenameInfo.IgnorePrefixQualifiers) {
571 size_t LastColonPos = NewName.find_last_of(
':');
572 if (LastColonPos != std::string::npos)
573 ReplacedName = std::string(NewName.substr(LastColonPos + 1));
575 if (RenameInfo.FromDecl && RenameInfo.Context) {
576 if (!llvm::isa<clang::TranslationUnitDecl>(
577 RenameInfo.Context->getDeclContext())) {
579 RenameInfo.Specifier, RenameInfo.Begin,
580 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
581 NewName.starts_with(
"::") ? NewName.str()
582 : (
"::" + NewName).str());
597 if (ActualName.starts_with(
"::") && !NewName.starts_with(
"::")) {
598 ReplacedName =
"::" + NewName.str();
603 if (NewName.starts_with(
"::") && NewName.substr(2) == ReplacedName)
604 ReplacedName = NewName.str();
606 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
611 for (
const auto *Using : Finder.getUsingDecls())
612 Replace(Using->getBeginLoc(), Using->getEndLoc(),
"using " + NewName.str());
Defines the clang::ASTContext interface.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol.
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
Provides functionality for finding all instances of a USR in a given AST.
SourceManager & getSourceManager()
const LangOptions & getLangOpts() const
static CharSourceRange getTokenRange(SourceRange R)
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
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.
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.
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.
ASTContext & getASTContext() const
SourceLocation getBeginLoc() const
Get the begin source location.
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.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.