Coverage Report

Created: 2020-09-22 08:39

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- USRFindingAction.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
/// Provides an action to find USR for the symbol at <offset>, as well as
11
/// all additional USRs.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
16
#include "clang/AST/AST.h"
17
#include "clang/AST/ASTConsumer.h"
18
#include "clang/AST/ASTContext.h"
19
#include "clang/AST/Decl.h"
20
#include "clang/AST/RecursiveASTVisitor.h"
21
#include "clang/Basic/FileManager.h"
22
#include "clang/Frontend/CompilerInstance.h"
23
#include "clang/Frontend/FrontendAction.h"
24
#include "clang/Lex/Lexer.h"
25
#include "clang/Lex/Preprocessor.h"
26
#include "clang/Tooling/CommonOptionsParser.h"
27
#include "clang/Tooling/Refactoring.h"
28
#include "clang/Tooling/Refactoring/Rename/USRFinder.h"
29
#include "clang/Tooling/Tooling.h"
30
31
#include <algorithm>
32
#include <set>
33
#include <string>
34
#include <vector>
35
36
using namespace llvm;
37
38
namespace clang {
39
namespace tooling {
40
41
335
const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl) {
42
335
  if (!FoundDecl)
43
0
    return nullptr;
44
  // If FoundDecl is a constructor or destructor, we want to instead take
45
  // the Decl of the corresponding class.
46
335
  if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl))
47
2
    FoundDecl = CtorDecl->getParent();
48
333
  else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
49
0
    FoundDecl = DtorDecl->getParent();
50
  // FIXME: (Alex L): Canonicalize implicit template instantions, just like
51
  // the indexer does it.
52
53
  // Note: please update the declaration's doc comment every time the
54
  // canonicalization rules are changed.
55
335
  return FoundDecl;
56
335
}
57
58
namespace {
59
// NamedDeclFindingConsumer should delegate finding USRs of given Decl to
60
// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given
61
// Decl refers to class and adds USRs of all overridden methods if Decl refers
62
// to virtual method.
63
class AdditionalUSRFinder : public RecursiveASTVisitor<AdditionalUSRFinder> {
64
public:
65
  AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context)
66
336
      : FoundDecl(FoundDecl), Context(Context) {}
67
68
336
  std::vector<std::string> Find() {
69
    // Fill OverriddenMethods and PartialSpecs storages.
70
336
    TraverseAST(Context);
71
336
    if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) {
72
40
      addUSRsOfOverridenFunctions(MethodDecl);
73
84
      for (const auto &OverriddenMethod : OverriddenMethods) {
74
84
        if (checkIfOverriddenFunctionAscends(OverriddenMethod))
75
30
          USRSet.insert(getUSRForDecl(OverriddenMethod));
76
84
      }
77
40
      addUSRsOfInstantiatedMethods(MethodDecl);
78
296
    } else if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(FoundDecl)) {
79
120
      handleCXXRecordDecl(RecordDecl);
80
176
    } else if (const auto *TemplateDecl =
81
23
                   dyn_cast<ClassTemplateDecl>(FoundDecl)) {
82
23
      handleClassTemplateDecl(TemplateDecl);
83
153
    } else {
84
153
      USRSet.insert(getUSRForDecl(FoundDecl));
85
153
    }
86
336
    return std::vector<std::string>(USRSet.begin(), USRSet.end());
87
336
  }
88
89
554
  bool shouldVisitTemplateInstantiations() const { return true; }
90
91
1.35k
  bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) {
92
1.35k
    if (MethodDecl->isVirtual())
93
114
      OverriddenMethods.push_back(MethodDecl);
94
1.35k
    if (MethodDecl->getInstantiatedFromMemberFunction())
95
101
      InstantiatedMethods.push_back(MethodDecl);
96
1.35k
    return true;
97
1.35k
  }
98
99
  bool VisitClassTemplatePartialSpecializationDecl(
100
1
      const ClassTemplatePartialSpecializationDecl *PartialSpec) {
101
1
    PartialSpecs.push_back(PartialSpec);
102
1
    return true;
103
1
  }
104
105
private:
106
120
  void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
107
120
    if (!RecordDecl->getDefinition()) {
108
1
      USRSet.insert(getUSRForDecl(RecordDecl));
109
1
      return;
110
1
    }
111
119
    RecordDecl = RecordDecl->getDefinition();
112
119
    if (const auto *ClassTemplateSpecDecl =
113
0
            dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
114
0
      handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate());
115
119
    addUSRsOfCtorDtors(RecordDecl);
116
119
  }
117
118
23
  void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) {
119
23
    for (const auto *Specialization : TemplateDecl->specializations())
120
31
      addUSRsOfCtorDtors(Specialization);
121
122
0
    for (const auto *PartialSpec : PartialSpecs) {
123
0
      if (PartialSpec->getSpecializedTemplate() == TemplateDecl)
124
0
        addUSRsOfCtorDtors(PartialSpec);
125
0
    }
126
23
    addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl());
127
23
  }
128
129
173
  void addUSRsOfCtorDtors(const CXXRecordDecl *RD) {
130
173
    const auto* RecordDecl = RD->getDefinition();
131
132
    // Skip if the CXXRecordDecl doesn't have definition.
133
173
    if (!RecordDecl) {
134
6
      USRSet.insert(getUSRForDecl(RD));
135
6
      return;
136
6
    }
137
138
167
    for (const auto *CtorDecl : RecordDecl->ctors())
139
210
      USRSet.insert(getUSRForDecl(CtorDecl));
140
    // Add template constructor decls, they are not in ctors() unfortunately.
141
167
    if (RecordDecl->hasUserDeclaredConstructor())
142
16
      for (const auto *D : RecordDecl->decls())
143
147
        if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
144
2
          if (const auto *Ctor =
145
2
                  dyn_cast<CXXConstructorDecl>(FTD->getTemplatedDecl()))
146
2
            USRSet.insert(getUSRForDecl(Ctor));
147
148
167
    USRSet.insert(getUSRForDecl(RecordDecl->getDestructor()));
149
167
    USRSet.insert(getUSRForDecl(RecordDecl));
150
167
  }
151
152
53
  void addUSRsOfOverridenFunctions(const CXXMethodDecl *MethodDecl) {
153
53
    USRSet.insert(getUSRForDecl(MethodDecl));
154
    // Recursively visit each OverridenMethod.
155
53
    for (const auto &OverriddenMethod : MethodDecl->overridden_methods())
156
13
      addUSRsOfOverridenFunctions(OverriddenMethod);
157
53
  }
158
159
40
  void addUSRsOfInstantiatedMethods(const CXXMethodDecl *MethodDecl) {
160
    // For renaming a class template method, all references of the instantiated
161
    // member methods should be renamed too, so add USRs of the instantiated
162
    // methods to the USR set.
163
40
    USRSet.insert(getUSRForDecl(MethodDecl));
164
40
    if (const auto *FT = MethodDecl->getInstantiatedFromMemberFunction())
165
3
      USRSet.insert(getUSRForDecl(FT));
166
44
    for (const auto *Method : InstantiatedMethods) {
167
44
      if (USRSet.find(getUSRForDecl(
168
44
              Method->getInstantiatedFromMemberFunction())) != USRSet.end())
169
20
        USRSet.insert(getUSRForDecl(Method));
170
44
    }
171
40
  }
172
173
105
  bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) {
174
51
    for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) {
175
51
      if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end())
176
30
        return true;
177
21
      return checkIfOverriddenFunctionAscends(OverriddenMethod);
178
21
    }
179
54
    return false;
180
105
  }
181
182
  const Decl *FoundDecl;
183
  ASTContext &Context;
184
  std::set<std::string> USRSet;
185
  std::vector<const CXXMethodDecl *> OverriddenMethods;
186
  std::vector<const CXXMethodDecl *> InstantiatedMethods;
187
  std::vector<const ClassTemplatePartialSpecializationDecl *> PartialSpecs;
188
};
189
} // namespace
190
191
std::vector<std::string> getUSRsForDeclaration(const NamedDecl *ND,
192
13
                                               ASTContext &Context) {
193
13
  AdditionalUSRFinder Finder(ND, Context);
194
13
  return Finder.Find();
195
13
}
196
197
class NamedDeclFindingConsumer : public ASTConsumer {
198
public:
199
  NamedDeclFindingConsumer(ArrayRef<unsigned> SymbolOffsets,
200
                           ArrayRef<std::string> QualifiedNames,
201
                           std::vector<std::string> &SpellingNames,
202
                           std::vector<std::vector<std::string>> &USRList,
203
                           bool Force, bool &ErrorOccurred)
204
      : SymbolOffsets(SymbolOffsets), QualifiedNames(QualifiedNames),
205
        SpellingNames(SpellingNames), USRList(USRList), Force(Force),
206
321
        ErrorOccurred(ErrorOccurred) {}
207
208
private:
209
  bool FindSymbol(ASTContext &Context, const SourceManager &SourceMgr,
210
326
                  unsigned SymbolOffset, const std::string &QualifiedName) {
211
326
    DiagnosticsEngine &Engine = Context.getDiagnostics();
212
326
    const FileID MainFileID = SourceMgr.getMainFileID();
213
214
326
    if (SymbolOffset >= SourceMgr.getFileIDSize(MainFileID)) {
215
1
      ErrorOccurred = true;
216
1
      unsigned InvalidOffset = Engine.getCustomDiagID(
217
1
          DiagnosticsEngine::Error,
218
1
          "SourceLocation in file %0 at offset %1 is invalid");
219
1
      Engine.Report(SourceLocation(), InvalidOffset)
220
1
          << SourceMgr.getFileEntryForID(MainFileID)->getName() << SymbolOffset;
221
1
      return false;
222
1
    }
223
224
325
    const SourceLocation Point = SourceMgr.getLocForStartOfFile(MainFileID)
225
325
                                     .getLocWithOffset(SymbolOffset);
226
325
    const NamedDecl *FoundDecl = QualifiedName.empty()
227
56
                                     ? getNamedDeclAt(Context, Point)
228
269
                                     : getNamedDeclFor(Context, QualifiedName);
229
230
325
    if (FoundDecl == nullptr) {
231
2
      if (QualifiedName.empty()) {
232
0
        FullSourceLoc FullLoc(Point, SourceMgr);
233
0
        unsigned CouldNotFindSymbolAt = Engine.getCustomDiagID(
234
0
            DiagnosticsEngine::Error,
235
0
            "clang-rename could not find symbol (offset %0)");
236
0
        Engine.Report(Point, CouldNotFindSymbolAt) << SymbolOffset;
237
0
        ErrorOccurred = true;
238
0
        return false;
239
0
      }
240
241
2
      if (Force) {
242
2
        SpellingNames.push_back(std::string());
243
2
        USRList.push_back(std::vector<std::string>());
244
2
        return true;
245
2
      }
246
247
0
      unsigned CouldNotFindSymbolNamed = Engine.getCustomDiagID(
248
0
          DiagnosticsEngine::Error, "clang-rename could not find symbol %0");
249
0
      Engine.Report(CouldNotFindSymbolNamed) << QualifiedName;
250
0
      ErrorOccurred = true;
251
0
      return false;
252
0
    }
253
254
323
    FoundDecl = getCanonicalSymbolDeclaration(FoundDecl);
255
323
    SpellingNames.push_back(FoundDecl->getNameAsString());
256
323
    AdditionalUSRFinder Finder(FoundDecl, Context);
257
323
    USRList.push_back(Finder.Find());
258
323
    return true;
259
323
  }
260
261
321
  void HandleTranslationUnit(ASTContext &Context) override {
262
321
    const SourceManager &SourceMgr = Context.getSourceManager();
263
57
    for (unsigned Offset : SymbolOffsets) {
264
57
      if (!FindSymbol(Context, SourceMgr, Offset, ""))
265
1
        return;
266
57
    }
267
320
    for (const std::string &QualifiedName : QualifiedNames) {
268
269
      if (!FindSymbol(Context, SourceMgr, 0, QualifiedName))
269
0
        return;
270
269
    }
271
320
  }
272
273
  ArrayRef<unsigned> SymbolOffsets;
274
  ArrayRef<std::string> QualifiedNames;
275
  std::vector<std::string> &SpellingNames;
276
  std::vector<std::vector<std::string>> &USRList;
277
  bool Force;
278
  bool &ErrorOccurred;
279
};
280
281
321
std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
282
321
  return std::make_unique<NamedDeclFindingConsumer>(
283
321
      SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
284
321
      ErrorOccurred);
285
321
}
286
287
} // end namespace tooling
288
} // end namespace clang