27 #include "llvm/ADT/StringRef.h"
28 #include "llvm/Support/Casting.h"
43 class USRLocFindingASTVisitor
44 :
public RecursiveSymbolVisitor<USRLocFindingASTVisitor> {
46 explicit USRLocFindingASTVisitor(
const std::vector<std::string> &USRs,
49 : RecursiveSymbolVisitor(Context.getSourceManager(),
50 Context.getLangOpts()),
51 USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) {
54 bool visitSymbolOccurrence(
const NamedDecl *ND,
57 assert(NameRanges.size() == 1 &&
58 "Multiple name pieces are not supported yet!");
59 SourceLocation Loc = NameRanges[0].getBegin();
60 const SourceManager &
SM =
Context.getSourceManager();
63 Loc = SM.getSpellingLoc(Loc);
64 checkAndAddLocation(Loc);
73 const std::vector<clang::SourceLocation> &getLocationsFound()
const {
78 void checkAndAddLocation(SourceLocation Loc) {
79 const SourceLocation BeginLoc = Loc;
80 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
83 Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
89 if (Offset != StringRef::npos)
99 SourceLocation StartLocationForType(TypeLoc TL) {
103 NestedNameSpecifierLoc NestedNameSpecifier =
104 ElaboratedTypeLoc.getQualifierLoc();
105 if (NestedNameSpecifier.getNestedNameSpecifier())
106 return NestedNameSpecifier.getBeginLoc();
107 TL = TL.getNextTypeLoc();
109 return TL.getLocStart();
112 SourceLocation EndLocationForType(TypeLoc TL) {
114 while (TL.getTypeLocClass() == TypeLoc::Elaborated ||
115 TL.getTypeLocClass() == TypeLoc::Qualified)
116 TL = TL.getNextTypeLoc();
121 if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) {
122 return TL.castAs<TemplateSpecializationTypeLoc>()
124 .getLocWithOffset(-1);
126 return TL.getEndLoc();
129 NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) {
131 while (TL.getTypeLocClass() == TypeLoc::Qualified)
132 TL = TL.getNextTypeLoc();
137 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier();
145 class RenameLocFinder :
public RecursiveASTVisitor<RenameLocFinder> {
148 :
USRSet(USRs.begin(), USRs.end()), Context(Context) {}
170 bool VisitNamedDecl(
const NamedDecl *Decl) {
172 if (llvm::isa<UsingDecl>(Decl))
176 if (llvm::isa<CXXDestructorDecl>(Decl))
179 if (Decl->isImplicit())
182 if (isInUSRSet(Decl)) {
183 RenameInfo Info = {Decl->getLocation(), Decl->getLocation(),
nullptr,
190 bool VisitDeclRefExpr(
const DeclRefExpr *Expr) {
191 const NamedDecl *
Decl = Expr->getFoundDecl();
192 if (isInUSRSet(Decl)) {
193 RenameInfo Info = {Expr->getSourceRange().getBegin(),
194 Expr->getSourceRange().getEnd(), Decl,
195 getClosestAncestorDecl(*Expr), Expr->getQualifier()};
202 bool VisitUsingDecl(
const UsingDecl *Using) {
203 for (
const auto *UsingShadow : Using->shadows()) {
204 if (isInUSRSet(UsingShadow->getTargetDecl())) {
212 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {
213 if (!NestedLoc.getNestedNameSpecifier()->getAsType())
215 if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc()))
218 if (
const auto *TargetDecl =
219 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) {
220 if (isInUSRSet(TargetDecl)) {
221 RenameInfo Info = {NestedLoc.getBeginLoc(),
222 EndLocationForType(NestedLoc.getTypeLoc()),
223 TargetDecl, getClosestAncestorDecl(NestedLoc),
224 NestedLoc.getNestedNameSpecifier()->getPrefix()};
231 bool VisitTypeLoc(TypeLoc Loc) {
232 if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc))
235 auto Parents =
Context.getParents(Loc);
236 TypeLoc ParentTypeLoc;
237 if (!Parents.empty()) {
242 if (
const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) {
243 VisitNestedNameSpecifierLocations(*NSL);
247 if (
const auto *TL = Parents[0].get<TypeLoc>())
253 if (
const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {
254 if (isInUSRSet(TargetDecl)) {
265 if (!ParentTypeLoc.isNull() &&
266 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))
268 RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc),
269 TargetDecl, getClosestAncestorDecl(Loc),
270 GetNestedNameForType(Loc)};
277 if (
const auto *TemplateSpecType =
278 dyn_cast<TemplateSpecializationType>(Loc.getType())) {
279 TypeLoc TargetLoc = Loc;
280 if (!ParentTypeLoc.isNull()) {
281 if (llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
282 TargetLoc = ParentTypeLoc;
285 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {
286 TypeLoc TargetLoc = Loc;
292 if (!ParentTypeLoc.isNull() &&
293 llvm::isa<ElaboratedType>(ParentTypeLoc.getType()))
294 TargetLoc = ParentTypeLoc;
296 StartLocationForType(TargetLoc), EndLocationForType(TargetLoc),
297 TemplateSpecType->getTemplateName().getAsTemplateDecl(),
298 getClosestAncestorDecl(
300 GetNestedNameForType(TargetLoc)};
308 const std::vector<RenameInfo> &getRenameInfos()
const {
return RenameInfos; }
311 const std::vector<const UsingDecl *> &getUsingDecls()
const {
318 bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL)
const {
319 while (!TL.isNull()) {
327 if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
336 if (TL.getTypeLocClass() == TypeLoc::Typedef)
338 TL = TL.getNextTypeLoc();
347 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {
348 if (
const auto *RD = Loc.getType()->getAsCXXRecordDecl())
354 template <
typename ASTNodeType>
355 const Decl *getClosestAncestorDecl(
const ASTNodeType &
Node) {
356 auto Parents =
Context.getParents(Node);
358 if (Parents.size() != 1)
360 if (ast_type_traits::ASTNodeKind::getFromNodeKind<Decl>().isBaseOf(
361 Parents[0].getNodeKind()))
362 return Parents[0].
template get<Decl>();
363 return getClosestAncestorDecl(Parents[0]);
368 const TypeLoc *getParentTypeLoc(TypeLoc Loc)
const {
369 auto Parents =
Context.getParents(Loc);
371 if (Parents.size() != 1)
373 return Parents[0].get<TypeLoc>();
377 bool isInUSRSet(
const Decl *Decl)
const {
381 return llvm::is_contained(
USRSet, USR);
384 const std::set<std::string>
USRSet;
394 std::vector<SourceLocation>
397 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->
getASTContext());
398 Visitor.TraverseDecl(Decl);
399 return Visitor.getLocationsFound();
402 std::vector<tooling::AtomicChange>
406 Finder.TraverseDecl(TranslationUnitDecl);
411 std::vector<tooling::AtomicChange> AtomicChanges;
413 llvm::StringRef
Text) {
415 llvm::Error Err = ReplaceChange.
replace(
416 SM, CharSourceRange::getTokenRange(Start, End),
Text);
418 llvm::errs() <<
"Faile to add replacement to AtomicChange: "
422 AtomicChanges.push_back(std::move(ReplaceChange));
425 for (
const auto &RenameInfo :
Finder.getRenameInfos()) {
426 std::string ReplacedName = NewName.str();
427 if (RenameInfo.FromDecl && RenameInfo.Context) {
428 if (!llvm::isa<clang::TranslationUnitDecl>(
429 RenameInfo.Context->getDeclContext())) {
431 RenameInfo.Specifier, RenameInfo.Context->getDeclContext(),
433 NewName.startswith(
"::") ? NewName.str() : (
"::" + NewName).str());
437 if (NewName.startswith(
"::") && NewName.substr(2) == ReplacedName)
438 ReplacedName = NewName.str();
439 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);
444 for (
const auto *Using :
Finder.getUsingDecls())
445 Replace(Using->getLocStart(), Using->getLocEnd(),
"using " + NewName.str());
447 return AtomicChanges;
Defines the clang::ASTContext interface.
Defines the SourceManager interface.
const NestedNameSpecifier * Specifier
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol...
const std::set< std::string > USRSet
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
std::vector< RenameInfo > RenameInfos
Methods for determining the USR of a symbol at a location in source code.
const std::string PrevName
Provides functionality for finding all instances of a USR in a given AST.
const NamedDecl * FromDecl
ASTMatchFinder *const Finder
Encodes a location in the source.
ASTContext & getASTContext() const LLVM_READONLY
std::vector< const UsingDecl * > UsingDecls
std::vector< clang::SourceLocation > LocationsFound
ast_type_traits::DynTypedNode Node
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.
TranslationUnitDecl - The top declaration context.
const ASTContext & Context
This class handles loading and caching of source files into memory.