blob: 3a5769b7f3b150b6d447c351efc6479f3ee8077e [file] [log] [blame]
Sean Callanan8c6934d2010-07-01 20:08:22 +00001//===-- ClangResultSynthesizer.cpp ------------------------------*- C++ -*-===//
2//
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"
15#include "clang/AST/Expr.h"
16#include "clang/AST/Stmt.h"
17#include "clang/Parse/Action.h"
18#include "clang/Parse/Parser.h"
19#include "clang/Parse/Scope.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/raw_ostream.h"
22#include "lldb/Core/Log.h"
23#include "lldb/Expression/ClangResultSynthesizer.h"
24
25using namespace llvm;
26using namespace clang;
27using namespace lldb_private;
28
29ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) :
30 m_passthrough(passthrough),
31 m_passthrough_sema(NULL),
32 m_sema(NULL),
33 m_ast_context(NULL)
34{
35 if (!m_passthrough)
36 return;
37
38 m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
39}
40
41ClangResultSynthesizer::~ClangResultSynthesizer()
42{
43}
44
45void
46ClangResultSynthesizer::Initialize(ASTContext &Context)
47{
48 m_ast_context = &Context;
49
50 if (m_passthrough)
51 m_passthrough->Initialize(Context);
52}
53
54void
55ClangResultSynthesizer::TransformTopLevelDecl(Decl* D)
56{
57 LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
58
59 if (linkage_spec_decl)
60 {
61 RecordDecl::decl_iterator decl_iterator;
62
63 for (decl_iterator = linkage_spec_decl->decls_begin();
64 decl_iterator != linkage_spec_decl->decls_end();
65 ++decl_iterator)
66 {
67 TransformTopLevelDecl(*decl_iterator);
68 }
69 }
70
71 FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
72
73 if (m_ast_context &&
74 function_decl &&
75 !strcmp(function_decl->getNameAsCString(),
76 "___clang_expr"))
77 {
78 SynthesizeResult(*m_ast_context, function_decl);
79 }
80}
81
82void
83ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
84{
85 DeclGroupRef::iterator decl_iterator;
86
87 for (decl_iterator = D.begin();
88 decl_iterator != D.end();
89 ++decl_iterator)
90 {
91 Decl *decl = *decl_iterator;
92
93 TransformTopLevelDecl(decl);
94 }
95
96 if (m_passthrough)
97 m_passthrough->HandleTopLevelDecl(D);
98}
99
100bool
101ClangResultSynthesizer::SynthesizeResult (ASTContext &Ctx,
102 FunctionDecl *FunDecl)
103{
104 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
105
106 if (!m_sema)
107 return false;
108
109 FunctionDecl *function_decl = FunDecl;
110
111 if (!function_decl)
112 return false;
113
114 Stmt *function_body = function_decl->getBody();
115 CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
116
117 if (!compound_stmt)
118 return false;
119
120 if (compound_stmt->body_empty())
121 return false;
122
123 Stmt **last_stmt_ptr = compound_stmt->body_end() - 1;
124 Stmt *last_stmt = *last_stmt_ptr;
125
126 Expr *last_expr = dyn_cast<Expr>(last_stmt);
127
128 if (!last_expr)
129 // No auxiliary variable necessary; expression returns void
130 return true;
131
132 QualType expr_qual_type = last_expr->getType();
133 clang::Type *expr_type = expr_qual_type.getTypePtr();
134
135 if (!expr_type)
136 return false;
137
138 if (expr_type->isVoidType())
139 return true;
140
141 if (log)
142 {
143 std::string s = expr_qual_type.getAsString();
144
145 log->Printf("Last statement's type: %s", s.c_str());
146 }
147
148 IdentifierInfo &result_id = Ctx.Idents.get("___clang_expr_result");
149
150 DeclContext *decl_context = function_decl->getDeclContext();
151
152 clang::VarDecl *result_decl = VarDecl::Create(Ctx,
153 function_decl,
154 SourceLocation(),
155 &result_id,
156 expr_qual_type,
157 NULL,
158 VarDecl::Static,
159 VarDecl::Static);
160
161 if (!result_decl)
162 return false;
163
164 function_decl->addDecl(result_decl);
165
166 ///////////////////////////////
167 // call AddInitializerToDecl
168 //
169
170 Parser::DeclPtrTy result_decl_ptr;
171 result_decl_ptr.set(result_decl);
172
173 m_action->AddInitializerToDecl(result_decl_ptr, Parser::ExprArg(*m_action, last_expr));
174
175 /////////////////////////////////
176 // call ConvertDeclToDeclGroup
177 //
178
179 Parser::DeclGroupPtrTy result_decl_group_ptr;
180
181 result_decl_group_ptr = m_action->ConvertDeclToDeclGroup(result_decl_ptr);
182
183 ////////////////////////
184 // call ActOnDeclStmt
185 //
186
187 Parser::OwningStmtResult result_initialization_stmt_result(m_action->ActOnDeclStmt(result_decl_group_ptr,
188 SourceLocation(),
189 SourceLocation()));
190
191
192 ///////////////////////////////////////////////
193 // Synthesize external void pointer variable
194 //
195
196 IdentifierInfo &result_ptr_id = Ctx.Idents.get("___clang_expr_result_ptr");
197
198 clang::VarDecl *result_ptr_decl = VarDecl::Create(Ctx,
199 decl_context,
200 SourceLocation(),
201 &result_ptr_id,
202 Ctx.VoidPtrTy,
203 NULL,
204 VarDecl::Extern,
205 VarDecl::Extern);
206
207 /////////////////////////////////////////////
208 // Build a DeclRef for the result variable
209 //
210
211 DeclRefExpr *result_decl_ref_expr = DeclRefExpr::Create(Ctx,
212 NULL,
213 SourceRange(),
214 result_decl,
215 SourceLocation(),
216 expr_qual_type);
217
218 ///////////////////////
219 // call ActOnUnaryOp
220 //
221
222 Scope my_scope(NULL, (Scope::BlockScope | Scope::FnScope | Scope::DeclScope));
223
224 Parser::DeclPtrTy result_ptr_decl_ptr;
225 result_ptr_decl_ptr.set(result_ptr_decl);
226
227 Parser::OwningExprResult addressof_expr_result(m_action->ActOnUnaryOp(&my_scope,
228 SourceLocation(),
229 tok::amp,
230 Parser::ExprArg(*m_action, result_decl_ref_expr)));
231
232 ////////////////////////////////////////////
233 // Build a DeclRef for the result pointer
234 //
235
236 DeclRefExpr *result_ptr_decl_ref_expr = DeclRefExpr::Create(Ctx,
237 NULL,
238 SourceRange(),
239 result_ptr_decl,
240 SourceLocation(),
241 Ctx.VoidPtrTy);
242
243 ////////////////////////
244 // call ActOnBinaryOp
245 //
246
247 Parser::OwningExprResult assignment_expr_result(m_action->ActOnBinOp(&my_scope,
248 SourceLocation(),
249 tok::equal,
250 Parser::ExprArg(*m_action, result_ptr_decl_ref_expr),
251 Parser::ExprArg(*m_action, addressof_expr_result.take())));
252
253 ////////////////////////////
254 // call ActOnCompoundStmt
255 //
256
257 void *stmts[2];
258
259 stmts[0] = result_initialization_stmt_result.take();
260 stmts[1] = assignment_expr_result.take();
261
262 Parser::OwningStmtResult compound_stmt_result(m_action->ActOnCompoundStmt(SourceLocation(),
263 SourceLocation(),
264 Parser::MultiStmtArg(*m_action, stmts, 2),
265 false));
266
267 ////////////////////////////////////////////////
268 // replace the old statement with the new one
269 //
270
271 *last_stmt_ptr = reinterpret_cast<Stmt*>(compound_stmt_result.take());
272
273 if (log)
274 {
275 std::string s;
276 raw_string_ostream os(s);
277
278 function_decl->print(os);
279
280 os.flush();
281
282 log->Printf("Transformed function AST:\n%s", s.c_str());
283 }
284
285 return true;
286}
287
288void
289ClangResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
290{
291 if (m_passthrough)
292 m_passthrough->HandleTranslationUnit(Ctx);
293}
294
295void
296ClangResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
297{
298 if (m_passthrough)
299 m_passthrough->HandleTagDeclDefinition(D);
300}
301
302void
303ClangResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
304{
305 if (m_passthrough)
306 m_passthrough->CompleteTentativeDefinition(D);
307}
308
309void
310ClangResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
311{
312 if (m_passthrough)
313 m_passthrough->HandleVTable(RD, DefinitionRequired);
314}
315
316void
317ClangResultSynthesizer::PrintStats()
318{
319 if (m_passthrough)
320 m_passthrough->PrintStats();
321}
322
323void
324ClangResultSynthesizer::InitializeSema(Sema &S)
325{
326 m_sema = &S;
327 m_action = reinterpret_cast<Action*>(m_sema);
328
329 if (m_passthrough_sema)
330 m_passthrough_sema->InitializeSema(S);
331}
332
333void
334ClangResultSynthesizer::ForgetSema()
335{
336 m_sema = NULL;
337 m_action = NULL;
338
339 if (m_passthrough_sema)
340 m_passthrough_sema->ForgetSema();
341}