clang: lib/Tooling/Refactoring/Rename/USRLocFinder.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

28#include "llvm/ADT/StringRef.h"

29#include "llvm/Support/Casting.h"

30#include

31#include

32#include

33#include

34

35using namespace llvm;

36

39

40namespace {

41

42

43

44bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) {

46 return false;

47 const clang::FullSourceLoc FullLoc(Loc, SM);

48 auto FileIdAndOffset = FullLoc.getSpellingLoc().getDecomposedLoc();

49 return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr;

50}

51

52

53

54class USRLocFindingASTVisitor

56public:

57 explicit USRLocFindingASTVisitor(const std::vectorstd::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 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

73 if (Loc.isMacroID())

74 Loc = SM.getSpellingLoc(Loc);

75 checkAndAddLocation(Loc);

76 }

77 return true;

78 }

79

80

81

82

83

84 SymbolOccurrences takeOccurrences() { return std::move(Occurrences); }

85

86private:

87 void checkAndAddLocation(SourceLocation Loc) {

88 const SourceLocation BeginLoc = Loc;

90 BeginLoc, 0, Context.getSourceManager(), Context.getLangOpts());

91 StringRef TokenName =

93 Context.getSourceManager(), Context.getLangOpts());

94 size_t Offset = TokenName.find(PrevName.getNamePieces()[0]);

95

96

97

98 if (Offset != StringRef::npos)

100 BeginLoc.getLocWithOffset(Offset));

101 }

102

103 const std::setstd::string USRSet;

104 const SymbolName PrevName;

106 const ASTContext &Context;

107};

108

109SourceLocation StartLocationForType(TypeLoc TL) {

110 if (auto QTL = TL.getAs())

111 TL = QTL.getUnqualifiedLoc();

112

113

114

115 switch (TL.getTypeLocClass()) {

116 case TypeLoc::Record:

117 case TypeLoc::InjectedClassName:

118 case TypeLoc::Enum: {

119 auto TTL = TL.castAs();

120 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())

121 return QualifierLoc.getBeginLoc();

122 return TTL.getNameLoc();

123 }

124 case TypeLoc::Typedef: {

125 auto TTL = TL.castAs();

126 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())

127 return QualifierLoc.getBeginLoc();

128 return TTL.getNameLoc();

129 }

130 case TypeLoc::UnresolvedUsing: {

131 auto TTL = TL.castAs();

132 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())

133 return QualifierLoc.getBeginLoc();

134 return TTL.getNameLoc();

135 }

136 case TypeLoc::Using: {

137 auto TTL = TL.castAs();

138 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())

139 return QualifierLoc.getBeginLoc();

140 return TTL.getNameLoc();

141 }

142 case TypeLoc::TemplateSpecialization: {

143 auto TTL = TL.castAs();

144 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())

145 return QualifierLoc.getBeginLoc();

146 return TTL.getTemplateNameLoc();

147 }

148 case TypeLoc::DeducedTemplateSpecialization: {

149 auto DTL = TL.castAsclang::DeducedTemplateSpecializationTypeLoc();

150 if (NestedNameSpecifierLoc QualifierLoc = DTL.getQualifierLoc())

151 return QualifierLoc.getBeginLoc();

152 return DTL.getTemplateNameLoc();

153 }

154 case TypeLoc::DependentName: {

155 auto TTL = TL.castAs();

156 if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc())

157 return QualifierLoc.getBeginLoc();

158 return TTL.getNameLoc();

159 }

160 default:

161 llvm_unreachable("unhandled TypeLoc class");

162 }

163}

164

165SourceLocation EndLocationForType(TypeLoc TL) {

166 if (auto QTL = TL.getAs())

167 TL = QTL.getUnqualifiedLoc();

168

169

170

171

172 if (auto TTL = TL.getAs())

173 return TTL.getLAngleLoc().getLocWithOffset(-1);

174 return TL.getEndLoc();

175}

176

177NestedNameSpecifier GetNestedNameForType(TypeLoc TL) {

178 if (auto QTL = TL.getAs())

179 TL = QTL.getUnqualifiedLoc();

180 return TL.getPrefix().getNestedNameSpecifier();

181}

182

183

184

185

186

187class RenameLocFinder : public RecursiveASTVisitor {

188public:

189 RenameLocFinder(llvm::ArrayRefstd::string USRs, ASTContext &Context)

190 : USRSet(USRs.begin(), USRs.end()), Context(Context) {}

191

192

193

194 struct RenameInfo {

195

196 SourceLocation Begin;

197

198 SourceLocation End;

199

200 const NamedDecl *FromDecl;

201

202 const Decl *Context;

203

204 NestedNameSpecifier Specifier;

205

206

207

208

209

210 bool IgnorePrefixQualifiers;

211 };

212

213 bool VisitNamedDecl(const NamedDecl *Decl) {

214

215 if (llvm::isa(Decl))

216 return true;

217

218

219 if (llvm::isa(Decl))

220 return true;

221

222 if (Decl->isImplicit())

223 return true;

224

225 if (isInUSRSet(Decl)) {

226

227

228 if (const auto* TAT = dyn_cast(Decl))

229 Decl = TAT->getTemplatedDecl();

230

231 auto StartLoc = Decl->getLocation();

232 auto EndLoc = StartLoc;

233 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {

234 RenameInfo Info = {StartLoc,

235 EndLoc,

236 nullptr,

237 nullptr,

238 std::nullopt,

239 true};

240 RenameInfos.push_back(Info);

241 }

242 }

243 return true;

244 }

245

246 bool VisitMemberExpr(const MemberExpr *Expr) {

247 const NamedDecl *Decl = Expr->getFoundDecl();

248 auto StartLoc = Expr->getMemberLoc();

249 auto EndLoc = Expr->getMemberLoc();

250 if (isInUSRSet(Decl)) {

251 RenameInfos.push_back({StartLoc, EndLoc,

252 nullptr,

253 nullptr,

254 std::nullopt,

255 true});

256 }

257 return true;

258 }

259

260 bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) {

261 for (const DesignatedInitExpr::Designator &D : E->designators()) {

262 if (D.isFieldDesignator()) {

263 if (const FieldDecl *Decl = D.getFieldDecl()) {

264 if (isInUSRSet(Decl)) {

265 auto StartLoc = D.getFieldLoc();

266 auto EndLoc = D.getFieldLoc();

267 RenameInfos.push_back({StartLoc, EndLoc,

268 nullptr,

269 nullptr,

270 std::nullopt,

271 true});

272 }

273 }

274 }

275 }

276 return true;

277 }

278

279 bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) {

280

281 for (const auto *Initializer : CD->inits()) {

282

284 continue;

285

286 if (const FieldDecl *FD = Initializer->getMember()) {

287 if (isInUSRSet(FD)) {

288 auto Loc = Initializer->getSourceLocation();

289 RenameInfos.push_back({Loc, Loc,

290 nullptr,

291 nullptr,

292 std::nullopt,

293 true});

294 }

295 }

296 }

297 return true;

298 }

299

300 bool VisitDeclRefExpr(const DeclRefExpr *Expr) {

301 const NamedDecl *Decl = Expr->getFoundDecl();

302

303

304 if (auto *UsingShadow = llvm::dyn_cast(Decl)) {

305 Decl = UsingShadow->getTargetDecl();

306 }

307

308 auto StartLoc = Expr->getBeginLoc();

309

310

311 SourceLocation EndLoc = Expr->hasExplicitTemplateArgs()

312 ? Expr->getLAngleLoc().getLocWithOffset(-1)

313 : Expr->getEndLoc();

314

315 if (const auto *MD = llvm::dyn_cast(Decl)) {

316 if (isInUSRSet(MD)) {

317

318

319

320 RenameInfos.push_back({EndLoc, EndLoc,

321 nullptr,

322 nullptr,

323 std::nullopt,

324 true});

325 return true;

326 }

327 }

328

329

330

331

332

333

334 if (const auto *T = llvm::dyn_cast(Decl)) {

335

336

337 if (!Expr->hasQualifier())

338 return true;

339

340 if (const auto *ED =

341 llvm::dyn_cast_or_null(getClosestAncestorDecl(*T))) {

342 if (ED->isScoped())

343 return true;

345 }

346

347

348

349

350

351

352

353

354

355

356 EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1);

357 assert(EndLoc.isValid() &&

358 "The enum constant should have prefix qualifers.");

359 }

360 if (isInUSRSet(Decl) &&

361 IsValidEditLoc(Context.getSourceManager(), StartLoc)) {

362 RenameInfo Info = {StartLoc,

363 EndLoc,

365 getClosestAncestorDecl(*Expr),

366 Expr->getQualifier(),

367 false};

368 RenameInfos.push_back(Info);

369 }

370

371 return true;

372 }

373

374 bool VisitUsingDecl(const UsingDecl *Using) {

375 for (const auto *UsingShadow : Using->shadows()) {

376 if (isInUSRSet(UsingShadow->getTargetDecl())) {

377 UsingDecls.push_back(Using);

378 break;

379 }

380 }

381 return true;

382 }

383

384 bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) {

385 TypeLoc TL = NestedLoc.getAsTypeLoc();

386 if (!TL)

387 return true;

388

389 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(TL)) {

390 if (isInUSRSet(TargetDecl)) {

391 RenameInfo Info = {NestedLoc.getBeginLoc(),

392 EndLocationForType(TL),

393 TargetDecl,

394 getClosestAncestorDecl(NestedLoc),

395 std::nullopt,

396 false};

397 RenameInfos.push_back(Info);

398 }

399 }

400 return true;

401 }

402

403 bool VisitTypeLoc(TypeLoc Loc) {

404 auto Parents = Context.getParents(Loc);

405 TypeLoc ParentTypeLoc;

406 if (!Parents.empty()) {

407

408

409

410

411 if (const auto *NSL = Parents[0].get()) {

412 VisitNestedNameSpecifierLocations(*NSL);

413 return true;

414 }

415

416 if (const auto *TL = Parents[0].get())

417 ParentTypeLoc = *TL;

418 }

419

420

421

422 if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(Loc)) {

423 if (isInUSRSet(TargetDecl)) {

424

425

426

427

428

429

430

431

432

433

434 if (!ParentTypeLoc.isNull() &&

435 isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc)))

436 return true;

437

438 auto StartLoc = StartLocationForType(Loc);

439 auto EndLoc = EndLocationForType(Loc);

440 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {

441 RenameInfo Info = {StartLoc,

442 EndLoc,

443 TargetDecl,

444 getClosestAncestorDecl(Loc),

445 GetNestedNameForType(Loc),

446 false};

447 RenameInfos.push_back(Info);

448 }

449 return true;

450 }

451 }

452

453

454 if (const auto *TemplateSpecType =

455 dyn_cast(Loc.getType())) {

456 if (isInUSRSet(TemplateSpecType->getTemplateName().getAsTemplateDecl())) {

457 auto StartLoc = StartLocationForType(Loc);

458 auto EndLoc = EndLocationForType(Loc);

459 if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) {

460 RenameInfo Info = {

461 StartLoc,

462 EndLoc,

463 TemplateSpecType->getTemplateName().getAsTemplateDecl(),

465 GetNestedNameForType(Loc),

466 false};

467 RenameInfos.push_back(Info);

468 }

469 }

470 }

471 return true;

472 }

473

474

475 const std::vector &getRenameInfos() const { return RenameInfos; }

476

477

478 const std::vector<const UsingDecl *> &getUsingDecls() const {

479 return UsingDecls;

480 }

481

482private:

483

484

485 const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) {

486 if (const auto* TT = Loc.getType()->getAsclang::TypedefType())

487 return TT->getDecl();

488 return Loc.getType()->getAsTagDecl();

489 }

490

491

492 template

493 const Decl *getClosestAncestorDecl(const ASTNodeType &Node) {

494 auto Parents = Context.getParents(Node);

495

496 if (Parents.size() != 1)

497 return nullptr;

499 return Parents[0].template get();

500 return getClosestAncestorDecl(Parents[0]);

501 }

502

503

504

505 const TypeLoc *getParentTypeLoc(TypeLoc Loc) const {

506 auto Parents = Context.getParents(Loc);

507

508 if (Parents.size() != 1)

509 return nullptr;

510 return Parents[0].get();

511 }

512

513

514 bool isInUSRSet(const Decl *Decl) const {

516 if (USR.empty())

517 return false;

518 return llvm::is_contained(USRSet, USR);

519 }

520

521 const std::setstd::string USRSet;

522 ASTContext &Context;

523 std::vector RenameInfos;

524

525

526 std::vector<const UsingDecl *> UsingDecls;

527};

528

529}

530

532 StringRef PrevName, Decl *Decl) {

533 USRLocFindingASTVisitor Visitor(USRs, PrevName, Decl->getASTContext());

534 Visitor.TraverseDecl(Decl);

535 return Visitor.takeOccurrences();

536}

537

538std::vectortooling::AtomicChange

543

546

547 std::vectortooling::AtomicChange AtomicChanges;

549 llvm::StringRef Text) {

551 llvm::Error Err = ReplaceChange.replace(

553 if (Err) {

554 llvm::errs() << "Failed to add replacement to AtomicChange: "

555 << llvm::toString(std::move(Err)) << "\n";

556 return;

557 }

558 AtomicChanges.push_back(std::move(ReplaceChange));

559 };

560

561 for (const auto &RenameInfo : Finder.getRenameInfos()) {

562 std::string ReplacedName = NewName.str();

563 if (RenameInfo.IgnorePrefixQualifiers) {

564

565 size_t LastColonPos = NewName.find_last_of(':');

566 if (LastColonPos != std:🧵:npos)

567 ReplacedName = std::string(NewName.substr(LastColonPos + 1));

568 } else {

569 if (RenameInfo.FromDecl && RenameInfo.Context) {

570 if (!llvm::isaclang::TranslationUnitDecl(

571 RenameInfo.Context->getDeclContext())) {

573 RenameInfo.Specifier, RenameInfo.Begin,

574 RenameInfo.Context->getDeclContext(), RenameInfo.FromDecl,

575 NewName.starts_with("::") ? NewName.str()

576 : ("::" + NewName).str());

577 } else {

578

579

580

581

582

583

584

587 SourceRange(RenameInfo.Begin, RenameInfo.End)),

589

590

591 if (ActualName.starts_with("::") && !NewName.starts_with("::")) {

592 ReplacedName = "::" + NewName.str();

593 }

594 }

595 }

596

597 if (NewName.starts_with("::") && NewName.substr(2) == ReplacedName)

598 ReplacedName = NewName.str();

599 }

600 Replace(RenameInfo.Begin, RenameInfo.End, ReplacedName);

601 }

602

603

604

605 for (const auto *Using : Finder.getUsingDecls())

606 Replace(Using->getBeginLoc(), Using->getEndLoc(), "using " + NewName.str());

607

609}

610

611}

612}

Defines the clang::ASTContext interface.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

A wrapper class around RecursiveASTVisitor that visits each occurrences of a named symbol.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

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.

SourceManager & getSourceManager()

const LangOptions & getLangOpts() const

static constexpr ASTNodeKind getFromNodeKind()

Construct an identifier for T.

static CharSourceRange getTokenRange(SourceRange R)

Decl - This represents one declaration (or definition), e.g.

ASTContext & getASTContext() const LLVM_READONLY

static DynTypedNode create(const T &Node)

Creates a DynTypedNode from Node.

static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)

Returns a string for the source that the range encompasses.

static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)

Computes the source location just past the end of the token at this source location.

Encodes a location in the source.

This class handles loading and caching of source files into memory.

A trivial tuple used to represent a source range.

The top declaration context.

ASTContext & getASTContext() const

std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl

All declarations that can appear in a module declaration.

The JSON file list parser is used to communicate input to InstallAPI.

const FunctionProtoType * T

Diagnostic wrappers for TextAPI types for error reporting.