ASTStructExtractor.cpp revision 293127
1210299Sed//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===//
2210299Sed//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ASTStructExtractor.h"
11
12#include "stdlib.h"
13#include "clang/AST/ASTContext.h"
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/DeclGroup.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/RecordLayout.h"
19#include "clang/AST/Stmt.h"
20#include "clang/Parse/Parser.h"
21#include "clang/Sema/Sema.h"
22#include "llvm/Support/Casting.h"
23#include "llvm/Support/raw_ostream.h"
24#include "lldb/Core/Log.h"
25
26using namespace llvm;
27using namespace clang;
28using namespace lldb_private;
29
30ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
31                                       const char *struct_name,
32                                       ClangFunctionCaller &function) :
33    m_ast_context (NULL),
34    m_passthrough (passthrough),
35    m_passthrough_sema (NULL),
36    m_sema (NULL),
37    m_action (NULL),
38    m_function (function),
39    m_struct_name (struct_name)
40{
41    if (!m_passthrough)
42        return;
43
44    m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
45}
46
47ASTStructExtractor::~ASTStructExtractor()
48{
49}
50
51void
52ASTStructExtractor::Initialize(ASTContext &Context)
53{
54    m_ast_context = &Context;
55
56    if (m_passthrough)
57        m_passthrough->Initialize(Context);
58}
59
60void
61ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F)
62{
63    if (!F->hasBody())
64        return;
65
66    Stmt *body_stmt = F->getBody();
67    CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(body_stmt);
68
69    if (!body_compound_stmt)
70        return; // do we have to handle this?
71
72    RecordDecl *struct_decl = NULL;
73
74    StringRef desired_name(m_struct_name.c_str());
75
76    for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(), be = body_compound_stmt->body_end();
77         bi != be;
78         ++bi)
79    {
80        Stmt *curr_stmt = *bi;
81        DeclStmt *curr_decl_stmt = dyn_cast<DeclStmt>(curr_stmt);
82        if (!curr_decl_stmt)
83            continue;
84        DeclGroupRef decl_group = curr_decl_stmt->getDeclGroup();
85        for (Decl *candidate_decl : decl_group)
86        {
87            RecordDecl *candidate_record_decl = dyn_cast<RecordDecl>(candidate_decl);
88            if (!candidate_record_decl)
89                continue;
90            if (candidate_record_decl->getName() == desired_name)
91            {
92                struct_decl = candidate_record_decl;
93                break;
94            }
95        }
96        if (struct_decl)
97            break;
98    }
99
100    if (!struct_decl)
101        return;
102
103    const ASTRecordLayout* struct_layout(&m_ast_context->getASTRecordLayout (struct_decl));
104
105    if (!struct_layout)
106        return;
107
108    m_function.m_struct_size = struct_layout->getSize().getQuantity(); // TODO Store m_struct_size as CharUnits
109    m_function.m_return_offset = struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8;
110    m_function.m_return_size = struct_layout->getDataSize().getQuantity() - m_function.m_return_offset;
111
112    for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount();
113         field_index < num_fields;
114         ++field_index)
115    {
116        m_function.m_member_offsets.push_back(struct_layout->getFieldOffset(field_index) / 8);
117    }
118
119    m_function.m_struct_valid = true;
120}
121
122void
123ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D)
124{
125    LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
126
127    if (linkage_spec_decl)
128    {
129        RecordDecl::decl_iterator decl_iterator;
130
131        for (decl_iterator = linkage_spec_decl->decls_begin();
132             decl_iterator != linkage_spec_decl->decls_end();
133             ++decl_iterator)
134        {
135            ExtractFromTopLevelDecl(*decl_iterator);
136        }
137    }
138
139    FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
140
141    if (m_ast_context &&
142        function_decl &&
143        !m_function.m_wrapper_function_name.compare(function_decl->getNameAsString().c_str()))
144    {
145        ExtractFromFunctionDecl(function_decl);
146    }
147}
148
149bool
150ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D)
151{
152    DeclGroupRef::iterator decl_iterator;
153
154    for (decl_iterator = D.begin();
155         decl_iterator != D.end();
156         ++decl_iterator)
157    {
158        Decl *decl = *decl_iterator;
159
160        ExtractFromTopLevelDecl(decl);
161    }
162
163    if (m_passthrough)
164        return m_passthrough->HandleTopLevelDecl(D);
165    return true;
166}
167
168void
169ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx)
170{
171    if (m_passthrough)
172        m_passthrough->HandleTranslationUnit(Ctx);
173}
174
175void
176ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D)
177{
178    if (m_passthrough)
179        m_passthrough->HandleTagDeclDefinition(D);
180}
181
182void
183ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D)
184{
185    if (m_passthrough)
186        m_passthrough->CompleteTentativeDefinition(D);
187}
188
189void
190ASTStructExtractor::HandleVTable(CXXRecordDecl *RD)
191{
192    if (m_passthrough)
193        m_passthrough->HandleVTable(RD);
194}
195
196void
197ASTStructExtractor::PrintStats()
198{
199    if (m_passthrough)
200        m_passthrough->PrintStats();
201}
202
203void
204ASTStructExtractor::InitializeSema(Sema &S)
205{
206    m_sema = &S;
207    m_action = reinterpret_cast<Action*>(m_sema);
208
209    if (m_passthrough_sema)
210        m_passthrough_sema->InitializeSema(S);
211}
212
213void
214ASTStructExtractor::ForgetSema()
215{
216    m_sema = NULL;
217    m_action = NULL;
218
219    if (m_passthrough_sema)
220        m_passthrough_sema->ForgetSema();
221}
222