28 #include "llvm/ADT/StringRef.h"
29 #include "llvm/Support/Casting.h"
48 std::pair<clang::FileID, unsigned> FileIdAndOffset =
49 FullLoc.getSpellingLoc().getDecomposedLoc();
50 return SM.getFileEntryForID(FileIdAndOffset.first) !=
nullptr;
55 class USRLocFindingASTVisitor
56 :
public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
58 explicit USRLocFindingASTVisitor(
const std::vector<std::string> &USRs,
60 const ASTContext &Context)
61 : RecursiveSymbolVisitor(Context.getSourceManager(),
62 Context.getLangOpts()),
63 USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
66 bool visitSymbolOccurrence(
const NamedDecl *ND,
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();
75 Loc =
SM.getSpellingLoc(Loc);
76 checkAndAddLocation(Loc);
88 void checkAndAddLocation(SourceLocation Loc) {
89 const SourceLocation BeginLoc = Loc;
90 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
91 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
93 Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
94 Context.getSourceManager(), Context.getLangOpts());
95 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);
99 if (
Offset != StringRef::npos)
100 Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol,
101 BeginLoc.getLocWithOffset(
Offset));
104 const std::set<std::string> USRSet;
105 const SymbolName PrevName;
107 const ASTContext &Context;
110 SourceLocation StartLocationForType(TypeLoc TL) {
114 NestedNameSpecifierLoc NestedNameSpecifier =
115 ElaboratedTypeLoc.getQualifierLoc();
116 if (NestedNameSpecifier.getNestedNameSpecifier())
117 return NestedNameSpecifier.getBeginLoc();
118 TL = TL.getNextTypeLoc();
120 return TL.getBeginLoc();
123 SourceLocation EndLocationForType(TypeLoc TL) {
125 while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
127 TL = TL.getNextTypeLoc();
132 if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
133 return TL.castAs<TemplateSpecializationTypeLoc>()
135 .getLocWithOffset(-1);
137 return TL.getEndLoc();
140 NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
143 TL = TL.getNextTypeLoc();
148 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
156 class RenameLocFinder :
public RecursiveASTVisitor<RenameLocFinder> {
159 : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
182 bool VisitNamedDecl(
const NamedDecl *Decl) {
184 if (llvm::isa<UsingDecl>(
Decl))
188 if (llvm::isa<CXXDestructorDecl>(
Decl))
191 if (
Decl->isImplicit())
194 if (isInUSRSet(
Decl)) {
197 if (
const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(
Decl))
198 Decl = TAT->getTemplatedDecl();
200 auto StartLoc =
Decl->getLocation();
201 auto EndLoc = StartLoc;
202 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
203 RenameInfo Info = {StartLoc,
209 RenameInfos.push_back(Info);
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,
229 bool VisitDesignatedInitExpr(
const DesignatedInitExpr *E) {
230 for (
const DesignatedInitExpr::Designator &D : E->designators()) {
231 if (D.isFieldDesignator() && D.getField()) {
232 const FieldDecl *
Decl = D.getField();
233 if (isInUSRSet(Decl)) {
234 auto StartLoc = D.getFieldLoc();
235 auto EndLoc = D.getFieldLoc();
236 RenameInfos.push_back({StartLoc, EndLoc,
247 bool VisitCXXConstructorDecl(
const CXXConstructorDecl *CD) {
249 for (
const auto *Initializer : CD->inits()) {
254 if (
const FieldDecl *FD =
Initializer->getMember()) {
255 if (isInUSRSet(FD)) {
257 RenameInfos.push_back({Loc, Loc,
268 bool VisitDeclRefExpr(
const DeclRefExpr *Expr) {
269 const NamedDecl *
Decl = Expr->getFoundDecl();
272 if (
auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
273 Decl = UsingShadow->getTargetDecl();
276 auto StartLoc = Expr->getBeginLoc();
279 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
280 ? Expr->getLAngleLoc().getLocWithOffset(-1)
283 if (
const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
284 if (isInUSRSet(MD)) {
288 RenameInfos.push_back({EndLoc, EndLoc,
302 if (
const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
305 if (!Expr->hasQualifier())
309 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
324 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
325 assert(EndLoc.isValid() &&
326 "The enum constant should have prefix qualifers.");
328 if (isInUSRSet(Decl) &&
329 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
330 RenameInfo Info = {StartLoc,
333 getClosestAncestorDecl(*Expr),
334 Expr->getQualifier(),
336 RenameInfos.push_back(Info);
342 bool VisitUsingDecl(
const UsingDecl *Using) {
343 for (
const auto *UsingShadow :
Using->shadows()) {
344 if (isInUSRSet(UsingShadow->getTargetDecl())) {
345 UsingDecls.push_back(Using);
352 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
353 if (!NestedLoc.getNestedNameSpecifier()->getAsType())
356 if (
const auto *TargetDecl =
357 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
358 if (isInUSRSet(TargetDecl)) {
359 RenameInfo Info = {NestedLoc.getBeginLoc(),
360 EndLocationForType(NestedLoc.getTypeLoc()),
362 getClosestAncestorDecl(NestedLoc),
363 NestedLoc.getNestedNameSpecifier()->getPrefix(),
365 RenameInfos.push_back(Info);
371 bool VisitTypeLoc(TypeLoc Loc) {
372 auto Parents = Context.getParents(Loc);
373 TypeLoc ParentTypeLoc;
374 if (!Parents.empty()) {
379 if (
const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
380 VisitNestedNameSpecifierLocations(*NSL);
384 if (
const auto *TL = Parents[0].get<TypeLoc>())
390 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
391 if (isInUSRSet(TargetDecl)) {
402 if (!ParentTypeLoc.isNull() &&
403 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
406 auto StartLoc = StartLocationForType(Loc);
407 auto EndLoc = EndLocationForType(Loc);
408 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
409 RenameInfo Info = {StartLoc,
412 getClosestAncestorDecl(Loc),
413 GetNestedNameForType(Loc),
415 RenameInfos.push_back(Info);
422 if (
const auto *TemplateSpecType =
423 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
424 TypeLoc TargetLoc = Loc;
425 if (!ParentTypeLoc.isNull()) {
426 if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
427 TargetLoc = ParentTypeLoc;
430 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
431 TypeLoc TargetLoc = Loc;
437 if (!ParentTypeLoc.isNull() &&
438 llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
439 TargetLoc = ParentTypeLoc;
441 auto StartLoc = StartLocationForType(TargetLoc);
442 auto EndLoc = EndLocationForType(TargetLoc);
443 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
447 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
449 GetNestedNameForType(TargetLoc),
451 RenameInfos.push_back(Info);
459 const std::vector<RenameInfo> &getRenameInfos()
const {
return RenameInfos; }
462 const std::vector<const UsingDecl *> &getUsingDecls()
const {
469 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
471 return TT->getDecl();
472 if (
const auto *RD = Loc.getType()->getAsCXXRecordDecl())
475 llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl()))
481 template <
typename ASTNodeType>
482 const Decl *getClosestAncestorDecl(
const ASTNodeType &
Node) {
483 auto Parents = Context.getParents(
Node);
485 if (Parents.size() != 1)
487 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind()))
488 return Parents[0].template get<Decl>();
489 return getClosestAncestorDecl(Parents[0]);
494 const TypeLoc *getParentTypeLoc(TypeLoc Loc)
const {
495 auto Parents = Context.getParents(Loc);
497 if (Parents.size() != 1)
499 return Parents[0].get<TypeLoc>();
503 bool isInUSRSet(
const Decl *Decl)
const {
507 return llvm::is_contained(USRSet, USR);
510 const std::set<std::string> USRSet;
512 std::vector<RenameInfo> RenameInfos;
515 std::vector<const UsingDecl *> UsingDecls;
523 Visitor.TraverseDecl(
Decl);
524 return Visitor.takeOccurrences();
527 std::vector<tooling::AtomicChange>
538 llvm::StringRef
Text) {
540 llvm::Error Err = ReplaceChange.
replace(
541 SM, CharSourceRange::getTokenRange(Start,
End),
Text);
543 llvm::errs() <<
"Failed to add replacement to AtomicChange: "
550 for (
const auto &RenameInfo : Finder.getRenameInfos()) {
552 if (RenameInfo.IgnorePrefixQualifers) {
554 size_t LastColonPos = NewName.find_last_of(
':');
555 if (LastColonPos != std::string::npos)
556 ReplacedName =
std::string(NewName.substr(LastColonPos + 1));
558 if (RenameInfo.FromDecl && RenameInfo.Context) {
559 if (!llvm::isa<clang::TranslationUnitDecl>(
560 RenameInfo.Context->getDeclContext())) {
562 RenameInfo.Specifier, RenameInfo.Begin,
563 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
564 NewName.startswith(
"::") ? NewName.str()
565 : (
"::" + NewName).str());
574 llvm::StringRef ActualName = Lexer::getSourceText(
575 CharSourceRange::getTokenRange(
580 if (ActualName.startswith(
"::") && !NewName.startswith(
"::")) {
581 ReplacedName =
"::" + NewName.str();
586 if (NewName.startswith(
"::") && NewName.substr(2) == ReplacedName)
587 ReplacedName = NewName.str();
589 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
594 for (
const auto *Using : Finder.getUsingDecls())
595 Replace(Using->getBeginLoc(), Using->getEndLoc(),
"using " + NewName.str());