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