28 #include "llvm/ADT/StringRef.h" 29 #include "llvm/Support/Casting.h" 48 std::pair<clang::FileID, unsigned> FileIdAndOffset =
49 FullLoc.getSpellingLoc().getDecomposedLoc();
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.getLocStart();
123 SourceLocation EndLocationForType(TypeLoc TL) {
125 while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
126 TL.getTypeLocClass() == TypeLoc::Qualified)
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) {
142 while (TL.getTypeLocClass() == TypeLoc::Qualified)
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 VisitCXXConstructorDecl(
const CXXConstructorDecl *CD) {
231 for (
const auto *Initializer : CD->inits()) {
233 if (!Initializer->isWritten())
236 if (
const FieldDecl *FD = Initializer->getMember()) {
237 if (isInUSRSet(FD)) {
238 auto Loc = Initializer->getSourceLocation();
239 RenameInfos.push_back({Loc, Loc,
250 bool VisitDeclRefExpr(
const DeclRefExpr *Expr) {
251 const NamedDecl *Decl = Expr->getFoundDecl();
254 if (
auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) {
255 Decl = UsingShadow->getTargetDecl();
258 auto StartLoc = Expr->getLocStart();
261 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()
262 ? Expr->getLAngleLoc().getLocWithOffset(-1)
265 if (
const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) {
266 if (isInUSRSet(MD)) {
270 RenameInfos.push_back({EndLoc, EndLoc,
284 if (
const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) {
287 if (!Expr->hasQualifier())
291 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) {
306 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);
307 assert(EndLoc.isValid() &&
308 "The enum constant should have prefix qualifers.");
310 if (isInUSRSet(Decl) &&
311 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
312 RenameInfo Info = {StartLoc,
315 getClosestAncestorDecl(*Expr),
316 Expr->getQualifier(),
318 RenameInfos.push_back(Info);
324 bool VisitUsingDecl(
const UsingDecl *Using) {
325 for (
const auto *UsingShadow : Using->shadows()) {
326 if (isInUSRSet(UsingShadow->getTargetDecl())) {
327 UsingDecls.push_back(Using);
334 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
335 if (!NestedLoc.getNestedNameSpecifier()->getAsType())
338 if (
const auto *TargetDecl =
339 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
340 if (isInUSRSet(TargetDecl)) {
341 RenameInfo Info = {NestedLoc.getBeginLoc(),
342 EndLocationForType(NestedLoc.getTypeLoc()),
344 getClosestAncestorDecl(NestedLoc),
345 NestedLoc.getNestedNameSpecifier()->getPrefix(),
347 RenameInfos.push_back(Info);
353 bool VisitTypeLoc(TypeLoc Loc) {
354 auto Parents = Context.getParents(Loc);
355 TypeLoc ParentTypeLoc;
356 if (!Parents.empty()) {
361 if (
const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
362 VisitNestedNameSpecifierLocations(*NSL);
366 if (
const auto *TL = Parents[0].get<TypeLoc>())
372 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
373 if (isInUSRSet(TargetDecl)) {
384 if (!ParentTypeLoc.isNull() &&
385 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
388 auto StartLoc = StartLocationForType(Loc);
389 auto EndLoc = EndLocationForType(Loc);
390 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
391 RenameInfo Info = {StartLoc,
394 getClosestAncestorDecl(Loc),
395 GetNestedNameForType(Loc),
397 RenameInfos.push_back(Info);
404 if (
const auto *TemplateSpecType =
405 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
406 TypeLoc TargetLoc = Loc;
407 if (!ParentTypeLoc.isNull()) {
408 if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
409 TargetLoc = ParentTypeLoc;
412 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
413 TypeLoc TargetLoc = Loc;
419 if (!ParentTypeLoc.isNull() &&
420 llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
421 TargetLoc = ParentTypeLoc;
423 auto StartLoc = StartLocationForType(TargetLoc);
424 auto EndLoc = EndLocationForType(TargetLoc);
425 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {
429 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
430 getClosestAncestorDecl(
432 GetNestedNameForType(TargetLoc),
434 RenameInfos.push_back(Info);
442 const std::vector<RenameInfo> &getRenameInfos()
const {
return RenameInfos; }
445 const std::vector<const UsingDecl *> &getUsingDecls()
const {
452 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
454 return TT->getDecl();
455 if (
const auto *RD = Loc.getType()->getAsCXXRecordDecl())
458 llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl()))
464 template <
typename ASTNodeType>
465 const Decl *getClosestAncestorDecl(
const ASTNodeType &
Node) {
466 auto Parents = Context.getParents(Node);
468 if (Parents.size() != 1)
470 if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
471 Parents[0].getNodeKind()))
472 return Parents[0].
template get<Decl>();
473 return getClosestAncestorDecl(Parents[0]);
478 const TypeLoc *getParentTypeLoc(TypeLoc Loc)
const {
479 auto Parents = Context.getParents(Loc);
481 if (Parents.size() != 1)
483 return Parents[0].get<TypeLoc>();
487 bool isInUSRSet(
const Decl *Decl)
const {
491 return llvm::is_contained(USRSet, USR);
494 const std::set<std::string> USRSet;
496 std::vector<RenameInfo> RenameInfos;
499 std::vector<const UsingDecl *> UsingDecls;
506 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->
getASTContext());
507 Visitor.TraverseDecl(Decl);
508 return Visitor.takeOccurrences();
511 std::vector<tooling::AtomicChange>
514 RenameLocFinder Finder(USRs, TranslationUnitDecl->
getASTContext());
515 Finder.TraverseDecl(TranslationUnitDecl);
522 llvm::StringRef
Text) {
524 llvm::Error Err = ReplaceChange.
replace(
525 SM, CharSourceRange::getTokenRange(Start, End),
Text);
527 llvm::errs() <<
"Failed to add replacement to AtomicChange: " 531 AtomicChanges.push_back(std::move(ReplaceChange));
534 for (
const auto &RenameInfo : Finder.getRenameInfos()) {
535 std::string ReplacedName = NewName.str();
536 if (RenameInfo.IgnorePrefixQualifers) {
538 size_t LastColonPos = NewName.find_last_of(
':');
539 if (LastColonPos != std::string::npos)
540 ReplacedName = NewName.substr(LastColonPos + 1);
542 if (RenameInfo.FromDecl && RenameInfo.Context) {
543 if (!llvm::isa<clang::TranslationUnitDecl>(
544 RenameInfo.Context->getDeclContext())) {
546 RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
548 NewName.startswith(
"::") ? NewName.str()
549 : (
"::" + NewName).str());
558 llvm::StringRef ActualName = Lexer::getSourceText(
559 CharSourceRange::getTokenRange(
564 if (ActualName.startswith(
"::") && !NewName.startswith(
"::")) {
565 ReplacedName =
"::" + NewName.str();
570 if (NewName.startswith(
"::") && NewName.substr(2) == ReplacedName)
571 ReplacedName = NewName.str();
573 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
578 for (
const auto *Using : Finder.getUsingDecls())
579 Replace(Using->getLocStart(), Using->getLocEnd(),
"using " + NewName.str());
Defines the clang::ASTContext interface.
bool IgnorePrefixQualifers
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
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...
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.
std::string toString(const til::SExpr *E)
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.