180814287SRaphael Isemann //===-- ASTStructExtractor.cpp --------------------------------------------===//
24dbb271fSSean Callanan //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64dbb271fSSean Callanan //
74dbb271fSSean Callanan //===----------------------------------------------------------------------===//
84dbb271fSSean Callanan 
94dbb271fSSean Callanan #include "ASTStructExtractor.h"
104dbb271fSSean Callanan 
116f9e6901SZachary Turner #include "lldb/Utility/Log.h"
124dbb271fSSean Callanan #include "clang/AST/ASTContext.h"
134dbb271fSSean Callanan #include "clang/AST/Decl.h"
144dbb271fSSean Callanan #include "clang/AST/DeclCXX.h"
154dbb271fSSean Callanan #include "clang/AST/DeclGroup.h"
164dbb271fSSean Callanan #include "clang/AST/Expr.h"
174dbb271fSSean Callanan #include "clang/AST/RecordLayout.h"
184dbb271fSSean Callanan #include "clang/AST/Stmt.h"
194dbb271fSSean Callanan #include "clang/Parse/Parser.h"
204dbb271fSSean Callanan #include "clang/Sema/Sema.h"
214dbb271fSSean Callanan #include "llvm/Support/Casting.h"
224dbb271fSSean Callanan #include "llvm/Support/raw_ostream.h"
2376e47d48SRaphael Isemann #include <cstdlib>
244dbb271fSSean Callanan 
254dbb271fSSean Callanan using namespace llvm;
264dbb271fSSean Callanan using namespace clang;
274dbb271fSSean Callanan using namespace lldb_private;
284dbb271fSSean Callanan 
ASTStructExtractor(ASTConsumer * passthrough,const char * struct_name,ClangFunctionCaller & function)294dbb271fSSean Callanan ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
304dbb271fSSean Callanan                                        const char *struct_name,
31b9c1b51eSKate Stone                                        ClangFunctionCaller &function)
32248a1305SKonrad Kleine     : m_ast_context(nullptr), m_passthrough(passthrough),
332e033244SRaphael Isemann       m_passthrough_sema(nullptr), m_sema(nullptr), m_function(function),
342e033244SRaphael Isemann       m_struct_name(struct_name) {
354dbb271fSSean Callanan   if (!m_passthrough)
364dbb271fSSean Callanan     return;
374dbb271fSSean Callanan 
384dbb271fSSean Callanan   m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
394dbb271fSSean Callanan }
404dbb271fSSean Callanan 
41*fd2433e1SJonas Devlieghere ASTStructExtractor::~ASTStructExtractor() = default;
424dbb271fSSean Callanan 
Initialize(ASTContext & Context)43b9c1b51eSKate Stone void ASTStructExtractor::Initialize(ASTContext &Context) {
444dbb271fSSean Callanan   m_ast_context = &Context;
454dbb271fSSean Callanan 
464dbb271fSSean Callanan   if (m_passthrough)
474dbb271fSSean Callanan     m_passthrough->Initialize(Context);
484dbb271fSSean Callanan }
494dbb271fSSean Callanan 
ExtractFromFunctionDecl(FunctionDecl * F)50b9c1b51eSKate Stone void ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) {
514dbb271fSSean Callanan   if (!F->hasBody())
524dbb271fSSean Callanan     return;
534dbb271fSSean Callanan 
544dbb271fSSean Callanan   Stmt *body_stmt = F->getBody();
554dbb271fSSean Callanan   CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(body_stmt);
564dbb271fSSean Callanan 
574dbb271fSSean Callanan   if (!body_compound_stmt)
584dbb271fSSean Callanan     return; // do we have to handle this?
594dbb271fSSean Callanan 
60248a1305SKonrad Kleine   RecordDecl *struct_decl = nullptr;
614dbb271fSSean Callanan 
62771ef6d4SMalcolm Parsons   StringRef desired_name(m_struct_name);
634dbb271fSSean Callanan 
64b9c1b51eSKate Stone   for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(),
65b9c1b51eSKate Stone                                          be = body_compound_stmt->body_end();
66b9c1b51eSKate Stone        bi != be; ++bi) {
674dbb271fSSean Callanan     Stmt *curr_stmt = *bi;
684dbb271fSSean Callanan     DeclStmt *curr_decl_stmt = dyn_cast<DeclStmt>(curr_stmt);
694dbb271fSSean Callanan     if (!curr_decl_stmt)
704dbb271fSSean Callanan       continue;
714dbb271fSSean Callanan     DeclGroupRef decl_group = curr_decl_stmt->getDeclGroup();
72b9c1b51eSKate Stone     for (Decl *candidate_decl : decl_group) {
734dbb271fSSean Callanan       RecordDecl *candidate_record_decl = dyn_cast<RecordDecl>(candidate_decl);
744dbb271fSSean Callanan       if (!candidate_record_decl)
754dbb271fSSean Callanan         continue;
76b9c1b51eSKate Stone       if (candidate_record_decl->getName() == desired_name) {
774dbb271fSSean Callanan         struct_decl = candidate_record_decl;
784dbb271fSSean Callanan         break;
794dbb271fSSean Callanan       }
804dbb271fSSean Callanan     }
814dbb271fSSean Callanan     if (struct_decl)
824dbb271fSSean Callanan       break;
834dbb271fSSean Callanan   }
844dbb271fSSean Callanan 
854dbb271fSSean Callanan   if (!struct_decl)
864dbb271fSSean Callanan     return;
874dbb271fSSean Callanan 
88b9c1b51eSKate Stone   const ASTRecordLayout *struct_layout(
89b9c1b51eSKate Stone       &m_ast_context->getASTRecordLayout(struct_decl));
904dbb271fSSean Callanan 
914dbb271fSSean Callanan   if (!struct_layout)
924dbb271fSSean Callanan     return;
934dbb271fSSean Callanan 
94b9c1b51eSKate Stone   m_function.m_struct_size =
95b9c1b51eSKate Stone       struct_layout->getSize()
96b9c1b51eSKate Stone           .getQuantity(); // TODO Store m_struct_size as CharUnits
97b9c1b51eSKate Stone   m_function.m_return_offset =
98b9c1b51eSKate Stone       struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8;
99b9c1b51eSKate Stone   m_function.m_return_size =
100b9c1b51eSKate Stone       struct_layout->getDataSize().getQuantity() - m_function.m_return_offset;
1014dbb271fSSean Callanan 
1024dbb271fSSean Callanan   for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount();
103b9c1b51eSKate Stone        field_index < num_fields; ++field_index) {
104b9c1b51eSKate Stone     m_function.m_member_offsets.push_back(
105b9c1b51eSKate Stone         struct_layout->getFieldOffset(field_index) / 8);
1064dbb271fSSean Callanan   }
1074dbb271fSSean Callanan 
1084dbb271fSSean Callanan   m_function.m_struct_valid = true;
1094dbb271fSSean Callanan }
1104dbb271fSSean Callanan 
ExtractFromTopLevelDecl(Decl * D)111b9c1b51eSKate Stone void ASTStructExtractor::ExtractFromTopLevelDecl(Decl *D) {
1124dbb271fSSean Callanan   LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
1134dbb271fSSean Callanan 
114b9c1b51eSKate Stone   if (linkage_spec_decl) {
1154dbb271fSSean Callanan     RecordDecl::decl_iterator decl_iterator;
1164dbb271fSSean Callanan 
1174dbb271fSSean Callanan     for (decl_iterator = linkage_spec_decl->decls_begin();
118b9c1b51eSKate Stone          decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) {
1194dbb271fSSean Callanan       ExtractFromTopLevelDecl(*decl_iterator);
1204dbb271fSSean Callanan     }
1214dbb271fSSean Callanan   }
1224dbb271fSSean Callanan 
1234dbb271fSSean Callanan   FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
1244dbb271fSSean Callanan 
125b9c1b51eSKate Stone   if (m_ast_context && function_decl &&
126b9c1b51eSKate Stone       !m_function.m_wrapper_function_name.compare(
127771ef6d4SMalcolm Parsons           function_decl->getNameAsString())) {
1284dbb271fSSean Callanan     ExtractFromFunctionDecl(function_decl);
1294dbb271fSSean Callanan   }
1304dbb271fSSean Callanan }
1314dbb271fSSean Callanan 
HandleTopLevelDecl(DeclGroupRef D)132b9c1b51eSKate Stone bool ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D) {
1334dbb271fSSean Callanan   DeclGroupRef::iterator decl_iterator;
1344dbb271fSSean Callanan 
135b9c1b51eSKate Stone   for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) {
1364dbb271fSSean Callanan     Decl *decl = *decl_iterator;
1374dbb271fSSean Callanan 
1384dbb271fSSean Callanan     ExtractFromTopLevelDecl(decl);
1394dbb271fSSean Callanan   }
1404dbb271fSSean Callanan 
1414dbb271fSSean Callanan   if (m_passthrough)
1424dbb271fSSean Callanan     return m_passthrough->HandleTopLevelDecl(D);
1434dbb271fSSean Callanan   return true;
1444dbb271fSSean Callanan }
1454dbb271fSSean Callanan 
HandleTranslationUnit(ASTContext & Ctx)146b9c1b51eSKate Stone void ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx) {
1474dbb271fSSean Callanan   if (m_passthrough)
1484dbb271fSSean Callanan     m_passthrough->HandleTranslationUnit(Ctx);
1494dbb271fSSean Callanan }
1504dbb271fSSean Callanan 
HandleTagDeclDefinition(TagDecl * D)151b9c1b51eSKate Stone void ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D) {
1524dbb271fSSean Callanan   if (m_passthrough)
1534dbb271fSSean Callanan     m_passthrough->HandleTagDeclDefinition(D);
1544dbb271fSSean Callanan }
1554dbb271fSSean Callanan 
CompleteTentativeDefinition(VarDecl * D)156b9c1b51eSKate Stone void ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D) {
1574dbb271fSSean Callanan   if (m_passthrough)
1584dbb271fSSean Callanan     m_passthrough->CompleteTentativeDefinition(D);
1594dbb271fSSean Callanan }
1604dbb271fSSean Callanan 
HandleVTable(CXXRecordDecl * RD)161b9c1b51eSKate Stone void ASTStructExtractor::HandleVTable(CXXRecordDecl *RD) {
1624dbb271fSSean Callanan   if (m_passthrough)
1634dbb271fSSean Callanan     m_passthrough->HandleVTable(RD);
1644dbb271fSSean Callanan }
1654dbb271fSSean Callanan 
PrintStats()166b9c1b51eSKate Stone void ASTStructExtractor::PrintStats() {
1674dbb271fSSean Callanan   if (m_passthrough)
1684dbb271fSSean Callanan     m_passthrough->PrintStats();
1694dbb271fSSean Callanan }
1704dbb271fSSean Callanan 
InitializeSema(Sema & S)171b9c1b51eSKate Stone void ASTStructExtractor::InitializeSema(Sema &S) {
1724dbb271fSSean Callanan   m_sema = &S;
1734dbb271fSSean Callanan 
1744dbb271fSSean Callanan   if (m_passthrough_sema)
1754dbb271fSSean Callanan     m_passthrough_sema->InitializeSema(S);
1764dbb271fSSean Callanan }
1774dbb271fSSean Callanan 
ForgetSema()178b9c1b51eSKate Stone void ASTStructExtractor::ForgetSema() {
179248a1305SKonrad Kleine   m_sema = nullptr;
1804dbb271fSSean Callanan 
1814dbb271fSSean Callanan   if (m_passthrough_sema)
1824dbb271fSSean Callanan     m_passthrough_sema->ForgetSema();
1834dbb271fSSean Callanan }
184