GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
143 / 144
99.3%
Branches:
74 / 220, 10 excl
33.6%
Functions:
27 / 33
81.8%

model/function.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/data/vector";
5 import "std/text/stringstream";
6
7 // Own imports
8 import "@/ast/ast-nodes";
9 import "@/reader/code-loc";
10 import "@/symboltablebuilder/super-type";
11 import "@/symboltablebuilder/qual-type";
12 import "@/symboltablebuilder/symbol-table-entry";
13 import "@/symboltablebuilder/scope";
14 import "@/model/generic-type";
15 import "@/irgenerator/name-mangling";
16
17 // Helper structs
18 962992 public type Param struct {
19 public QualType qualType
20 public bool isOptional = false
21 }
22
23 // Type aliases
24 public type ParamList alias Vector<Param>;
25
26 749814 public type Function struct {
27 public String name
28 public QualType thisType
29 public QualType returnType
30 public ParamList paramList
31 public Vector<GenericType> templateTypes
32 public TypeMapping typeMapping
33 57852 public SymbolTableEntry* entry = nil<SymbolTableEntry*>
34 57852 public ASTNode* declNode = nil<ASTNode*>
35 57852 public Scope* bodyScope = nil<Scope*>
36 public String predefinedMangledName
37 public String mangleSuffix
38 57852 public Function* genericPreset = nil<Function*>
39 // Interface default method, that implements this struct method, if the struct does not implement it itself
40 57852 public Function* defaultMethod = nil<Function*>
41 57852 public bool isVararg = false
42 57852 public bool mangleFunctionName = true
43 57852 public bool alreadyTypeChecked = false
44 57852 public bool used = false
45 57852 public bool implicitDefault = false
46 57852 public bool isVirtual = false
47 57852 public bool isNewlyInserted = false
48 57852 public bool isInterfaceDefaultMethod = false // Default implementation of an interface method, defined as method of the interface
49 57852 public unsigned long vtableIndex = 0ul
50 }
51
52 57852 public p Function.ctor(const String& name, SymbolTableEntry* entry, const QualType& thisType, const QualType& returnType, const ParamList& paramList, const Vector<GenericType>& templateTypes, ASTNode* declNode) {
53 57852 this.name = name;
54 57852 this.entry = entry;
55 57852 this.thisType = thisType;
56 57852 this.returnType = returnType;
57 57852 this.paramList = paramList;
58 57852 this.templateTypes = templateTypes;
59 57852 this.declNode = declNode;
60 57852 }
61
62 /**
63 * Retrieve the parameter types of the current function
64 *
65 * @return Vector of parameter types
66 */
67 255601 public f<QualTypeList> Function.getParamTypes() {
68 255601 result = Vector<QualType>();
69
2/2
✓ Branch 0 taken 392042 times.
✓ Branch 1 taken 255601 times.
647643 foreach const Param& param : this.paramList {
70 392042 result.pushBack(param.qualType);
71 392042 }
72 255601 }
73
74 /**
75 * Get a string representation of the current function.
76 *
77 * Example:
78 * string Vector<double>.setData<double>(double)
79 *
80 * @param withThisType Include 'this' type in signature
81 * @param withTemplateTypes Include concrete template types in the signature
82 * @param withTypeAliases Print type aliases as is and not decompose them
83 * @param withSize Print array sizes
84 * @return String representation as function signature
85 */
86 248398 public f<String> Function.getSignature(bool withThisType = true, bool withTemplateTypes = true, bool withTypeAliases = true, bool withSize = false) {
87 248398 QualTypeList concreteTemplateTypes;
88
3/10
✗ Branch 0 not taken.
✓ Branch 1 taken 38191 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 210205 times.
248398 if withTemplateTypes {
89 248396 concreteTemplateTypes.reserve(this.templateTypes.getSize());
90
4/10
✓ Branch 0 taken 11777 times.
✓ Branch 1 taken 38191 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 118404 times.
✓ Branch 9 taken 210205 times.
378577 foreach const GenericType& genericType : this.templateTypes {
91
7/20
✗ Branch 0 not taken.
✓ Branch 1 taken 11777 times.
✓ Branch 2 taken 11771 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1576 times.
✓ Branch 17 taken 116828 times.
✓ Branch 18 taken 62599 times.
✓ Branch 19 taken 55805 times.
130181 if genericType.qualType.is(SuperType::TY_GENERIC) && !this.typeMapping.isEmpty() {
92 74370 const String& subType = genericType.qualType.getSubType();
93 74370 assert this.typeMapping.contains(subType);
94 74370 concreteTemplateTypes.pushBack(this.typeMapping.get(subType));
95 74370 } else {
96 55811 concreteTemplateTypes.pushBack(genericType.qualType);
97 55811 }
98 130181 }
99 248396 }
100
101 496796 return getFunctionSignature(this.name, this.thisType, this.returnType, this.paramList, concreteTemplateTypes, true, withThisType, true, withTypeAliases, withSize);
102 248398 }
103
104 /**
105 * Get a string representation of a function. This is a free function, since Spice has no static methods.
106 *
107 * @param name Function name
108 * @param thisType This symbol type
109 * @param returnType Return symbol type
110 * @param paramList Param symbol types
111 * @param concreteTemplateTypes Concrete template symbol types
112 * @param withReturnType Include return type in signature
113 * @param withThisType Include 'this' type in signature
114 * @param ignorePublic Not include public modifiers in signature
115 * @param withTypeAliases Print type aliases as is and not decompose them
116 * @param withSize Print array sizes
117 * @return Function signature
118 */
119 248419 public f<String> getFunctionSignature(const String& name, const QualType& thisType, const QualType& returnType, const ParamList& paramList, const QualTypeList& concreteTemplateTypes, bool withReturnType = true, bool withThisType = true, bool ignorePublic = true, bool withTypeAliases = true, bool withSize = false) {
120 248419 StringStream signature;
121
122 // Build return type string
123
2/12
✗ Branch 0 not taken.
✓ Branch 1 taken 248398 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
248419 if withReturnType {
124
2/12
✓ Branch 0 taken 100289 times.
✓ Branch 1 taken 148109 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
248398 if returnType.is(SuperType::TY_DYN) {
125 100289 signature << "p ";
126 100289 } else {
127 148109 signature << "f<";
128 148109 returnType.getName(signature, withSize, ignorePublic, withTypeAliases);
129 148109 signature << "> ";
130 148109 }
131 248398 }
132
133 // Build this type string
134
7/24
✓ Branch 0 taken 125922 times.
✓ Branch 1 taken 122476 times.
✓ Branch 2 taken 174763 times.
✓ Branch 3 taken 73635 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 21 times.
✓ Branch 10 taken 17 times.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
248419 if withThisType && !thisType.is(SuperType::TY_DYN) {
135 73639 const QualType thisBaseType = thisType.getBase();
136 73639 signature << thisBaseType.getSubType();
137 73639 const QualTypeList& thisTemplateTypes = thisType.getTemplateTypes();
138
4/12
✓ Branch 0 taken 37711 times.
✓ Branch 1 taken 35924 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
73639 if !thisTemplateTypes.isEmpty() {
139 35925 signature << "<";
140
4/12
✓ Branch 0 taken 43292 times.
✓ Branch 1 taken 35924 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
79218 foreach unsigned long i, const QualType& templateType : thisTemplateTypes {
141
3/12
✓ Branch 0 taken 35924 times.
✓ Branch 1 taken 7368 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
43293 if i > 0ul { signature << ","; }
142 43293 templateType.getName(signature, withSize, ignorePublic, withTypeAliases);
143 43293 }
144 35925 signature << ">";
145 35925 }
146 73639 signature << MEMBER_ACCESS_TOKEN;
147 73639 }
148
149 // Name
150 248419 signature << name;
151
152 // Build template type string
153
3/12
✓ Branch 0 taken 141029 times.
✓ Branch 1 taken 107369 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
248419 if !concreteTemplateTypes.isEmpty() {
154 107369 signature << "<";
155
2/12
✓ Branch 0 taken 130181 times.
✓ Branch 1 taken 107369 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
237550 foreach unsigned long i, const QualType& templateType : concreteTemplateTypes {
156
2/12
✓ Branch 0 taken 107369 times.
✓ Branch 1 taken 22812 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
130181 if i > 0ul { signature << ","; }
157 130181 templateType.getName(signature, withSize, ignorePublic, withTypeAliases);
158 130181 }
159 107369 signature << ">";
160 107369 }
161
162 // Parameter type string
163 248419 signature << "(";
164
4/12
✓ Branch 0 taken 248398 times.
✓ Branch 1 taken 290415 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
538853 foreach unsigned long i, const Param& param : paramList {
165
4/12
✓ Branch 0 taken 174984 times.
✓ Branch 1 taken 115431 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
290434 if i > 0ul { signature << ","; }
166 290434 param.qualType.getName(signature, withSize, ignorePublic, withTypeAliases);
167
2/12
✓ Branch 0 taken 290415 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
290434 if param.isOptional { signature << "?"; }
168 290434 }
169 248419 signature << ")";
170
171 496838 return signature.str();
172 248419 }
173
174 /**
175 * Get the name of the scope, where members and the body of the function live
176 *
177 * @return Scope name
178 */
179 125922 public f<String> Function.getScopeName() {
180 125922 return this.getSignature(false, true, false, true);
181 }
182
183 /**
184 * Get the mangled name of the function
185 *
186 * @return Mangled name
187 */
188 184732 public f<String> Function.getMangledName() {
189 // Note: members are returned via an explicit `String(...)` copy, so that the copy ctor is invoked for sure. A shallow
190 // alias of the member buffer leads to a double free once both the returned value and the owning struct are destructed.
191 // A struct method, which is inherited from an interface default method, is implemented by the default method
192
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 184723 times.
184732 if this.defaultMethod != nil<Function*> {
193 9 return this.defaultMethod.getMangledName();
194 }
195 // Use predefined mangled name if available
196
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 184721 times.
184723 if !this.predefinedMangledName.isEmpty() {
197 2 return String(this.predefinedMangledName);
198 }
199 // Use function name if mangling is disabled
200
2/2
✓ Branch 0 taken 16540 times.
✓ Branch 1 taken 168181 times.
184721 if !this.mangleFunctionName {
201 16540 return String(this.name);
202 }
203 // Use normal name mangling
204 168181 return mangleFunction(*this);
205 }
206
207 /**
208 * Get the name of the symbol table entry of the default constructor of a struct
209 *
210 * @param structCodeLoc Code location of the struct
211 * @return Symbol table entry name
212 */
213 201 public f<String> getSymbolTableEntryNameDefaultCtor(const CodeLoc& structCodeLoc) {
214 402 return "default_" + CTOR_FUNCTION_NAME + ":" + structCodeLoc.toString();
215 201 }
216
217 /**
218 * Get the name of the symbol table entry of the default copy constructor of a struct
219 *
220 * @param structCodeLoc Code location of the struct
221 * @return Symbol table entry name
222 */
223 983 public f<String> getSymbolTableEntryNameDefaultCopyCtor(const CodeLoc& structCodeLoc) {
224 1966 return "default_copy" + CTOR_FUNCTION_NAME + ":" + structCodeLoc.toString();
225 983 }
226
227 /**
228 * Get the name of the symbol table entry of the default move constructor of a struct
229 *
230 * @param structCodeLoc Code location of the struct
231 * @return Symbol table entry name
232 */
233 21 public f<String> getSymbolTableEntryNameDefaultMoveCtor(const CodeLoc& structCodeLoc) {
234 42 return "default_move" + CTOR_FUNCTION_NAME + ":" + structCodeLoc.toString();
235 21 }
236
237 /**
238 * Get the name of the symbol table entry of the default destructor of a struct
239 *
240 * @param structCodeLoc Code location of the struct
241 * @return Symbol table entry name
242 */
243 531 public f<String> getSymbolTableEntryNameDefaultDtor(const CodeLoc& structCodeLoc) {
244 1062 return "default_" + DTOR_FUNCTION_NAME + ":" + structCodeLoc.toString();
245 531 }
246
247 /**
248 * Checks if a function contains optional parameters.
249 * This would imply that the function is not substantiated by its optional parameters yet.
250 *
251 * @return Substantiated params or not
252 */
253 3427413 public f<bool> Function.hasSubstantiatedParams() {
254
2/2
✓ Branch 0 taken 5734314 times.
✓ Branch 1 taken 3427413 times.
9161727 foreach const Param& param : this.paramList {
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5734314 times.
5734314 if param.isOptional {
256 ✗ return false;
257 }
258 5734314 }
259 3427413 return true;
260 }
261
262 /**
263 * Checks if a function contains template types.
264 * This would imply that the function is not substantiated by its generic types yet.
265 *
266 * @return Substantiated generics or not
267 */
268 493233 public f<bool> Function.hasSubstantiatedGenerics() {
269
2/2
✓ Branch 0 taken 299298 times.
✓ Branch 1 taken 315935 times.
615233 foreach const GenericType& genericType : this.templateTypes {
270 // A template slot that is not generic (anymore) is already substantiated. This is the case for the default members
271 // of an already-concrete struct manifestation (e.g. HashEntry<int, String>.dtor()), whose template type list holds
272 // the concrete types instead of generic placeholders. Only generic types carry a sub type usable as a mapping key.
273
2/2
✓ Branch 0 taken 4652 times.
✓ Branch 1 taken 294646 times.
299298 if !genericType.qualType.is(SuperType::TY_GENERIC) {
274 4652 continue;
275 }
276
2/2
✓ Branch 0 taken 177298 times.
✓ Branch 1 taken 117348 times.
294646 if !this.typeMapping.contains(genericType.qualType.getSubType()) {
277 177298 return false;
278 }
279 117348 }
280 315935 return true;
281 }
282
283 /**
284 * Checks if a function contains optional parameters or has generic types present.
285 * This would imply that the function is not fully substantiated yet.
286 *
287 * @return Fully substantiated or not
288 */
289 493233 public f<bool> Function.isFullySubstantiated() {
290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 493233 times.
493233 return this.hasSubstantiatedParams() && this.hasSubstantiatedGenerics();
291 }
292
293 /**
294 * Returns, if this function is a substantiation of a generic one.
295 *
296 * @return Generic substantiation or not
297 */
298 2624350 public f<bool> Function.isGenericSubstantiation() {
299 2624350 return this.genericPreset != nil<Function*>;
300 }
301
302 /**
303 * Retrieve the declaration code location of this function
304 *
305 * @return Declaration code location
306 */
307 1643 public f<CodeLoc&> Function.getDeclCodeLoc() {
308 1643 return this.declNode.codeLoc;
309 }
310
311 /**
312 * Check if the current function is a method (has a 'this' type)
313 *
314 * @return Method or not
315 */
316 677777 public f<bool> Function.isMethod() {
317 677777 return !this.thisType.is(SuperType::TY_DYN);
318 }
319
320 /**
321 * Check if the current function is a function (has a return type)
322 *
323 * @return Function or not
324 */
325 84684 public f<bool> Function.isFunction() {
326 84684 return !this.returnType.is(SuperType::TY_DYN);
327 }
328
329 /**
330 * Check if the current function is a procedure (has no return type)
331 *
332 * @return Procedure or not
333 */
334 80097 public f<bool> Function.isProcedure() {
335 80097 return this.returnType.is(SuperType::TY_DYN);
336 }
337
338 /**
339 * Check if the current function is a normal function (no method)
340 *
341 * @return Normal function or not
342 */
343 2637 public f<bool> Function.isNormalFunction() {
344
2/2
✓ Branch 0 taken 544 times.
✓ Branch 1 taken 2093 times.
2637 return this.isFunction() && !this.isMethod();
345 }
346
347 /**
348 * Check if the current function is a virtual method
349 *
350 * @return Virtual method or not
351 */
352 34702 public f<bool> Function.isVirtualMethod() {
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34702 times.
34702 return this.isMethod() && this.isVirtual;
354 }
355
356 35303 public f<bool> Function.isInheritedDefaultMethod() {
357 35303 return this.defaultMethod != nil<Function*>;
358 }
359