Alex Lorenz | 4abbd92 | 2017-06-30 16:36:09 +0000 | [diff] [blame] | 1 | //===--- USRLocFinder.cpp - Clang refactoring library ---------------------===// |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// |
| 10 | /// \file |
Alex Lorenz | 4abbd92 | 2017-06-30 16:36:09 +0000 | [diff] [blame] | 11 | /// \brief Methods for finding all instances of a USR. Our strategy is very |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 12 | /// simple; we just compare the USR at every relevant AST node with the one |
| 13 | /// provided. |
| 14 | /// |
| 15 | //===----------------------------------------------------------------------===// |
| 16 | |
Alex Lorenz | 4abbd92 | 2017-06-30 16:36:09 +0000 | [diff] [blame] | 17 | #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 18 | #include "clang/AST/ASTContext.h" |
| 19 | #include "clang/AST/RecursiveASTVisitor.h" |
Eugene Zelenko | 8615047 | 2016-11-29 18:24:01 +0000 | [diff] [blame] | 20 | #include "clang/Basic/LLVM.h" |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 21 | #include "clang/Basic/SourceLocation.h" |
Eugene Zelenko | 8615047 | 2016-11-29 18:24:01 +0000 | [diff] [blame] | 22 | #include "clang/Basic/SourceManager.h" |
Miklos Vajna | 1d48e50 | 2016-05-13 09:17:32 +0000 | [diff] [blame] | 23 | #include "clang/Lex/Lexer.h" |
Haojian Wu | 74f823a | 2017-04-04 09:30:06 +0000 | [diff] [blame] | 24 | #include "clang/Tooling/Core/Lookup.h" |
Alex Lorenz | 98394f8 | 2017-07-13 10:36:33 +0000 | [diff] [blame] | 25 | #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" |
Alex Lorenz | 4abbd92 | 2017-06-30 16:36:09 +0000 | [diff] [blame] | 26 | #include "clang/Tooling/Refactoring/Rename/USRFinder.h" |
Eugene Zelenko | 8615047 | 2016-11-29 18:24:01 +0000 | [diff] [blame] | 27 | #include "llvm/ADT/StringRef.h" |
| 28 | #include "llvm/Support/Casting.h" |
| 29 | #include <cstddef> |
| 30 | #include <set> |
| 31 | #include <string> |
| 32 | #include <vector> |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 33 | |
| 34 | using namespace llvm; |
| 35 | |
| 36 | namespace clang { |
Alex Lorenz | 4abbd92 | 2017-06-30 16:36:09 +0000 | [diff] [blame] | 37 | namespace tooling { |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 38 | |
| 39 | namespace { |
Eugene Zelenko | 8615047 | 2016-11-29 18:24:01 +0000 | [diff] [blame] | 40 | |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 41 | // \brief This visitor recursively searches for all instances of a USR in a |
| 42 | // translation unit and stores them for later usage. |
| 43 | class USRLocFindingASTVisitor |
Alex Lorenz | 98394f8 | 2017-07-13 10:36:33 +0000 | [diff] [blame] | 44 | : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> { |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 45 | public: |
Kirill Bobyrev | 83d5d56 | 2016-07-29 10:16:45 +0000 | [diff] [blame] | 46 | explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs, |
| 47 | StringRef PrevName, |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 48 | const ASTContext &Context) |
Alex Lorenz | 98394f8 | 2017-07-13 10:36:33 +0000 | [diff] [blame] | 49 | : RecursiveSymbolVisitor(Context.getSourceManager(), |
| 50 | Context.getLangOpts()), |
| 51 | USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { |
Kirill Bobyrev | 83d5d56 | 2016-07-29 10:16:45 +0000 | [diff] [blame] | 52 | } |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 53 | |
Alex Lorenz | 98394f8 | 2017-07-13 10:36:33 +0000 | [diff] [blame] | 54 | bool visitSymbolOccurrence(const NamedDecl *ND, |
| 55 | ArrayRef<SourceRange> NameRanges) { |
| 56 | if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) { |
| 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(); |
| 61 | // TODO: Deal with macro occurrences correctly. |
| 62 | if (Loc.isMacroID()) |
| 63 | Loc = SM.getSpellingLoc(Loc); |
| 64 | checkAndAddLocation(Loc); |
Kirill Bobyrev | 9e0dab9 | 2016-08-02 09:38:38 +0000 | [diff] [blame] | 65 | } |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 66 | return true; |
| 67 | } |
| 68 | |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 69 | // Non-visitors: |
| 70 | |
| 71 | // \brief Returns a list of unique locations. Duplicate or overlapping |
| 72 | // locations are erroneous and should be reported! |
| 73 | const std::vector<clang::SourceLocation> &getLocationsFound() const { |
| 74 | return LocationsFound; |
| 75 | } |
| 76 | |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 77 | private: |
| 78 | void checkAndAddLocation(SourceLocation Loc) { |
Kirill Bobyrev | 6b7d8c2 | 2016-08-15 23:20:05 +0000 | [diff] [blame] | 79 | const SourceLocation BeginLoc = Loc; |
| 80 | const SourceLocation EndLoc = Lexer::getLocForEndOfToken( |
Kirill Bobyrev | 83d5d56 | 2016-07-29 10:16:45 +0000 | [diff] [blame] | 81 | BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 82 | StringRef TokenName = |
| 83 | Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), |
| 84 | Context.getSourceManager(), Context.getLangOpts()); |
| 85 | size_t Offset = TokenName.find(PrevName); |
Kirill Bobyrev | 8769778 | 2016-09-04 22:50:41 +0000 | [diff] [blame] | 86 | |
| 87 | // The token of the source location we find actually has the old |
| 88 | // name. |
| 89 | if (Offset != StringRef::npos) |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 90 | LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 91 | } |
| 92 | |
Kirill Bobyrev | 83d5d56 | 2016-07-29 10:16:45 +0000 | [diff] [blame] | 93 | const std::set<std::string> USRSet; |
Miklos Vajna | a7445f1 | 2016-05-17 18:17:16 +0000 | [diff] [blame] | 94 | const std::string PrevName; |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 95 | std::vector<clang::SourceLocation> LocationsFound; |
Kirill Bobyrev | a3432fa | 2016-07-22 13:41:09 +0000 | [diff] [blame] | 96 | const ASTContext &Context; |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 97 | }; |
Eugene Zelenko | 8615047 | 2016-11-29 18:24:01 +0000 | [diff] [blame] | 98 | |
Haojian Wu | 74f823a | 2017-04-04 09:30:06 +0000 | [diff] [blame] | 99 | SourceLocation StartLocationForType(TypeLoc TL) { |
| 100 | // For elaborated types (e.g. `struct a::A`) we want the portion after the |
| 101 | // `struct` but including the namespace qualifier, `a::`. |
| 102 | if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) { |
| 103 | NestedNameSpecifierLoc NestedNameSpecifier = |
| 104 | ElaboratedTypeLoc.getQualifierLoc(); |
| 105 | if (NestedNameSpecifier.getNestedNameSpecifier()) |
| 106 | return NestedNameSpecifier.getBeginLoc(); |
| 107 | TL = TL.getNextTypeLoc(); |
| 108 | } |
| 109 | return TL.getLocStart(); |
| 110 | } |
| 111 | |
| 112 | SourceLocation EndLocationForType(TypeLoc TL) { |
| 113 | // Dig past any namespace or keyword qualifications. |
| 114 | while (TL.getTypeLocClass() == TypeLoc::Elaborated || |
| 115 | TL.getTypeLocClass() == TypeLoc::Qualified) |
| 116 | TL = TL.getNextTypeLoc(); |
| 117 | |
| 118 | // The location for template specializations (e.g. Foo<int>) includes the |
| 119 | // templated types in its location range. We want to restrict this to just |
| 120 | // before the `<` character. |
| 121 | if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { |
| 122 | return TL.castAs<TemplateSpecializationTypeLoc>() |
| 123 | .getLAngleLoc() |
| 124 | .getLocWithOffset(-1); |
| 125 | } |
| 126 | return TL.getEndLoc(); |
| 127 | } |
| 128 | |
| 129 | NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { |
| 130 | // Dig past any keyword qualifications. |
| 131 | while (TL.getTypeLocClass() == TypeLoc::Qualified) |
| 132 | TL = TL.getNextTypeLoc(); |
| 133 | |
| 134 | // For elaborated types (e.g. `struct a::A`) we want the portion after the |
| 135 | // `struct` but including the namespace qualifier, `a::`. |
| 136 | if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) |
| 137 | return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); |
| 138 | return nullptr; |
| 139 | } |
| 140 | |
| 141 | // Find all locations identified by the given USRs for rename. |
| 142 | // |
| 143 | // This class will traverse the AST and find every AST node whose USR is in the |
| 144 | // given USRs' set. |
Miklos Vajna | a60cae2 | 2017-04-23 16:07:06 +0000 | [diff] [blame] | 145 | class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> { |
Haojian Wu | 74f823a | 2017-04-04 09:30:06 +0000 | [diff] [blame] | 146 | public: |
| 147 | RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context) |
| 148 | : USRSet(USRs.begin(), USRs.end()), Context(Context) {} |
| 149 | |
| 150 | // A structure records all information of a symbol reference being renamed. |
| 151 | // We try to add as few prefix qualifiers as possible. |
| 152 | struct RenameInfo { |
| 153 | // The begin location of a symbol being renamed. |
| 154 | SourceLocation Begin; |
| 155 | // The end location of a symbol being renamed. |
| 156 | SourceLocation End; |
| 157 | // The declaration of a symbol being renamed (can be nullptr). |
| 158 | const NamedDecl *FromDecl; |
| 159 | // The declaration in which the nested name is contained (can be nullptr). |
| 160 | const Decl *Context; |
| 161 | // The nested name being replaced (can be nullptr). |
| 162 | const NestedNameSpecifier *Specifier; |
| 163 | }; |
| 164 | |
| 165 | // FIXME: Currently, prefix qualifiers will be added to the renamed symbol |
| 166 | // definition (e.g. "class Foo {};" => "class b::Bar {};" when renaming |
| 167 | // "a::Foo" to "b::Bar"). |
| 168 | // For renaming declarations/definitions, prefix qualifiers should be filtered |
| 169 | // out. |
| 170 | bool VisitNamedDecl(const NamedDecl *Decl) { |
| 171 | // UsingDecl has been handled in other place. |
| 172 | if (llvm::isa<UsingDecl>(Decl)) |
| 173 | return true; |
| 174 | |
| 175 | // DestructorDecl has been handled in Typeloc. |
| 176 | if (llvm::isa<CXXDestructorDecl>(Decl)) |
| 177 | return true; |
| 178 | |
| 179 | if (Decl->isImplicit()) |
| 180 | return true; |
| 181 | |
| 182 | if (isInUSRSet(Decl)) { |
| 183 | RenameInfo Info = {Decl->getLocation(), Decl->getLocation(), nullptr, |
| 184 | nullptr, nullptr}; |
| 185 | RenameInfos.push_back(Info); |
| 186 | } |
| 187 | return true; |
| 188 | } |
| 189 | |
| 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()}; |
| 196 | RenameInfos.push_back(Info); |
| 197 | } |
| 198 | |
| 199 | return true; |
| 200 | } |
| 201 | |
| 202 | bool VisitUsingDecl(const UsingDecl *Using) { |
| 203 | for (const auto *UsingShadow : Using->shadows()) { |
| 204 | if (isInUSRSet(UsingShadow->getTargetDecl())) { |
| 205 | UsingDecls.push_back(Using); |
| 206 | break; |
| 207 | } |
| 208 | } |
| 209 | return true; |
| 210 | } |
| 211 | |
| 212 | bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { |
| 213 | if (!NestedLoc.getNestedNameSpecifier()->getAsType()) |
| 214 | return true; |
| 215 | if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc())) |
| 216 | return true; |
| 217 | |
| 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()}; |
| 225 | RenameInfos.push_back(Info); |
| 226 | } |
| 227 | } |
| 228 | return true; |
| 229 | } |
| 230 | |
| 231 | bool VisitTypeLoc(TypeLoc Loc) { |
| 232 | if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc)) |
| 233 | return true; |
| 234 | |
| 235 | auto Parents = Context.getParents(Loc); |
| 236 | TypeLoc ParentTypeLoc; |
| 237 | if (!Parents.empty()) { |
| 238 | // Handle cases of nested name specificier locations. |
| 239 | // |
| 240 | // The VisitNestedNameSpecifierLoc interface is not impelmented in |
| 241 | // RecursiveASTVisitor, we have to handle it explicitly. |
| 242 | if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) { |
| 243 | VisitNestedNameSpecifierLocations(*NSL); |
| 244 | return true; |
| 245 | } |
| 246 | |
| 247 | if (const auto *TL = Parents[0].get<TypeLoc>()) |
| 248 | ParentTypeLoc = *TL; |
| 249 | } |
| 250 | |
| 251 | // Handle the outermost TypeLoc which is directly linked to the interesting |
| 252 | // declaration and don't handle nested name specifier locations. |
| 253 | if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) { |
| 254 | if (isInUSRSet(TargetDecl)) { |
| 255 | // Only handle the outermost typeLoc. |
| 256 | // |
| 257 | // For a type like "a::Foo", there will be two typeLocs for it. |
| 258 | // One ElaboratedType, the other is RecordType: |
| 259 | // |
| 260 | // ElaboratedType 0x33b9390 'a::Foo' sugar |
| 261 | // `-RecordType 0x338fef0 'class a::Foo' |
| 262 | // `-CXXRecord 0x338fe58 'Foo' |
| 263 | // |
| 264 | // Skip if this is an inner typeLoc. |
| 265 | if (!ParentTypeLoc.isNull() && |
| 266 | isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) |
| 267 | return true; |
| 268 | RenameInfo Info = {StartLocationForType(Loc), EndLocationForType(Loc), |
| 269 | TargetDecl, getClosestAncestorDecl(Loc), |
| 270 | GetNestedNameForType(Loc)}; |
| 271 | RenameInfos.push_back(Info); |
| 272 | return true; |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | // Handle specific template class specialiation cases. |
| 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; |
| 283 | } |
| 284 | |
| 285 | if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) { |
| 286 | TypeLoc TargetLoc = Loc; |
| 287 | // FIXME: Find a better way to handle this case. |
| 288 | // For the qualified template class specification type like |
| 289 | // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc |
| 290 | // (ElaboratedType) of the TemplateSpecializationType in order to |
| 291 | // catch the prefix qualifiers "ns::". |
| 292 | if (!ParentTypeLoc.isNull() && |
| 293 | llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) |
| 294 | TargetLoc = ParentTypeLoc; |
| 295 | RenameInfo Info = { |
| 296 | StartLocationForType(TargetLoc), EndLocationForType(TargetLoc), |
| 297 | TemplateSpecType->getTemplateName().getAsTemplateDecl(), |
| 298 | getClosestAncestorDecl( |
| 299 | ast_type_traits::DynTypedNode::create(TargetLoc)), |
| 300 | GetNestedNameForType(TargetLoc)}; |
| 301 | RenameInfos.push_back(Info); |
| 302 | } |
| 303 | } |
| 304 | return true; |
| 305 | } |
| 306 | |
| 307 | // Returns a list of RenameInfo. |
| 308 | const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; } |
| 309 | |
| 310 | // Returns a list of using declarations which are needed to update. |
| 311 | const std::vector<const UsingDecl *> &getUsingDecls() const { |
| 312 | return UsingDecls; |
| 313 | } |
| 314 | |
| 315 | private: |
| 316 | // FIXME: This method may not be suitable for renaming other types like alias |
| 317 | // types. Need to figure out a way to handle it. |
| 318 | bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const { |
| 319 | while (!TL.isNull()) { |
| 320 | // SubstTemplateTypeParm is the TypeLocation class for a substituted type |
| 321 | // inside a template expansion so we ignore these. For example: |
| 322 | // |
| 323 | // template<typename T> struct S { |
| 324 | // T t; // <-- this T becomes a TypeLoc(int) with class |
| 325 | // // SubstTemplateTypeParm when S<int> is instantiated |
| 326 | // } |
| 327 | if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm) |
| 328 | return true; |
| 329 | |
| 330 | // Typedef is the TypeLocation class for a type which is a typedef to the |
| 331 | // type we want to replace. We ignore the use of the typedef as we will |
| 332 | // replace the definition of it. For example: |
| 333 | // |
| 334 | // typedef int T; |
| 335 | // T a; // <--- This T is a TypeLoc(int) with class Typedef. |
| 336 | if (TL.getTypeLocClass() == TypeLoc::Typedef) |
| 337 | return true; |
| 338 | TL = TL.getNextTypeLoc(); |
| 339 | } |
| 340 | return false; |
| 341 | } |
| 342 | |
| 343 | // Get the supported declaration from a given typeLoc. If the declaration type |
| 344 | // is not supported, returns nullptr. |
| 345 | // |
| 346 | // FIXME: support more types, e.g. enum, type alias. |
| 347 | const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { |
| 348 | if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) |
| 349 | return RD; |
| 350 | return nullptr; |
| 351 | } |
| 352 | |
| 353 | // Get the closest ancester which is a declaration of a given AST node. |
| 354 | template <typename ASTNodeType> |
Haojian Wu | 43ba525 | 2017-04-04 09:53:55 +0000 | [diff] [blame] | 355 | const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { |
Haojian Wu | 74f823a | 2017-04-04 09:30:06 +0000 | [diff] [blame] | 356 | auto Parents = Context.getParents(Node); |
| 357 | // FIXME: figure out how to handle it when there are multiple parents. |
| 358 | if (Parents.size() != 1) |
| 359 | return nullptr; |
| 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]); |
| 364 | } |
| 365 | |
| 366 | // Get the parent typeLoc of a given typeLoc. If there is no such parent, |
| 367 | // return nullptr. |
| 368 | const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { |
| 369 | auto Parents = Context.getParents(Loc); |
| 370 | // FIXME: figure out how to handle it when there are multiple parents. |
| 371 | if (Parents.size() != 1) |
| 372 | return nullptr; |
| 373 | return Parents[0].get<TypeLoc>(); |
| 374 | } |
| 375 | |
| 376 | // Check whether the USR of a given Decl is in the USRSet. |
| 377 | bool isInUSRSet(const Decl *Decl) const { |
| 378 | auto USR = getUSRForDecl(Decl); |
| 379 | if (USR.empty()) |
| 380 | return false; |
| 381 | return llvm::is_contained(USRSet, USR); |
| 382 | } |
| 383 | |
| 384 | const std::set<std::string> USRSet; |
| 385 | ASTContext &Context; |
| 386 | std::vector<RenameInfo> RenameInfos; |
| 387 | // Record all interested using declarations which contains the using-shadow |
| 388 | // declarations of the symbol declarations being renamed. |
| 389 | std::vector<const UsingDecl *> UsingDecls; |
| 390 | }; |
| 391 | |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 392 | } // namespace |
| 393 | |
Kirill Bobyrev | 83d5d56 | 2016-07-29 10:16:45 +0000 | [diff] [blame] | 394 | std::vector<SourceLocation> |
| 395 | getLocationsOfUSRs(const std::vector<std::string> &USRs, StringRef PrevName, |
| 396 | Decl *Decl) { |
| 397 | USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); |
Kirill Bobyrev | 32db769 | 2016-07-15 11:29:16 +0000 | [diff] [blame] | 398 | Visitor.TraverseDecl(Decl); |
| 399 | return Visitor.getLocationsFound(); |
Manuel Klimek | de23726 | 2014-08-20 01:39:05 +0000 | [diff] [blame] | 400 | } |
| 401 | |
Haojian Wu | 74f823a | 2017-04-04 09:30:06 +0000 | [diff] [blame] | 402 | std::vector<tooling::AtomicChange> |
| 403 | createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, |
| 404 | llvm::StringRef NewName, Decl *TranslationUnitDecl) { |
| 405 | RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); |
| 406 | Finder.TraverseDecl(TranslationUnitDecl); |
| 407 | |
| 408 | const SourceManager &SM = |
| 409 | TranslationUnitDecl->getASTContext().getSourceManager(); |
| 410 | |
| 411 | std::vector<tooling::AtomicChange> AtomicChanges; |
| 412 | auto Replace = [&](SourceLocation Start, SourceLocation End, |
| 413 | llvm::StringRef Text) { |
| 414 | tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); |
| 415 | llvm::Error Err = ReplaceChange.replace( |
| 416 | SM, CharSourceRange::getTokenRange(Start, End), Text); |
| 417 | if (Err) { |
| 418 | llvm::errs() << "Faile to add replacement to AtomicChange: " |
| 419 | << llvm::toString(std::move(Err)) << "\n"; |
| 420 | return; |
| 421 | } |
| 422 | AtomicChanges.push_back(std::move(ReplaceChange)); |
| 423 | }; |
| 424 | |
| 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())) { |
| 430 | ReplacedName = tooling::replaceNestedName( |
| 431 | RenameInfo.Specifier, RenameInfo.Context->getDeclContext(), |
| 432 | RenameInfo.FromDecl, |
| 433 | NewName.startswith("::") ? NewName.str() : ("::" + NewName).str()); |
| 434 | } |
| 435 | } |
| 436 | // If the NewName contains leading "::", add it back. |
| 437 | if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) |
| 438 | ReplacedName = NewName.str(); |
| 439 | Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); |
| 440 | } |
| 441 | |
| 442 | // Hanlde using declarations explicitly as "using a::Foo" don't trigger |
| 443 | // typeLoc for "a::Foo". |
| 444 | for (const auto *Using : Finder.getUsingDecls()) |
| 445 | Replace(Using->getLocStart(), Using->getLocEnd(), "using " + NewName.str()); |
| 446 | |
| 447 | return AtomicChanges; |
| 448 | } |
| 449 | |
Alex Lorenz | 4abbd92 | 2017-06-30 16:36:09 +0000 | [diff] [blame] | 450 | } // end namespace tooling |
| 451 | } // end namespace clang |