GCC Code Coverage Report


Directory: ../
File: src/typechecker/StructManager.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 137 141 97.2%
Functions: 11 11 100.0%
Branches: 155 267 58.1%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "StructManager.h"
4
5 #include <ast/ASTNodes.h>
6 #include <exception/SemanticError.h>
7 #include <symboltablebuilder/Scope.h>
8 #include <symboltablebuilder/SymbolTableBuilder.h>
9 #include <typechecker/TypeMatcher.h>
10 #include <util/CodeLoc.h>
11 #include <util/CustomHashFunctions.h>
12
13 namespace spice::compiler {
14
15 // Static member initialization
16 std::unordered_map<uint64_t, Struct *> StructManager::lookupCache = {};
17
18 581 Struct *StructManager::insert(Scope *insertScope, Struct &spiceStruct, std::vector<Struct *> *nodeStructList) {
19 // Open a new manifestation list. Which gets filled by the substantiated manifestations of the struct
20
3/6
✓ Branch 0 (2→3) taken 581 times.
✗ Branch 1 (2→22) not taken.
✓ Branch 2 (3→4) taken 581 times.
✗ Branch 3 (3→19) not taken.
✓ Branch 4 (4→5) taken 581 times.
✗ Branch 5 (4→17) not taken.
581 const std::string structId = spiceStruct.name + ":" + spiceStruct.declNode->codeLoc.toPrettyLineAndColumn();
21
2/4
✓ Branch 0 (8→9) taken 581 times.
✗ Branch 1 (8→25) not taken.
✓ Branch 2 (9→10) taken 581 times.
✗ Branch 3 (9→23) not taken.
581 insertScope->structs.insert({structId, StructManifestationList()});
22
23 // Save substantiation in declaration node
24
1/2
✓ Branch 0 (12→13) taken 581 times.
✗ Branch 1 (12→29) not taken.
581 Struct *substantiation = insertSubstantiation(insertScope, spiceStruct, spiceStruct.declNode);
25
1/2
✓ Branch 0 (13→14) taken 581 times.
✗ Branch 1 (13→29) not taken.
581 nodeStructList->push_back(substantiation);
26
27 581 return substantiation;
28 581 }
29
30 914 Struct *StructManager::insertSubstantiation(Scope *insertScope, Struct &newManifestation, const ASTNode *declNode) {
31
1/2
✓ Branch 0 (2→3) taken 914 times.
✗ Branch 1 (2→42) not taken.
914 const std::string signature = newManifestation.getSignature();
32
33 #ifndef NDEBUG
34 // Make sure that the manifestation does not exist already
35
5/8
✓ Branch 0 (3→4) taken 914 times.
✗ Branch 1 (3→31) not taken.
✓ Branch 2 (4→5) taken 914 times.
✗ Branch 3 (4→31) not taken.
✓ Branch 4 (5→6) taken 914 times.
✗ Branch 5 (5→31) not taken.
✓ Branch 6 (13→7) taken 1382 times.
✓ Branch 7 (13→14) taken 914 times.
2296 for (const auto &val : insertScope->structs | std::views::values)
36
2/4
✓ Branch 0 (8→9) taken 1382 times.
✗ Branch 1 (8→31) not taken.
✗ Branch 2 (9→10) not taken.
✓ Branch 3 (9→11) taken 1382 times.
1382 assert(!val.contains(signature));
37 #endif
38
39 // Retrieve the matching manifestation list of the scope
40
3/6
✓ Branch 0 (14→15) taken 914 times.
✗ Branch 1 (14→37) not taken.
✓ Branch 2 (15→16) taken 914 times.
✗ Branch 3 (15→34) not taken.
✓ Branch 4 (16→17) taken 914 times.
✗ Branch 5 (16→32) not taken.
914 const std::string structId = newManifestation.name + ":" + declNode->codeLoc.toPrettyLineAndColumn();
41
2/4
✓ Branch 0 (19→20) taken 914 times.
✗ Branch 1 (19→38) not taken.
✗ Branch 2 (20→21) not taken.
✓ Branch 3 (20→22) taken 914 times.
914 assert(insertScope->structs.contains(structId));
42
1/2
✓ Branch 0 (22→23) taken 914 times.
✗ Branch 1 (22→38) not taken.
914 StructManifestationList &manifestationList = insertScope->structs.at(structId);
43
44 // Add substantiated struct
45 914 newManifestation.manifestationIndex = manifestationList.size();
46
1/2
✓ Branch 0 (24→25) taken 914 times.
✗ Branch 1 (24→38) not taken.
914 manifestationList.emplace(signature, newManifestation);
47
1/2
✓ Branch 0 (25→26) taken 914 times.
✗ Branch 1 (25→38) not taken.
1828 return &manifestationList.at(signature);
48 914 }
49
50 /**
51 * Check if there is a struct in this scope, fulfilling all given requirements and if found, return it.
52 * If more than one struct matches the requirement, an error gets thrown
53 *
54 * @param matchScope Scope to match against
55 * @param qt Struct name requirement
56 * @param reqTemplateTypes Template types to substantiate generic types
57 * @param node Instantiation AST node for printing error messages
58 * @return Matched struct or nullptr
59 */
60 20176 Struct *StructManager::match(Scope *matchScope, const std::string &qt, const QualTypeList &reqTemplateTypes,
61 const ASTNode *node) {
62 // Do cache lookup
63
1/2
✓ Branch 0 (2→3) taken 20176 times.
✗ Branch 1 (2→214) not taken.
20176 const uint64_t cacheKey = getCacheKey(matchScope, qt, reqTemplateTypes);
64
3/4
✓ Branch 0 (3→4) taken 20176 times.
✗ Branch 1 (3→214) not taken.
✓ Branch 2 (4→5) taken 19187 times.
✓ Branch 3 (4→7) taken 989 times.
20176 if (lookupCache.contains(cacheKey))
65
1/2
✓ Branch 0 (5→6) taken 19187 times.
✗ Branch 1 (5→214) not taken.
19187 return lookupCache.at(cacheKey);
66
67 // Copy the registry to prevent iterating over items, that are created within the loop
68
1/2
✓ Branch 0 (7→8) taken 989 times.
✗ Branch 1 (7→214) not taken.
989 StructRegistry structRegistry = matchScope->structs;
69 // Loop over struct registry to find structs, that match the requirements of the instantiation
70 989 std::vector<Struct *> matches;
71
2/2
✓ Branch 0 (146→10) taken 1545 times.
✓ Branch 1 (146→147) taken 989 times.
2534 for (const auto &[structId, m] : structRegistry) {
72 // Copy the manifestation list to prevent iterating over items, that are created within the loop
73
1/2
✓ Branch 0 (13→14) taken 1545 times.
✗ Branch 1 (13→199) not taken.
1545 const StructManifestationList manifestations = m;
74
2/2
✓ Branch 0 (142→16) taken 2153 times.
✓ Branch 1 (142→143) taken 731 times.
2884 for (const auto &[mangledName, presetStruct] : manifestations) {
75 // Skip generic substantiations to prevent double matching of a struct
76
3/4
✓ Branch 0 (19→20) taken 2153 times.
✗ Branch 1 (19→195) not taken.
✓ Branch 2 (20→21) taken 608 times.
✓ Branch 3 (20→22) taken 1545 times.
2153 if (presetStruct.isGenericSubstantiation())
77 1006 continue;
78
79 // Copy the struct to be able to substantiate types
80
1/2
✓ Branch 0 (22→23) taken 1545 times.
✗ Branch 1 (22→195) not taken.
1545 Struct candidate = presetStruct;
81
82 // Check name requirement
83
2/2
✓ Branch 0 (24→25) taken 592 times.
✓ Branch 1 (24→26) taken 953 times.
1545 if (!matchName(candidate, qt))
84 592 break; // Leave the whole manifestation list, because all manifestations in this list have the same name
85
86 // Prepare mapping table from generic type name to concrete type
87 953 TypeMapping &typeMapping = candidate.typeMapping;
88 953 typeMapping.clear();
89
1/2
✓ Branch 0 (28→29) taken 953 times.
✗ Branch 1 (28→193) not taken.
953 typeMapping.reserve(candidate.templateTypes.size());
90
91 // Check template types requirement
92
3/4
✓ Branch 0 (29→30) taken 953 times.
✗ Branch 1 (29→193) not taken.
✓ Branch 2 (30→31) taken 1 times.
✓ Branch 3 (30→32) taken 952 times.
953 if (!matchTemplateTypes(candidate, reqTemplateTypes, typeMapping, node))
93 1 continue; // Leave this manifestation and continue with the next one
94
95 // Map field types from generic to concrete
96
1/2
✓ Branch 0 (32→33) taken 952 times.
✗ Branch 1 (32→193) not taken.
952 substantiateFieldTypes(candidate, typeMapping, node);
97
98 // We found a match! -> Set the actual candidate and its entry to used
99 952 candidate.used = true;
100 952 candidate.entry->used = true;
101
102 // Check if it needs to be substantiated
103
2/2
✓ Branch 0 (34→35) taken 397 times.
✓ Branch 1 (34→47) taken 555 times.
952 if (presetStruct.templateTypes.empty()) {
104
5/10
✓ Branch 0 (35→36) taken 397 times.
✗ Branch 1 (35→193) not taken.
✓ Branch 2 (36→37) taken 397 times.
✗ Branch 3 (36→41) not taken.
✓ Branch 4 (37→38) taken 397 times.
✗ Branch 5 (37→193) not taken.
✓ Branch 6 (38→39) taken 397 times.
✗ Branch 7 (38→193) not taken.
✓ Branch 8 (39→40) taken 397 times.
✗ Branch 9 (39→41) not taken.
397 assert(matchScope->structs.contains(structId) && matchScope->structs.at(structId).contains(mangledName));
105
3/6
✓ Branch 0 (42→43) taken 397 times.
✗ Branch 1 (42→168) not taken.
✓ Branch 2 (43→44) taken 397 times.
✗ Branch 3 (43→168) not taken.
✓ Branch 4 (44→45) taken 397 times.
✗ Branch 5 (44→168) not taken.
397 matches.push_back(&matchScope->structs.at(structId).at(mangledName));
106 397 matches.back()->used = true;
107 397 continue; // Match was successful -> match the next struct
108 }
109
110 // Check if we already have this manifestation and can simply re-use it
111
4/6
✓ Branch 0 (47→48) taken 555 times.
✗ Branch 1 (47→171) not taken.
✓ Branch 2 (48→49) taken 555 times.
✗ Branch 3 (48→169) not taken.
✓ Branch 4 (50→51) taken 222 times.
✓ Branch 5 (50→57) taken 333 times.
555 if (manifestations.contains(candidate.getSignature())) {
112
4/8
✓ Branch 0 (51→52) taken 222 times.
✗ Branch 1 (51→175) not taken.
✓ Branch 2 (52→53) taken 222 times.
✗ Branch 3 (52→174) not taken.
✓ Branch 4 (53→54) taken 222 times.
✗ Branch 5 (53→172) not taken.
✓ Branch 6 (54→55) taken 222 times.
✗ Branch 7 (54→172) not taken.
222 matches.push_back(&matchScope->structs.at(structId).at(candidate.getSignature()));
113 222 break; // Leave the whole manifestation list to not double-match the manifestation
114 }
115
116 // Insert the substantiated version if required
117
1/2
✓ Branch 0 (57→58) taken 333 times.
✗ Branch 1 (57→193) not taken.
333 Struct *substantiatedStruct = insertSubstantiation(matchScope, candidate, presetStruct.declNode);
118
2/4
✓ Branch 0 (58→59) taken 333 times.
✗ Branch 1 (58→193) not taken.
✓ Branch 2 (59→60) taken 333 times.
✗ Branch 3 (59→193) not taken.
333 substantiatedStruct->genericPreset = &matchScope->structs.at(structId).at(mangledName);
119
2/4
✓ Branch 0 (60→61) taken 333 times.
✗ Branch 1 (60→193) not taken.
✓ Branch 2 (61→62) taken 333 times.
✗ Branch 3 (61→193) not taken.
333 substantiatedStruct->declNode->getStructManifestations()->push_back(substantiatedStruct);
120
121 // Copy struct entry
122
1/2
✓ Branch 0 (62→63) taken 333 times.
✗ Branch 1 (62→193) not taken.
333 const std::string newSignature = substantiatedStruct->getSignature();
123
1/2
✓ Branch 0 (63→64) taken 333 times.
✗ Branch 1 (63→191) not taken.
333 matchScope->lookupStrict(substantiatedStruct->name)->used = true;
124
1/2
✓ Branch 0 (66→67) taken 333 times.
✗ Branch 1 (66→191) not taken.
333 substantiatedStruct->entry = matchScope->symbolTable.copySymbol(substantiatedStruct->name, newSignature);
125
1/2
✗ Branch 0 (67→68) not taken.
✓ Branch 1 (67→69) taken 333 times.
333 assert(substantiatedStruct->entry != nullptr);
126
127 // Copy struct scope
128
1/2
✓ Branch 0 (69→70) taken 333 times.
✗ Branch 1 (69→191) not taken.
333 const std::string oldScopeName = STRUCT_SCOPE_PREFIX + presetStruct.name;
129
1/2
✓ Branch 0 (70→71) taken 333 times.
✗ Branch 1 (70→189) not taken.
333 const std::string newScopeName = STRUCT_SCOPE_PREFIX + newSignature;
130
1/2
✓ Branch 0 (71→72) taken 333 times.
✗ Branch 1 (71→187) not taken.
333 substantiatedStruct->scope = matchScope->copyChildScope(oldScopeName, newScopeName);
131
1/2
✗ Branch 0 (72→73) not taken.
✓ Branch 1 (72→74) taken 333 times.
333 assert(substantiatedStruct->scope != nullptr);
132 333 substantiatedStruct->scope->isGenericScope = false;
133
134 // Attach the template types to the new struct entry
135
1/2
✓ Branch 0 (74→75) taken 333 times.
✗ Branch 1 (74→179) not taken.
333 QualType entryType = substantiatedStruct->entry->getQualType()
136
2/4
✓ Branch 0 (75→76) taken 333 times.
✗ Branch 1 (75→178) not taken.
✓ Branch 2 (76→77) taken 333 times.
✗ Branch 3 (76→176) not taken.
666 .getWithTemplateTypes(substantiatedStruct->getTemplateTypes())
137
1/2
✓ Branch 0 (77→78) taken 333 times.
✗ Branch 1 (77→176) not taken.
333 .getWithBodyScope(substantiatedStruct->scope);
138
1/2
✓ Branch 0 (79→80) taken 333 times.
✗ Branch 1 (79→187) not taken.
333 substantiatedStruct->entry->updateType(entryType, true);
139
140 // Replace symbol types of field entries with concrete types
141
1/2
✗ Branch 0 (80→81) not taken.
✓ Branch 1 (80→82) taken 333 times.
333 assert(substantiatedStruct->scope != nullptr);
142 333 const size_t fieldCount = substantiatedStruct->fieldTypes.size();
143
1/2
✓ Branch 0 (83→84) taken 333 times.
✗ Branch 1 (83→187) not taken.
333 const size_t explicitFieldsStartIdx = substantiatedStruct->scope->getFieldCount() - fieldCount;
144
2/2
✓ Branch 0 (108→85) taken 781 times.
✓ Branch 1 (108→109) taken 333 times.
1114 for (size_t i = 0; i < fieldCount; i++) {
145 // Replace field type with concrete template type
146
1/2
✗ Branch 0 (85→86) not taken.
✓ Branch 1 (85→87) taken 781 times.
781 SymbolTableEntry *fieldEntry = substantiatedStruct->scope->lookupField(explicitFieldsStartIdx + i);
147
3/6
✓ Branch 0 (90→91) taken 781 times.
✗ Branch 1 (90→94) not taken.
✓ Branch 2 (91→92) taken 781 times.
✗ Branch 3 (91→182) not taken.
✓ Branch 4 (92→93) taken 781 times.
✗ Branch 5 (92→94) not taken.
781 assert(fieldEntry != nullptr && fieldEntry->isField());
148
1/2
✓ Branch 0 (95→96) taken 781 times.
✗ Branch 1 (95→182) not taken.
781 QualType &fieldType = substantiatedStruct->fieldTypes.at(i);
149
1/2
✓ Branch 0 (96→97) taken 781 times.
✗ Branch 1 (96→182) not taken.
781 QualType baseType = fieldType.getBase();
150
151 // Set the body scope of fields that are of type <candidate-struct>*
152
4/6
✓ Branch 0 (97→98) taken 781 times.
✗ Branch 1 (97→182) not taken.
✓ Branch 2 (98→99) taken 781 times.
✗ Branch 3 (98→182) not taken.
✓ Branch 4 (99→100) taken 18 times.
✓ Branch 5 (99→103) taken 763 times.
781 if (baseType.matches(substantiatedStruct->entry->getQualType(), false, true, true))
153
2/4
✓ Branch 0 (100→101) taken 18 times.
✗ Branch 1 (100→180) not taken.
✓ Branch 2 (101→102) taken 18 times.
✗ Branch 3 (101→180) not taken.
18 fieldType = fieldType.replaceBaseType(baseType.getWithBodyScope(substantiatedStruct->scope));
154
155
1/2
✓ Branch 0 (103→104) taken 781 times.
✗ Branch 1 (103→182) not taken.
781 fieldEntry->updateType(fieldType, /*overwriteExistingType=*/true);
156
157 // Instantiate structs
158
3/4
✓ Branch 0 (104→105) taken 781 times.
✗ Branch 1 (104→182) not taken.
✓ Branch 2 (105→106) taken 293 times.
✓ Branch 3 (105→107) taken 488 times.
781 if (baseType.is(TY_STRUCT))
159
1/2
✓ Branch 0 (106→107) taken 293 times.
✗ Branch 1 (106→182) not taken.
293 baseType.getStruct(node);
160 }
161
162 // Instantiate implemented interfaces if required
163
2/2
✓ Branch 0 (128→111) taken 112 times.
✓ Branch 1 (128→129) taken 333 times.
445 for (QualType &interfaceType : substantiatedStruct->interfaceTypes) {
164 // Skip non-generic interfaces
165
2/4
✓ Branch 0 (112→113) taken 112 times.
✗ Branch 1 (112→185) not taken.
✗ Branch 2 (113→114) not taken.
✓ Branch 3 (113→115) taken 112 times.
112 if (!interfaceType.hasAnyGenericParts())
166 continue;
167
168 // Build template types
169
2/4
✓ Branch 0 (115→116) taken 112 times.
✗ Branch 1 (115→185) not taken.
✓ Branch 2 (116→117) taken 112 times.
✗ Branch 3 (116→185) not taken.
112 QualTypeList templateTypes = interfaceType.getTemplateTypes();
170
1/2
✓ Branch 0 (117→118) taken 112 times.
✗ Branch 1 (117→183) not taken.
112 TypeMatcher::substantiateTypesWithTypeMapping(templateTypes, typeMapping, node);
171
172 // Instantiate interface
173
1/2
✓ Branch 0 (118→119) taken 112 times.
✗ Branch 1 (118→183) not taken.
112 Scope *interfaceMatchScope = interfaceType.getBodyScope()->parent;
174
2/4
✓ Branch 0 (119→120) taken 112 times.
✗ Branch 1 (119→183) not taken.
✓ Branch 2 (120→121) taken 112 times.
✗ Branch 3 (120→183) not taken.
112 Interface *spiceInterface = InterfaceManager::match(interfaceMatchScope, interfaceType.getSubType(), templateTypes, node);
175
1/2
✗ Branch 0 (121→122) not taken.
✓ Branch 1 (121→123) taken 112 times.
112 assert(spiceInterface != nullptr);
176
177
1/2
✓ Branch 0 (123→124) taken 112 times.
✗ Branch 1 (123→183) not taken.
112 interfaceType = spiceInterface->entry->getQualType();
178 112 }
179
180 // Add to matched structs
181
1/2
✓ Branch 0 (129→130) taken 333 times.
✗ Branch 1 (129→187) not taken.
333 matches.push_back(substantiatedStruct);
182
3/3
✓ Branch 0 (135→136) taken 333 times.
✓ Branch 1 (135→138) taken 398 times.
✓ Branch 2 (135→139) taken 814 times.
1545 }
183 1545 }
184
185 // If no matches were found, return a nullptr
186
2/2
✓ Branch 0 (148→149) taken 37 times.
✓ Branch 1 (148→150) taken 952 times.
989 if (matches.empty())
187 37 return nullptr;
188
189 // Check if more than one struct matches the requirements
190
1/2
✗ Branch 0 (151→152) not taken.
✓ Branch 1 (151→160) taken 952 times.
952 if (matches.size() > 1)
191 throw SemanticError(node, STRUCT_AMBIGUITY, "Multiple structs match the requested signature");
192
193 // Insert into cache
194
1/2
✓ Branch 0 (161→162) taken 952 times.
✗ Branch 1 (161→210) not taken.
952 lookupCache[cacheKey] = matches.front();
195
196 952 return matches.front();
197 989 }
198
199 /**
200 * Checks if the matching candidate fulfills the name requirement
201 *
202 * @param candidate Matching candidate struct
203 * @param reqName Requested struct name
204 * @return Fulfilled or not
205 */
206 1545 bool StructManager::matchName(const Struct &candidate, const std::string &reqName) { return candidate.name == reqName; }
207
208 /**
209 * Checks if the matching candidate fulfills the template types requirement
210 *
211 * @param candidate Matching candidate struct
212 * @param reqTemplateTypes Requested struct template types
213 * @param typeMapping Generic type mapping
214 * @param node Instantiation AST node for printing error messages
215 * @return Fulfilled or not
216 */
217 953 bool StructManager::matchTemplateTypes(Struct &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping,
218 const ASTNode *node) {
219 // Check if the number of types match
220 953 const size_t typeCount = reqTemplateTypes.size();
221
2/2
✓ Branch 0 (4→5) taken 1 times.
✓ Branch 1 (4→6) taken 952 times.
953 if (typeCount != candidate.templateTypes.size())
222 1 return false;
223
224 // Give the type matcher a way to retrieve instances of GenericType by their name
225 2696 TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) {
226 792 return getGenericTypeOfCandidateByName(candidate, genericTypeName);
227 952 };
228
229 // Loop over all template types
230
2/2
✓ Branch 0 (17→8) taken 792 times.
✓ Branch 1 (17→18) taken 952 times.
1744 for (size_t i = 0; i < typeCount; i++) {
231
1/2
✓ Branch 0 (8→9) taken 792 times.
✗ Branch 1 (8→22) not taken.
792 const QualType &reqType = reqTemplateTypes.at(i);
232
1/2
✓ Branch 0 (9→10) taken 792 times.
✗ Branch 1 (9→22) not taken.
792 QualType &candidateType = candidate.templateTypes.at(i);
233
234 // Check if the requested template type matches the candidate template type. The type mapping may be extended
235
2/4
✓ Branch 0 (10→11) taken 792 times.
✗ Branch 1 (10→22) not taken.
✗ Branch 2 (11→12) not taken.
✓ Branch 3 (11→13) taken 792 times.
792 if (!TypeMatcher::matchRequestedToCandidateType(candidateType, reqType, typeMapping, genericTypeResolver, false))
236 return false;
237
238 // Substantiate the candidate param type, based on the type mapping
239
2/4
✓ Branch 0 (13→14) taken 792 times.
✗ Branch 1 (13→22) not taken.
✓ Branch 2 (14→15) taken 792 times.
✗ Branch 3 (14→16) not taken.
792 if (candidateType.hasAnyGenericParts())
240
1/2
✓ Branch 0 (15→16) taken 792 times.
✗ Branch 1 (15→22) not taken.
792 TypeMatcher::substantiateTypeWithTypeMapping(candidateType, typeMapping, node);
241 }
242
243 952 return true;
244 952 }
245
246 /**
247 * Come up with the concrete field types, by applying the type mapping onto the generic field types
248 *
249 * @param candidate Candidate struct
250 * @param typeMapping Generic type mapping
251 * @param node Instantiation AST node for printing error messages
252 */
253 952 void StructManager::substantiateFieldTypes(Struct &candidate, const TypeMapping &typeMapping, const ASTNode *node) {
254 // Loop over all implicit fields and substantiate the generic ones
255 952 const size_t fieldCount = candidate.scope->getFieldCount() - candidate.fieldTypes.size();
256
2/2
✓ Branch 0 (16→5) taken 210 times.
✓ Branch 1 (16→17) taken 952 times.
1162 for (size_t i = 0; i < fieldCount; i++) {
257
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 210 times.
210 SymbolTableEntry *fieldEntry = candidate.scope->lookupField(i);
258
1/2
✓ Branch 0 (10→11) taken 210 times.
✗ Branch 1 (10→27) not taken.
210 QualType fieldType = fieldEntry->getQualType();
259
3/4
✓ Branch 0 (11→12) taken 210 times.
✗ Branch 1 (11→27) not taken.
✓ Branch 2 (12→13) taken 156 times.
✓ Branch 3 (12→15) taken 54 times.
210 if (fieldType.hasAnyGenericParts()) {
260
1/2
✓ Branch 0 (13→14) taken 156 times.
✗ Branch 1 (13→27) not taken.
156 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node);
261
1/2
✓ Branch 0 (14→15) taken 156 times.
✗ Branch 1 (14→27) not taken.
156 fieldEntry->updateType(fieldType, true);
262 }
263 }
264
265 // Loop over all explicit field types and substantiate the generic ones
266
2/2
✓ Branch 0 (25→19) taken 2137 times.
✓ Branch 1 (25→26) taken 952 times.
3089 for (QualType &fieldType : candidate.fieldTypes)
267
3/4
✓ Branch 0 (20→21) taken 2137 times.
✗ Branch 1 (20→28) not taken.
✓ Branch 2 (21→22) taken 872 times.
✓ Branch 3 (21→23) taken 1265 times.
2137 if (fieldType.hasAnyGenericParts())
268
1/2
✓ Branch 0 (22→23) taken 872 times.
✗ Branch 1 (22→28) not taken.
872 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node);
269 952 }
270
271 /**
272 * Searches the candidate template types for a generic type object with a certain name and return it
273 *
274 * @param candidate Matching candidate struct
275 * @param templateTypeName Template type name
276 * @return Generic type object
277 */
278 792 const GenericType *StructManager::getGenericTypeOfCandidateByName(const Struct &candidate, const std::string &templateTypeName) {
279
1/2
✓ Branch 0 (14→4) taken 1031 times.
✗ Branch 1 (14→15) not taken.
1031 for (const GenericType &templateType : candidate.templateTypes) {
280
3/4
✓ Branch 0 (5→6) taken 1031 times.
✗ Branch 1 (5→17) not taken.
✓ Branch 2 (6→7) taken 163 times.
✓ Branch 3 (6→8) taken 868 times.
1031 if (!templateType.is(TY_GENERIC))
281 163 continue;
282
3/4
✓ Branch 0 (8→9) taken 868 times.
✗ Branch 1 (8→17) not taken.
✓ Branch 2 (10→11) taken 792 times.
✓ Branch 3 (10→12) taken 76 times.
868 if (templateType.getSubType() == templateTypeName)
283 792 return &templateType;
284 }
285 return nullptr;
286 }
287
288 /**
289 * Calculate the cache key for the struct lookup cache
290 *
291 * @param scope Scope to match against
292 * @param name Struct name requirement
293 * @param templateTypes Template types to substantiate generic types
294 * @return Cache key
295 */
296 20176 uint64_t StructManager::getCacheKey(Scope *scope, const std::string &name, const QualTypeList &templateTypes) {
297 10166 const auto pred = [](size_t acc, const QualType &val) {
298 // Combine the previous hash value with the current element's hash, adjusted by a prime number to reduce collisions
299 10166 return acc * 31 + std::hash<QualType>{}(val);
300 };
301 // Calculate the cache key
302 20176 const uint64_t scopeHash = std::hash<Scope *>{}(scope);
303 20176 const uint64_t hashName = std::hash<std::string>{}(name);
304 20176 const uint64_t hashTemplateTypes = std::accumulate(templateTypes.begin(), templateTypes.end(), 0u, pred);
305 20176 return scopeHash ^ (hashName << 1) ^ (hashTemplateTypes << 2);
306 }
307
308 /**
309 * Clear all statics
310 */
311 401 void StructManager::clear() { lookupCache.clear(); }
312
313 } // namespace spice::compiler
314