1 | //===-- ASTStructExtractor.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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ASTStructExtractor.h" |
10 | |
11 | #include "lldb/Utility/Log.h" |
12 | #include "clang/AST/ASTContext.h" |
13 | #include "clang/AST/Decl.h" |
14 | #include "clang/AST/DeclCXX.h" |
15 | #include "clang/AST/DeclGroup.h" |
16 | #include "clang/AST/Expr.h" |
17 | #include "clang/AST/RecordLayout.h" |
18 | #include "clang/AST/Stmt.h" |
19 | #include "clang/Parse/Parser.h" |
20 | #include "clang/Sema/Sema.h" |
21 | #include "llvm/Support/Casting.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | #include <cstdlib> |
24 | |
25 | using namespace llvm; |
26 | using namespace clang; |
27 | using namespace lldb_private; |
28 | |
29 | ASTStructExtractor::(ASTConsumer *passthrough, |
30 | const char *struct_name, |
31 | ClangFunctionCaller &function) |
32 | : m_ast_context(nullptr), m_passthrough(passthrough), |
33 | m_passthrough_sema(nullptr), m_sema(nullptr), m_function(function), |
34 | m_struct_name(struct_name) { |
35 | if (!m_passthrough) |
36 | return; |
37 | |
38 | m_passthrough_sema = dyn_cast<SemaConsumer>(Val: passthrough); |
39 | } |
40 | |
41 | ASTStructExtractor::() = default; |
42 | |
43 | void ASTStructExtractor::(ASTContext &Context) { |
44 | m_ast_context = &Context; |
45 | |
46 | if (m_passthrough) |
47 | m_passthrough->Initialize(Context); |
48 | } |
49 | |
50 | void ASTStructExtractor::(FunctionDecl *F) { |
51 | if (!F->hasBody()) |
52 | return; |
53 | |
54 | Stmt *body_stmt = F->getBody(); |
55 | CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(Val: body_stmt); |
56 | |
57 | if (!body_compound_stmt) |
58 | return; // do we have to handle this? |
59 | |
60 | RecordDecl *struct_decl = nullptr; |
61 | |
62 | StringRef desired_name(m_struct_name); |
63 | |
64 | for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(), |
65 | be = body_compound_stmt->body_end(); |
66 | bi != be; ++bi) { |
67 | Stmt *curr_stmt = *bi; |
68 | DeclStmt *curr_decl_stmt = dyn_cast<DeclStmt>(Val: curr_stmt); |
69 | if (!curr_decl_stmt) |
70 | continue; |
71 | DeclGroupRef decl_group = curr_decl_stmt->getDeclGroup(); |
72 | for (Decl *candidate_decl : decl_group) { |
73 | RecordDecl *candidate_record_decl = dyn_cast<RecordDecl>(Val: candidate_decl); |
74 | if (!candidate_record_decl) |
75 | continue; |
76 | if (candidate_record_decl->getName() == desired_name) { |
77 | struct_decl = candidate_record_decl; |
78 | break; |
79 | } |
80 | } |
81 | if (struct_decl) |
82 | break; |
83 | } |
84 | |
85 | if (!struct_decl) |
86 | return; |
87 | |
88 | const ASTRecordLayout *struct_layout( |
89 | &m_ast_context->getASTRecordLayout(D: struct_decl)); |
90 | |
91 | if (!struct_layout) |
92 | return; |
93 | |
94 | m_function.m_struct_size = |
95 | struct_layout->getSize() |
96 | .getQuantity(); // TODO Store m_struct_size as CharUnits |
97 | m_function.m_return_offset = |
98 | struct_layout->getFieldOffset(FieldNo: struct_layout->getFieldCount() - 1) / 8; |
99 | m_function.m_return_size = |
100 | struct_layout->getDataSize().getQuantity() - m_function.m_return_offset; |
101 | |
102 | for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount(); |
103 | field_index < num_fields; ++field_index) { |
104 | m_function.m_member_offsets.push_back( |
105 | x: struct_layout->getFieldOffset(FieldNo: field_index) / 8); |
106 | } |
107 | |
108 | m_function.m_struct_valid = true; |
109 | } |
110 | |
111 | void ASTStructExtractor::(Decl *D) { |
112 | LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(Val: D); |
113 | |
114 | if (linkage_spec_decl) { |
115 | RecordDecl::decl_iterator decl_iterator; |
116 | |
117 | for (decl_iterator = linkage_spec_decl->decls_begin(); |
118 | decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) { |
119 | ExtractFromTopLevelDecl(D: *decl_iterator); |
120 | } |
121 | } |
122 | |
123 | FunctionDecl *function_decl = dyn_cast<FunctionDecl>(Val: D); |
124 | |
125 | if (m_ast_context && function_decl && |
126 | !m_function.m_wrapper_function_name.compare( |
127 | function_decl->getNameAsString())) { |
128 | ExtractFromFunctionDecl(F: function_decl); |
129 | } |
130 | } |
131 | |
132 | bool ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D) { |
133 | DeclGroupRef::iterator decl_iterator; |
134 | |
135 | for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) { |
136 | Decl *decl = *decl_iterator; |
137 | |
138 | ExtractFromTopLevelDecl(D: decl); |
139 | } |
140 | |
141 | if (m_passthrough) |
142 | return m_passthrough->HandleTopLevelDecl(D); |
143 | return true; |
144 | } |
145 | |
146 | void ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx) { |
147 | if (m_passthrough) |
148 | m_passthrough->HandleTranslationUnit(Ctx); |
149 | } |
150 | |
151 | void ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D) { |
152 | if (m_passthrough) |
153 | m_passthrough->HandleTagDeclDefinition(D); |
154 | } |
155 | |
156 | void ASTStructExtractor::(VarDecl *D) { |
157 | if (m_passthrough) |
158 | m_passthrough->CompleteTentativeDefinition(D); |
159 | } |
160 | |
161 | void ASTStructExtractor::HandleVTable(CXXRecordDecl *RD) { |
162 | if (m_passthrough) |
163 | m_passthrough->HandleVTable(RD); |
164 | } |
165 | |
166 | void ASTStructExtractor::() { |
167 | if (m_passthrough) |
168 | m_passthrough->PrintStats(); |
169 | } |
170 | |
171 | void ASTStructExtractor::(Sema &S) { |
172 | m_sema = &S; |
173 | |
174 | if (m_passthrough_sema) |
175 | m_passthrough_sema->InitializeSema(S); |
176 | } |
177 | |
178 | void ASTStructExtractor::() { |
179 | m_sema = nullptr; |
180 | |
181 | if (m_passthrough_sema) |
182 | m_passthrough_sema->ForgetSema(); |
183 | } |
184 | |