1 | //===-- ASTResultSynthesizer.cpp ------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ASTResultSynthesizer.h" |
10 | |
11 | #include "ClangASTImporter.h" |
12 | #include "ClangPersistentVariables.h" |
13 | |
14 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
15 | #include "lldb/Target/Target.h" |
16 | #include "lldb/Utility/LLDBAssert.h" |
17 | #include "lldb/Utility/LLDBLog.h" |
18 | #include "lldb/Utility/Log.h" |
19 | #include "clang/AST/ASTContext.h" |
20 | #include "clang/AST/Decl.h" |
21 | #include "clang/AST/DeclCXX.h" |
22 | #include "clang/AST/DeclGroup.h" |
23 | #include "clang/AST/DeclObjC.h" |
24 | #include "clang/AST/Expr.h" |
25 | #include "clang/AST/Stmt.h" |
26 | #include "clang/Parse/Parser.h" |
27 | #include "clang/Sema/SemaDiagnostic.h" |
28 | #include "llvm/Support/Casting.h" |
29 | #include "llvm/Support/raw_ostream.h" |
30 | #include <cstdlib> |
31 | |
32 | using namespace llvm; |
33 | using namespace clang; |
34 | using namespace lldb_private; |
35 | |
36 | ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, |
37 | bool top_level, Target &target) |
38 | : m_ast_context(nullptr), m_passthrough(passthrough), |
39 | m_passthrough_sema(nullptr), m_target(target), m_sema(nullptr), |
40 | m_top_level(top_level) { |
41 | if (!m_passthrough) |
42 | return; |
43 | |
44 | m_passthrough_sema = dyn_cast<SemaConsumer>(Val: passthrough); |
45 | } |
46 | |
47 | ASTResultSynthesizer::~ASTResultSynthesizer() = default; |
48 | |
49 | void ASTResultSynthesizer::Initialize(ASTContext &Context) { |
50 | m_ast_context = &Context; |
51 | |
52 | if (m_passthrough) |
53 | m_passthrough->Initialize(Context); |
54 | } |
55 | |
56 | void ASTResultSynthesizer::TransformTopLevelDecl(Decl *D) { |
57 | Log *log = GetLog(mask: LLDBLog::Expressions); |
58 | |
59 | if (NamedDecl *named_decl = dyn_cast<NamedDecl>(Val: D)) { |
60 | if (log && log->GetVerbose()) { |
61 | if (named_decl->getIdentifier()) |
62 | LLDB_LOGF(log, "TransformTopLevelDecl(%s)" , |
63 | named_decl->getIdentifier()->getNameStart()); |
64 | else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(Val: D)) |
65 | LLDB_LOGF(log, "TransformTopLevelDecl(%s)" , |
66 | method_decl->getSelector().getAsString().c_str()); |
67 | else |
68 | LLDB_LOGF(log, "TransformTopLevelDecl(<complex>)" ); |
69 | } |
70 | |
71 | if (m_top_level) { |
72 | RecordPersistentDecl(D: named_decl); |
73 | } |
74 | } |
75 | |
76 | if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(Val: D)) { |
77 | RecordDecl::decl_iterator decl_iterator; |
78 | |
79 | for (decl_iterator = linkage_spec_decl->decls_begin(); |
80 | decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) { |
81 | TransformTopLevelDecl(D: *decl_iterator); |
82 | } |
83 | } else if (!m_top_level) { |
84 | if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(Val: D)) { |
85 | if (m_ast_context && |
86 | !method_decl->getSelector().getAsString().compare(s: "$__lldb_expr:" )) { |
87 | RecordPersistentTypes(method_decl); |
88 | SynthesizeObjCMethodResult(MethodDecl: method_decl); |
89 | } |
90 | } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(Val: D)) { |
91 | // When completing user input the body of the function may be a nullptr. |
92 | if (m_ast_context && function_decl->hasBody() && |
93 | !function_decl->getNameInfo().getAsString().compare(s: "$__lldb_expr" )) { |
94 | RecordPersistentTypes(function_decl); |
95 | SynthesizeFunctionResult(FunDecl: function_decl); |
96 | } |
97 | } |
98 | } |
99 | } |
100 | |
101 | bool ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) { |
102 | DeclGroupRef::iterator decl_iterator; |
103 | |
104 | for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) { |
105 | Decl *decl = *decl_iterator; |
106 | |
107 | TransformTopLevelDecl(D: decl); |
108 | } |
109 | |
110 | if (m_passthrough) |
111 | return m_passthrough->HandleTopLevelDecl(D); |
112 | return true; |
113 | } |
114 | |
115 | bool ASTResultSynthesizer::SynthesizeFunctionResult(FunctionDecl *FunDecl) { |
116 | Log *log = GetLog(mask: LLDBLog::Expressions); |
117 | |
118 | if (!m_sema) |
119 | return false; |
120 | |
121 | FunctionDecl *function_decl = FunDecl; |
122 | |
123 | if (!function_decl) |
124 | return false; |
125 | |
126 | if (log && log->GetVerbose()) { |
127 | std::string s; |
128 | raw_string_ostream os(s); |
129 | |
130 | function_decl->print(os); |
131 | |
132 | os.flush(); |
133 | |
134 | LLDB_LOGF(log, "Untransformed function AST:\n%s" , s.c_str()); |
135 | } |
136 | |
137 | Stmt *function_body = function_decl->getBody(); |
138 | CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(Val: function_body); |
139 | |
140 | bool ret = SynthesizeBodyResult(compound_stmt, function_decl); |
141 | |
142 | if (log && log->GetVerbose()) { |
143 | std::string s; |
144 | raw_string_ostream os(s); |
145 | |
146 | function_decl->print(os); |
147 | |
148 | os.flush(); |
149 | |
150 | LLDB_LOGF(log, "Transformed function AST:\n%s" , s.c_str()); |
151 | } |
152 | |
153 | return ret; |
154 | } |
155 | |
156 | bool ASTResultSynthesizer::SynthesizeObjCMethodResult( |
157 | ObjCMethodDecl *MethodDecl) { |
158 | Log *log = GetLog(mask: LLDBLog::Expressions); |
159 | |
160 | if (!m_sema) |
161 | return false; |
162 | |
163 | if (!MethodDecl) |
164 | return false; |
165 | |
166 | if (log && log->GetVerbose()) { |
167 | std::string s; |
168 | raw_string_ostream os(s); |
169 | |
170 | MethodDecl->print(os); |
171 | |
172 | os.flush(); |
173 | |
174 | LLDB_LOGF(log, "Untransformed method AST:\n%s" , s.c_str()); |
175 | } |
176 | |
177 | Stmt *method_body = MethodDecl->getBody(); |
178 | |
179 | if (!method_body) |
180 | return false; |
181 | |
182 | CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(Val: method_body); |
183 | |
184 | bool ret = SynthesizeBodyResult(compound_stmt, MethodDecl); |
185 | |
186 | if (log && log->GetVerbose()) { |
187 | std::string s; |
188 | raw_string_ostream os(s); |
189 | |
190 | MethodDecl->print(os); |
191 | |
192 | os.flush(); |
193 | |
194 | LLDB_LOGF(log, "Transformed method AST:\n%s" , s.c_str()); |
195 | } |
196 | |
197 | return ret; |
198 | } |
199 | |
200 | /// Returns true if LLDB can take the address of the given lvalue for the sake |
201 | /// of capturing the expression result. Returns false if LLDB should instead |
202 | /// store the expression result in a result variable. |
203 | static bool CanTakeAddressOfLValue(const Expr *lvalue_expr) { |
204 | assert(lvalue_expr->getValueKind() == VK_LValue && |
205 | "lvalue_expr not a lvalue" ); |
206 | |
207 | QualType qt = lvalue_expr->getType(); |
208 | // If the lvalue has const-qualified non-volatile integral or enum type, then |
209 | // the underlying value might come from a const static data member as |
210 | // described in C++11 [class.static.data]p3. If that's the case, then the |
211 | // value might not have an address if the user didn't also define the member |
212 | // in a namespace scope. Taking the address would cause that LLDB later fails |
213 | // to link the expression, so those lvalues should be stored in a result |
214 | // variable. |
215 | if (qt->isIntegralOrEnumerationType() && qt.isConstQualified() && |
216 | !qt.isVolatileQualified()) |
217 | return false; |
218 | return true; |
219 | } |
220 | |
221 | bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, |
222 | DeclContext *DC) { |
223 | Log *log = GetLog(mask: LLDBLog::Expressions); |
224 | |
225 | ASTContext &Ctx(*m_ast_context); |
226 | |
227 | if (!Body) |
228 | return false; |
229 | |
230 | if (Body->body_empty()) |
231 | return false; |
232 | |
233 | Stmt **last_stmt_ptr = Body->body_end() - 1; |
234 | Stmt *last_stmt = *last_stmt_ptr; |
235 | |
236 | while (isa<NullStmt>(Val: last_stmt)) { |
237 | if (last_stmt_ptr != Body->body_begin()) { |
238 | last_stmt_ptr--; |
239 | last_stmt = *last_stmt_ptr; |
240 | } else { |
241 | return false; |
242 | } |
243 | } |
244 | |
245 | Expr *last_expr = dyn_cast<Expr>(Val: last_stmt); |
246 | |
247 | if (!last_expr) |
248 | // No auxiliary variable necessary; expression returns void |
249 | return true; |
250 | |
251 | // In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off |
252 | // if that's the case. |
253 | |
254 | do { |
255 | ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(Val: last_expr); |
256 | |
257 | if (!implicit_cast) |
258 | break; |
259 | |
260 | if (implicit_cast->getCastKind() != CK_LValueToRValue) |
261 | break; |
262 | |
263 | last_expr = implicit_cast->getSubExpr(); |
264 | } while (false); |
265 | |
266 | // is_lvalue is used to record whether the expression returns an assignable |
267 | // Lvalue or an Rvalue. This is relevant because they are handled |
268 | // differently. |
269 | // |
270 | // For Lvalues |
271 | // |
272 | // - In AST result synthesis (here!) the expression E is transformed into an |
273 | // initialization T *$__lldb_expr_result_ptr = &E. |
274 | // |
275 | // - In structure allocation, a pointer-sized slot is allocated in the |
276 | // struct that is to be passed into the expression. |
277 | // |
278 | // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are |
279 | // redirected at an entry in the struct ($__lldb_arg) passed into the |
280 | // expression. (Other persistent variables are treated similarly, having |
281 | // been materialized as references, but in those cases the value of the |
282 | // reference itself is never modified.) |
283 | // |
284 | // - During materialization, $0 (the result persistent variable) is ignored. |
285 | // |
286 | // - During dematerialization, $0 is marked up as a load address with value |
287 | // equal to the contents of the structure entry. |
288 | // |
289 | // - Note: if we cannot take an address of the resulting Lvalue (e.g. it's |
290 | // a static const member without an out-of-class definition), then we |
291 | // follow the Rvalue route. |
292 | // |
293 | // For Rvalues |
294 | // |
295 | // - In AST result synthesis the expression E is transformed into an |
296 | // initialization static T $__lldb_expr_result = E. |
297 | // |
298 | // - In structure allocation, a pointer-sized slot is allocated in the |
299 | // struct that is to be passed into the expression. |
300 | // |
301 | // - In IR transformations, an instruction is inserted at the beginning of |
302 | // the function to dereference the pointer resident in the slot. Reads and |
303 | // writes to $__lldb_expr_result are redirected at that dereferenced |
304 | // version. Guard variables for the static variable are excised. |
305 | // |
306 | // - During materialization, $0 (the result persistent variable) is |
307 | // populated with the location of a newly-allocated area of memory. |
308 | // |
309 | // - During dematerialization, $0 is ignored. |
310 | |
311 | bool is_lvalue = last_expr->getValueKind() == VK_LValue && |
312 | last_expr->getObjectKind() == OK_Ordinary; |
313 | |
314 | QualType expr_qual_type = last_expr->getType(); |
315 | const clang::Type *expr_type = expr_qual_type.getTypePtr(); |
316 | |
317 | if (!expr_type) |
318 | return false; |
319 | |
320 | if (expr_type->isVoidType()) |
321 | return true; |
322 | |
323 | if (log) { |
324 | std::string s = expr_qual_type.getAsString(); |
325 | |
326 | LLDB_LOGF(log, "Last statement is an %s with type: %s" , |
327 | (is_lvalue ? "lvalue" : "rvalue" ), s.c_str()); |
328 | } |
329 | |
330 | clang::VarDecl *result_decl = nullptr; |
331 | |
332 | if (is_lvalue && CanTakeAddressOfLValue(lvalue_expr: last_expr)) { |
333 | IdentifierInfo *result_ptr_id; |
334 | |
335 | if (expr_type->isFunctionType()) |
336 | result_ptr_id = |
337 | &Ctx.Idents.get(Name: "$__lldb_expr_result" ); // functions actually should |
338 | // be treated like function |
339 | // pointers |
340 | else |
341 | result_ptr_id = &Ctx.Idents.get(Name: "$__lldb_expr_result_ptr" ); |
342 | |
343 | m_sema->RequireCompleteType(last_expr->getSourceRange().getBegin(), |
344 | expr_qual_type, |
345 | clang::diag::err_incomplete_type); |
346 | |
347 | QualType ptr_qual_type; |
348 | |
349 | if (expr_qual_type->getAs<ObjCObjectType>() != nullptr) |
350 | ptr_qual_type = Ctx.getObjCObjectPointerType(OIT: expr_qual_type); |
351 | else |
352 | ptr_qual_type = Ctx.getPointerType(T: expr_qual_type); |
353 | |
354 | result_decl = |
355 | VarDecl::Create(C&: Ctx, DC, StartLoc: SourceLocation(), IdLoc: SourceLocation(), |
356 | Id: result_ptr_id, T: ptr_qual_type, TInfo: nullptr, S: SC_Static); |
357 | |
358 | if (!result_decl) |
359 | return false; |
360 | |
361 | ExprResult address_of_expr = |
362 | m_sema->CreateBuiltinUnaryOp(OpLoc: SourceLocation(), Opc: UO_AddrOf, InputExpr: last_expr); |
363 | if (address_of_expr.get()) |
364 | m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true); |
365 | else |
366 | return false; |
367 | } else { |
368 | IdentifierInfo &result_id = Ctx.Idents.get(Name: "$__lldb_expr_result" ); |
369 | |
370 | result_decl = |
371 | VarDecl::Create(C&: Ctx, DC, StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &result_id, |
372 | T: expr_qual_type, TInfo: nullptr, S: SC_Static); |
373 | |
374 | if (!result_decl) |
375 | return false; |
376 | |
377 | m_sema->AddInitializerToDecl(result_decl, last_expr, true); |
378 | } |
379 | |
380 | DC->addDecl(result_decl); |
381 | |
382 | /////////////////////////////// |
383 | // call AddInitializerToDecl |
384 | // |
385 | |
386 | // m_sema->AddInitializerToDecl(result_decl, last_expr); |
387 | |
388 | ///////////////////////////////// |
389 | // call ConvertDeclToDeclGroup |
390 | // |
391 | |
392 | Sema::DeclGroupPtrTy result_decl_group_ptr; |
393 | |
394 | result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl); |
395 | |
396 | //////////////////////// |
397 | // call ActOnDeclStmt |
398 | // |
399 | |
400 | StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt( |
401 | Decl: result_decl_group_ptr, StartLoc: SourceLocation(), EndLoc: SourceLocation())); |
402 | |
403 | //////////////////////////////////////////////// |
404 | // replace the old statement with the new one |
405 | // |
406 | |
407 | *last_stmt_ptr = static_cast<Stmt *>(result_initialization_stmt_result.get()); |
408 | |
409 | return true; |
410 | } |
411 | |
412 | void ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) { |
413 | if (m_passthrough) |
414 | m_passthrough->HandleTranslationUnit(Ctx); |
415 | } |
416 | |
417 | void ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx) { |
418 | typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator; |
419 | |
420 | for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()), |
421 | e = TypeDeclIterator(FunDeclCtx->decls_end()); |
422 | i != e; ++i) { |
423 | MaybeRecordPersistentType(D: *i); |
424 | } |
425 | } |
426 | |
427 | void ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D) { |
428 | if (!D->getIdentifier()) |
429 | return; |
430 | |
431 | StringRef name = D->getName(); |
432 | if (name.empty() || name.front() != '$') |
433 | return; |
434 | |
435 | LLDB_LOG(GetLog(LLDBLog::Expressions), "Recording persistent type {0}" , name); |
436 | |
437 | m_decls.push_back(D); |
438 | } |
439 | |
440 | void ASTResultSynthesizer::RecordPersistentDecl(NamedDecl *D) { |
441 | lldbassert(m_top_level); |
442 | |
443 | if (!D->getIdentifier()) |
444 | return; |
445 | |
446 | StringRef name = D->getName(); |
447 | if (name.empty()) |
448 | return; |
449 | |
450 | LLDB_LOG(GetLog(LLDBLog::Expressions), "Recording persistent decl {0}" , name); |
451 | |
452 | m_decls.push_back(x: D); |
453 | } |
454 | |
455 | void ASTResultSynthesizer::CommitPersistentDecls() { |
456 | auto *state = |
457 | m_target.GetPersistentExpressionStateForLanguage(language: lldb::eLanguageTypeC); |
458 | if (!state) |
459 | return; |
460 | |
461 | auto *persistent_vars = llvm::cast<ClangPersistentVariables>(Val: state); |
462 | |
463 | lldb::TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget( |
464 | target&: m_target, lang_opts: m_ast_context->getLangOpts()); |
465 | |
466 | for (clang::NamedDecl *decl : m_decls) { |
467 | StringRef name = decl->getName(); |
468 | |
469 | Decl *D_scratch = persistent_vars->GetClangASTImporter()->DeportDecl( |
470 | &scratch_ts_sp->getASTContext(), decl); |
471 | |
472 | if (!D_scratch) { |
473 | Log *log = GetLog(mask: LLDBLog::Expressions); |
474 | |
475 | if (log) { |
476 | std::string s; |
477 | llvm::raw_string_ostream ss(s); |
478 | decl->dump(ss); |
479 | ss.flush(); |
480 | |
481 | LLDB_LOGF(log, "Couldn't commit persistent decl: %s\n" , s.c_str()); |
482 | } |
483 | |
484 | continue; |
485 | } |
486 | |
487 | if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(Val: D_scratch)) |
488 | persistent_vars->RegisterPersistentDecl(name: ConstString(name), |
489 | decl: NamedDecl_scratch, ctx: scratch_ts_sp); |
490 | } |
491 | } |
492 | |
493 | void ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) { |
494 | if (m_passthrough) |
495 | m_passthrough->HandleTagDeclDefinition(D); |
496 | } |
497 | |
498 | void ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) { |
499 | if (m_passthrough) |
500 | m_passthrough->CompleteTentativeDefinition(D); |
501 | } |
502 | |
503 | void ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD) { |
504 | if (m_passthrough) |
505 | m_passthrough->HandleVTable(RD); |
506 | } |
507 | |
508 | void ASTResultSynthesizer::PrintStats() { |
509 | if (m_passthrough) |
510 | m_passthrough->PrintStats(); |
511 | } |
512 | |
513 | void ASTResultSynthesizer::InitializeSema(Sema &S) { |
514 | m_sema = &S; |
515 | |
516 | if (m_passthrough_sema) |
517 | m_passthrough_sema->InitializeSema(S); |
518 | } |
519 | |
520 | void ASTResultSynthesizer::ForgetSema() { |
521 | m_sema = nullptr; |
522 | |
523 | if (m_passthrough_sema) |
524 | m_passthrough_sema->ForgetSema(); |
525 | } |
526 | |