27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/Support/Casting.h" 47 std::pair<clang::FileID, unsigned> FileIdAndOffset =
48 FullLoc.getSpellingLoc().getDecomposedLoc();
54 class 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();
74 Loc = SM.getSpellingLoc(Loc);
75 checkAndAddLocation(Loc);
87 void checkAndAddLocation(SourceLocation Loc) {
88 const SourceLocation BeginLoc = Loc;
89 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
90 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());
92 Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
93 Context.getSourceManager(), Context.getLangOpts());
94 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);
98 if (Offset != StringRef::npos)
99 Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol,
100 BeginLoc.getLocWithOffset(Offset));
103 const std::set<std::string> USRSet;
104 const SymbolName PrevName;
106 const ASTContext &Context;
109 SourceLocation StartLocationForType(TypeLoc TL) {
113 NestedNameSpecifierLoc NestedNameSpecifier =
114 ElaboratedTypeLoc.getQualifierLoc();
115 if (NestedNameSpecifier.getNestedNameSpecifier())
116 return NestedNameSpecifier.getBeginLoc();
117 TL = TL.getNextTypeLoc();
119 return TL.getBeginLoc();
122 SourceLocation EndLocationForType(TypeLoc TL) {
124 while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
125 TL.getTypeLocClass() == TypeLoc::Qualified)
126 TL = TL.getNextTypeLoc();
131 if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
132 return TL.castAs<TemplateSpecializationTypeLoc>()
134 .getLocWithOffset(-1);
136 return TL.getEndLoc();
139 NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
141 while (TL.getTypeLocClass() == TypeLoc::Qualified)
142 TL = TL.getNextTypeLoc();
147 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
155 class RenameLocFinder :
public RecursiveASTVisitor<RenameLocFinder> {
158 : USRSet(USRs.begin(), USRs.end()), Context(Context) {}
181 bool VisitNamedDecl(
const NamedDecl *Decl) {
183 if (llvm::isa<UsingDecl>(Decl))
187 if (llvm::isa<CXXDestructorDecl>(Decl))
190 if (Decl->isImplicit())
193 if (isInUSRSet(Decl)) {
196 if (
const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl))
197 Decl = TAT->getTemplatedDecl();
199 auto StartLoc = Decl->getLocation();
200 auto EndLoc = StartLoc;
201 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
202 RenameInfo Info = {StartLoc,
208 RenameInfos.push_back(Info);
214 bool VisitMemberExpr(
const MemberExpr *Expr) {
215 const NamedDecl *Decl = Expr->getFoundDecl();
216 auto StartLoc = Expr->getMemberLoc();
217 auto EndLoc = Expr->getMemberLoc();
218 if (isInUSRSet(Decl)) {
219 RenameInfos.push_back({StartLoc, EndLoc,
228 bool VisitCXXConstructorDecl(
const CXXConstructorDecl *CD) {
230 for (
const auto *Initializer : CD->inits()) {
232 if (!Initializer->isWritten())
235 if (
const FieldDecl *FD = Initializer->getMember()) {
236 if (isInUSRSet(FD)) {
237 auto Loc = Initializer->getSourceLocation();
238 RenameInfos.push_back({Loc, Loc,
249 bool VisitDeclRefExpr(
const DeclRefExpr *Expr) {
250 const NamedDecl *Decl = Expr->getFoundDecl();
253 if (
auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
254 Decl = UsingShadow->getTargetDecl();
257 auto StartLoc = Expr->getBeginLoc();
260 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
261 ? Expr->getLAngleLoc().getLocWithOffset(-1)
264 if (
const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
265 if (isInUSRSet(MD)) {
269 RenameInfos.push_back({EndLoc, EndLoc,
283 if (
const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
286 if (!Expr->hasQualifier())
290 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
305 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
306 assert(EndLoc.isValid() &&
307 "The enum constant should have prefix qualifers.");
309 if (isInUSRSet(Decl) &&
310 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
311 RenameInfo Info = {StartLoc,
314 getClosestAncestorDecl(*Expr),
315 Expr->getQualifier(),
317 RenameInfos.push_back(Info);
323 bool VisitUsingDecl(
const UsingDecl *Using) {
324 for (
const auto *UsingShadow : Using->shadows()) {
325 if (isInUSRSet(UsingShadow->getTargetDecl())) {
326 UsingDecls.push_back(Using);
333 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
334 if (!NestedLoc.getNestedNameSpecifier()->getAsType())
337 if (
const auto *TargetDecl =
338 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
339 if (isInUSRSet(TargetDecl)) {
340 RenameInfo Info = {NestedLoc.getBeginLoc(),
341 EndLocationForType(NestedLoc.getTypeLoc()),
343 getClosestAncestorDecl(NestedLoc),
344 NestedLoc.getNestedNameSpecifier()->getPrefix(),
346 RenameInfos.push_back(Info);
352 bool VisitTypeLoc(TypeLoc Loc) {
353 auto Parents = Context.getParents(Loc);
354 TypeLoc ParentTypeLoc;
355 if (!Parents.empty()) {
360 if (
const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
361 VisitNestedNameSpecifierLocations(*NSL);
365 if (
const auto *TL = Parents[0].get<TypeLoc>())
371 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
372 if (isInUSRSet(TargetDecl)) {
383 if (!ParentTypeLoc.isNull() &&
384 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
387 auto StartLoc = StartLocationForType(Loc);
388 auto EndLoc = EndLocationForType(Loc);
389 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
390 RenameInfo Info = {StartLoc,
393 getClosestAncestorDecl(Loc),
394 GetNestedNameForType(Loc),
396 RenameInfos.push_back(Info);
403 if (
const auto *TemplateSpecType =
404 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
405 TypeLoc TargetLoc = Loc;
406 if (!ParentTypeLoc.isNull()) {
407 if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
408 TargetLoc = ParentTypeLoc;
411 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
412 TypeLoc TargetLoc = Loc;
418 if (!ParentTypeLoc.isNull() &&
419 llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
420 TargetLoc = ParentTypeLoc;
422 auto StartLoc = StartLocationForType(TargetLoc);
423 auto EndLoc = EndLocationForType(TargetLoc);
424 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
428 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
429 getClosestAncestorDecl(
431 GetNestedNameForType(TargetLoc),
433 RenameInfos.push_back(Info);
441 const std::vector<RenameInfo> &getRenameInfos()
const {
return RenameInfos; }
444 const std::vector<const UsingDecl *> &getUsingDecls()
const {
451 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
453 return TT->getDecl();
454 if (
const auto *RD = Loc.getType()->getAsCXXRecordDecl())
457 llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl()))
463 template <
typename ASTNodeType>
464 const Decl *getClosestAncestorDecl(
const ASTNodeType &
Node) {
465 auto Parents = Context.getParents(Node);
467 if (Parents.size() != 1)
469 if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
470 Parents[0].getNodeKind()))
471 return Parents[0].
template get<Decl>();
472 return getClosestAncestorDecl(Parents[0]);
477 const TypeLoc *getParentTypeLoc(TypeLoc Loc)
const {
478 auto Parents = Context.getParents(Loc);
480 if (Parents.size() != 1)
482 return Parents[0].get<TypeLoc>();
486 bool isInUSRSet(
const Decl *Decl)
const {
490 return llvm::is_contained(USRSet, USR);
493 const std::set<std::string> USRSet;
495 std::vector<RenameInfo> RenameInfos;
498 std::vector<const UsingDecl *> UsingDecls;
505 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->
getASTContext());
506 Visitor.TraverseDecl(Decl);
507 return Visitor.takeOccurrences();
510 std::vector<tooling::AtomicChange>
513 RenameLocFinder Finder(USRs, TranslationUnitDecl->
getASTContext());
514 Finder.TraverseDecl(TranslationUnitDecl);
521 llvm::StringRef
Text) {
523 llvm::Error Err = ReplaceChange.
replace(
524 SM, CharSourceRange::getTokenRange(Start, End),
Text);
526 llvm::errs() <<
"Failed to add replacement to AtomicChange: " 530 AtomicChanges.push_back(std::move(ReplaceChange));
533 for (
const auto &RenameInfo : Finder.getRenameInfos()) {
534 std::string ReplacedName = NewName.str();
535 if (RenameInfo.IgnorePrefixQualifers) {
537 size_t LastColonPos = NewName.find_last_of(
':');
538 if (LastColonPos != std::string::npos)
539 ReplacedName = NewName.substr(LastColonPos + 1);
541 if (RenameInfo.FromDecl && RenameInfo.Context) {
542 if (!llvm::isa<clang::TranslationUnitDecl>(
543 RenameInfo.Context->getDeclContext())) {
545 RenameInfo.Specifier, RenameInfo.Begin,
546 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,
547 NewName.startswith(
"::") ? NewName.str()
548 : (
"::" + NewName).str());
557 llvm::StringRef ActualName = Lexer::getSourceText(
558 CharSourceRange::getTokenRange(
563 if (ActualName.startswith(
"::") && !NewName.startswith(
"::")) {
564 ReplacedName =
"::" + NewName.str();
569 if (NewName.startswith(
"::") && NewName.substr(2) == ReplacedName)
570 ReplacedName = NewName.str();
572 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
577 for (
const auto *Using : Finder.getUsingDecls())
578 Replace(Using->getBeginLoc(), Using->getEndLoc(),
"using " + NewName.str());
Defines the clang::ASTContext interface.
bool IgnorePrefixQualifers
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
const NestedNameSpecifier * Specifier
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol...
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
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.
Provides functionality for finding all instances of a USR in a given AST.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
const NamedDecl * FromDecl
Encodes a location in the source.
ASTContext & getASTContext() const LLVM_READONLY
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.
SourceManager & getSourceManager()
Defines the clang::SourceLocation class and associated facilities.
A SourceLocation and its associated SourceManager.
The top declaration context.
A trivial tuple used to represent a source range.
const LangOptions & getLangOpts() const
This class handles loading and caching of source files into memory.