GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.7% 29 / 0 / 30
Functions: 100.0% 9 / 0 / 9
Branches: 65.9% 29 / 0 / 44

src/model/Struct.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "Struct.h"
4
5 #include <ast/ASTNodes.h>
6 #include <model/GenericType.h>
7 #include <symboltablebuilder/Scope.h>
8
9 namespace spice::compiler {
10
11 static constexpr auto STRUCT_SCOPE_PREFIX = "struct:";
12
13 7639 Struct::Struct(std::string name, SymbolTableEntry *entry, Scope *scope, QualTypeList fieldTypes,
14 std::vector<GenericType> templateTypes, QualTypeList interfaceTypes, ASTNode *declNode)
15 7639 : StructBase(std::move(name), entry, scope, std::move(templateTypes), declNode), fieldTypes(std::move(fieldTypes)),
16
1/2
✓ Branch 8 → 9 taken 7639 times.
✗ Branch 8 → 18 not taken.
38195 interfaceTypes(std::move(interfaceTypes)) {}
17
18 /**
19 * Retrieve the name of the scope, where members and methods are placed. This is used to navigate to the scope of the struct
20 * from the parent scope.
21 *
22 * @return Name of the struct scope
23 */
24 9504 std::string Struct::getScopeName() const {
25
5/8
✓ Branch 2 → 3 taken 9504 times.
✗ Branch 2 → 13 not taken.
✓ Branch 3 → 4 taken 4752 times.
✓ Branch 3 → 5 taken 4752 times.
✓ Branch 4 → 6 taken 4752 times.
✗ Branch 4 → 13 not taken.
✓ Branch 5 → 6 taken 4752 times.
✗ Branch 5 → 13 not taken.
9504 const std::string &appendix = isGenericSubstantiation() ? getSignature() : name;
26
1/2
✓ Branch 6 → 7 taken 9504 times.
✗ Branch 6 → 11 not taken.
19008 return STRUCT_SCOPE_PREFIX + appendix;
27 9504 }
28
29 /**
30 * Retrieve the name of the scope, where members and methods are placed. This is used to navigate to the scope of the
31 * struct from the parent scope.
32 *
33 * @param name Struct name
34 * @param concreteTemplateTypes Concrete template types
35 * @return Name of the struct scope
36 */
37 173290 std::string Struct::getScopeName(const std::string &name, const QualTypeList &concreteTemplateTypes) {
38
2/4
✓ Branch 2 → 3 taken 173290 times.
✗ Branch 2 → 10 not taken.
✓ Branch 3 → 4 taken 173290 times.
✗ Branch 3 → 8 not taken.
346580 return STRUCT_SCOPE_PREFIX + getSignature(name, concreteTemplateTypes);
39 }
40
41 /**
42 * Checks at least one field is a reference.
43 * This is used to prohibit constant instantiations.
44 *
45 * @return Has reference as field type or not
46 */
47 3525 bool Struct::hasReferenceFields() const {
48 10859 return std::ranges::any_of(fieldTypes, [](const QualType &fieldType) { return fieldType.isRef(); });
49 }
50
51 /**
52 * Checks if the LLVM struct type of this struct carries a synthesized vtable pointer as its first element, which
53 * shifts all fields by one element. Structs that implement interfaces receive their vtable pointer through their
54 * leading implicit interface field instead, so only structs that request a vtable without implementing any
55 * interface carry the extra element.
56 *
57 * @return Carries a synthesized vtable pointer or not
58 */
59 22756 bool Struct::hasSynthesizedVTablePtr() const {
60
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 22756 times.
22756 assert(declNode->isStructDef());
61
1/2
✓ Branch 5 → 6 taken 22756 times.
✗ Branch 5 → 7 not taken.
22756 const auto structDeclNode = spice_pointer_cast<const StructDefNode *>(declNode);
62
4/4
✓ Branch 14 → 15 taken 17566 times.
✓ Branch 14 → 17 taken 5190 times.
✓ Branch 15 → 16 taken 234 times.
✓ Branch 15 → 17 taken 17332 times.
22756 return !structDeclNode->hasInterfaces && structDeclNode->emitVTable;
63 }
64
65 /**
66 * Check that all fields are in a certain lifecycle state.
67 *
68 * @param state Lifecycle state to check for
69 * @return nullptr if all fields are in this state, otherwise the first mismatched field symbol
70 */
71 8128 const SymbolTableEntry *Struct::areAllFieldsInState(LifecycleState state) const {
72
2/2
✓ Branch 21 → 3 taken 13234 times.
✓ Branch 21 → 22 taken 8128 times.
21362 for (size_t i = 0; i < fieldTypes.size(); i++) {
73
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 13234 times.
13234 const SymbolTableEntry *fieldSymbol = scope->lookupField(i);
74
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 13234 times.
13234 assert(fieldSymbol != nullptr);
75
4/6
✓ Branch 11 → 12 taken 12876 times.
✓ Branch 11 → 16 taken 358 times.
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 12876 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 13234 times.
13234 if (!fieldSymbol->isImplicitField && fieldSymbol->getLifecycle().getCurrentState() != state)
76 return fieldSymbol;
77 }
78 8128 return nullptr;
79 }
80
81 /**
82 * Check that all fields are initialized.
83 *
84 * @return nullptr if all fields are initialized, otherwise the first uninitialized field symbol
85 */
86 8128 const SymbolTableEntry *Struct::areAllFieldsInitialized() const { return areAllFieldsInState(INITIALIZED); }
87
88 /**
89 * Reset the initialization state of all fields to DECLARED.
90 *
91 * @param node AST node to associate with the update
92 */
93 20698 void Struct::resetFieldSymbolsToDeclared(const ASTNode *node) const {
94 // Reset every explicit field
95 20698 const size_t fieldCount = scope->getFieldCount();
96
2/2
✓ Branch 14 → 4 taken 50290 times.
✓ Branch 14 → 15 taken 20698 times.
70988 for (size_t i = 0; i < fieldCount; i++) {
97
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 50290 times.
50290 SymbolTableEntry *fieldSymbol = scope->lookupField(i);
98
2/2
✓ Branch 10 → 11 taken 45394 times.
✓ Branch 10 → 13 taken 4896 times.
50290 if (!fieldSymbol->isImplicitField)
99
1/2
✓ Branch 11 → 12 taken 45394 times.
✗ Branch 11 → 16 not taken.
45394 fieldSymbol->updateState(DECLARED, node);
100 }
101 20698 }
102
103 } // namespace spice::compiler
104