brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.1 KiB · de4de0a Raw
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