Coverage Report

Created: 2022-01-08 10:46

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/tools/lldb-instr/Instrument.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "clang/AST/AST.h"
2
#include "clang/AST/ASTConsumer.h"
3
#include "clang/AST/RecursiveASTVisitor.h"
4
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
5
#include "clang/Frontend/ASTConsumers.h"
6
#include "clang/Frontend/CompilerInstance.h"
7
#include "clang/Frontend/FrontendActions.h"
8
#include "clang/Rewrite/Core/Rewriter.h"
9
#include "clang/Tooling/CommonOptionsParser.h"
10
#include "clang/Tooling/Tooling.h"
11
12
#include "llvm/ADT/StringExtras.h"
13
#include "llvm/ADT/StringRef.h"
14
#include "llvm/Support/raw_ostream.h"
15
16
#include <sstream>
17
#include <string>
18
19
using namespace clang;
20
using namespace clang::driver;
21
using namespace clang::tooling;
22
23
static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");
24
25
/// Get the macro name for recording method calls.
26
///
27
/// LLDB_RECORD_METHOD
28
/// LLDB_RECORD_METHOD_CONST
29
/// LLDB_RECORD_METHOD_NO_ARGS
30
/// LLDB_RECORD_METHOD_CONST_NO_ARGS
31
/// LLDB_RECORD_STATIC_METHOD
32
/// LLDB_RECORD_STATIC_METHOD_NO_ARGS
33
static std::string GetRecordMethodMacroName(bool Static, bool Const,
34
0
                                            bool NoArgs) {
35
0
  std::string Macro;
36
0
  llvm::raw_string_ostream OS(Macro);
37
38
0
  OS << "LLDB_RECORD";
39
0
  if (Static)
40
0
    OS << "_STATIC";
41
0
  OS << "_METHOD";
42
0
  if (Const)
43
0
    OS << "_CONST";
44
0
  if (NoArgs)
45
0
    OS << "_NO_ARGS";
46
47
0
  return OS.str();
48
0
}
49
50
/// Get the macro name for register methods.
51
///
52
/// LLDB_REGISTER_CONSTRUCTOR
53
/// LLDB_REGISTER_METHOD
54
/// LLDB_REGISTER_METHOD_CONST
55
/// LLDB_REGISTER_STATIC_METHOD
56
0
static std::string GetRegisterMethodMacroName(bool Static, bool Const) {
57
0
  std::string Macro;
58
0
  llvm::raw_string_ostream OS(Macro);
59
60
0
  OS << "LLDB_REGISTER";
61
0
  if (Static)
62
0
    OS << "_STATIC";
63
0
  OS << "_METHOD";
64
0
  if (Const)
65
0
    OS << "_CONST";
66
67
0
  return OS.str();
68
0
}
69
70
static std::string GetRecordMethodMacro(StringRef Result, StringRef Class,
71
                                        StringRef Method, StringRef Signature,
72
                                        StringRef Values, bool Static,
73
0
                                        bool Const) {
74
0
  std::string Macro;
75
0
  llvm::raw_string_ostream OS(Macro);
76
77
0
  OS << GetRecordMethodMacroName(Static, Const, Values.empty());
78
0
  OS << "(" << Result << ", " << Class << ", " << Method;
79
80
0
  if (!Values.empty()) {
81
0
    OS << ", (" << Signature << "), " << Values << ");\n\n";
82
0
  } else {
83
0
    OS << ");\n\n";
84
0
  }
85
86
0
  return OS.str();
87
0
}
88
89
static std::string GetRecordConstructorMacro(StringRef Class,
90
                                             StringRef Signature,
91
0
                                             StringRef Values) {
92
0
  std::string Macro;
93
0
  llvm::raw_string_ostream OS(Macro);
94
0
  if (!Values.empty()) {
95
0
    OS << "LLDB_RECORD_CONSTRUCTOR(" << Class << ", (" << Signature << "), "
96
0
       << Values << ");\n\n";
97
0
  } else {
98
0
    OS << "LLDB_RECORD_CONSTRUCTOR_NO_ARGS(" << Class << ");\n\n";
99
0
  }
100
0
  return OS.str();
101
0
}
102
103
static std::string GetRecordDummyMacro(StringRef Result, StringRef Class,
104
                                       StringRef Method, StringRef Signature,
105
0
                                       StringRef Values) {
106
0
  assert(!Values.empty());
107
0
  std::string Macro;
108
0
  llvm::raw_string_ostream OS(Macro);
109
110
0
  OS << "LLDB_RECORD_DUMMY(" << Result << ", " << Class << ", " << Method;
111
0
  OS << ", (" << Signature << "), " << Values << ");\n\n";
112
113
0
  return OS.str();
114
0
}
115
116
static std::string GetRegisterConstructorMacro(StringRef Class,
117
0
                                               StringRef Signature) {
118
0
  std::string Macro;
119
0
  llvm::raw_string_ostream OS(Macro);
120
0
  OS << "LLDB_REGISTER_CONSTRUCTOR(" << Class << ", (" << Signature << "));\n";
121
0
  return OS.str();
122
0
}
123
124
static std::string GetRegisterMethodMacro(StringRef Result, StringRef Class,
125
                                          StringRef Method, StringRef Signature,
126
0
                                          bool Static, bool Const) {
127
0
  std::string Macro;
128
0
  llvm::raw_string_ostream OS(Macro);
129
0
  OS << GetRegisterMethodMacroName(Static, Const);
130
0
  OS << "(" << Result << ", " << Class << ", " << Method << ", (" << Signature
131
0
     << "));\n";
132
0
  return OS.str();
133
0
}
134
135
class SBReturnVisitor : public RecursiveASTVisitor<SBReturnVisitor> {
136
public:
137
0
  SBReturnVisitor(Rewriter &R) : MyRewriter(R) {}
138
139
0
  bool VisitReturnStmt(ReturnStmt *Stmt) {
140
0
    Expr *E = Stmt->getRetValue();
141
142
0
    if (E->getBeginLoc().isMacroID())
143
0
      return false;
144
145
0
    SourceRange R(E->getBeginLoc(), E->getEndLoc());
146
147
0
    StringRef WrittenExpr = Lexer::getSourceText(
148
0
        CharSourceRange::getTokenRange(R), MyRewriter.getSourceMgr(),
149
0
        MyRewriter.getLangOpts());
150
151
0
    std::string ReplacementText =
152
0
        "LLDB_RECORD_RESULT(" + WrittenExpr.str() + ")";
153
0
    MyRewriter.ReplaceText(R, ReplacementText);
154
155
0
    return true;
156
0
  }
157
158
private:
159
  Rewriter &MyRewriter;
160
};
161
162
class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
163
public:
164
  SBVisitor(Rewriter &R, ASTContext &Context)
165
0
      : MyRewriter(R), Context(Context) {}
166
167
0
  bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
168
    // Not all decls should be registered. Please refer to that method's
169
    // comment for details.
170
0
    if (ShouldSkip(Decl))
171
0
      return false;
172
173
    // Skip CXXMethodDecls that already starts with a macro. This should make
174
    // it easier to rerun the tool to find missing macros.
175
0
    Stmt *Body = Decl->getBody();
176
0
    for (auto &C : Body->children()) {
177
0
      if (C->getBeginLoc().isMacroID())
178
0
        return false;
179
0
      break;
180
0
    }
181
182
    // Print 'bool' instead of '_Bool'.
183
0
    PrintingPolicy Policy(Context.getLangOpts());
184
0
    Policy.Bool = true;
185
186
    // Unsupported signatures get a dummy macro.
187
0
    bool ShouldInsertDummy = false;
188
189
    // Collect the functions parameter types and names.
190
0
    std::vector<std::string> ParamTypes;
191
0
    std::vector<std::string> ParamNames;
192
0
    for (auto *P : Decl->parameters()) {
193
0
      QualType T = P->getType();
194
0
      ParamTypes.push_back(T.getAsString(Policy));
195
0
      ParamNames.push_back(P->getNameAsString());
196
197
      // Currently we don't support functions that have function pointers as an
198
      // argument, in which case we insert a dummy macro.
199
0
      ShouldInsertDummy |= T->isFunctionPointerType();
200
0
    }
201
202
    // Convert the two lists to string for the macros.
203
0
    std::string ParamTypesStr = llvm::join(ParamTypes, ", ");
204
0
    std::string ParamNamesStr = llvm::join(ParamNames, ", ");
205
206
0
    CXXRecordDecl *Record = Decl->getParent();
207
0
    QualType ReturnType = Decl->getReturnType();
208
209
    // Construct the macros.
210
0
    std::string Macro;
211
0
    if (ShouldInsertDummy) {
212
      // Don't insert a register call for dummy macros.
213
0
      Macro = GetRecordDummyMacro(
214
0
          ReturnType.getAsString(Policy), Record->getNameAsString(),
215
0
          Decl->getNameAsString(), ParamTypesStr, ParamNamesStr);
216
217
0
    } else if (isa<CXXConstructorDecl>(Decl)) {
218
0
      llvm::outs() << GetRegisterConstructorMacro(Record->getNameAsString(),
219
0
                                                  ParamTypesStr);
220
221
0
      Macro = GetRecordConstructorMacro(Record->getNameAsString(),
222
0
                                        ParamTypesStr, ParamNamesStr);
223
0
    } else {
224
0
      llvm::outs() << GetRegisterMethodMacro(
225
0
          ReturnType.getAsString(Policy), Record->getNameAsString(),
226
0
          Decl->getNameAsString(), ParamTypesStr, Decl->isStatic(),
227
0
          Decl->isConst());
228
229
0
      Macro = GetRecordMethodMacro(
230
0
          ReturnType.getAsString(Policy), Record->getNameAsString(),
231
0
          Decl->getNameAsString(), ParamTypesStr, ParamNamesStr,
232
0
          Decl->isStatic(), Decl->isConst());
233
0
    }
234
235
    // Insert the macro at the beginning of the function. We don't attempt to
236
    // fix the formatting and instead rely on clang-format to fix it after the
237
    // tool has run. This is also the reason that the macros end with two
238
    // newlines, counting on clang-format to normalize this in case the macro
239
    // got inserted before an existing newline.
240
0
    SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
241
0
        Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
242
0
        MyRewriter.getLangOpts());
243
0
    MyRewriter.InsertTextAfter(InsertLoc, Macro);
244
245
    // If the function returns a class or struct, we need to wrap its return
246
    // statement(s).
247
0
    bool ShouldRecordResult = ReturnType->isStructureOrClassType() ||
248
0
                              ReturnType->getPointeeCXXRecordDecl();
249
0
    if (!ShouldInsertDummy && ShouldRecordResult) {
250
0
      SBReturnVisitor Visitor(MyRewriter);
251
0
      Visitor.TraverseDecl(Decl);
252
0
    }
253
254
0
    return true;
255
0
  }
256
257
private:
258
  /// Determine whether we need to consider the given CXXMethodDecl.
259
  ///
260
  /// Currently we skip the following cases:
261
  ///  1. Decls outside the main source file,
262
  ///  2. Decls that are only present in the source file,
263
  ///  3. Decls that are not definitions,
264
  ///  4. Non-public methods,
265
  ///  5. Variadic methods.
266
  ///  6. Destructors.
267
0
  bool ShouldSkip(CXXMethodDecl *Decl) {
268
    // Skip anything outside the main file.
269
0
    if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
270
0
      return true;
271
272
    // Skip if the canonical decl in the current decl. It means that the method
273
    // is declared in the implementation and is therefore not exposed as part
274
    // of the API.
275
0
    if (Decl == Decl->getCanonicalDecl())
276
0
      return true;
277
278
    // Skip decls that have no body, i.e. are just declarations.
279
0
    Stmt *Body = Decl->getBody();
280
0
    if (!Body)
281
0
      return true;
282
283
    // Skip non-public methods.
284
0
    AccessSpecifier AS = Decl->getAccess();
285
0
    if (AS != AccessSpecifier::AS_public)
286
0
      return true;
287
288
    // Skip variadic methods.
289
0
    if (Decl->isVariadic())
290
0
      return true;
291
292
    // Skip destructors.
293
0
    if (isa<CXXDestructorDecl>(Decl))
294
0
      return true;
295
296
0
    return false;
297
0
  }
298
299
  Rewriter &MyRewriter;
300
  ASTContext &Context;
301
};
302
303
class SBConsumer : public ASTConsumer {
304
public:
305
0
  SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
306
307
  // Override the method that gets called for each parsed top-level
308
  // declaration.
309
0
  bool HandleTopLevelDecl(DeclGroupRef DR) override {
310
0
    for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
311
0
      Visitor.TraverseDecl(*b);
312
0
    }
313
0
    return true;
314
0
  }
315
316
private:
317
  SBVisitor Visitor;
318
};
319
320
class SBAction : public ASTFrontendAction {
321
public:
322
0
  SBAction() = default;
323
324
0
  bool BeginSourceFileAction(CompilerInstance &CI) override {
325
0
    llvm::outs() << "{\n";
326
0
    return true;
327
0
  }
328
329
0
  void EndSourceFileAction() override {
330
0
    llvm::outs() << "}\n";
331
0
    MyRewriter.overwriteChangedFiles();
332
0
  }
333
334
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
335
0
                                                 StringRef File) override {
336
0
    MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
337
0
    return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
338
0
  }
339
340
private:
341
  Rewriter MyRewriter;
342
};
343
344
20
int main(int argc, const char **argv) {
345
20
  auto ExpectedParser = CommonOptionsParser::create(
346
20
      argc, argv, InstrCategory, llvm::cl::OneOrMore,
347
20
      "Utility for generating the macros for LLDB's "
348
20
      "instrumentation framework.");
349
20
  if (!ExpectedParser) {
350
0
    llvm::errs() << ExpectedParser.takeError();
351
0
    return 1;
352
0
  }
353
20
  CommonOptionsParser &OP = ExpectedParser.get();
354
355
20
  auto PCHOpts = std::make_shared<PCHContainerOperations>();
356
20
  PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
357
20
  PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
358
359
20
  ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);
360
20
  return T.run(newFrontendActionFactory<SBAction>().get());
361
20
}