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