• 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

61.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) {
6,792✔
27
  auto start_scope = loc.getScope();
6,792✔
28
  return start_scope->getSubprogram();
6,792✔
29
}
6,792✔
30

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

39
}  // namespace scope
40

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

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

66
  if (const auto gv = std::get_if<llvm::DIGlobalVariable*>(&data.di_variable.value())) {
814!
67
    const auto* global_var = *gv;
407✔
68
    return make_source_loc(global_var);
407✔
69
  }
407✔
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
}
7,224✔
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) {
7,199✔
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) {
14,398✔
92
    auto count = llvm::count_if(f.qual, [](auto& qual) { return qual == Qualifier::kPtr; });
12,961✔
93
    if (count < ptr_level) {
7,199✔
94
      const auto begin = f.qual.begin();
445✔
95
      f.qual.insert(begin, Qualifier{Qualifier::kPtr});
445✔
96
    }
445✔
97
  };
7,199✔
98
  std::visit(overload{[&](dimeta::QualifiedFundamental& f) -> void { add_pointer(f); },
19,032✔
99
                      [&](dimeta::QualifiedCompound& q) -> void { add_pointer(q); }},
9,764✔
100
             type);
7,199✔
101
}
7,199✔
102

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

116
}  // namespace detail
117

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

125
  if (!type_data.entry_type) {
7,199!
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.");
14,398!
131

132
  // If a member is the entry type, we ignore that:
133
  auto* type = type_data.entry_type.value();
7,199!
134
  if (const auto* derived_member_maybe = llvm::dyn_cast<llvm::DIDerivedType>(type)) {
11,903!
135
    if (di::util::is_member(*derived_member_maybe)) {
4,704!
136
      type = derived_member_maybe->getBaseType();
44!
137
    }
44✔
138
  }
4,704✔
139

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

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

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

164
std::optional<LocatedType> located_type_for(const llvm::AllocaInst* ai) {
4,443✔
165
  return get_located_type(ai);
4,443✔
166
}
784✔
167

168
std::optional<LocatedType> located_type_for(const llvm::CallBase* cb) {
10,915✔
169
  return get_located_type(cb);
10,915✔
170
}
1,298✔
171

172
std::optional<LocatedType> located_type_for(const llvm::GlobalVariable* gv) {
407✔
173
  return get_located_type(gv);
407✔
174
}
90✔
175

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