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

source code of lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp