517 lines · cpp
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-exception6//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>(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(LLDBLog::Expressions);58 59 if (NamedDecl *named_decl = dyn_cast<NamedDecl>(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>(D))65 LLDB_LOGF(log, "TransformTopLevelDecl(%s)",66 method_decl->getSelector().getAsString().c_str());67 else68 LLDB_LOGF(log, "TransformTopLevelDecl(<complex>)");69 }70 71 if (m_top_level) {72 RecordPersistentDecl(named_decl);73 }74 }75 76 if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(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(*decl_iterator);82 }83 } else if (!m_top_level) {84 if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) {85 if (m_ast_context &&86 method_decl->getSelector().getAsString() == "$__lldb_expr:") {87 RecordPersistentTypes(method_decl);88 SynthesizeObjCMethodResult(method_decl);89 }90 } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(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(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(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(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>(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(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>(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 sake193/// of capturing the expression result. Returns false if LLDB should instead194/// 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, then201 // the underlying value might come from a const static data member as202 // described in C++11 [class.static.data]p3. If that's the case, then the203 // value might not have an address if the user didn't also define the member204 // in a namespace scope. Taking the address would cause that LLDB later fails205 // to link the expression, so those lvalues should be stored in a result206 // 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(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>(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>(last_stmt);238 239 if (!last_expr)240 // No auxiliary variable necessary; expression returns void241 return true;242 243 // In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off244 // if that's the case.245 246 do {247 ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(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 assignable259 // Lvalue or an Rvalue. This is relevant because they are handled260 // differently.261 //262 // For Lvalues263 //264 // - In AST result synthesis (here!) the expression E is transformed into an265 // initialization T *$__lldb_expr_result_ptr = &E.266 //267 // - In structure allocation, a pointer-sized slot is allocated in the268 // struct that is to be passed into the expression.269 //270 // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are271 // redirected at an entry in the struct ($__lldb_arg) passed into the272 // expression. (Other persistent variables are treated similarly, having273 // been materialized as references, but in those cases the value of the274 // 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 value279 // equal to the contents of the structure entry.280 //281 // - Note: if we cannot take an address of the resulting Lvalue (e.g. it's282 // a static const member without an out-of-class definition), then we283 // follow the Rvalue route.284 //285 // For Rvalues286 //287 // - In AST result synthesis the expression E is transformed into an288 // initialization static T $__lldb_expr_result = E.289 //290 // - In structure allocation, a pointer-sized slot is allocated in the291 // struct that is to be passed into the expression.292 //293 // - In IR transformations, an instruction is inserted at the beginning of294 // the function to dereference the pointer resident in the slot. Reads and295 // writes to $__lldb_expr_result are redirected at that dereferenced296 // version. Guard variables for the static variable are excised.297 //298 // - During materialization, $0 (the result persistent variable) is299 // 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(last_expr)) {325 IdentifierInfo *result_ptr_id;326 327 if (expr_type->isFunctionType())328 result_ptr_id =329 &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should330 // be treated like function331 // pointers332 else333 result_ptr_id = &Ctx.Idents.get("$__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(expr_qual_type);343 else344 ptr_qual_type = Ctx.getPointerType(expr_qual_type);345 346 result_decl =347 VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(),348 result_ptr_id, ptr_qual_type, nullptr, SC_Static);349 350 if (!result_decl)351 return false;352 353 ExprResult address_of_expr =354 m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);355 if (address_of_expr.get())356 m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true);357 else358 return false;359 } else {360 IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");361 362 result_decl =363 VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id,364 expr_qual_type, nullptr, 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 AddInitializerToDecl376 //377 378 // m_sema->AddInitializerToDecl(result_decl, last_expr);379 380 /////////////////////////////////381 // call ConvertDeclToDeclGroup382 //383 384 Sema::DeclGroupPtrTy result_decl_group_ptr;385 386 result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);387 388 ////////////////////////389 // call ActOnDeclStmt390 //391 392 StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(393 result_decl_group_ptr, SourceLocation(), SourceLocation()));394 395 ////////////////////////////////////////////////396 // replace the old statement with the new one397 //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(*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(D);445}446 447void ASTResultSynthesizer::CommitPersistentDecls() {448 auto *state =449 m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC);450 if (!state)451 return;452 453 auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);454 455 lldb::TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(456 m_target, 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(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>(D_scratch))479 persistent_vars->RegisterPersistentDecl(ConstString(name),480 NamedDecl_scratch, 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