blob: b2b593bbed9bff57c021ac36ce9d1f0cd4294c17 [file] [log] [blame]
Sean Callanan1a8d4092010-08-27 01:01:44 +00001//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
Sean Callanan116be532010-07-01 20:08:22 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "stdlib.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/DeclGroup.h"
Sean Callanan17827832010-12-13 22:46:15 +000015#include "clang/AST/DeclObjC.h"
Sean Callanan116be532010-07-01 20:08:22 +000016#include "clang/AST/Expr.h"
17#include "clang/AST/Stmt.h"
Sean Callanan116be532010-07-01 20:08:22 +000018#include "clang/Parse/Parser.h"
Sean Callanan116be532010-07-01 20:08:22 +000019#include "llvm/Support/Casting.h"
20#include "llvm/Support/raw_ostream.h"
21#include "lldb/Core/Log.h"
Sean Callananbccce812011-08-23 21:20:51 +000022#include "lldb/Expression/ClangPersistentVariables.h"
Sean Callanan1a8d4092010-08-27 01:01:44 +000023#include "lldb/Expression/ASTResultSynthesizer.h"
Sean Callananbccce812011-08-23 21:20:51 +000024#include "lldb/Symbol/ClangASTContext.h"
Sean Callanan116be532010-07-01 20:08:22 +000025
26using namespace llvm;
27using namespace clang;
28using namespace lldb_private;
29
Sean Callananf7c3e272010-11-19 02:52:21 +000030ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
Sean Callananbccce812011-08-23 21:20:51 +000031 TypeFromUser desired_type,
32 ASTContext &scratch_ast_context,
33 ClangPersistentVariables &persistent_vars) :
Greg Claytonc8e11e12010-07-12 23:14:00 +000034 m_ast_context (NULL),
35 m_passthrough (passthrough),
36 m_passthrough_sema (NULL),
Sean Callananf7c3e272010-11-19 02:52:21 +000037 m_sema (NULL),
Sean Callananbccce812011-08-23 21:20:51 +000038 m_desired_type (desired_type),
39 m_scratch_ast_context (scratch_ast_context),
40 m_persistent_vars (persistent_vars)
Sean Callanan116be532010-07-01 20:08:22 +000041{
42 if (!m_passthrough)
43 return;
44
45 m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
46}
47
Sean Callanan1a8d4092010-08-27 01:01:44 +000048ASTResultSynthesizer::~ASTResultSynthesizer()
Sean Callanan116be532010-07-01 20:08:22 +000049{
50}
51
52void
Sean Callanan1a8d4092010-08-27 01:01:44 +000053ASTResultSynthesizer::Initialize(ASTContext &Context)
Sean Callanan116be532010-07-01 20:08:22 +000054{
55 m_ast_context = &Context;
56
57 if (m_passthrough)
58 m_passthrough->Initialize(Context);
59}
60
61void
Sean Callanan1a8d4092010-08-27 01:01:44 +000062ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
Sean Callanan116be532010-07-01 20:08:22 +000063{
Sean Callanan17827832010-12-13 22:46:15 +000064 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
65
66 if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
67 {
68 if (log)
69 {
70 if (named_decl->getIdentifier())
71 log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
72 else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
73 log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
74 else
75 log->Printf("TransformTopLevelDecl(<complex>)");
76 }
77
78 }
Sean Callanan116be532010-07-01 20:08:22 +000079
Sean Callanan17827832010-12-13 22:46:15 +000080 if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
Sean Callanan116be532010-07-01 20:08:22 +000081 {
82 RecordDecl::decl_iterator decl_iterator;
83
84 for (decl_iterator = linkage_spec_decl->decls_begin();
85 decl_iterator != linkage_spec_decl->decls_end();
86 ++decl_iterator)
87 {
88 TransformTopLevelDecl(*decl_iterator);
89 }
90 }
Sean Callanan17827832010-12-13 22:46:15 +000091 else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
Sean Callanan116be532010-07-01 20:08:22 +000092 {
Sean Callanan17827832010-12-13 22:46:15 +000093 if (m_ast_context &&
94 !method_decl->getSelector().getAsString().compare("$__lldb_expr:"))
95 {
Sean Callananbccce812011-08-23 21:20:51 +000096 RecordPersistentTypes(method_decl);
Sean Callanan17827832010-12-13 22:46:15 +000097 SynthesizeObjCMethodResult(method_decl);
98 }
99 }
100 else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D))
101 {
102 if (m_ast_context &&
103 !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
104 {
Sean Callananbccce812011-08-23 21:20:51 +0000105 RecordPersistentTypes(function_decl);
Sean Callanan17827832010-12-13 22:46:15 +0000106 SynthesizeFunctionResult(function_decl);
107 }
Sean Callanan116be532010-07-01 20:08:22 +0000108 }
109}
110
111void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000112ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
Sean Callanan116be532010-07-01 20:08:22 +0000113{
114 DeclGroupRef::iterator decl_iterator;
115
116 for (decl_iterator = D.begin();
117 decl_iterator != D.end();
118 ++decl_iterator)
119 {
120 Decl *decl = *decl_iterator;
121
122 TransformTopLevelDecl(decl);
123 }
124
125 if (m_passthrough)
126 m_passthrough->HandleTopLevelDecl(D);
127}
128
129bool
Sean Callanan17827832010-12-13 22:46:15 +0000130ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
Sean Callanan116be532010-07-01 20:08:22 +0000131{
Greg Clayton2d4edfb2010-11-06 01:53:30 +0000132 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
Sean Callanan116be532010-07-01 20:08:22 +0000133
Sean Callanan17827832010-12-13 22:46:15 +0000134 ASTContext &Ctx(*m_ast_context);
135
Sean Callanan116be532010-07-01 20:08:22 +0000136 if (!m_sema)
137 return false;
Sean Callanan17827832010-12-13 22:46:15 +0000138
Sean Callanan116be532010-07-01 20:08:22 +0000139 FunctionDecl *function_decl = FunDecl;
140
141 if (!function_decl)
142 return false;
143
Jim Inghame3be0c52011-01-22 01:25:40 +0000144 if (log && log->GetVerbose())
Sean Callanan9e6ed532010-09-13 21:34:21 +0000145 {
146 std::string s;
147 raw_string_ostream os(s);
148
Sean Callananc31ba262010-09-22 00:33:31 +0000149 Ctx.getTranslationUnitDecl()->print(os);
Sean Callanan9e6ed532010-09-13 21:34:21 +0000150
151 os.flush();
152
Sean Callananc31ba262010-09-22 00:33:31 +0000153 log->Printf("AST context before transforming:\n%s", s.c_str());
Sean Callanan9e6ed532010-09-13 21:34:21 +0000154 }
155
Sean Callanan116be532010-07-01 20:08:22 +0000156 Stmt *function_body = function_decl->getBody();
157 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
158
Sean Callanan17827832010-12-13 22:46:15 +0000159 bool ret = SynthesizeBodyResult (compound_stmt,
160 function_decl);
Jim Inghame3be0c52011-01-22 01:25:40 +0000161
162 if (log && log->GetVerbose())
Sean Callanan17827832010-12-13 22:46:15 +0000163 {
164 std::string s;
165 raw_string_ostream os(s);
166
167 function_decl->print(os);
168
169 os.flush();
170
Jim Inghame3be0c52011-01-22 01:25:40 +0000171 log->Printf ("Transformed function AST:\n%s", s.c_str());
Sean Callanan17827832010-12-13 22:46:15 +0000172 }
173
174 return ret;
175}
176
177bool
178ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
179{
180 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
181
182 ASTContext &Ctx(*m_ast_context);
183
184 if (!m_sema)
185 return false;
186
187 if (!MethodDecl)
188 return false;
189
Jim Inghame3be0c52011-01-22 01:25:40 +0000190 if (log && log->GetVerbose())
Sean Callanan17827832010-12-13 22:46:15 +0000191 {
192 std::string s;
193 raw_string_ostream os(s);
194
195 Ctx.getTranslationUnitDecl()->print(os);
196
197 os.flush();
198
199 log->Printf("AST context before transforming:\n%s", s.c_str());
200 }
201
202 Stmt *method_body = MethodDecl->getBody();
203 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
204
205 bool ret = SynthesizeBodyResult (compound_stmt,
206 MethodDecl);
207
208 if (log)
209 {
210 std::string s;
211 raw_string_ostream os(s);
212
213 MethodDecl->print(os);
214
215 os.flush();
216
217 log->Printf("Transformed function AST:\n%s", s.c_str());
218 }
219
220 return ret;
221}
222
223bool
224ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
225 DeclContext *DC)
226{
227 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
228
229 ASTContext &Ctx(*m_ast_context);
Sean Callanan22c52d92011-07-18 21:30:18 +0000230
231 if (!Body)
Sean Callanan116be532010-07-01 20:08:22 +0000232 return false;
233
Sean Callanan22c52d92011-07-18 21:30:18 +0000234 if (Body->body_empty())
Sean Callanan116be532010-07-01 20:08:22 +0000235 return false;
236
Sean Callanan22c52d92011-07-18 21:30:18 +0000237 Stmt **last_stmt_ptr = Body->body_end() - 1;
Sean Callanan116be532010-07-01 20:08:22 +0000238 Stmt *last_stmt = *last_stmt_ptr;
239
Sean Callanan9e6ed532010-09-13 21:34:21 +0000240 while (dyn_cast<NullStmt>(last_stmt))
241 {
Sean Callanan22c52d92011-07-18 21:30:18 +0000242 if (last_stmt_ptr != Body->body_begin())
Sean Callanan9e6ed532010-09-13 21:34:21 +0000243 {
244 last_stmt_ptr--;
245 last_stmt = *last_stmt_ptr;
246 }
Sean Callanan2d1f4be2011-02-22 21:52:56 +0000247 else
248 {
249 return false;
250 }
Sean Callanan9e6ed532010-09-13 21:34:21 +0000251 }
252
Sean Callanan116be532010-07-01 20:08:22 +0000253 Expr *last_expr = dyn_cast<Expr>(last_stmt);
254
255 if (!last_expr)
256 // No auxiliary variable necessary; expression returns void
257 return true;
258
Sean Callanan92adcac2011-01-13 08:53:35 +0000259 // is_lvalue is used to record whether the expression returns an assignable Lvalue or an
260 // Rvalue. This is relevant because they are handled differently.
261 //
262 // For Lvalues
263 //
264 // - In AST result synthesis (here!) the expression E is transformed into an initialization
265 // T *$__lldb_expr_result_ptr = &E.
266 //
267 // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
268 // passed into the expression.
269 //
270 // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are redirected at
271 // an entry in the struct ($__lldb_arg) passed into the expression. (Other persistent
272 // variables are treated similarly, having been materialized as references, but in those
273 // cases the value of the reference itself is never modified.)
274 //
275 // - During materialization, $0 (the result persistent variable) is ignored.
276 //
277 // - During dematerialization, $0 is marked up as a load address with value equal to the
278 // contents of the structure entry.
279 //
280 // For Rvalues
281 //
282 // - In AST result synthesis the expression E is transformed into an initialization
283 // static T $__lldb_expr_result = E.
284 //
285 // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
286 // passed into the expression.
287 //
288 // - In IR transformations, an instruction is inserted at the beginning of the function to
289 // dereference the pointer resident in the slot. Reads and writes to $__lldb_expr_result
290 // are redirected at that dereferenced version. Guard variables for the static variable
291 // are excised.
292 //
293 // - During materialization, $0 (the result persistent variable) is populated with the location
294 // of a newly-allocated area of memory.
295 //
296 // - During dematerialization, $0 is ignored.
297
298 bool is_lvalue =
299 (last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) &&
300 (last_expr->getObjectKind() == OK_Ordinary);
301
Sean Callanan116be532010-07-01 20:08:22 +0000302 QualType expr_qual_type = last_expr->getType();
Sean Callanan78e37602011-01-27 04:42:51 +0000303 const clang::Type *expr_type = expr_qual_type.getTypePtr();
Sean Callanan116be532010-07-01 20:08:22 +0000304
305 if (!expr_type)
306 return false;
307
308 if (expr_type->isVoidType())
309 return true;
310
311 if (log)
312 {
313 std::string s = expr_qual_type.getAsString();
314
Sean Callanan92adcac2011-01-13 08:53:35 +0000315 log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
Sean Callanan116be532010-07-01 20:08:22 +0000316 }
317
Sean Callanan77eaf442011-07-08 00:39:14 +0000318 clang::VarDecl *result_decl = NULL;
Sean Callanan116be532010-07-01 20:08:22 +0000319
Sean Callanan92adcac2011-01-13 08:53:35 +0000320 if (is_lvalue)
321 {
Sean Callanan0c4d8d22011-08-04 21:37:47 +0000322 IdentifierInfo *result_ptr_id;
323
324 if (expr_type->isFunctionType())
325 result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should be treated like function pointers
326 else
327 result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
Sean Callanan92adcac2011-01-13 08:53:35 +0000328
329 QualType ptr_qual_type = Ctx.getPointerType(expr_qual_type);
330
331 result_decl = VarDecl::Create(Ctx,
332 DC,
333 SourceLocation(),
Sean Callananfb0b7582011-03-15 00:17:19 +0000334 SourceLocation(),
Sean Callanan0c4d8d22011-08-04 21:37:47 +0000335 result_ptr_id,
Sean Callanan92adcac2011-01-13 08:53:35 +0000336 ptr_qual_type,
337 NULL,
338 SC_Static,
339 SC_Static);
340
341 if (!result_decl)
342 return false;
343
344 ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
345
Sean Callananfb0b7582011-03-15 00:17:19 +0000346 m_sema->AddInitializerToDecl(result_decl, address_of_expr.take(), true, true);
Sean Callanan92adcac2011-01-13 08:53:35 +0000347 }
348 else
349 {
350 IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
351
352 result_decl = VarDecl::Create(Ctx,
353 DC,
Sean Callananfb0b7582011-03-15 00:17:19 +0000354 SourceLocation(),
355 SourceLocation(),
Sean Callanan92adcac2011-01-13 08:53:35 +0000356 &result_id,
357 expr_qual_type,
358 NULL,
359 SC_Static,
360 SC_Static);
361
362 if (!result_decl)
363 return false;
364
Sean Callananfb0b7582011-03-15 00:17:19 +0000365 m_sema->AddInitializerToDecl(result_decl, last_expr, true, true);
Sean Callanan92adcac2011-01-13 08:53:35 +0000366 }
Sean Callanan116be532010-07-01 20:08:22 +0000367
Sean Callanan17827832010-12-13 22:46:15 +0000368 DC->addDecl(result_decl);
Sean Callanan116be532010-07-01 20:08:22 +0000369
370 ///////////////////////////////
371 // call AddInitializerToDecl
372 //
Sean Callanane2ef6e32010-09-23 03:01:22 +0000373
Sean Callanan92adcac2011-01-13 08:53:35 +0000374 //m_sema->AddInitializerToDecl(result_decl, last_expr);
Sean Callanan116be532010-07-01 20:08:22 +0000375
376 /////////////////////////////////
377 // call ConvertDeclToDeclGroup
378 //
379
Sean Callanane2ef6e32010-09-23 03:01:22 +0000380 Sema::DeclGroupPtrTy result_decl_group_ptr;
Sean Callanan116be532010-07-01 20:08:22 +0000381
Sean Callanane2ef6e32010-09-23 03:01:22 +0000382 result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
Sean Callanan116be532010-07-01 20:08:22 +0000383
384 ////////////////////////
385 // call ActOnDeclStmt
386 //
387
Sean Callanane2ef6e32010-09-23 03:01:22 +0000388 StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr,
389 SourceLocation(),
390 SourceLocation()));
Sean Callanan116be532010-07-01 20:08:22 +0000391
Sean Callanan116be532010-07-01 20:08:22 +0000392 ////////////////////////////////////////////////
393 // replace the old statement with the new one
394 //
395
Sean Callananddb46ef2010-07-24 01:37:44 +0000396 *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());
Sean Callanan116be532010-07-01 20:08:22 +0000397
Sean Callanan116be532010-07-01 20:08:22 +0000398 return true;
399}
400
401void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000402ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
Sean Callanan116be532010-07-01 20:08:22 +0000403{
404 if (m_passthrough)
405 m_passthrough->HandleTranslationUnit(Ctx);
406}
407
Sean Callananbccce812011-08-23 21:20:51 +0000408void
409ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx)
410{
411 typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
412
413 for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
414 e = TypeDeclIterator(FunDeclCtx->decls_end());
415 i != e;
416 ++i)
417 {
418 MaybeRecordPersistentType(*i);
419 }
420}
421
422void
423ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D)
424{
425 if (!D->getIdentifier())
426 return;
427
428 StringRef name = D->getName();
429
430 if (name.size() == 0 || name[0] != '$')
431 return;
432
433 lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
434
435 ConstString name_cs(name.str().c_str());
436
437 if (log)
438 log->Printf ("Recording persistent type %s\n", name_cs.GetCString());
439
440 Decl *D_scratch = ClangASTContext::CopyDecl(&m_scratch_ast_context,
441 m_ast_context,
442 D);
443
444 TypeDecl *TD_scratch = dyn_cast<TypeDecl>(D_scratch);
445
446 if (TD_scratch)
447 m_persistent_vars.RegisterPersistentType(name_cs, TD_scratch);
448}
449
Sean Callanan116be532010-07-01 20:08:22 +0000450void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000451ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
Sean Callananbccce812011-08-23 21:20:51 +0000452{
Sean Callanan116be532010-07-01 20:08:22 +0000453 if (m_passthrough)
454 m_passthrough->HandleTagDeclDefinition(D);
455}
456
457void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000458ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
Sean Callanan116be532010-07-01 20:08:22 +0000459{
460 if (m_passthrough)
461 m_passthrough->CompleteTentativeDefinition(D);
462}
463
464void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000465ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
Sean Callanan116be532010-07-01 20:08:22 +0000466{
467 if (m_passthrough)
468 m_passthrough->HandleVTable(RD, DefinitionRequired);
469}
470
471void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000472ASTResultSynthesizer::PrintStats()
Sean Callanan116be532010-07-01 20:08:22 +0000473{
474 if (m_passthrough)
475 m_passthrough->PrintStats();
476}
477
478void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000479ASTResultSynthesizer::InitializeSema(Sema &S)
Sean Callanan116be532010-07-01 20:08:22 +0000480{
481 m_sema = &S;
Sean Callanan116be532010-07-01 20:08:22 +0000482
483 if (m_passthrough_sema)
484 m_passthrough_sema->InitializeSema(S);
485}
486
487void
Sean Callanan1a8d4092010-08-27 01:01:44 +0000488ASTResultSynthesizer::ForgetSema()
Sean Callanan116be532010-07-01 20:08:22 +0000489{
490 m_sema = NULL;
Sean Callanan116be532010-07-01 20:08:22 +0000491
492 if (m_passthrough_sema)
493 m_passthrough_sema->ForgetSema();
494}