Coverage Report

Created: 2023-09-21 18:56

/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
class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
26
public:
27
  SBVisitor(Rewriter &R, ASTContext &Context)
28
0
      : MyRewriter(R), Context(Context) {}
29
30
0
  bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
31
    // Not all decls should be registered. Please refer to that method's
32
    // comment for details.
33
0
    if (ShouldSkip(Decl))
34
0
      return false;
35
36
    // Print 'bool' instead of '_Bool'.
37
0
    PrintingPolicy Policy(Context.getLangOpts());
38
0
    Policy.Bool = true;
39
40
    // Collect the functions parameter types and names.
41
0
    std::vector<std::string> ParamNames;
42
0
    if (!Decl->isStatic())
43
0
      ParamNames.push_back("this");
44
0
    for (auto *P : Decl->parameters())
45
0
      ParamNames.push_back(P->getNameAsString());
46
47
    // Construct the macros.
48
0
    std::string Buffer;
49
0
    llvm::raw_string_ostream Macro(Buffer);
50
0
    if (ParamNames.empty()) {
51
0
      Macro << "LLDB_INSTRUMENT()";
52
0
    } else {
53
0
      Macro << "LLDB_INSTRUMENT_VA(" << llvm::join(ParamNames, ", ") << ")";
54
0
    }
55
56
0
    Stmt *Body = Decl->getBody();
57
0
    for (auto &C : Body->children()) {
58
0
      if (C->getBeginLoc().isMacroID()) {
59
0
        CharSourceRange Range =
60
0
            MyRewriter.getSourceMgr().getExpansionRange(C->getSourceRange());
61
0
        MyRewriter.ReplaceText(Range, Macro.str());
62
0
      } else {
63
0
        Macro << ";";
64
0
        SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
65
0
            Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
66
0
            MyRewriter.getLangOpts());
67
0
        MyRewriter.InsertTextAfter(InsertLoc, Macro.str());
68
0
      }
69
0
      break;
70
0
    }
71
72
0
    return true;
73
0
  }
74
75
private:
76
  /// Determine whether we need to consider the given CXXMethodDecl.
77
  ///
78
  /// Currently we skip the following cases:
79
  ///  1. Decls outside the main source file,
80
  ///  2. Decls that are only present in the source file,
81
  ///  3. Decls that are not definitions,
82
  ///  4. Non-public methods,
83
  ///  5. Variadic methods.
84
  ///  6. Destructors.
85
0
  bool ShouldSkip(CXXMethodDecl *Decl) {
86
    // Skip anything outside the main file.
87
0
    if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
88
0
      return true;
89
90
    // Skip if the canonical decl in the current decl. It means that the method
91
    // is declared in the implementation and is therefore not exposed as part
92
    // of the API.
93
0
    if (Decl == Decl->getCanonicalDecl())
94
0
      return true;
95
96
    // Skip decls that have no body, i.e. are just declarations.
97
0
    Stmt *Body = Decl->getBody();
98
0
    if (!Body)
99
0
      return true;
100
101
    // Skip non-public methods.
102
0
    AccessSpecifier AS = Decl->getAccess();
103
0
    if (AS != AccessSpecifier::AS_public)
104
0
      return true;
105
106
    // Skip variadic methods.
107
0
    if (Decl->isVariadic())
108
0
      return true;
109
110
    // Skip destructors.
111
0
    if (isa<CXXDestructorDecl>(Decl))
112
0
      return true;
113
114
0
    return false;
115
0
  }
116
117
  Rewriter &MyRewriter;
118
  ASTContext &Context;
119
};
120
121
class SBConsumer : public ASTConsumer {
122
public:
123
0
  SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
124
125
  // Override the method that gets called for each parsed top-level
126
  // declaration.
127
0
  bool HandleTopLevelDecl(DeclGroupRef DR) override {
128
0
    for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
129
0
      Visitor.TraverseDecl(*b);
130
0
    }
131
0
    return true;
132
0
  }
133
134
private:
135
  SBVisitor Visitor;
136
};
137
138
class SBAction : public ASTFrontendAction {
139
public:
140
0
  SBAction() = default;
141
142
0
  bool BeginSourceFileAction(CompilerInstance &CI) override { return true; }
143
144
0
  void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }
145
146
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
147
0
                                                 StringRef File) override {
148
0
    MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
149
0
    return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
150
0
  }
151
152
private:
153
  Rewriter MyRewriter;
154
};
155
156
22
int main(int argc, const char **argv) {
157
22
  auto ExpectedParser = CommonOptionsParser::create(
158
22
      argc, argv, InstrCategory, llvm::cl::OneOrMore,
159
22
      "Utility for generating the macros for LLDB's "
160
22
      "instrumentation framework.");
161
22
  if (!ExpectedParser) {
162
0
    llvm::errs() << ExpectedParser.takeError();
163
0
    return 1;
164
0
  }
165
22
  CommonOptionsParser &OP = ExpectedParser.get();
166
167
22
  auto PCHOpts = std::make_shared<PCHContainerOperations>();
168
22
  PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
169
22
  PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
170
171
22
  ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);
172
22
  return T.run(newFrontendActionFactory<SBAction>().get());
173
22
}