1061da546Spatrick #include "clang/AST/AST.h"
2061da546Spatrick #include "clang/AST/ASTConsumer.h"
3061da546Spatrick #include "clang/AST/RecursiveASTVisitor.h"
4061da546Spatrick #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
5061da546Spatrick #include "clang/Frontend/ASTConsumers.h"
6061da546Spatrick #include "clang/Frontend/CompilerInstance.h"
7061da546Spatrick #include "clang/Frontend/FrontendActions.h"
8061da546Spatrick #include "clang/Rewrite/Core/Rewriter.h"
9061da546Spatrick #include "clang/Tooling/CommonOptionsParser.h"
10061da546Spatrick #include "clang/Tooling/Tooling.h"
11061da546Spatrick
12061da546Spatrick #include "llvm/ADT/StringExtras.h"
13061da546Spatrick #include "llvm/ADT/StringRef.h"
14061da546Spatrick #include "llvm/Support/raw_ostream.h"
15061da546Spatrick
16061da546Spatrick #include <sstream>
17061da546Spatrick #include <string>
18061da546Spatrick
19061da546Spatrick using namespace clang;
20061da546Spatrick using namespace clang::driver;
21061da546Spatrick using namespace clang::tooling;
22061da546Spatrick
23061da546Spatrick static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");
24061da546Spatrick
25061da546Spatrick class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
26061da546Spatrick public:
SBVisitor(Rewriter & R,ASTContext & Context)27061da546Spatrick SBVisitor(Rewriter &R, ASTContext &Context)
28061da546Spatrick : MyRewriter(R), Context(Context) {}
29061da546Spatrick
VisitCXXMethodDecl(CXXMethodDecl * Decl)30061da546Spatrick bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
31061da546Spatrick // Not all decls should be registered. Please refer to that method's
32061da546Spatrick // comment for details.
33061da546Spatrick if (ShouldSkip(Decl))
34061da546Spatrick return false;
35061da546Spatrick
36061da546Spatrick // Print 'bool' instead of '_Bool'.
37061da546Spatrick PrintingPolicy Policy(Context.getLangOpts());
38061da546Spatrick Policy.Bool = true;
39061da546Spatrick
40061da546Spatrick // Collect the functions parameter types and names.
41061da546Spatrick std::vector<std::string> ParamNames;
42*f6aab3d8Srobert if (!Decl->isStatic())
43*f6aab3d8Srobert ParamNames.push_back("this");
44*f6aab3d8Srobert for (auto *P : Decl->parameters())
45061da546Spatrick ParamNames.push_back(P->getNameAsString());
46061da546Spatrick
47061da546Spatrick // Construct the macros.
48*f6aab3d8Srobert std::string Buffer;
49*f6aab3d8Srobert llvm::raw_string_ostream Macro(Buffer);
50*f6aab3d8Srobert if (ParamNames.empty()) {
51*f6aab3d8Srobert Macro << "LLDB_INSTRUMENT()";
52061da546Spatrick } else {
53*f6aab3d8Srobert Macro << "LLDB_INSTRUMENT_VA(" << llvm::join(ParamNames, ", ") << ")";
54061da546Spatrick }
55061da546Spatrick
56*f6aab3d8Srobert Stmt *Body = Decl->getBody();
57*f6aab3d8Srobert for (auto &C : Body->children()) {
58*f6aab3d8Srobert if (C->getBeginLoc().isMacroID()) {
59*f6aab3d8Srobert CharSourceRange Range =
60*f6aab3d8Srobert MyRewriter.getSourceMgr().getExpansionRange(C->getSourceRange());
61*f6aab3d8Srobert MyRewriter.ReplaceText(Range, Macro.str());
62*f6aab3d8Srobert } else {
63*f6aab3d8Srobert Macro << ";";
64061da546Spatrick SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
65061da546Spatrick Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
66061da546Spatrick MyRewriter.getLangOpts());
67*f6aab3d8Srobert MyRewriter.InsertTextAfter(InsertLoc, Macro.str());
68*f6aab3d8Srobert }
69*f6aab3d8Srobert break;
70061da546Spatrick }
71061da546Spatrick
72061da546Spatrick return true;
73061da546Spatrick }
74061da546Spatrick
75061da546Spatrick private:
76061da546Spatrick /// Determine whether we need to consider the given CXXMethodDecl.
77061da546Spatrick ///
78061da546Spatrick /// Currently we skip the following cases:
79061da546Spatrick /// 1. Decls outside the main source file,
80061da546Spatrick /// 2. Decls that are only present in the source file,
81061da546Spatrick /// 3. Decls that are not definitions,
82061da546Spatrick /// 4. Non-public methods,
83061da546Spatrick /// 5. Variadic methods.
84061da546Spatrick /// 6. Destructors.
ShouldSkip(CXXMethodDecl * Decl)85061da546Spatrick bool ShouldSkip(CXXMethodDecl *Decl) {
86061da546Spatrick // Skip anything outside the main file.
87061da546Spatrick if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
88061da546Spatrick return true;
89061da546Spatrick
90061da546Spatrick // Skip if the canonical decl in the current decl. It means that the method
91061da546Spatrick // is declared in the implementation and is therefore not exposed as part
92061da546Spatrick // of the API.
93061da546Spatrick if (Decl == Decl->getCanonicalDecl())
94061da546Spatrick return true;
95061da546Spatrick
96061da546Spatrick // Skip decls that have no body, i.e. are just declarations.
97061da546Spatrick Stmt *Body = Decl->getBody();
98061da546Spatrick if (!Body)
99061da546Spatrick return true;
100061da546Spatrick
101061da546Spatrick // Skip non-public methods.
102061da546Spatrick AccessSpecifier AS = Decl->getAccess();
103061da546Spatrick if (AS != AccessSpecifier::AS_public)
104061da546Spatrick return true;
105061da546Spatrick
106061da546Spatrick // Skip variadic methods.
107061da546Spatrick if (Decl->isVariadic())
108061da546Spatrick return true;
109061da546Spatrick
110061da546Spatrick // Skip destructors.
111061da546Spatrick if (isa<CXXDestructorDecl>(Decl))
112061da546Spatrick return true;
113061da546Spatrick
114061da546Spatrick return false;
115061da546Spatrick }
116061da546Spatrick
117061da546Spatrick Rewriter &MyRewriter;
118061da546Spatrick ASTContext &Context;
119061da546Spatrick };
120061da546Spatrick
121061da546Spatrick class SBConsumer : public ASTConsumer {
122061da546Spatrick public:
SBConsumer(Rewriter & R,ASTContext & Context)123061da546Spatrick SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
124061da546Spatrick
125061da546Spatrick // Override the method that gets called for each parsed top-level
126061da546Spatrick // declaration.
HandleTopLevelDecl(DeclGroupRef DR)127061da546Spatrick bool HandleTopLevelDecl(DeclGroupRef DR) override {
128061da546Spatrick for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
129061da546Spatrick Visitor.TraverseDecl(*b);
130061da546Spatrick }
131061da546Spatrick return true;
132061da546Spatrick }
133061da546Spatrick
134061da546Spatrick private:
135061da546Spatrick SBVisitor Visitor;
136061da546Spatrick };
137061da546Spatrick
138061da546Spatrick class SBAction : public ASTFrontendAction {
139061da546Spatrick public:
140061da546Spatrick SBAction() = default;
141061da546Spatrick
BeginSourceFileAction(CompilerInstance & CI)142*f6aab3d8Srobert bool BeginSourceFileAction(CompilerInstance &CI) override { return true; }
143061da546Spatrick
EndSourceFileAction()144*f6aab3d8Srobert void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }
145061da546Spatrick
CreateASTConsumer(CompilerInstance & CI,StringRef File)146061da546Spatrick std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
147061da546Spatrick StringRef File) override {
148061da546Spatrick MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
149061da546Spatrick return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
150061da546Spatrick }
151061da546Spatrick
152061da546Spatrick private:
153061da546Spatrick Rewriter MyRewriter;
154061da546Spatrick };
155061da546Spatrick
main(int argc,const char ** argv)156061da546Spatrick int main(int argc, const char **argv) {
157be691f3bSpatrick auto ExpectedParser = CommonOptionsParser::create(
158be691f3bSpatrick argc, argv, InstrCategory, llvm::cl::OneOrMore,
159061da546Spatrick "Utility for generating the macros for LLDB's "
160061da546Spatrick "instrumentation framework.");
161be691f3bSpatrick if (!ExpectedParser) {
162be691f3bSpatrick llvm::errs() << ExpectedParser.takeError();
163be691f3bSpatrick return 1;
164be691f3bSpatrick }
165be691f3bSpatrick CommonOptionsParser &OP = ExpectedParser.get();
166061da546Spatrick
167061da546Spatrick auto PCHOpts = std::make_shared<PCHContainerOperations>();
168061da546Spatrick PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
169061da546Spatrick PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
170061da546Spatrick
171061da546Spatrick ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);
172061da546Spatrick return T.run(newFrontendActionFactory<SBAction>().get());
173061da546Spatrick }
174