• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ahueck / llvm-dimeta / 13933486559

18 Mar 2025 09:06PM UTC coverage: 83.197% (-0.4%) from 83.637%
13933486559

push

github

web-flow
Refactoring (#35)

1027 of 1482 branches covered (69.3%)

Branch coverage included in aggregate %.

86 of 87 new or added lines in 10 files covered. (98.85%)

17 existing lines in 7 files now uncovered.

1924 of 2065 relevant lines covered (93.17%)

3950.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.61
/lib/type/DIParser.cpp
1
//  llvm-dimeta library
2
//  Copyright (c) 2022-2025 llvm-dimeta authors
3
//  Distributed under the BSD 3-Clause license.
4
//  (See accompanying file LICENSE)
5
//  SPDX-License-Identifier: BSD-3-Clause
6
//
7

8
#include "DIParser.h"
9

10
#include "DIVisitor.h"
11
#include "DimetaData.h"
12
#include "support/Logger.h"
13

14
#include <cstdlib>
15
#include <llvm/BinaryFormat/Dwarf.h>
16

17
namespace dimeta::diparser {
18

19
class DIEventVisitor : public visitor::DINodeVisitor<DIEventVisitor> {
20
  // TODO visitVariable
21
 private:
22
  state::MetaData current_;
23
  state::MetaStack stack_;
24
  DIParseEvents& events_;
25
  struct EnumMeta {
26
    llvm::DIType* enum_base{nullptr};
27
    bool is_enum{false};
28
  };
29
  EnumMeta enum_data_{};
3,333✔
30

31
 public:
32
  explicit DIEventVisitor(DIParseEvents& events);
33
  ~DIEventVisitor();
34

35
  bool visitBasicType(const llvm::DIBasicType*);
36

37
  bool visitDerivedType(const llvm::DIDerivedType*);
38

39
  bool visitCompositeType(const llvm::DICompositeType*);
40

41
  bool visitNode(const llvm::DINode* node);
42

43
  bool visitRecurringCompositeType(const llvm::DICompositeType*);
44

45
  void leaveBasicType(const llvm::DIBasicType*);
46

47
  void leaveCompositeType(const llvm::DICompositeType*);
48

49
  void leaveRecurringCompositeType(const llvm::DICompositeType*);
50
};
51

52
DIEventVisitor::DIEventVisitor(DIParseEvents& events) : events_{events} {
3,333✔
53
}
3,333✔
54

55
DIEventVisitor::~DIEventVisitor() = default;
3,333✔
56

57
bool DIEventVisitor::visitBasicType(const llvm::DIBasicType* basic_type) {
5,141✔
58
  //  state::Entity fundamental_e{state::Entity::freestanding};
59
  current_.type = const_cast<llvm::DIBasicType*>(basic_type);
5,141✔
60

61
  if (current_.is_member) {
5,141✔
62
    assert(!stack_.empty() && "Free standing fundamental requires empty stack");
6,156!
63
    //    fundamental_e = state::Entity::member;
64
  }
3,078✔
65
  // create (free-standing) fundamental (finished recursion)
66
  //  current_.state = fundamental_e;
67

68
  if (enum_data_.is_enum) {
5,141✔
69
    // pattern matches enum types
70
    //    events.make_enum_member()
71
    enum_data_.enum_base = current_.type;
15✔
72
    return true;
15✔
73
  }
74

75
  events_.make_fundamental(current_);
5,126✔
76

77
  return true;
5,126✔
78
}
5,141✔
79

80
bool DIEventVisitor::visitDerivedType(const llvm::DIDerivedType* derived_type) {
13,749✔
81
  using namespace llvm::dwarf;
82

83
  const auto make_member = [&](const auto* derived) {
17,932✔
84
    current_.member_name      = derived_type->getName();
4,183✔
85
    current_.is_member        = true;
4,183✔
86
    current_.member_offset    = derived_type->getOffsetInBits() / 8;
4,183✔
87
    current_.member_size      = derived_type->getSizeInBits() / 8;
4,183✔
88
    current_.is_member_static = derived->isStaticMember();
4,183✔
89
  };
4,183✔
90

91
  const auto tag = derived_type->getTag();
13,749✔
92
  switch (tag) {
13,749✔
93
    case DW_TAG_member: {
94
      make_member(derived_type);
4,135✔
95
      break;
4,135✔
96
    }
97
    case DW_TAG_variable: {
98
      // see test ir/02_mpicxx.ll: Datatype has a static member,
99
      // which is encoded as a variable, and not as a member (variable)
100
      if (!derived_type->isStaticMember()) {
48!
101
        LOG_WARNING("Variable is not a static member. " << *derived_type)
×
102
      } else {
×
103
        make_member(derived_type);
48✔
104
      }
105
      break;
48✔
106
    }
107
    case DW_TAG_typedef:
108
      current_.typedef_names.emplace_back(derived_type->getName());
4,315✔
109
      break;
4,315✔
110
    case DW_TAG_inheritance:
111
      current_.is_base_class = true;
684✔
112
      current_.member_offset = derived_type->getOffsetInBits() / 8;
684✔
113
      break;
684✔
114
    case DW_TAG_pointer_type:
115
      current_.dwarf_tags.emplace_back(tag);
4,198✔
116
      // array of pointers:
117
      if (!current_.arrays.empty()) {
4,198✔
118
        current_.arrays.back().array_of_pointer = derived_type->getSizeInBits();
130✔
119
      }
130✔
120
      break;
4,198✔
121
    default:
122
      current_.dwarf_tags.emplace_back(tag);
369✔
123
  }
369✔
124

125
  if (tag == DW_TAG_pointer_type && derived_type->getBaseType() == nullptr) {
13,749✔
126
    // void* pointer has no basetype
127
    current_.type        = const_cast<llvm::DIDerivedType*>(derived_type);
261✔
128
    current_.is_void_ptr = true;
261✔
129
    events_.make_void_ptr(current_);
261✔
130
    current_ = state::MetaData{};
261✔
131
    return true;
156✔
132
  }
133

134
  // FIXME: hacky (current_.clear()) so vtable pointer -> pointer is not applied to vtable type.
135
  if (derived_type->getName() == "__vtbl_ptr_type") {
13,488✔
136
    assert(!stack_.empty() && "Vtable requires composite on stack");
334!
137
    // Create vtbl_ptr_type member to containing compound (first on stack)
138
    current_.type = const_cast<llvm::DIDerivedType*>(derived_type);
167✔
139
    //    current_.state = state::Entity::member;
140
    events_.make_vtable(current_);
167✔
141
    current_ = state::MetaData{};
167✔
142
  }
111✔
143

144
  return true;
13,488✔
145
}
13,749✔
146

147
bool DIEventVisitor::visitNode(const llvm::DINode* node) {
491✔
148
  if (const auto* enumerator = llvm::dyn_cast<llvm::DIEnumerator>(node)) {
982✔
149
    assert(enum_data_.enum_base != nullptr && "Enumerator needs a base type.");
60!
150
    current_.member_name   = enumerator->getName();
30✔
151
    current_.member_offset = 0;
30✔
152
    current_.member_size   = enum_data_.enum_base->getSizeInBits() / 8;
30✔
153
    current_.type          = enum_data_.enum_base;
30✔
154
    current_.is_member     = true;
30✔
155
    events_.make_enum_member(current_);
30✔
156
  } else if (const auto* sub_range = llvm::dyn_cast<llvm::DISubrange>(node)) {
952!
157
    assert(!current_.arrays.empty() && "Subrange requires array composite on stack");
922!
158
    if (sub_range->getCount().is<llvm::ConstantInt*>()) {
461!
159
      const auto* count = sub_range->getCount().get<llvm::ConstantInt*>();
461✔
160
      auto& array       = current_.arrays.back();
461✔
161
      if (!count->getValue().isNegative()) {
461✔
162
        auto range_count = count->getValue().getLimitedValue();
456✔
163
        array.subranges.push_back(range_count);
456✔
164
      } else {
456✔
165
        // see test cpp/stack_static_members_array.cpp
166
        // static int[] equals subrange(count: -1), we set simply to 0 for neg. numbers
167
        array.subranges.push_back(0);
5✔
168
      }
169
      // LOG_FATAL(range_count);
170
    }
461✔
171
  }
461✔
172
  return true;
491✔
173
}
174

175
bool DIEventVisitor::visitCompositeType(const llvm::DICompositeType* composite_type) {
3,062✔
176
  // See, e.g., pass/c/stack_struct_array.c:
177
  if (composite_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
3,062✔
178
    current_.is_vector = composite_type->isVector();
431✔
179
    current_.dwarf_tags.emplace_back(current_.is_vector ? static_cast<unsigned>(state::CustomDwarfTag::kVector)
431✔
180
                                                        : static_cast<unsigned>(llvm::dwarf::DW_TAG_array_type));
181
    current_.arrays.emplace_back(
862✔
182
        state::MetaData::ArrayData{composite_type->getSizeInBits(), Extent{0}, {}, composite_type->isVector()});
431✔
183
    // current_.array_size_bits =composite_type->getSizeInBits();
184
    return true;
431✔
185
  }
186

187
  current_.type            = const_cast<llvm::DICompositeType*>(composite_type);
2,631✔
188
  current_.has_vtable      = composite_type->getVTableHolder() == composite_type;
2,631✔
189
  current_.is_forward_decl = composite_type->isForwardDecl();
2,631✔
190

191
  enum_data_.is_enum = composite_type->getTag() == llvm::dwarf::DW_TAG_enumeration_type;
2,631✔
192
  //  current_.state      = state::Entity::Undef;  // determined in "leave" function
193

194
  events_.make_composite(current_);
2,631✔
195

196
  // "open" a composite type parsing (everything in the follow-up depth search gets added to that
197
  // current composite, such as members).
198
  // The so-far collected current_ metadata is used when leaving the opened composite:
199
  // Clear current_, as that meta info applied to the "composite_type"
200
  stack_.emplace_back(current_);
2,631✔
201
  current_ = state::MetaData{};
2,631✔
202

203
  return true;
1,581✔
204
}
1,838✔
205

206
void DIEventVisitor::leaveCompositeType(const llvm::DICompositeType* composite_type) {
3,062✔
207
  // See, e.g., pass/c/stack_struct_array.c:
208
  if (composite_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
3,062✔
209
    return;
431✔
210
  }
211

212
  assert(!stack_.empty() && "Required metadata is missing!");
5,262!
213

214
  //  state::Entity composite_e{state::Entity::freestanding};
215
  auto meta_for_composite = stack_.pop_back_val();
2,631✔
216

217
  if (meta_for_composite.is_member) {
2,631✔
218
    // add as member with current_meta data, and add it to current back_val() composite type.
219
    assert(!stack_.empty() && "Member composite requires composite on stack");
1,436!
220
    //    composite_e = state::Entity::member;
221
  }
718✔
222

223
  if (meta_for_composite.is_base_class) {
2,631✔
224
    // add as base class to back_val() composite type
225
    //    assert(composite_e != state::Entity::member);
226
    assert(!stack_.empty() && "Base composite requires composite on stack");
1,368!
227
    //    composite_e = state::Entity::base;
228
  }
684✔
229

230
  if (!(meta_for_composite.is_member || meta_for_composite.is_base_class)) {
2,631✔
231
    // create (free-standing) compound (finished recursion)
232
    assert(stack_.empty() && "Free standing composite requires empty stack");
2,458!
233
    //    assert(composite_e == state::Entity::freestanding);
234
  }
1,229✔
235

236
  //  meta_for_composite.state = composite_e;
237
  events_.finalize_composite(meta_for_composite);
2,631✔
238

239
  enum_data_ = EnumMeta{};
2,631✔
240
}
3,062✔
241

242
void DIEventVisitor::leaveBasicType(const llvm::DIBasicType*) {
5,141✔
243
  current_ = state::MetaData{};
5,141✔
244
}
3,087✔
245

246
bool DIEventVisitor::visitRecurringCompositeType(const llvm::DICompositeType* recurring_composite) {
185✔
247
  current_.is_recurring = true;
185✔
248
  return this->visitCompositeType(recurring_composite);
185✔
249
}
250

251
void DIEventVisitor::leaveRecurringCompositeType(const llvm::DICompositeType* recurring_composite) {
185✔
252
  this->leaveCompositeType(recurring_composite);
185✔
253
}
185✔
254

255
void visit_node(const llvm::DINode* node, DIParseEvents& event_handler) {
3,333✔
256
  DIEventVisitor event_visitor{event_handler};
3,333✔
257
  const bool result = event_visitor.traverseNode(node);
3,333✔
258
  if (!result) {
3,333!
259
    LOG_DEBUG("Did not parse properly: " << log::ditype_str(node));
UNCOV
260
  }
×
261
}
3,333✔
262

263
}  // namespace dimeta::diparser
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc