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;
55class 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();
76 checkAndAddLocation(
Loc);
88 void checkAndAddLocation(SourceLocation
Loc) {
89 const SourceLocation BeginLoc =
Loc;
91 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
94 Context.getSourceManager(), Context.getLangOpts());
95 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);
99 if (Offset != StringRef::npos)
101 BeginLoc.getLocWithOffset(Offset));
104 const std::set<std::string> USRSet;
105 const SymbolName PrevName;
107 const ASTContext &Context;
110SourceLocation 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();
123SourceLocation 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();
140NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
143 TL = TL.getNextTypeLoc();
148 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
156class 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()) {
232 if (
const FieldDecl *Decl =
D.getFieldDecl()) {
233 if (isInUSRSet(Decl)) {
234 auto StartLoc =
D.getFieldLoc();
235 auto EndLoc =
D.getFieldLoc();
236 RenameInfos.push_back({StartLoc, EndLoc,
248 bool VisitCXXConstructorDecl(
const CXXConstructorDecl *CD) {
255 if (
const FieldDecl *FD =
Initializer->getMember()) {
256 if (isInUSRSet(FD)) {
258 RenameInfos.push_back({
Loc,
Loc,
269 bool VisitDeclRefExpr(
const DeclRefExpr *Expr) {
270 const NamedDecl *
Decl = Expr->getFoundDecl();
273 if (
auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
274 Decl = UsingShadow->getTargetDecl();
277 auto StartLoc = Expr->getBeginLoc();
280 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
281 ? Expr->getLAngleLoc().getLocWithOffset(-1)
284 if (
const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
285 if (isInUSRSet(MD)) {
289 RenameInfos.push_back({EndLoc, EndLoc,
303 if (
const auto *
T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
306 if (!Expr->hasQualifier())
310 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*
T))) {
325 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
326 assert(EndLoc.isValid() &&
327 "The enum constant should have prefix qualifers.");
329 if (isInUSRSet(Decl) &&
330 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
331 RenameInfo Info = {StartLoc,
334 getClosestAncestorDecl(*Expr),
335 Expr->getQualifier(),
337 RenameInfos.push_back(Info);
343 bool VisitUsingDecl(
const UsingDecl *Using) {
344 for (
const auto *UsingShadow :
Using->shadows()) {
345 if (isInUSRSet(UsingShadow->getTargetDecl())) {
346 UsingDecls.push_back(Using);
353 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
354 if (!NestedLoc.getNestedNameSpecifier()->getAsType())
357 if (
const auto *TargetDecl =
358 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
359 if (isInUSRSet(TargetDecl)) {
360 RenameInfo Info = {NestedLoc.getBeginLoc(),
361 EndLocationForType(NestedLoc.getTypeLoc()),
363 getClosestAncestorDecl(NestedLoc),
364 NestedLoc.getNestedNameSpecifier()->getPrefix(),
366 RenameInfos.push_back(Info);
372 bool VisitTypeLoc(TypeLoc
Loc) {
373 auto Parents = Context.getParents(
Loc);
374 TypeLoc ParentTypeLoc;
375 if (!Parents.empty()) {
380 if (
const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
381 VisitNestedNameSpecifierLocations(*NSL);
385 if (
const auto *TL = Parents[0].get<TypeLoc>())
391 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(
Loc)) {
392 if (isInUSRSet(TargetDecl)) {
403 if (!ParentTypeLoc.isNull() &&
404 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
407 auto StartLoc = StartLocationForType(
Loc);
408 auto EndLoc = EndLocationForType(
Loc);
409 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
410 RenameInfo Info = {StartLoc,
413 getClosestAncestorDecl(
Loc),
414 GetNestedNameForType(
Loc),
416 RenameInfos.push_back(Info);
423 if (
const auto *TemplateSpecType =
424 dyn_cast<TemplateSpecializationType>(
Loc.getType())) {
425 TypeLoc TargetLoc =
Loc;
426 if (!ParentTypeLoc.isNull()) {
427 if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
428 TargetLoc = ParentTypeLoc;
431 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
432 TypeLoc TargetLoc =
Loc;
438 if (!ParentTypeLoc.isNull() &&
439 llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
440 TargetLoc = ParentTypeLoc;
442 auto StartLoc = StartLocationForType(TargetLoc);
443 auto EndLoc = EndLocationForType(TargetLoc);
444 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
448 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
450 GetNestedNameForType(TargetLoc),
452 RenameInfos.push_back(Info);
460 const std::vector<RenameInfo> &getRenameInfos()
const {
return RenameInfos; }
463 const std::vector<const UsingDecl *> &getUsingDecls()
const {
470 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc
Loc) {
472 return TT->getDecl();
473 if (
const auto *RD =
Loc.getType()->getAsCXXRecordDecl())
476 llvm::dyn_cast_or_null<EnumDecl>(
Loc.getType()->getAsTagDecl()))
482 template <
typename ASTNodeType>
483 const Decl *getClosestAncestorDecl(
const ASTNodeType &
Node) {
484 auto Parents = Context.getParents(
Node);
486 if (Parents.size() != 1)
488 if (ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(Parents[0].getNodeKind()))
489 return Parents[0].template get<Decl>();
490 return getClosestAncestorDecl(Parents[0]);
495 const TypeLoc *getParentTypeLoc(TypeLoc
Loc)
const {
496 auto Parents = Context.getParents(
Loc);
498 if (Parents.size() != 1)
500 return Parents[0].get<TypeLoc>();
504 bool isInUSRSet(
const Decl *Decl)
const {
508 return llvm::is_contained(USRSet, USR);
511 const std::set<std::string> USRSet;
513 std::vector<RenameInfo> RenameInfos;
516 std::vector<const UsingDecl *> UsingDecls;
524 Visitor.TraverseDecl(
Decl);
525 return Visitor.takeOccurrences();
528std::vector<tooling::AtomicChange>
539 llvm::StringRef
Text) {
541 llvm::Error Err = ReplaceChange.
replace(
544 llvm::errs() <<
"Failed to add replacement to AtomicChange: "
545 << llvm::toString(std::move(Err)) <<
"\n";
551 for (
const auto &RenameInfo : Finder.getRenameInfos()) {
552 std::string ReplacedName = NewName.str();
553 if (RenameInfo.IgnorePrefixQualifers) {
555 size_t LastColonPos = NewName.find_last_of(
':');
556 if (LastColonPos != std::string::npos)
557 ReplacedName = std::string(NewName.substr(LastColonPos + 1));
559 if (RenameInfo.FromDecl && RenameInfo.Context) {
560 if (!llvm::isa<clang::TranslationUnitDecl>(
561 RenameInfo.Context->getDeclContext())) {
563 RenameInfo.Specifier, RenameInfo.Begin,
564 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
565 NewName.starts_with(
"::") ? NewName.str()
566 : (
"::" + NewName).str());
581 if (ActualName.starts_with(
"::") && !NewName.starts_with(
"::")) {
582 ReplacedName =
"::" + NewName.str();
587 if (NewName.starts_with(
"::") && NewName.substr(2) == ReplacedName)
588 ReplacedName = NewName.str();
590 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
595 for (
const auto *Using : Finder.getUsingDecls())
596 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 IgnorePrefixQualifers
const NestedNameSpecifier * Specifier
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
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.