blob: a2850f5461b4e0597ae7894e38903f005658c7b5 [file] [log] [blame]
Jonas Devlieghereedff5f42019-02-06 04:33:14 +00001#include "clang/AST/AST.h"
2#include "clang/AST/ASTConsumer.h"
3#include "clang/AST/RecursiveASTVisitor.h"
4#include "clang/Frontend/ASTConsumers.h"
5#include "clang/Frontend/CompilerInstance.h"
6#include "clang/Frontend/FrontendActions.h"
7#include "clang/Rewrite/Core/Rewriter.h"
8#include "clang/Tooling/CommonOptionsParser.h"
9#include "clang/Tooling/Tooling.h"
10
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/Support/raw_ostream.h"
14
15#include <sstream>
16#include <string>
17
18using namespace clang;
19using namespace clang::driver;
20using namespace clang::tooling;
21
22static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");
23
24/// Get the macro name for recording method calls.
25///
26/// LLDB_RECORD_METHOD
27/// LLDB_RECORD_METHOD_CONST
28/// LLDB_RECORD_METHOD_NO_ARGS
29/// LLDB_RECORD_METHOD_CONST_NO_ARGS
30/// LLDB_RECORD_STATIC_METHOD
31/// LLDB_RECORD_STATIC_METHOD_NO_ARGS
32static std::string GetRecordMethodMacroName(bool Static, bool Const,
33 bool NoArgs) {
34 std::string Macro;
35 llvm::raw_string_ostream OS(Macro);
36
37 OS << "LLDB_RECORD";
38 if (Static)
39 OS << "_STATIC";
40 OS << "_METHOD";
41 if (Const)
42 OS << "_CONST";
43 if (NoArgs)
44 OS << "_NO_ARGS";
45
46 return OS.str();
47}
48
49/// Get the macro name for register methods.
50///
51/// LLDB_REGISTER_CONSTRUCTOR
52/// LLDB_REGISTER_METHOD
53/// LLDB_REGISTER_METHOD_CONST
54/// LLDB_REGISTER_STATIC_METHOD
55static std::string GetRegisterMethodMacroName(bool Static, bool Const) {
56 std::string Macro;
57 llvm::raw_string_ostream OS(Macro);
58
59 OS << "LLDB_REGISTER";
60 if (Static)
61 OS << "_STATIC";
62 OS << "_METHOD";
63 if (Const)
64 OS << "_CONST";
65
66 return OS.str();
67}
68
69static std::string GetRecordMethodMacro(StringRef Result, StringRef Class,
70 StringRef Method, StringRef Signature,
71 StringRef Values, bool Static,
72 bool Const) {
73 std::string Macro;
74 llvm::raw_string_ostream OS(Macro);
75
76 OS << GetRecordMethodMacroName(Static, Const, Values.empty());
77 OS << "(" << Result << ", " << Class << ", " << Method;
78
79 if (!Values.empty()) {
80 OS << ", (" << Signature << "), " << Values << ");\n\n";
81 } else {
82 OS << ");\n\n";
83 }
84
85 return OS.str();
86}
87
88static std::string GetRecordConstructorMacro(StringRef Class,
89 StringRef Signature,
90 StringRef Values) {
91 std::string Macro;
92 llvm::raw_string_ostream OS(Macro);
93 if (!Values.empty()) {
94 OS << "LLDB_RECORD_CONSTRUCTOR(" << Class << ", (" << Signature << "), "
95 << Values << ");\n\n";
96 } else {
97 OS << "LLDB_RECORD_CONSTRUCTOR_NO_ARGS(" << Class << ");\n\n";
98 }
99 return OS.str();
100}
101
102static std::string GetRegisterConstructorMacro(StringRef Class,
103 StringRef Signature) {
104 std::string Macro;
105 llvm::raw_string_ostream OS(Macro);
106 OS << "LLDB_REGISTER_CONSTRUCTOR(" << Class << ", (" << Signature
107 << "));\n\n";
108 return OS.str();
109}
110
111static std::string GetRegisterMethodMacro(StringRef Result, StringRef Class,
112 StringRef Method, StringRef Signature,
113 bool Static, bool Const) {
114 std::string Macro;
115 llvm::raw_string_ostream OS(Macro);
116 OS << GetRegisterMethodMacroName(Static, Const);
117 OS << "(" << Result << ", " << Class << ", " << Method << ", (" << Signature
118 << "));\n";
119 return OS.str();
120}
121
122class SBVisitor : public RecursiveASTVisitor<SBVisitor> {
123public:
124 SBVisitor(Rewriter &R, ASTContext &Context)
125 : MyRewriter(R), Context(Context) {}
126
127 bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
128 // Not all decls should be registered. Please refer to that method's
129 // comment for details.
130 if (ShouldSkip(Decl))
131 return false;
132
133 // Print 'bool' instead of '_Bool'.
134 PrintingPolicy Policy(Context.getLangOpts());
135 Policy.Bool = true;
136
137 // Collect the functions parameter types and names.
138 std::vector<std::string> ParamTypes;
139 std::vector<std::string> ParamNames;
140 for (auto *P : Decl->parameters()) {
141 QualType T = P->getType();
142
143 // Currently we don't support functions that have function pointers as an
144 // argument.
145 if (T->isFunctionPointerType())
146 return false;
147
148 // Currently we don't support functions that have void pointers as an
149 // argument.
150 if (T->isVoidPointerType())
151 return false;
152
153 ParamTypes.push_back(T.getAsString(Policy));
154 ParamNames.push_back(P->getNameAsString());
155 }
156
157 // Convert the two lists to string for the macros.
158 std::string ParamTypesStr = llvm::join(ParamTypes, ", ");
159 std::string ParamNamesStr = llvm::join(ParamNames, ", ");
160
161 CXXRecordDecl *Record = Decl->getParent();
162 QualType ReturnType = Decl->getReturnType();
163
164 // Construct the macros.
165 std::string Macro;
166 if (isa<CXXConstructorDecl>(Decl)) {
167 llvm::outs() << GetRegisterConstructorMacro(Record->getNameAsString(),
168 ParamTypesStr);
169
170 Macro = GetRecordConstructorMacro(Record->getNameAsString(),
171 ParamTypesStr, ParamNamesStr);
172 } else {
173 llvm::outs() << GetRegisterMethodMacro(
174 ReturnType.getAsString(Policy), Record->getNameAsString(),
175 Decl->getNameAsString(), ParamTypesStr, Decl->isStatic(),
176 Decl->isConst());
177
178 Macro = GetRecordMethodMacro(
179 ReturnType.getAsString(Policy), Record->getNameAsString(),
180 Decl->getNameAsString(), ParamTypesStr, ParamNamesStr,
181 Decl->isStatic(), Decl->isConst());
182 }
183
184 // If this CXXMethodDecl already starts with a macro we're done.
185 Stmt *Body = Decl->getBody();
186 for (auto &C : Body->children()) {
187 if (C->getBeginLoc().isMacroID())
188 return false;
189 break;
190 }
191
192 // Insert the macro at the beginning of the function. We don't attempt to
193 // fix the formatting and instead rely on clang-format to fix it after the
194 // tool has run. This is also the reason that the macros end with two
195 // newlines, counting on clang-format to normalize this in case the macro
196 // got inserted before an existing newline.
197 SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
198 Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),
199 MyRewriter.getLangOpts());
200 MyRewriter.InsertTextAfter(InsertLoc, Macro);
201
202 return true;
203 }
204
205private:
206 /// Determine whether we need to consider the given CXXMethodDecl.
207 ///
208 /// Currently we skip the following cases:
209 /// 1. Decls outside the main source file,
210 /// 2. Decls that are only present in the source file,
211 /// 3. Decls that are not definitions,
212 /// 4. Non-public decls,
213 /// 5. Destructors.
214 bool ShouldSkip(CXXMethodDecl *Decl) {
215 // Skip anything outside the main file.
216 if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))
217 return true;
218
219 // Skip if the canonical decl in the current decl. It means that the method
220 // is declared in the implementation and is therefore not exposed as part
221 // of the API.
222 if (Decl == Decl->getCanonicalDecl())
223 return true;
224
225 // Skip decls that have no body, i.e. are just declarations.
226 Stmt *Body = Decl->getBody();
227 if (!Body)
228 return true;
229
230 // Skip non-public decls.
231 AccessSpecifier AS = Decl->getAccess();
232 if (AS != AccessSpecifier::AS_public)
233 return true;
234
235 // Skip destructors.
236 if (isa<CXXDestructorDecl>(Decl))
237 return true;
238
239 return false;
240 }
241
242 Rewriter &MyRewriter;
243 ASTContext &Context;
244};
245
246class SBConsumer : public ASTConsumer {
247public:
248 SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}
249
250 // Override the method that gets called for each parsed top-level
251 // declaration.
252 bool HandleTopLevelDecl(DeclGroupRef DR) override {
253 for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
254 Visitor.TraverseDecl(*b);
255 }
256 return true;
257 }
258
259private:
260 SBVisitor Visitor;
261};
262
263class SBAction : public ASTFrontendAction {
264public:
265 SBAction() = default;
266
267 void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }
268
269 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
270 StringRef file) override {
271 MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
272 return llvm::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());
273 }
274
275private:
276 Rewriter MyRewriter;
277};
278
279int main(int argc, const char **argv) {
280 CommonOptionsParser OP(argc, argv, InstrCategory,
281 "Utility for generating the macros for LLDB's "
282 "instrumentation framework.");
283 ClangTool T(OP.getCompilations(), OP.getSourcePathList());
284 return T.run(newFrontendActionFactory<SBAction>().get());
285}