Coverage Report

Created: 2023-11-11 10:31

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