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

rieske / trans / 28460720020

30 Jun 2026 04:42PM UTC coverage: 90.232% (-0.3%) from 90.53%
28460720020

Pull #44

github

rieske
Support pointer members in structs including self-reference

Apply declarator pointer levels when building field types so `int *p`
is not stored as `int`. Use a shared StructBody for struct tags so
`struct Node *next` can refer to an incomplete Node that is completed
when the definition finishes. Tests for int* members and linked nodes.
Pull Request #44: Implement C structs with member access

245 of 306 new or added lines in 12 files covered. (80.07%)

29 existing lines in 3 files now uncovered.

5358 of 5938 relevant lines covered (90.23%)

236113.43 hits per line

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

82.66
/src/types/Type.cpp
1
#include "Type.h"
2

3
#include <stdexcept>
4
#include <algorithm>
5
#include <sstream>
6

7
namespace type {
8

9
static const int POINTER_SIZE {8};
10

11
Type voidType() {
48✔
12
    return Type{{}};
48✔
13
}
14

15
Type primitive(const Primitive& primitive, const std::vector<Qualifier>& qualifiers) {
4,614✔
16
    return Type{primitive, qualifiers};
4,614✔
17
}
18

19
Type pointer(const Type& pointsTo, const std::vector<Qualifier>& qualifiers) {
1,284✔
20
    auto p = Type{pointsTo};
1,284✔
21
    p._indirection = pointsTo._indirection+1;
1,284✔
22
    return p;
1,284✔
23
}
24

25
Type function(const Type& returnType, const std::vector<Type>& arguments) {
2,124✔
26
    return Type{returnType, arguments};
2,124✔
27
}
28

29
Type signedCharacter(const std::vector<Qualifier>& qualifiers) {
832✔
30
    return primitive(Primitive::signedCharacter(), qualifiers);
832✔
31
}
32
Type unsignedCharacter(const std::vector<Qualifier>& qualifiers) {
4✔
33
    return primitive(Primitive::unsignedCharacter(), qualifiers);
4✔
34
}
35

36
Type signedInteger(const std::vector<Qualifier>& qualifiers) {
3,762✔
37
    return primitive(Primitive::signedInteger(), qualifiers);
3,762✔
38
}
39

40
Type unsignedInteger(const std::vector<Qualifier>& qualifiers) {
4✔
41
    return primitive(Primitive::unsignedInteger(), qualifiers);
4✔
42
}
43

44
Type signedLong(const std::vector<Qualifier>& qualifiers) {
2✔
45
    return primitive(Primitive::signedLong(), qualifiers);
2✔
46
}
47

48
Type unsignedLong(const std::vector<Qualifier>& qualifiers) {
4✔
49
    return primitive(Primitive::unsignedLong(), qualifiers);
4✔
50
}
51

52
Type floating(const std::vector<Qualifier>& qualifiers) {
2✔
53
    return primitive(Primitive::floating(), qualifiers);
2✔
54
}
55

56
Type doubleFloating(const std::vector<Qualifier>& qualifiers) {
2✔
57
    return primitive(Primitive::doubleFloating(), qualifiers);
2✔
58
}
59

60
Type longDoubleFloating(const std::vector<Qualifier>& qualifiers) {
2✔
61
    return primitive(Primitive::longDoubleFloating(), qualifiers);
2✔
62
}
63

64
Type::Type(std::vector<Qualifier> qualifiers) {
4,672✔
65
    for (const auto& qualifier: qualifiers) {
4,680✔
66
        switch(qualifier) {
8✔
67
            case Qualifier::CONST:
4✔
68
                this->_const = true;
4✔
69
                break;
4✔
70
            case Qualifier::VOLATILE:
4✔
71
                this->_volatile = true;
4✔
72
                break;
4✔
73
            default:
×
74
                throw std::invalid_argument{"Unsupported type qualifier"};
×
75
        }
76
    }
77
}
4,672✔
78

79
Type::Type(const Primitive& primitive, std::vector<Qualifier> qualifiers):
4,614✔
80
    Type{qualifiers}
4,614✔
81
{
82
    _primitive = primitive;
4,614✔
83
}
4,614✔
84

85
Type::Type(const Type& returnType, const std::vector<Type>& arguments) {
2,124✔
86
    std::vector<std::unique_ptr<Type>> args;
2,124✔
87
    for (const auto& arg : arguments) {
2,468✔
88
        args.push_back(std::make_unique<Type>(arg));
344✔
89
    }
90
    _function = Function{std::make_unique<Type>(returnType), std::move(args)};
2,124✔
91
}
2,124✔
92

93
int Type::getSize() const {
4,826✔
94
    if (isPointer()) {
4,826✔
95
        return POINTER_SIZE;
1,366✔
96
    }
97
    if (isPrimitive()) {
3,460✔
98
        return _primitive->getSize();
3,438✔
99
    }
100
    if (isStructure()) {
22✔
101
        return _structure->size;
12✔
102
    }
103
    return _size;
10✔
104
}
105

106
bool Type::canAssignFrom(const Type& other) const {
1,006✔
107
    // TODO:
108
    return true;
1,006✔
109
}
110

111
bool Type::isVoid() const {
10,098✔
112
    return !isPrimitive() && !isFunction() && !isPointer() && !isStructure();
10,098✔
113
}
114

115
bool Type::isPrimitive() const {
19,682✔
116
    return _primitive.has_value();
19,682✔
117
}
118

119
Primitive Type::getPrimitive() const {
60✔
120
    return *_primitive;
60✔
121
}
122

123
bool Type::isConst() const {
6,064✔
124
    return _const;
6,064✔
125
}
126

127
bool Type::isVolatile() const {
6,064✔
128
    return _volatile;
6,064✔
129
}
130

131
bool Type::isPointer() const {
13,986✔
132
    return _indirection;
13,986✔
133
}
134

135
bool Type::isFunction() const {
164✔
136
    return _function.has_value();
164✔
137
}
138

139
Function Type::getFunction() const {
1,278✔
140
    return *_function;
1,278✔
141
}
142

143

144
Type Type::dereference() const {
1,490✔
145
    if (!isPointer()) {
1,490✔
146
        throw std::domain_error{"can not dereference non-pointer type"};
×
147
    }
148
    Type pointsTo = Type{*this};
1,490✔
149
    --pointsTo._indirection;
1,490✔
150
    return pointsTo;
1,490✔
151
}
152

153
std::string Type::to_string() const {
7,470✔
154
    if (isVoid()) {
7,470✔
155
        return "void";
20✔
156
    }
157
    if (isPointer()) {
7,460✔
158
        return dereference().to_string() + "*";
1,382✔
159
    }
160
    if (isPrimitive()) {
6,078✔
161
        std::stringstream str;
6,036✔
162
        if (isConst()) {
6,036✔
163
            str << "const ";
4✔
164
        }
165
        if (isVolatile()) {
6,036✔
166
            str << "volatile ";
4✔
167
        }
168
        str << _primitive->to_string();
6,036✔
169
        return str.str();
6,036✔
170
    }
6,036✔
171
    if (isFunction()) {
42✔
172
        return _function->to_string();
8✔
173
    }
174
    return "unknown type";
68✔
175
}
176

177

178
Type::Member::Member(std::string n, Type t, int off) :
20✔
179
        name { std::move(n) },
20✔
180
        type { std::make_unique<Type>(std::move(t)) },
20✔
181
        offsetBytes { off }
20✔
182
{
183
}
20✔
184

NEW
185
Type::Member::Member(const Member& other) :
×
NEW
186
        name { other.name },
×
NEW
187
        type { other.type ? std::make_unique<Type>(*other.type) : nullptr },
×
NEW
188
        offsetBytes { other.offsetBytes }
×
189
{
NEW
190
}
×
191

NEW
192
Type::Member& Type::Member::operator=(const Member& other) {
×
NEW
193
    if (this != &other) {
×
NEW
194
        name = other.name;
×
NEW
195
        type = other.type ? std::make_unique<Type>(*other.type) : nullptr;
×
NEW
196
        offsetBytes = other.offsetBytes;
×
197
    }
NEW
198
    return *this;
×
199
}
200

201
namespace {
202
constexpr int WORD_ALIGN = 8;
203

204
int alignUp(int value, int alignment) {
50✔
205
    return (value + alignment - 1) / alignment * alignment;
50✔
206
}
207

208
int memberStride(const Type& memberType) {
20✔
209
    int size = memberType.getSize();
20✔
210
    if (size < 1) {
20✔
NEW
211
        size = 1;
×
212
    }
213
    // Pointers and incomplete structs still get a full word as a member slot.
214
    return alignUp(size, WORD_ALIGN);
20✔
215
}
216

217
void layoutMembers(Type::StructBody& body, std::vector<std::pair<std::string, Type>> members) {
10✔
218
    body.members.clear();
10✔
219
    int offset = 0;
10✔
220
    for (auto& entry : members) {
30✔
221
        offset = alignUp(offset, WORD_ALIGN);
20✔
222
        body.members.emplace_back(entry.first, entry.second, offset);
20✔
223
        offset += memberStride(entry.second);
20✔
224
    }
225
    body.size = alignUp(offset, WORD_ALIGN);
10✔
226
    body.complete = true;
10✔
227
}
10✔
228
} // namespace
229

230
Type incompleteStructure() {
10✔
231
    Type result { std::vector<Qualifier> {} };
10✔
232
    result._structure = std::make_shared<Type::StructBody>();
10✔
233
    result._structure->complete = false;
10✔
234
    result._structure->size = 0;
10✔
235
    result._size = 0;
10✔
236
    return result;
10✔
NEW
237
}
×
238

NEW
239
Type structure(std::vector<std::pair<std::string, Type>> members) {
×
NEW
240
    Type result = incompleteStructure();
×
NEW
241
    completeStructure(result, std::move(members));
×
NEW
242
    return result;
×
NEW
243
}
×
244

245
void completeStructure(Type& structType, std::vector<std::pair<std::string, Type>> members) {
10✔
246
    if (!structType._structure) {
10✔
NEW
247
        structType._structure = std::make_shared<Type::StructBody>();
×
248
    }
249
    layoutMembers(*structType._structure, std::move(members));
10✔
250
    structType._size = structType._structure->size;
10✔
251
}
10✔
252

253
bool Type::isStructure() const {
134✔
254
    return _structure != nullptr;
134✔
255
}
256

NEW
257
bool Type::isCompleteStructure() const {
×
NEW
258
    return _structure && _structure->complete;
×
259
}
260

NEW
261
const std::vector<Type::Member>& Type::getStructMembers() const {
×
NEW
262
    return _structure->members;
×
263
}
264

265
bool Type::memberOffset(const std::string& memberName, int& offsetBytes) const {
48✔
266
    if (!_structure) {
48✔
NEW
267
        return false;
×
268
    }
269
    for (const auto& member : _structure->members) {
72✔
270
        if (member.name == memberName) {
72✔
271
            offsetBytes = member.offsetBytes;
48✔
272
            return true;
48✔
273
        }
274
    }
NEW
275
    return false;
×
276
}
277

278
bool Type::memberType(const std::string& memberName, Type& outType) const {
48✔
279
    if (!_structure) {
48✔
NEW
280
        return false;
×
281
    }
282
    for (const auto& member : _structure->members) {
72✔
283
        if (member.name == memberName) {
72✔
284
            outType = *member.type;
48✔
285
            return true;
48✔
286
        }
287
    }
NEW
288
    return false;
×
289
}
290

291
} // namespace type
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