164562Sgshapiro//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===// 264562Sgshapiro// 364562Sgshapiro// The LLVM Compiler Infrastructure 490792Sgshapiro// 590792Sgshapiro// This file is distributed under the University of Illinois Open Source 690792Sgshapiro// License. See LICENSE.TXT for details. 790792Sgshapiro// 864562Sgshapiro//===----------------------------------------------------------------------===// 964562Sgshapiro 1064562Sgshapiro#include "stdlib.h" 1164562Sgshapiro#include "clang/AST/ASTContext.h" 1264562Sgshapiro#include "clang/AST/Decl.h" 1364562Sgshapiro#include "clang/AST/DeclCXX.h" 1464562Sgshapiro#include "clang/AST/DeclGroup.h" 15173340Sgshapiro#include "clang/AST/Expr.h" 1664562Sgshapiro#include "clang/AST/RecordLayout.h" 1764562Sgshapiro#include "clang/AST/Stmt.h" 1864562Sgshapiro#include "clang/Parse/Parser.h" 1990792Sgshapiro#include "clang/Sema/Sema.h" 2090792Sgshapiro#include "llvm/Support/Casting.h" 21173340Sgshapiro#include "llvm/Support/raw_ostream.h" 2264562Sgshapiro#include "lldb/Core/Log.h" 2364562Sgshapiro#include "lldb/Expression/ASTStructExtractor.h" 2464562Sgshapiro 2564562Sgshapirousing namespace llvm; 2664562Sgshapirousing namespace clang; 2790792Sgshapirousing namespace lldb_private; 2890792Sgshapiro 29173340SgshapiroASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, 3064562Sgshapiro const char *struct_name, 31285303Sgshapiro ClangFunction &function) : 32285303Sgshapiro m_ast_context (NULL), 33285303Sgshapiro m_passthrough (passthrough), 3490792Sgshapiro m_passthrough_sema (NULL), 35173340Sgshapiro m_sema (NULL), 3690792Sgshapiro m_action (NULL), 3798121Sgshapiro m_function (function), 3898121Sgshapiro m_struct_name (struct_name) 39173340Sgshapiro{ 40173340Sgshapiro if (!m_passthrough) 4164562Sgshapiro return; 4271345Sgshapiro 4371345Sgshapiro m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough); 4471345Sgshapiro} 4571345Sgshapiro 4671345SgshapiroASTStructExtractor::~ASTStructExtractor() 47266692Sgshapiro{ 48} 49 50void 51ASTStructExtractor::Initialize(ASTContext &Context) 52{ 53 m_ast_context = &Context; 54 55 if (m_passthrough) 56 m_passthrough->Initialize(Context); 57} 58 59void 60ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) 61{ 62 if (!F->hasBody()) 63 return; 64 65 Stmt *body_stmt = F->getBody(); 66 CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(body_stmt); 67 68 if (!body_compound_stmt) 69 return; // do we have to handle this? 70 71 RecordDecl *struct_decl = NULL; 72 73 StringRef desired_name(m_struct_name.c_str()); 74 75 for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(), be = body_compound_stmt->body_end(); 76 bi != be; 77 ++bi) 78 { 79 Stmt *curr_stmt = *bi; 80 DeclStmt *curr_decl_stmt = dyn_cast<DeclStmt>(curr_stmt); 81 if (!curr_decl_stmt) 82 continue; 83 DeclGroupRef decl_group = curr_decl_stmt->getDeclGroup(); 84 for (Decl *candidate_decl : decl_group) 85 { 86 RecordDecl *candidate_record_decl = dyn_cast<RecordDecl>(candidate_decl); 87 if (!candidate_record_decl) 88 continue; 89 if (candidate_record_decl->getName() == desired_name) 90 { 91 struct_decl = candidate_record_decl; 92 break; 93 } 94 } 95 if (struct_decl) 96 break; 97 } 98 99 if (!struct_decl) 100 return; 101 102 const ASTRecordLayout* struct_layout(&m_ast_context->getASTRecordLayout (struct_decl)); 103 104 if (!struct_layout) 105 return; 106 107 m_function.m_struct_size = struct_layout->getSize().getQuantity(); // TODO Store m_struct_size as CharUnits 108 m_function.m_return_offset = struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8; 109 m_function.m_return_size = struct_layout->getDataSize().getQuantity() - m_function.m_return_offset; 110 111 for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount(); 112 field_index < num_fields; 113 ++field_index) 114 { 115 m_function.m_member_offsets.push_back(struct_layout->getFieldOffset(field_index) / 8); 116 } 117 118 m_function.m_struct_valid = true; 119} 120 121void 122ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D) 123{ 124 LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D); 125 126 if (linkage_spec_decl) 127 { 128 RecordDecl::decl_iterator decl_iterator; 129 130 for (decl_iterator = linkage_spec_decl->decls_begin(); 131 decl_iterator != linkage_spec_decl->decls_end(); 132 ++decl_iterator) 133 { 134 ExtractFromTopLevelDecl(*decl_iterator); 135 } 136 } 137 138 FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D); 139 140 if (m_ast_context && 141 function_decl && 142 !m_function.m_wrapper_function_name.compare(function_decl->getNameAsString().c_str())) 143 { 144 ExtractFromFunctionDecl(function_decl); 145 } 146} 147 148bool 149ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D) 150{ 151 DeclGroupRef::iterator decl_iterator; 152 153 for (decl_iterator = D.begin(); 154 decl_iterator != D.end(); 155 ++decl_iterator) 156 { 157 Decl *decl = *decl_iterator; 158 159 ExtractFromTopLevelDecl(decl); 160 } 161 162 if (m_passthrough) 163 return m_passthrough->HandleTopLevelDecl(D); 164 return true; 165} 166 167void 168ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx) 169{ 170 if (m_passthrough) 171 m_passthrough->HandleTranslationUnit(Ctx); 172} 173 174void 175ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D) 176{ 177 if (m_passthrough) 178 m_passthrough->HandleTagDeclDefinition(D); 179} 180 181void 182ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D) 183{ 184 if (m_passthrough) 185 m_passthrough->CompleteTentativeDefinition(D); 186} 187 188void 189ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) 190{ 191 if (m_passthrough) 192 m_passthrough->HandleVTable(RD, DefinitionRequired); 193} 194 195void 196ASTStructExtractor::PrintStats() 197{ 198 if (m_passthrough) 199 m_passthrough->PrintStats(); 200} 201 202void 203ASTStructExtractor::InitializeSema(Sema &S) 204{ 205 m_sema = &S; 206 m_action = reinterpret_cast<Action*>(m_sema); 207 208 if (m_passthrough_sema) 209 m_passthrough_sema->InitializeSema(S); 210} 211 212void 213ASTStructExtractor::ForgetSema() 214{ 215 m_sema = NULL; 216 m_action = NULL; 217 218 if (m_passthrough_sema) 219 m_passthrough_sema->ForgetSema(); 220} 221