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

ahueck / llvm-dimeta / 27200736110

09 Jun 2026 10:42AM UTC coverage: 73.527% (+0.2%) from 73.309%
27200736110

push

github

web-flow
Extended support for allocation routines (#59)

2247 of 3765 branches covered (59.68%)

Branch coverage included in aggregate %.

151 of 168 new or added lines in 6 files covered. (89.88%)

2 existing lines in 2 files now uncovered.

2694 of 2955 relevant lines covered (91.17%)

20005.86 hits per line

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

68.55
/lib/type/SourceLocType.cpp
1
//  llvm-dimeta library
2
//  Copyright (c) 2022-2026 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 "DIUtil.h"
9
#include "Dimeta.h"
10
#include "DimetaData.h"
11
#include "DimetaParse.h"
12
#include "support/Logger.h"
13

14
#include "llvm/IR/DebugInfoMetadata.h"
15

16
#include <algorithm>
17
#include <cstddef>
18
#include <cstdint>
19
#include <llvm/ADT/STLExtras.h>
20
#include <llvm/IR/Value.h>
21
#include <optional>
22

23
namespace dimeta {
24

25
namespace scope {
26

27
std::optional<llvm::DILocalScope*> get_parent_function(const llvm::DILocation& loc) {
11,487 ✔
28
  auto start_scope = loc.getScope();
11,487 ✔
29
  return start_scope->getSubprogram();
11,487 ✔
30
}
11,487 ✔
31

32
std::string get_parent_function_name(const llvm::DILocation& loc) {
11,487 ✔
33
  auto sub_prog = scope::get_parent_function(loc);
11,487 ✔
34
  if (sub_prog) {
11,487 !
35
    return std::string{sub_prog.value()->getName()};
11,487 !
36
  }
37
  return std::string{};
×
38
}
11,487 ✔
39

40
}  // namespace scope
41

42
std::optional<location::SourceLocation> location_for(const DimetaData& data) {
12,484 ✔
43
  if (data.di_location) {
12,484 ✔
44
    auto loc = data.di_location.value();
11,487 ✔
45
    return location::SourceLocation{std::string{loc->getFilename()},        //
11,487 !
46
                                    scope::get_parent_function_name(*loc),  //
11,487 !
47
                                    loc->getLine()};
11,487 !
48
  }
11,487 ✔
49
  if (!data.di_variable) {
997 ✔
50
    return {};
55 ✔
51
  }
52

53
  const auto make_source_loc = [](const auto* variable) {
1,884 ✔
54
    const auto file           = std::string{variable->getFilename()};
942 !
55
    const auto function_scope = [](const auto alloc) -> std::string {
2,826 !
56
      const auto* scope = alloc->getScope();
942 ✔
57
      if (scope) {
942 !
58
        return std::string{scope->getName()};
912 !
59
      }
60
      return "";
30 !
61
    }(variable);
1,884 ✔
62
    return location::SourceLocation{file,            //
942 !
63
                                    function_scope,  //
942 !
64
                                    variable->getLine()};
942 !
65
  };
942 ✔
66

67
  if (const auto gv = std::get_if<llvm::DIGlobalVariable*>(&data.di_variable.value())) {
1,884 !
68
    const auto* global_var = *gv;
942 ✔
69
    return make_source_loc(global_var);
942 ✔
70
  }
942 ✔
71

72
  if (const auto alloc_var = std::get_if<llvm::DILocalVariable*>(&data.di_variable.value())) {
×
73
    const auto* alloc = *alloc_var;
×
74
    return make_source_loc(alloc);
×
75
  }
×
76

77
  return {};
×
78
}
12,484 ✔
79

80
namespace detail {
81
template <class... Ts>
82
struct overload : Ts... {
83
  using Ts::operator()...;
84
};
85
template <class... Ts>
86
overload(Ts...) -> overload<Ts...>;
87

88
template <typename Type>
89
void reset_pointer_qualifier(Type& type, int ptr_level) {
12,429 ✔
90
  // "new" can have type_data.pointer_level != metadata pointer level -> if that is the case, we add that qualifier to
91
  // begin of list
92
  const auto add_pointer = [&](auto& f) {
24,858 ✔
93
    auto count = llvm::count_if(f.qual, [](auto& qual) { return qual == Qualifier::kPtr; });
22,487 ✔
94
    if (count < ptr_level) {
12,429 ✔
95
      const auto begin = f.qual.begin();
693 ✔
96
      f.qual.insert(begin, Qualifier{Qualifier::kPtr});
693 ✔
97
    }
693 ✔
98
  };
12,429 ✔
99
  std::visit(overload{[&](dimeta::QualifiedFundamental& f) -> void { add_pointer(f); },
33,057 ✔
100
                      [&](dimeta::QualifiedCompound& q) -> void { add_pointer(q); }},
16,659 ✔
101
             type);
12,429 ✔
102
}
12,429 ✔
103

104
template <typename Type>
105
void reset_shape_qualifier(Type& type, const ShapeData& shape) {
84 ✔
106
  auto ordered_shapes = shape.shapes;
84 ✔
107
  std::stable_sort(ordered_shapes.begin(), ordered_shapes.end(), [](const auto& lhs, const auto& rhs) {
108 !
108
    if (lhs.index < 0 && rhs.index < 0) {
24 !
NEW
109
      return false;
×
110
    }
111
    if (lhs.index < 0) {
24 !
NEW
112
      return false;
×
113
    }
114
    if (rhs.index < 0) {
24 !
NEW
115
      return true;
×
116
    }
117
    return lhs.index < rhs.index;
24 ✔
118
  });
24 ✔
119

120
  const auto add_shape = [&](auto& f) {
168 ✔
121
    f.array_size.clear();
84 ✔
122
    for (const auto& index : ordered_shapes) {
192 ✔
123
      f.array_size.push_back(index.dim);
108 ✔
124
    }
108 ✔
125
  };
84 ✔
126
  std::visit(overload{[&](dimeta::QualifiedFundamental& f) -> void { add_shape(f); },
208 !
127
                      [&](dimeta::QualifiedCompound& q) -> void { add_shape(q); }},
128 ✔
128
             type);
84 ✔
129
}
84 ✔
130

131
}  // namespace detail
132

133
std::optional<LocatedType> located_type_for(const DimetaData& type_data) {
12,484 ✔
134
  auto loc = location_for(type_data);
12,484 ✔
135
  if (!loc) {
12,484 ✔
136
    LOG_DEBUG("Could not determine source location.");
137
    return {};
55 ✔
138
  }
139

140
  if (!type_data.entry_type) {
12,429 !
141
    LOG_DEBUG("Could not determine type (missing entry type).");
142
    return {};
×
143
  }
144

145
  assert(type_data.entry_type.has_value() && "Parsing stack type requires entry type.");
24,858 !
146

147
  // If a member is the entry type, we ignore that:
148
  auto* type = type_data.entry_type.value();
12,429 !
149
  if (const auto* derived_member_maybe = llvm::dyn_cast<llvm::DIDerivedType>(type)) {
20,539 !
150
    if (di::util::is_member(*derived_member_maybe)) {
8,110 !
151
      type = derived_member_maybe->getBaseType();
244 !
152
    }
244 ✔
153
  }
8,110 ✔
154

155
  auto dimeta_result = parser::make_dimetadata(type);
12,429 !
156
  if (!dimeta_result) {
12,429 !
157
    return {};
×
158
  }
159

160
  detail::reset_pointer_qualifier(dimeta_result->type_, type_data.pointer_level);
12,429 !
161
  // Fortran:
162
  if (type_data.shape_descriptor) {
12,429 ✔
163
    LOG_DEBUG("Reset shape of array")
164
    detail::reset_shape_qualifier(dimeta_result->type_, type_data.shape_descriptor.value());
84 !
165
  }
84 ✔
166
  return LocatedType{dimeta_result->type_, loc.value()};
12,429 !
167
}
12,484 ✔
168

169
template <typename IRNode>
170
std::optional<LocatedType> get_located_type(const IRNode* node) {
8,208 ✔
171
  auto type_data = type_for(node);
8,208 ✔
172
  if (!type_data) {
8,208 !
173
    LOG_DEBUG("Could not determine type.");
UNCOV
174
    return {};
×
175
  }
176
  return located_type_for(type_data.value());
8,208 !
177
}
8,208 ✔
178

179
std::optional<LocatedType> located_type_for(const llvm::AllocaInst* ai) {
7,266 ✔
180
  return get_located_type(ai);
7,266 ✔
181
}
3,496 ✔
182

183
std::optional<LocatedType> located_type_for(const llvm::CallBase* cb, const CallBaseTypeConfig& config) {
17,200 ✔
184
  auto type_data = type_for(cb, config);
17,200 ✔
185
  if (!type_data) {
17,200 ✔
186
    LOG_DEBUG("Could not determine type.");
187
    return {};
12,924 ✔
188
  }
189
  return located_type_for(type_data.value());
4,276 !
190
}
17,200 ✔
191

192
std::optional<LocatedType> located_type_for(const llvm::GlobalVariable* gv) {
942 ✔
193
  return get_located_type(gv);
942 ✔
194
}
544 ✔
195

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

© 2026 Coveralls, Inc