1 //===--- USRLocFinder.cpp - Clang refactoring library ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Methods for finding all instances of a USR. Our strategy is very 11 /// simple; we just compare the USR at every relevant AST node with the one 12 /// provided. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h" 17 #include "clang/AST/ASTContext.h" 18 #include "clang/AST/RecursiveASTVisitor.h" 19 #include "clang/Basic/LLVM.h" 20 #include "clang/Basic/SourceLocation.h" 21 #include "clang/Basic/SourceManager.h" 22 #include "clang/Lex/Lexer.h" 23 #include "clang/Tooling/Core/Lookup.h" 24 #include "clang/Tooling/Refactoring/RecursiveSymbolVisitor.h" 25 #include "clang/Tooling/Refactoring/Rename/SymbolName.h" 26 #include "clang/Tooling/Refactoring/Rename/USRFinder.h" 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/Support/Casting.h" 29 #include <cstddef> 30 #include <set> 31 #include <string> 32 #include <vector> 33 34 using namespace llvm; 35 36 namespace clang { 37 namespace tooling { 38 39 namespace { 40 41 // Returns true if the given Loc is valid for edit. We don't edit the 42 // SourceLocations that are valid or in temporary buffer. 43 bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) { 44 if (Loc.isInvalid()) 45 return false; 46 const clang::FullSourceLoc FullLoc(Loc, SM); 47 std::pair<clang::FileID, unsigned> FileIdAndOffset = 48 FullLoc.getSpellingLoc().getDecomposedLoc(); 49 return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr; 50 } 51 52 // This visitor recursively searches for all instances of a USR in a 53 // translation unit and stores them for later usage. 54 class USRLocFindingASTVisitor 55 : public RecursiveSymbolVisitor<USRLocFindingASTVisitor> { 56 public: 57 explicit USRLocFindingASTVisitor(const std::vector<std::string> &USRs, 58 StringRef PrevName, 59 const ASTContext &Context) 60 : RecursiveSymbolVisitor(Context.getSourceManager(), 61 Context.getLangOpts()), 62 USRSet(USRs.begin(), USRs.end()), PrevName(PrevName), Context(Context) { 63 } 64 65 bool visitSymbolOccurrence(const NamedDecl *ND, 66 ArrayRef<SourceRange> NameRanges) { 67 if (USRSet.find(getUSRForDecl(ND)) != USRSet.end()) { 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(); 72 // TODO: Deal with macro occurrences correctly. 73 if (Loc.isMacroID()) 74 Loc = SM.getSpellingLoc(Loc); 75 checkAndAddLocation(Loc); 76 } 77 return true; 78 } 79 80 // Non-visitors: 81 82 /// Returns a set of unique symbol occurrences. Duplicate or 83 /// overlapping occurrences are erroneous and should be reported! 84 SymbolOccurrences takeOccurrences() { return std::move(Occurrences); } 85 86 private: 87 void checkAndAddLocation(SourceLocation Loc) { 88 const SourceLocation BeginLoc = Loc; 89 const SourceLocation EndLoc = Lexer::getLocForEndOfToken( 90 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts()); 91 StringRef TokenName = 92 Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), 93 Context.getSourceManager(), Context.getLangOpts()); 94 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]); 95 96 // The token of the source location we find actually has the old 97 // name. 98 if (Offset != StringRef::npos) 99 Occurrences.emplace_back(PrevName, SymbolOccurrence::MatchingSymbol, 100 BeginLoc.getLocWithOffset(Offset)); 101 } 102 103 const std::set<std::string> USRSet; 104 const SymbolName PrevName; 105 SymbolOccurrences Occurrences; 106 const ASTContext &Context; 107 }; 108 109 SourceLocation StartLocationForType(TypeLoc TL) { 110 // For elaborated types (e.g. `struct a::A`) we want the portion after the 111 // `struct` but including the namespace qualifier, `a::`. 112 if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) { 113 NestedNameSpecifierLoc NestedNameSpecifier = 114 ElaboratedTypeLoc.getQualifierLoc(); 115 if (NestedNameSpecifier.getNestedNameSpecifier()) 116 return NestedNameSpecifier.getBeginLoc(); 117 TL = TL.getNextTypeLoc(); 118 } 119 return TL.getBeginLoc(); 120 } 121 122 SourceLocation EndLocationForType(TypeLoc TL) { 123 // Dig past any namespace or keyword qualifications. 124 while (TL.getTypeLocClass() == TypeLoc::Elaborated || 125 TL.getTypeLocClass() == TypeLoc::Qualified) 126 TL = TL.getNextTypeLoc(); 127 128 // The location for template specializations (e.g. Foo<int>) includes the 129 // templated types in its location range. We want to restrict this to just 130 // before the `<` character. 131 if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { 132 return TL.castAs<TemplateSpecializationTypeLoc>() 133 .getLAngleLoc() 134 .getLocWithOffset(-1); 135 } 136 return TL.getEndLoc(); 137 } 138 139 NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { 140 // Dig past any keyword qualifications. 141 while (TL.getTypeLocClass() == TypeLoc::Qualified) 142 TL = TL.getNextTypeLoc(); 143 144 // For elaborated types (e.g. `struct a::A`) we want the portion after the 145 // `struct` but including the namespace qualifier, `a::`. 146 if (auto ElaboratedTypeLoc = TL.getAs<clang::ElaboratedTypeLoc>()) 147 return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); 148 return nullptr; 149 } 150 151 // Find all locations identified by the given USRs for rename. 152 // 153 // This class will traverse the AST and find every AST node whose USR is in the 154 // given USRs' set. 155 class RenameLocFinder : public RecursiveASTVisitor<RenameLocFinder> { 156 public: 157 RenameLocFinder(llvm::ArrayRef<std::string> USRs, ASTContext &Context) 158 : USRSet(USRs.begin(), USRs.end()), Context(Context) {} 159 160 // A structure records all information of a symbol reference being renamed. 161 // We try to add as few prefix qualifiers as possible. 162 struct RenameInfo { 163 // The begin location of a symbol being renamed. 164 SourceLocation Begin; 165 // The end location of a symbol being renamed. 166 SourceLocation End; 167 // The declaration of a symbol being renamed (can be nullptr). 168 const NamedDecl *FromDecl; 169 // The declaration in which the nested name is contained (can be nullptr). 170 const Decl *Context; 171 // The nested name being replaced (can be nullptr). 172 const NestedNameSpecifier *Specifier; 173 // Determine whether the prefix qualifiers of the NewName should be ignored. 174 // Normally, we set it to true for the symbol declaration and definition to 175 // avoid adding prefix qualifiers. 176 // For example, if it is true and NewName is "a::b::foo", then the symbol 177 // occurrence which the RenameInfo points to will be renamed to "foo". 178 bool IgnorePrefixQualifers; 179 }; 180 181 bool VisitNamedDecl(const NamedDecl *Decl) { 182 // UsingDecl has been handled in other place. 183 if (llvm::isa<UsingDecl>(Decl)) 184 return true; 185 186 // DestructorDecl has been handled in Typeloc. 187 if (llvm::isa<CXXDestructorDecl>(Decl)) 188 return true; 189 190 if (Decl->isImplicit()) 191 return true; 192 193 if (isInUSRSet(Decl)) { 194 // For the case of renaming an alias template, we actually rename the 195 // underlying alias declaration of the template. 196 if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl)) 197 Decl = TAT->getTemplatedDecl(); 198 199 auto StartLoc = Decl->getLocation(); 200 auto EndLoc = StartLoc; 201 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 202 RenameInfo Info = {StartLoc, 203 EndLoc, 204 /*FromDecl=*/nullptr, 205 /*Context=*/nullptr, 206 /*Specifier=*/nullptr, 207 /*IgnorePrefixQualifers=*/true}; 208 RenameInfos.push_back(Info); 209 } 210 } 211 return true; 212 } 213 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, 220 /*FromDecl=*/nullptr, 221 /*Context=*/nullptr, 222 /*Specifier=*/nullptr, 223 /*IgnorePrefixQualifiers=*/true}); 224 } 225 return true; 226 } 227 228 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { 229 // Fix the constructor initializer when renaming class members. 230 for (const auto *Initializer : CD->inits()) { 231 // Ignore implicit initializers. 232 if (!Initializer->isWritten()) 233 continue; 234 235 if (const FieldDecl *FD = Initializer->getMember()) { 236 if (isInUSRSet(FD)) { 237 auto Loc = Initializer->getSourceLocation(); 238 RenameInfos.push_back({Loc, Loc, 239 /*FromDecl=*/nullptr, 240 /*Context=*/nullptr, 241 /*Specifier=*/nullptr, 242 /*IgnorePrefixQualifiers=*/true}); 243 } 244 } 245 } 246 return true; 247 } 248 249 bool VisitDeclRefExpr(const DeclRefExpr *Expr) { 250 const NamedDecl *Decl = Expr->getFoundDecl(); 251 // Get the underlying declaration of the shadow declaration introduced by a 252 // using declaration. 253 if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { 254 Decl = UsingShadow->getTargetDecl(); 255 } 256 257 auto StartLoc = Expr->getBeginLoc(); 258 // For template function call expressions like `foo<int>()`, we want to 259 // restrict the end of location to just before the `<` character. 260 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs() 261 ? Expr->getLAngleLoc().getLocWithOffset(-1) 262 : Expr->getEndLoc(); 263 264 if (const auto *MD = llvm::dyn_cast<CXXMethodDecl>(Decl)) { 265 if (isInUSRSet(MD)) { 266 // Handle renaming static template class methods, we only rename the 267 // name without prefix qualifiers and restrict the source range to the 268 // name. 269 RenameInfos.push_back({EndLoc, EndLoc, 270 /*FromDecl=*/nullptr, 271 /*Context=*/nullptr, 272 /*Specifier=*/nullptr, 273 /*IgnorePrefixQualifiers=*/true}); 274 return true; 275 } 276 } 277 278 // In case of renaming an enum declaration, we have to explicitly handle 279 // unscoped enum constants referenced in expressions (e.g. 280 // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped 281 // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by 282 // TypeLoc. 283 if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) { 284 // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`) 285 // when renaming an unscoped enum declaration with a new namespace. 286 if (!Expr->hasQualifier()) 287 return true; 288 289 if (const auto *ED = 290 llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) { 291 if (ED->isScoped()) 292 return true; 293 Decl = ED; 294 } 295 // The current fix would qualify "ns1::ns2::Green" as 296 // "ns1::ns2::Color::Green". 297 // 298 // Get the EndLoc of the replacement by moving 1 character backward ( 299 // to exclude the last '::'). 300 // 301 // ns1::ns2::Green; 302 // ^ ^^ 303 // BeginLoc |EndLoc of the qualifier 304 // new EndLoc 305 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1); 306 assert(EndLoc.isValid() && 307 "The enum constant should have prefix qualifers."); 308 } 309 if (isInUSRSet(Decl) && 310 IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 311 RenameInfo Info = {StartLoc, 312 EndLoc, 313 Decl, 314 getClosestAncestorDecl(*Expr), 315 Expr->getQualifier(), 316 /*IgnorePrefixQualifers=*/false}; 317 RenameInfos.push_back(Info); 318 } 319 320 return true; 321 } 322 323 bool VisitUsingDecl(const UsingDecl *Using) { 324 for (const auto *UsingShadow : Using->shadows()) { 325 if (isInUSRSet(UsingShadow->getTargetDecl())) { 326 UsingDecls.push_back(Using); 327 break; 328 } 329 } 330 return true; 331 } 332 333 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { 334 if (!NestedLoc.getNestedNameSpecifier()->getAsType()) 335 return true; 336 337 if (const auto *TargetDecl = 338 getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { 339 if (isInUSRSet(TargetDecl)) { 340 RenameInfo Info = {NestedLoc.getBeginLoc(), 341 EndLocationForType(NestedLoc.getTypeLoc()), 342 TargetDecl, 343 getClosestAncestorDecl(NestedLoc), 344 NestedLoc.getNestedNameSpecifier()->getPrefix(), 345 /*IgnorePrefixQualifers=*/false}; 346 RenameInfos.push_back(Info); 347 } 348 } 349 return true; 350 } 351 352 bool VisitTypeLoc(TypeLoc Loc) { 353 auto Parents = Context.getParents(Loc); 354 TypeLoc ParentTypeLoc; 355 if (!Parents.empty()) { 356 // Handle cases of nested name specificier locations. 357 // 358 // The VisitNestedNameSpecifierLoc interface is not impelmented in 359 // RecursiveASTVisitor, we have to handle it explicitly. 360 if (const auto *NSL = Parents[0].get<NestedNameSpecifierLoc>()) { 361 VisitNestedNameSpecifierLocations(*NSL); 362 return true; 363 } 364 365 if (const auto *TL = Parents[0].get<TypeLoc>()) 366 ParentTypeLoc = *TL; 367 } 368 369 // Handle the outermost TypeLoc which is directly linked to the interesting 370 // declaration and don't handle nested name specifier locations. 371 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) { 372 if (isInUSRSet(TargetDecl)) { 373 // Only handle the outermost typeLoc. 374 // 375 // For a type like "a::Foo", there will be two typeLocs for it. 376 // One ElaboratedType, the other is RecordType: 377 // 378 // ElaboratedType 0x33b9390 'a::Foo' sugar 379 // `-RecordType 0x338fef0 'class a::Foo' 380 // `-CXXRecord 0x338fe58 'Foo' 381 // 382 // Skip if this is an inner typeLoc. 383 if (!ParentTypeLoc.isNull() && 384 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) 385 return true; 386 387 auto StartLoc = StartLocationForType(Loc); 388 auto EndLoc = EndLocationForType(Loc); 389 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 390 RenameInfo Info = {StartLoc, 391 EndLoc, 392 TargetDecl, 393 getClosestAncestorDecl(Loc), 394 GetNestedNameForType(Loc), 395 /*IgnorePrefixQualifers=*/false}; 396 RenameInfos.push_back(Info); 397 } 398 return true; 399 } 400 } 401 402 // Handle specific template class specialiation cases. 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; 409 } 410 411 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) { 412 TypeLoc TargetLoc = Loc; 413 // FIXME: Find a better way to handle this case. 414 // For the qualified template class specification type like 415 // "ns::Foo<int>" in "ns::Foo<int>& f();", we want the parent typeLoc 416 // (ElaboratedType) of the TemplateSpecializationType in order to 417 // catch the prefix qualifiers "ns::". 418 if (!ParentTypeLoc.isNull() && 419 llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) 420 TargetLoc = ParentTypeLoc; 421 422 auto StartLoc = StartLocationForType(TargetLoc); 423 auto EndLoc = EndLocationForType(TargetLoc); 424 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { 425 RenameInfo Info = { 426 StartLoc, 427 EndLoc, 428 TemplateSpecType->getTemplateName().getAsTemplateDecl(), 429 getClosestAncestorDecl( 430 ast_type_traits::DynTypedNode::create(TargetLoc)), 431 GetNestedNameForType(TargetLoc), 432 /*IgnorePrefixQualifers=*/false}; 433 RenameInfos.push_back(Info); 434 } 435 } 436 } 437 return true; 438 } 439 440 // Returns a list of RenameInfo. 441 const std::vector<RenameInfo> &getRenameInfos() const { return RenameInfos; } 442 443 // Returns a list of using declarations which are needed to update. 444 const std::vector<const UsingDecl *> &getUsingDecls() const { 445 return UsingDecls; 446 } 447 448 private: 449 // Get the supported declaration from a given typeLoc. If the declaration type 450 // is not supported, returns nullptr. 451 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { 452 if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>()) 453 return TT->getDecl(); 454 if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) 455 return RD; 456 if (const auto *ED = 457 llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl())) 458 return ED; 459 return nullptr; 460 } 461 462 // Get the closest ancester which is a declaration of a given AST node. 463 template <typename ASTNodeType> 464 const Decl *getClosestAncestorDecl(const ASTNodeType &Node) { 465 auto Parents = Context.getParents(Node); 466 // FIXME: figure out how to handle it when there are multiple parents. 467 if (Parents.size() != 1) 468 return nullptr; 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]); 473 } 474 475 // Get the parent typeLoc of a given typeLoc. If there is no such parent, 476 // return nullptr. 477 const TypeLoc *getParentTypeLoc(TypeLoc Loc) const { 478 auto Parents = Context.getParents(Loc); 479 // FIXME: figure out how to handle it when there are multiple parents. 480 if (Parents.size() != 1) 481 return nullptr; 482 return Parents[0].get<TypeLoc>(); 483 } 484 485 // Check whether the USR of a given Decl is in the USRSet. 486 bool isInUSRSet(const Decl *Decl) const { 487 auto USR = getUSRForDecl(Decl); 488 if (USR.empty()) 489 return false; 490 return llvm::is_contained(USRSet, USR); 491 } 492 493 const std::set<std::string> USRSet; 494 ASTContext &Context; 495 std::vector<RenameInfo> RenameInfos; 496 // Record all interested using declarations which contains the using-shadow 497 // declarations of the symbol declarations being renamed. 498 std::vector<const UsingDecl *> UsingDecls; 499 }; 500 501 } // namespace 502 503 SymbolOccurrences getOccurrencesOfUSRs(ArrayRef<std::string> USRs, 504 StringRef PrevName, Decl *Decl) { 505 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext()); 506 Visitor.TraverseDecl(Decl); 507 return Visitor.takeOccurrences(); 508 } 509 510 std::vector<tooling::AtomicChange> 511 createRenameAtomicChanges(llvm::ArrayRef<std::string> USRs, 512 llvm::StringRef NewName, Decl *TranslationUnitDecl) { 513 RenameLocFinder Finder(USRs, TranslationUnitDecl->getASTContext()); 514 Finder.TraverseDecl(TranslationUnitDecl); 515 516 const SourceManager &SM = 517 TranslationUnitDecl->getASTContext().getSourceManager(); 518 519 std::vector<tooling::AtomicChange> AtomicChanges; 520 auto Replace = [&](SourceLocation Start, SourceLocation End, 521 llvm::StringRef Text) { 522 tooling::AtomicChange ReplaceChange = tooling::AtomicChange(SM, Start); 523 llvm::Error Err = ReplaceChange.replace( 524 SM, CharSourceRange::getTokenRange(Start, End), Text); 525 if (Err) { 526 llvm::errs() << "Failed to add replacement to AtomicChange: " 527 << llvm::toString(std::move(Err)) << "\n"; 528 return; 529 } 530 AtomicChanges.push_back(std::move(ReplaceChange)); 531 }; 532 533 for (const auto &RenameInfo : Finder.getRenameInfos()) { 534 std::string ReplacedName = NewName.str(); 535 if (RenameInfo.IgnorePrefixQualifers) { 536 // Get the name without prefix qualifiers from NewName. 537 size_t LastColonPos = NewName.find_last_of(':'); 538 if (LastColonPos != std::string::npos) 539 ReplacedName = NewName.substr(LastColonPos + 1); 540 } else { 541 if (RenameInfo.FromDecl && RenameInfo.Context) { 542 if (!llvm::isa<clang::TranslationUnitDecl>( 543 RenameInfo.Context->getDeclContext())) { 544 ReplacedName = tooling::replaceNestedName( 545 RenameInfo.Specifier, RenameInfo.Begin, 546 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl, 547 NewName.startswith("::") ? NewName.str() 548 : ("::" + NewName).str()); 549 } else { 550 // This fixes the case where type `T` is a parameter inside a function 551 // type (e.g. `std::function<void(T)>`) and the DeclContext of `T` 552 // becomes the translation unit. As a workaround, we simply use 553 // fully-qualified name here for all references whose `DeclContext` is 554 // the translation unit and ignore the possible existence of 555 // using-decls (in the global scope) that can shorten the replaced 556 // name. 557 llvm::StringRef ActualName = Lexer::getSourceText( 558 CharSourceRange::getTokenRange( 559 SourceRange(RenameInfo.Begin, RenameInfo.End)), 560 SM, TranslationUnitDecl->getASTContext().getLangOpts()); 561 // Add the leading "::" back if the name written in the code contains 562 // it. 563 if (ActualName.startswith("::") && !NewName.startswith("::")) { 564 ReplacedName = "::" + NewName.str(); 565 } 566 } 567 } 568 // If the NewName contains leading "::", add it back. 569 if (NewName.startswith("::") && NewName.substr(2) == ReplacedName) 570 ReplacedName = NewName.str(); 571 } 572 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName); 573 } 574 575 // Hanlde using declarations explicitly as "using a::Foo" don't trigger 576 // typeLoc for "a::Foo". 577 for (const auto *Using : Finder.getUsingDecls()) 578 Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str()); 579 580 return AtomicChanges; 581 } 582 583 } // end namespace tooling 584 } // end namespace clang 585