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

ahueck / llvm-dimeta / 25370412405

05 May 2026 10:12AM UTC coverage: 73.596% (+0.3%) from 73.295%
25370412405

push

github

web-flow
Support custom allocators (#58)

2241 of 3751 branches covered (59.74%)

Branch coverage included in aggregate %.

125 of 139 new or added lines in 5 files covered. (89.93%)

2 existing lines in 2 files now uncovered.

2687 of 2945 relevant lines covered (91.24%)

20073.69 hits per line

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

70.09
/lib/type/SourceLocType.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 "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 <cstddef>
17
#include <cstdint>
18
#include <llvm/ADT/STLExtras.h>
19
#include <llvm/IR/Value.h>
20
#include <optional>
21

22
namespace dimeta {
23

24
namespace scope {
25

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

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

39
}  // namespace scope
40

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

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

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

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

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

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

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

103
template <typename Type>
104
void reset_shape_qualifier(Type& type, const ShapeData& shape) {
84✔
105
  const auto add_shape = [&](auto& f) {
168✔
106
    f.array_size.clear();
84✔
107
    for (auto index : shape.shapes) {
192✔
108
      f.array_size.push_back(index.dim);
108✔
109
    }
108✔
110
  };
84✔
111
  std::visit(overload{[&](dimeta::QualifiedFundamental& f) -> void { add_shape(f); },
208✔
112
                      [&](dimeta::QualifiedCompound& q) -> void { add_shape(q); }},
128✔
113
             type);
84✔
114
}
84✔
115

116
}  // namespace detail
117

118
std::optional<LocatedType> located_type_for(const DimetaData& type_data) {
12,484✔
119
  auto loc = location_for(type_data);
12,484✔
120
  if (!loc) {
12,484✔
121
    LOG_DEBUG("Could not determine source location.");
122
    return {};
55✔
123
  }
124

125
  if (!type_data.entry_type) {
12,429!
126
    LOG_DEBUG("Could not determine type (missing entry type).");
127
    return {};
×
128
  }
129

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

132
  // If a member is the entry type, we ignore that:
133
  auto* type = type_data.entry_type.value();
12,429!
134
  if (const auto* derived_member_maybe = llvm::dyn_cast<llvm::DIDerivedType>(type)) {
20,539!
135
    if (di::util::is_member(*derived_member_maybe)) {
8,110!
136
      type = derived_member_maybe->getBaseType();
244!
137
    }
244✔
138
  }
8,110✔
139

140
  auto dimeta_result = parser::make_dimetadata(type);
12,429!
141
  if (!dimeta_result) {
12,429!
142
    return {};
×
143
  }
144

145
  detail::reset_pointer_qualifier(dimeta_result->type_, type_data.pointer_level);
12,429!
146
  // Fortran:
147
  if (type_data.shape_descriptor) {
12,429✔
148
    LOG_DEBUG("Reset shape of array")
149
    detail::reset_shape_qualifier(dimeta_result->type_, type_data.shape_descriptor.value());
84!
150
  }
84✔
151
  return LocatedType{dimeta_result->type_, loc.value()};
12,429!
152
}
12,484✔
153

154
template <typename IRNode>
155
std::optional<LocatedType> get_located_type(const IRNode* node) {
8,208✔
156
  auto type_data = type_for(node);
8,208✔
157
  if (!type_data) {
8,208!
158
    LOG_DEBUG("Could not determine type.");
UNCOV
159
    return {};
×
160
  }
161
  return located_type_for(type_data.value());
8,208!
162
}
8,208✔
163

164
std::optional<LocatedType> located_type_for(const llvm::AllocaInst* ai) {
7,266✔
165
  return get_located_type(ai);
7,266✔
166
}
3,496✔
167

168
std::optional<LocatedType> located_type_for(const llvm::CallBase* cb, const CallBaseTypeConfig& config) {
17,200✔
169
  auto type_data = type_for(cb, config);
17,200✔
170
  if (!type_data) {
17,200✔
171
    LOG_DEBUG("Could not determine type.");
172
    return {};
12,924✔
173
  }
174
  return located_type_for(type_data.value());
4,276!
175
}
17,200✔
176

177
std::optional<LocatedType> located_type_for(const llvm::GlobalVariable* gv) {
942✔
178
  return get_located_type(gv);
942✔
179
}
544✔
180

181
}  // namespace dimeta
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