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

ahueck / llvm-dimeta / 23296997048

19 Mar 2026 01:23PM UTC coverage: 64.594% (-9.0%) from 73.626%
23296997048

Pull #49

github

web-flow
Merge f45516abb into cefb3414f
Pull Request #49: Initial Fortran Support

1854 of 3670 branches covered (50.52%)

Branch coverage included in aggregate %.

164 of 435 new or added lines in 15 files covered. (37.7%)

20 existing lines in 6 files now uncovered.

2333 of 2812 relevant lines covered (82.97%)

11668.39 hits per line

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

72.82
/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 <cassert>
15
#include <cstdlib>
16
#include <llvm/BinaryFormat/Dwarf.h>
17
#include <llvm/IR/Constants.h>
18
#include <llvm/IR/DebugInfoMetadata.h>
19
#include <llvm/Support/Casting.h>
20
#include <optional>
21

22
namespace dimeta::diparser {
23

24
class DIEventVisitor : public visitor::DINodeVisitor<DIEventVisitor> {
25
  // TODO visitVariable
26
 private:
27
  state::MetaData current_;
28
  state::MetaStack stack_;
29
  DIParseEvents& events_;
30
  struct EnumMeta {
31
    llvm::DIType* enum_base{nullptr};
32
    bool is_enum{false};
33
  };
34
  EnumMeta enum_data_{};
9,049✔
35

36
 public:
37
  explicit DIEventVisitor(DIParseEvents& events);
38
  ~DIEventVisitor();
39

40
  bool visitBasicType(const llvm::DIBasicType*);
41

42
  bool visitStringType(const llvm::DIStringType*);
43

44
  bool visitDerivedType(const llvm::DIDerivedType*);
45

46
  bool visitCompositeType(const llvm::DICompositeType*);
47

48
  bool visitNode(const llvm::DINode* node);
49
  void leaveNode(const llvm::DINode* node);
50

51
  bool visitRecurringCompositeType(const llvm::DICompositeType*);
52

53
  void leaveBasicType(const llvm::DIBasicType*);
54

55
  void leaveStringType(const llvm::DIStringType*);
56

57
  void leaveCompositeType(const llvm::DICompositeType*);
58

59
  void leaveRecurringCompositeType(const llvm::DICompositeType*);
60
};
61

62
DIEventVisitor::DIEventVisitor(DIParseEvents& events) : events_{events} {
9,049!
63
}
9,049✔
64

65
DIEventVisitor::~DIEventVisitor() = default;
9,049✔
66

67
bool DIEventVisitor::visitBasicType(const llvm::DIBasicType* basic_type) {
16,238✔
68
  //  state::Entity fundamental_e{state::Entity::freestanding};
69
  current_.type = const_cast<llvm::DIBasicType*>(basic_type);
16,238✔
70

71
  if (current_.is_member) {
16,238✔
72
    assert(!stack_.empty() && "Free standing fundamental requires empty stack");
21,168!
73
    //    fundamental_e = state::Entity::member;
74
  }
10,584✔
75
  // create (free-standing) fundamental (finished recursion)
76
  //  current_.state = fundamental_e;
77

78
  if (enum_data_.is_enum) {
16,238✔
79
    // pattern matches enum types
80
    //    events.make_enum_member()
81
    enum_data_.enum_base = current_.type;
33✔
82
    return true;
33✔
83
  }
84

85
  events_.make_fundamental(current_);
16,205✔
86

87
  return true;
16,205✔
88
}
16,238✔
89

NEW
90
bool DIEventVisitor::visitStringType(const llvm::DIStringType* string_type) {
×
NEW
91
  current_.type = const_cast<llvm::DIStringType*>(string_type);
×
NEW
92
  events_.make_string(current_);
×
NEW
93
  return true;
×
94
}
95

96
bool DIEventVisitor::visitDerivedType(const llvm::DIDerivedType* derived_type) {
37,681✔
97
  using namespace llvm::dwarf;
98

99
  const auto make_member = [&](const auto* derived) {
51,129✔
100
    current_.member_name      = derived_type->getName();
13,448✔
101
    current_.is_member        = true;
13,448✔
102
    current_.member_offset    = derived_type->getOffsetInBits() / 8;
13,448✔
103
    current_.member_size      = derived_type->getSizeInBits() / 8;
13,448✔
104
    current_.is_member_static = derived->isStaticMember();
13,448✔
105
  };
13,448✔
106

107
  current_.derived_size = derived_type->getSizeInBits() / 8;
37,681✔
108

109
  const auto tag = derived_type->getTag();
37,681✔
110
  switch (tag) {
37,681✔
111
    case DW_TAG_member: {
112
      make_member(derived_type);
13,265✔
113
      break;
13,265✔
114
    }
115
    case DW_TAG_variable: {
116
      // see test ir/02_mpicxx.ll: Datatype has a static member,
117
      // which is encoded as a variable, and not as a member (variable)
118
      if (!derived_type->isStaticMember()) {
183!
119
        LOG_WARNING("Variable is not a static member. " << *derived_type)
×
120
      } else {
×
121
        make_member(derived_type);
183✔
122
      }
123
      break;
183✔
124
    }
125
    case DW_TAG_typedef:
126
      current_.typedef_names.emplace_back(derived_type->getName());
10,154✔
127
      break;
10,154✔
128
    case DW_TAG_inheritance:
129
      current_.is_base_class = true;
1,480✔
130
      current_.member_offset = derived_type->getOffsetInBits() / 8;
1,480✔
131
      break;
1,480✔
132
    case DW_TAG_pointer_type:
133
      current_.dwarf_tags.emplace_back(tag);
11,767✔
134
      // array of pointers:
135
      if (!current_.arrays.empty()) {
11,767✔
136
        current_.arrays.back().array_of_pointer = derived_type->getSizeInBits();
385✔
137
      }
385✔
138
      break;
11,767✔
139
    default:
140
      current_.dwarf_tags.emplace_back(tag);
832✔
141
  }
832✔
142

143
  if (tag == DW_TAG_pointer_type && derived_type->getBaseType() == nullptr) {
37,681✔
144
    // void* pointer has no basetype
145
    current_.type        = const_cast<llvm::DIDerivedType*>(derived_type);
706✔
146
    current_.is_void_ptr = true;
706✔
147
    events_.make_void_ptr(current_);
706✔
148
    current_ = state::MetaData{};
706!
149
    return true;
330✔
150
  }
151

152
  // FIXME: hacky (current_.clear()) so vtable pointer -> pointer is not applied to vtable type.
153
  if (derived_type->getName() == "__vtbl_ptr_type") {
36,975✔
154
    assert(!stack_.empty() && "Vtable requires composite on stack");
656!
155
    // Create vtbl_ptr_type member to containing compound (first on stack)
156
    current_.type = const_cast<llvm::DIDerivedType*>(derived_type);
328✔
157
    //    current_.state = state::Entity::member;
158
    events_.make_vtable(current_);
328✔
159
    current_ = state::MetaData{};
328!
160
  }
163✔
161

162
  return true;
36,975✔
163
}
37,681✔
164

165
bool DIEventVisitor::visitNode(const llvm::DINode* node) {
2,267✔
166
  if (const auto* enumerator = llvm::dyn_cast<llvm::DIEnumerator>(node)) {
4,534✔
167
    assert(enum_data_.enum_base != nullptr && "Enumerator needs a base type.");
132!
168
    current_.member_name   = enumerator->getName();
66✔
169
    current_.member_offset = 0;
66✔
170
    current_.member_size   = enum_data_.enum_base->getSizeInBits() / 8;
66✔
171
    current_.type          = enum_data_.enum_base;
66✔
172
    current_.is_member     = true;
66✔
173
    events_.make_enum_member(current_);
66✔
174
  } else if (const auto* sub_range = llvm::dyn_cast<llvm::DISubrange>(node)) {
4,468✔
175
    assert(!current_.arrays.empty() && "Subrange requires array composite on stack");
3,658!
176

177
    const auto subrange_constant = [&sub_range]() -> std::optional<const llvm::ConstantInt*> {
3,658✔
178
#if LLVM_VERSION_MAJOR > 19
179
      if (llvm::isa<llvm::ConstantInt*>(sub_range->getCount())) {
660!
180
        auto* count = llvm::cast<llvm::ConstantInt*>(sub_range->getCount());
660✔
181
        return count;
660✔
182
      }
660✔
183
#else
184
      if (sub_range->getCount().is<llvm::ConstantInt*>()) {
1,169!
185
        auto* count = sub_range->getCount().get<llvm::ConstantInt*>();
1,169✔
186
        return count;
1,169✔
187
      }
1,169✔
188
#endif
189
      return {};
×
190
    }();
1,829✔
191

192
    if (subrange_constant.has_value()) {
1,829!
193
      const auto* count = subrange_constant.value();
1,829✔
194
      auto& array       = current_.arrays.back();
1,829✔
195
      if (!count->getValue().isNegative()) {
1,829✔
196
        auto range_count = count->getValue().getLimitedValue();
1,818✔
197
        array.subranges.push_back(range_count);
1,818✔
198
      } else {
1,818✔
199
        // see test cpp/stack_static_members_array.cpp
200
        // static int[] equals subrange(count: -1), we set simply to 0 for neg. numbers
201
        array.subranges.push_back(0);
11✔
202
      }
203
      // LOG_FATAL(range_count);
204
    }
1,829✔
205
  } else if (const auto* sub_routine = llvm::dyn_cast<llvm::DISubroutineType>(node)) {
2,573!
206
    // LOG_FATAL(sub_routine);
207
    current_.type = const_cast<llvm::DISubroutineType*>(sub_routine);
372✔
208
    events_.make_function_ptr(current_);
372✔
209
  }
372✔
210
  return true;
2,267✔
211
}
212

213
bool DIEventVisitor::visitCompositeType(const llvm::DICompositeType* composite_type) {
8,424✔
214
  // See, e.g., pass/c/stack_struct_array.c:
215
  if (composite_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
8,424✔
216
    current_.is_vector = composite_type->isVector();
1,763✔
217
    current_.dwarf_tags.emplace_back(current_.is_vector ? static_cast<unsigned>(state::CustomDwarfTag::kVector)
1,763✔
218
                                                        : static_cast<unsigned>(llvm::dwarf::DW_TAG_array_type));
219
    if (composite_type->getRawAssociated()) {
1,763!
220
      // Fortran pointer allocations use "associated" tag
221
      LOG_DEBUG("Associated: array of pointer")
NEW
222
      current_.dwarf_tags.emplace_back(llvm::dwarf::DW_TAG_pointer_type);
×
NEW
223
    }
×
224

225
    current_.arrays.emplace_back(
1,763!
226
        state::MetaData::ArrayData{composite_type->getSizeInBits(), Extent{0}, {}, composite_type->isVector()});
1,763!
227
    // current_.array_size_bits =composite_type->getSizeInBits();
228
    return true;
1,763✔
229
  }
230

231
  current_.type            = const_cast<llvm::DICompositeType*>(composite_type);
6,661✔
232
  current_.has_vtable      = composite_type->getVTableHolder() == composite_type;
6,661✔
233
  current_.is_forward_decl = composite_type->isForwardDecl();
6,661✔
234

235
  enum_data_.is_enum = composite_type->getTag() == llvm::dwarf::DW_TAG_enumeration_type;
6,661✔
236
  //  current_.state      = state::Entity::Undef;  // determined in "leave" function
237

238
  events_.make_composite(current_);
6,661✔
239

240
  // "open" a composite type parsing (everything in the follow-up depth search gets added to that
241
  // current composite, such as members).
242
  // The so-far collected current_ metadata is used when leaving the opened composite:
243
  // Clear current_, as that meta info applied to the "composite_type"
244
  stack_.emplace_back(current_);
6,661✔
245
  current_ = state::MetaData{};
6,661!
246

247
  return true;
2,940✔
248
}
3,641✔
249

250
void DIEventVisitor::leaveCompositeType(const llvm::DICompositeType* composite_type) {
8,424✔
251
  // See, e.g., pass/c/stack_struct_array.c:
252
  if (composite_type->getTag() == llvm::dwarf::DW_TAG_array_type) {
8,424✔
253
    return;
1,763✔
254
  }
255

256
  assert(!stack_.empty() && "Required metadata is missing!");
13,322!
257

258
  //  state::Entity composite_e{state::Entity::freestanding};
259
  auto meta_for_composite = stack_.pop_back_val();
6,661✔
260

261
  if (meta_for_composite.is_member) {
6,661✔
262
    // add as member with current_meta data, and add it to current back_val() composite type.
263
    assert(!stack_.empty() && "Member composite requires composite on stack");
4,016!
264
    //    composite_e = state::Entity::member;
265
  }
2,008✔
266

267
  if (meta_for_composite.is_base_class) {
6,661✔
268
    // add as base class to back_val() composite type
269
    //    assert(composite_e != state::Entity::member);
270
    assert(!stack_.empty() && "Base composite requires composite on stack");
2,960!
271
    //    composite_e = state::Entity::base;
272
  }
1,480✔
273

274
  if (!(meta_for_composite.is_member || meta_for_composite.is_base_class)) {
6,661✔
275
    // create (free-standing) compound (finished recursion)
276
    assert(stack_.empty() && "Free standing composite requires empty stack");
6,346!
277
    //    assert(composite_e == state::Entity::freestanding);
278
  }
3,173✔
279

280
  //  meta_for_composite.state = composite_e;
281
  events_.finalize_composite(meta_for_composite);
6,661!
282

283
  enum_data_ = EnumMeta{};
6,661✔
284
}
9,582✔
285

286
void DIEventVisitor::leaveBasicType(const llvm::DIBasicType*) {
16,238✔
287
  current_ = state::MetaData{};
16,238!
288
}
7,257✔
289

NEW
290
void DIEventVisitor::leaveStringType(const llvm::DIStringType*) {
×
NEW
291
  current_ = state::MetaData{};
×
292
}
293

294
void DIEventVisitor::leaveNode(const llvm::DINode* node) {
2,267✔
295
  if (llvm::isa<llvm::DISubroutineType>(node)) {
2,267✔
296
    current_ = state::MetaData{};
372!
297
  }
183✔
298
}
2,267✔
299

300
bool DIEventVisitor::visitRecurringCompositeType(const llvm::DICompositeType* recurring_composite) {
363✔
301
  current_.is_recurring = true;
363✔
302
  return this->visitCompositeType(recurring_composite);
363✔
303
}
304

305
void DIEventVisitor::leaveRecurringCompositeType(const llvm::DICompositeType* recurring_composite) {
363✔
306
  this->leaveCompositeType(recurring_composite);
363✔
307
}
363✔
308

309
void visit_node(const llvm::DINode* node, DIParseEvents& event_handler) {
9,049✔
310
  DIEventVisitor event_visitor{event_handler};
9,049✔
311
  const bool result = event_visitor.traverseNode(node);
9,049!
312
  if (!result) {
9,049!
313
    LOG_DEBUG("Did not parse properly: " << log::ditype_str(node));
314
  }
×
315
}
9,049✔
316

317
}  // 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