GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 85.0% 442 / 3 / 523
Functions: 93.0% 40 / 0 / 43
Branches: 46.0% 458 / 12 / 1008

src/SourceFile.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "SourceFile.h"
4
5 #include <ast/ASTBuilder.h>
6 #include <driver/Driver.h>
7 #include <exception/AntlrThrowingErrorListener.h>
8 #include <exception/CompilerError.h>
9 #include <global/GlobalResourceManager.h>
10 #include <global/TypeRegistry.h>
11 #include <importcollector/ImportCollector.h>
12 #include <irgenerator/IRGenerator.h>
13 #include <iroptimizer/IROptimizer.h>
14 #include <linker/BitcodeLinker.h>
15 #include <objectemitter/ObjectEmitter.h>
16 #include <symboltablebuilder/SymbolTable.h>
17 #include <symboltablebuilder/SymbolTableBuilder.h>
18 #include <typechecker/FunctionManager.h>
19 #include <typechecker/InterfaceManager.h>
20 #include <typechecker/MacroDefs.h>
21 #include <typechecker/StructManager.h>
22 #include <typechecker/TypeChecker.h>
23 #include <util/CompilerWarning.h>
24 #include <util/FileUtil.h>
25 #include <util/SystemUtil.h>
26 #include <util/Timer.h>
27 #include <visualizer/ASTVisualizer.h>
28 #include <visualizer/CSTVisualizer.h>
29 #include <visualizer/DependencyGraphVisualizer.h>
30
31 #include <llvm/IR/Module.h>
32 #include <llvm/MC/TargetRegistry.h>
33
34 namespace spice::compiler {
35
36 2242 SourceFile::SourceFile(GlobalResourceManager &resourceManager, SourceFile *parent, std::string name,
37 const std::filesystem::path &filePath, bool stdFile)
38
1/2
✓ Branch 6 → 7 taken 2242 times.
✗ Branch 6 → 120 not taken.
6726 : name(std::move(name)), filePath(filePath), isStdFile(stdFile), parent(parent),
39
3/4
✓ Branch 14 → 15 taken 2 times.
✓ Branch 14 → 16 taken 2240 times.
✓ Branch 17 → 18 taken 2242 times.
✗ Branch 17 → 60 not taken.
2242 builder(resourceManager.cliOptions.useLTO ? resourceManager.ltoContext : context), resourceManager(resourceManager),
40
1/2
✓ Branch 12 → 13 taken 2242 times.
✗ Branch 12 → 108 not taken.
6726 cliOptions(resourceManager.cliOptions) {
41 // Deduce fileName and fileDir
42
3/6
✓ Branch 25 → 26 taken 2242 times.
✗ Branch 25 → 65 not taken.
✓ Branch 26 → 27 taken 2242 times.
✗ Branch 26 → 63 not taken.
✓ Branch 27 → 28 taken 2242 times.
✗ Branch 27 → 61 not taken.
2242 fileName = std::filesystem::path(filePath).filename().string();
43
3/6
✓ Branch 32 → 33 taken 2242 times.
✗ Branch 32 → 72 not taken.
✓ Branch 33 → 34 taken 2242 times.
✗ Branch 33 → 70 not taken.
✓ Branch 34 → 35 taken 2242 times.
✗ Branch 34 → 68 not taken.
2242 fileDir = std::filesystem::path(filePath).parent_path().string();
44
45 // Discard value names if not required
46
1/2
✓ Branch 39 → 40 taken 2242 times.
✗ Branch 39 → 89 not taken.
2242 context.setDiscardValueNames(!cliOptions.namesForIRValues);
47
48 // Search after the selected target
49 2242 std::string error;
50
1/2
✓ Branch 41 → 42 taken 2242 times.
✗ Branch 41 → 87 not taken.
2242 const llvm::Target *target = llvm::TargetRegistry::lookupTarget(cliOptions.targetTriple, error);
51
1/2
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 48 taken 2242 times.
2242 if (!target)
52 throw CompilerError(TARGET_NOT_AVAILABLE, "Selected target was not found: " + error); // GCOV_EXCL_LINE
53
54 // Create the target machine
55
1/2
✓ Branch 48 → 49 taken 2242 times.
✗ Branch 48 → 87 not taken.
2242 llvm::TargetOptions opt;
56 2242 opt.MCOptions.AsmVerbose = true;
57 2242 opt.MCOptions.PreserveAsmComments = true;
58 2242 const std::string &cpuName = resourceManager.cpuName;
59 2242 const std::string &features = resourceManager.cpuFeatures;
60 2242 const llvm::Triple &targetTriple = cliOptions.targetTriple;
61 2242 constexpr llvm::Reloc::Model relocModel = llvm::Reloc::PIC_;
62
1/2
✓ Branch 53 → 54 taken 2242 times.
✗ Branch 53 → 81 not taken.
2242 llvm::TargetMachine *targetMachineRaw = target->createTargetMachine(targetTriple, cpuName, features, opt, relocModel);
63 2242 targetMachine = std::unique_ptr<llvm::TargetMachine>(targetMachineRaw);
64 2242 }
65
66 3459 void SourceFile::runLexer() {
67
2/2
✓ Branch 2 → 3 taken 535 times.
✓ Branch 2 → 4 taken 2924 times.
3459 if (isMainFile)
68
1/2
✓ Branch 3 → 4 taken 535 times.
✗ Branch 3 → 89 not taken.
535 resourceManager.totalTimer.start();
69
70 // Check if this stage has already been done
71
2/2
✓ Branch 4 → 5 taken 1219 times.
✓ Branch 4 → 6 taken 2240 times.
3459 if (previousStage >= LEXER)
72 1219 return;
73
74
1/2
✓ Branch 6 → 7 taken 2240 times.
✗ Branch 6 → 89 not taken.
2240 Timer timer(&compilerOutput.times.lexer);
75
1/2
✓ Branch 7 → 8 taken 2240 times.
✗ Branch 7 → 89 not taken.
2240 timer.start();
76
77 // Read from the input source file
78
1/2
✓ Branch 8 → 9 taken 2240 times.
✗ Branch 8 → 89 not taken.
2240 std::ifstream fileInputStream(filePath);
79
3/4
✓ Branch 9 → 10 taken 2240 times.
✗ Branch 9 → 87 not taken.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 20 taken 2239 times.
2240 if (!fileInputStream)
80
4/8
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 65 not taken.
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 63 not taken.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 61 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 58 not taken.
1 throw CompilerError(SOURCE_FILE_NOT_FOUND, "Source file at path '" + filePath.string() + "' does not exist.");
81
82 // Tokenize input
83
1/2
✓ Branch 20 → 21 taken 2239 times.
✗ Branch 20 → 70 not taken.
2239 antlrCtx.inputStream = std::make_unique<antlr4::ANTLRInputStream>(fileInputStream);
84
1/2
✓ Branch 24 → 25 taken 2239 times.
✗ Branch 24 → 71 not taken.
2239 antlrCtx.lexer = std::make_unique<SpiceLexer>(antlrCtx.inputStream.get());
85
1/2
✓ Branch 28 → 29 taken 2239 times.
✗ Branch 28 → 87 not taken.
2239 antlrCtx.lexer->removeErrorListeners();
86
1/2
✓ Branch 29 → 30 taken 2239 times.
✗ Branch 29 → 73 not taken.
2239 antlrCtx.lexerErrorHandler = std::make_unique<AntlrThrowingErrorListener>(ThrowingErrorListenerMode::LEXER, this);
87
1/2
✓ Branch 34 → 35 taken 2239 times.
✗ Branch 34 → 87 not taken.
2239 antlrCtx.lexer->addErrorListener(antlrCtx.lexerErrorHandler.get());
88
1/2
✓ Branch 36 → 37 taken 2239 times.
✗ Branch 36 → 76 not taken.
2239 antlrCtx.tokenStream = std::make_unique<antlr4::CommonTokenStream>(antlrCtx.lexer.get());
89
90 // Calculate cache key
91
1/2
✓ Branch 39 → 40 taken 2239 times.
✗ Branch 39 → 87 not taken.
2239 std::stringstream cacheKeyString;
92
4/6
✓ Branch 40 → 41 taken 2239 times.
✗ Branch 40 → 85 not taken.
✓ Branch 42 → 43 taken 2238 times.
✓ Branch 42 → 80 taken 1 time.
✓ Branch 44 → 45 taken 2238 times.
✗ Branch 44 → 78 not taken.
2239 cacheKeyString << std::hex << std::hash<std::string>{}(antlrCtx.tokenStream->getText());
93
1/2
✓ Branch 46 → 47 taken 2238 times.
✗ Branch 46 → 82 not taken.
2238 cacheKey = cacheKeyString.str();
94
95 // Try to load from cache
96
1/2
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 52 taken 2238 times.
2238 if (!cliOptions.ignoreCache)
97 restoredFromCache = resourceManager.cacheManager.lookupSourceFile(this);
98
99 2238 previousStage = LEXER;
100
1/2
✓ Branch 52 → 53 taken 2238 times.
✗ Branch 52 → 85 not taken.
2238 timer.stop();
101
1/2
✓ Branch 53 → 54 taken 2238 times.
✗ Branch 53 → 83 not taken.
2238 printStatusMessage("Lexer", IO_CODE, IO_TOKENS, compilerOutput.times.lexer);
102 2241 }
103
104 3457 void SourceFile::runParser() {
105 // Skip if restored from the cache or this stage has already been done
106
3/4
✓ Branch 2 → 3 taken 3457 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 1219 times.
✓ Branch 3 → 5 taken 2238 times.
3457 if (restoredFromCache || previousStage >= PARSER)
107 1219 return;
108
109
1/2
✓ Branch 5 → 6 taken 2238 times.
✗ Branch 5 → 32 not taken.
2238 Timer timer(&compilerOutput.times.parser);
110
1/2
✓ Branch 6 → 7 taken 2238 times.
✗ Branch 6 → 32 not taken.
2238 timer.start();
111
112 // Parse input
113
1/2
✓ Branch 8 → 9 taken 2238 times.
✗ Branch 8 → 25 not taken.
2238 antlrCtx.parser = std::make_unique<SpiceParser>(antlrCtx.tokenStream.get()); // Check for syntax errors
114
1/2
✓ Branch 12 → 13 taken 2238 times.
✗ Branch 12 → 32 not taken.
2238 antlrCtx.parser->removeErrorListeners();
115
1/2
✓ Branch 13 → 14 taken 2238 times.
✗ Branch 13 → 27 not taken.
2238 antlrCtx.parserErrorHandler = std::make_unique<AntlrThrowingErrorListener>(ThrowingErrorListenerMode::PARSER, this);
116
1/2
✓ Branch 18 → 19 taken 2238 times.
✗ Branch 18 → 32 not taken.
2238 antlrCtx.parser->addErrorListener(antlrCtx.parserErrorHandler.get());
117
1/2
✓ Branch 20 → 21 taken 2238 times.
✗ Branch 20 → 32 not taken.
2238 antlrCtx.parser->removeParseListeners();
118
119 2238 previousStage = PARSER;
120
1/2
✓ Branch 21 → 22 taken 2238 times.
✗ Branch 21 → 32 not taken.
2238 timer.stop();
121
1/2
✓ Branch 22 → 23 taken 2238 times.
✗ Branch 22 → 30 not taken.
2238 printStatusMessage("Parser", IO_TOKENS, IO_CST, compilerOutput.times.parser);
122 }
123
124 2932 void SourceFile::runCSTVisualizer() {
125 // Only execute if enabled
126
3/6
✓ Branch 2 → 3 taken 2932 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 2932 times.
✗ Branch 3 → 6 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2932 times.
2932 if (restoredFromCache || (!cliOptions.dump.dumpCST && !cliOptions.testMode))
127 1219 return;
128 // Check if this stage has already been done
129
2/2
✓ Branch 6 → 7 taken 1219 times.
✓ Branch 6 → 8 taken 1713 times.
2932 if (previousStage >= CST_VISUALIZER)
130 1219 return;
131
132
1/2
✓ Branch 8 → 9 taken 1713 times.
✗ Branch 8 → 66 not taken.
1713 Timer timer(&compilerOutput.times.cstVisualizer);
133
1/2
✓ Branch 9 → 10 taken 1713 times.
✗ Branch 9 → 66 not taken.
1713 timer.start();
134
135 // Generate dot code for this source file
136
1/2
✓ Branch 10 → 11 taken 1713 times.
✗ Branch 10 → 66 not taken.
1713 std::stringstream dotCode;
137
1/2
✓ Branch 11 → 12 taken 1713 times.
✗ Branch 11 → 64 not taken.
1713 visualizerPreamble(dotCode);
138
1/2
✓ Branch 14 → 15 taken 1713 times.
✗ Branch 14 → 64 not taken.
1713 CSTVisualizer cstVisualizer(resourceManager, this, antlrCtx.lexer.get(), antlrCtx.parser.get());
139
6/12
✓ Branch 15 → 16 taken 1713 times.
✗ Branch 15 → 62 not taken.
✓ Branch 17 → 18 taken 1713 times.
✗ Branch 17 → 51 not taken.
✓ Branch 18 → 19 taken 1713 times.
✗ Branch 18 → 51 not taken.
✓ Branch 19 → 20 taken 1713 times.
✗ Branch 19 → 49 not taken.
✓ Branch 20 → 21 taken 1713 times.
✗ Branch 20 → 47 not taken.
✓ Branch 21 → 22 taken 1713 times.
✗ Branch 21 → 47 not taken.
1713 dotCode << " " << std::any_cast<std::string>(cstVisualizer.visit(antlrCtx.parser->entry())) << "}";
140
1/2
✓ Branch 25 → 26 taken 1713 times.
✗ Branch 25 → 62 not taken.
1713 antlrCtx.parser->reset();
141
142 // Dump the serialized CST string and the SVG file
143
2/4
✓ Branch 26 → 27 taken 1713 times.
✗ Branch 26 → 28 not taken.
✓ Branch 27 → 28 taken 1713 times.
✗ Branch 27 → 32 not taken.
1713 if (cliOptions.dump.dumpCST || cliOptions.testMode)
144
1/2
✓ Branch 28 → 29 taken 1713 times.
✗ Branch 28 → 53 not taken.
1713 compilerOutput.cstString = dotCode.str();
145
146
1/2
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 40 taken 1713 times.
1713 if (cliOptions.dump.dumpCST)
147 visualizerOutput("CST", compilerOutput.cstString);
148
149 1713 previousStage = CST_VISUALIZER;
150
1/2
✓ Branch 40 → 41 taken 1713 times.
✗ Branch 40 → 62 not taken.
1713 timer.stop();
151
1/2
✓ Branch 41 → 42 taken 1713 times.
✗ Branch 41 → 60 not taken.
1713 printStatusMessage("CST Visualizer", IO_CST, IO_CST, compilerOutput.times.cstVisualizer);
152 1713 }
153
154 3457 void SourceFile::runASTBuilder() {
155 // Skip if restored from the cache or this stage has already been done
156
3/4
✓ Branch 2 → 3 taken 3457 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 1219 times.
✓ Branch 3 → 5 taken 2238 times.
3457 if (restoredFromCache || previousStage >= AST_BUILDER)
157 1219 return;
158
159
1/2
✓ Branch 5 → 6 taken 2238 times.
✗ Branch 5 → 36 not taken.
2238 Timer timer(&compilerOutput.times.astBuilder);
160
1/2
✓ Branch 6 → 7 taken 2238 times.
✗ Branch 6 → 36 not taken.
2238 timer.start();
161
162 // Build AST for this source file
163
1/2
✓ Branch 8 → 9 taken 2238 times.
✗ Branch 8 → 36 not taken.
2238 ASTBuilder astBuilder(resourceManager, this, antlrCtx.inputStream.get());
164
5/6
✓ Branch 10 → 11 taken 2236 times.
✓ Branch 10 → 26 taken 2 times.
✓ Branch 11 → 12 taken 2230 times.
✓ Branch 11 → 26 taken 6 times.
✓ Branch 12 → 13 taken 2230 times.
✗ Branch 12 → 24 not taken.
2238 ast = std::any_cast<EntryNode *>(astBuilder.visit(antlrCtx.parser->entry()));
165
1/2
✓ Branch 15 → 16 taken 2230 times.
✗ Branch 15 → 34 not taken.
2230 antlrCtx.parser->reset();
166
167 // Create global scope
168
1/2
✓ Branch 16 → 17 taken 2230 times.
✗ Branch 16 → 27 not taken.
2230 globalScope = std::make_unique<Scope>(nullptr, this, ScopeType::GLOBAL, &ast->codeLoc);
169
170 2230 previousStage = AST_BUILDER;
171
1/2
✓ Branch 19 → 20 taken 2230 times.
✗ Branch 19 → 34 not taken.
2230 timer.stop();
172
1/2
✓ Branch 20 → 21 taken 2230 times.
✗ Branch 20 → 32 not taken.
2230 printStatusMessage("AST Builder", IO_CST, IO_AST, compilerOutput.times.astBuilder);
173 2238 }
174
175 2932 void SourceFile::runASTVisualizer() {
176 // Only execute if enabled
177
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2932 times.
2932 if (restoredFromCache)
178 1219 return;
179
2/4
✓ Branch 4 → 5 taken 2932 times.
✗ Branch 4 → 7 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2932 times.
2932 if (!cliOptions.dump.dumpAST && !cliOptions.testMode)
180 return;
181 // Check if this stage has already been done
182
2/2
✓ Branch 7 → 8 taken 1219 times.
✓ Branch 7 → 9 taken 1713 times.
2932 if (previousStage >= AST_VISUALIZER)
183 1219 return;
184
185
1/2
✓ Branch 9 → 10 taken 1713 times.
✗ Branch 9 → 58 not taken.
1713 Timer timer(&compilerOutput.times.astVisualizer);
186
1/2
✓ Branch 10 → 11 taken 1713 times.
✗ Branch 10 → 58 not taken.
1713 timer.start();
187
188 // Generate dot code for this source file
189
1/2
✓ Branch 11 → 12 taken 1713 times.
✗ Branch 11 → 58 not taken.
1713 std::stringstream dotCode;
190
1/2
✓ Branch 12 → 13 taken 1713 times.
✗ Branch 12 → 56 not taken.
1713 visualizerPreamble(dotCode);
191
1/2
✓ Branch 13 → 14 taken 1713 times.
✗ Branch 13 → 56 not taken.
1713 ASTVisualizer astVisualizer(resourceManager, this);
192
5/10
✓ Branch 14 → 15 taken 1713 times.
✗ Branch 14 → 54 not taken.
✓ Branch 15 → 16 taken 1713 times.
✗ Branch 15 → 43 not taken.
✓ Branch 16 → 17 taken 1713 times.
✗ Branch 16 → 41 not taken.
✓ Branch 17 → 18 taken 1713 times.
✗ Branch 17 → 39 not taken.
✓ Branch 18 → 19 taken 1713 times.
✗ Branch 18 → 39 not taken.
1713 dotCode << " " << std::any_cast<std::string>(astVisualizer.visit(ast)) << "}";
193
194 // Dump the serialized AST string and the SVG file
195
1/2
✓ Branch 21 → 22 taken 1713 times.
✗ Branch 21 → 45 not taken.
1713 compilerOutput.astString = dotCode.str();
196
197
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 32 taken 1713 times.
1713 if (cliOptions.dump.dumpAST)
198 visualizerOutput("AST", compilerOutput.astString);
199
200 1713 previousStage = AST_VISUALIZER;
201
1/2
✓ Branch 32 → 33 taken 1713 times.
✗ Branch 32 → 54 not taken.
1713 timer.stop();
202
1/2
✓ Branch 33 → 34 taken 1713 times.
✗ Branch 33 → 52 not taken.
1713 printStatusMessage("AST Visualizer", IO_AST, IO_AST, compilerOutput.times.astVisualizer);
203 1713 }
204
205 3449 void SourceFile::runImportCollector() { // NOLINT(misc-no-recursion)
206 // Skip if restored from the cache or this stage has already been done
207
3/4
✓ Branch 2 → 3 taken 3449 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 1219 times.
✓ Branch 3 → 5 taken 2230 times.
3449 if (restoredFromCache || previousStage >= IMPORT_COLLECTOR)
208 1219 return;
209
210
1/2
✓ Branch 5 → 6 taken 2230 times.
✗ Branch 5 → 30 not taken.
2230 Timer timer(&compilerOutput.times.importCollector);
211
1/2
✓ Branch 6 → 7 taken 2230 times.
✗ Branch 6 → 30 not taken.
2230 timer.start();
212
213 // Collect the imports for this source file
214
1/2
✓ Branch 7 → 8 taken 2230 times.
✗ Branch 7 → 30 not taken.
2230 ImportCollector importCollector(resourceManager, this);
215
2/2
✓ Branch 8 → 9 taken 2225 times.
✓ Branch 8 → 24 taken 5 times.
2230 importCollector.visit(ast);
216
217 2225 previousStage = IMPORT_COLLECTOR;
218
1/2
✓ Branch 10 → 11 taken 2225 times.
✗ Branch 10 → 28 not taken.
2225 timer.stop();
219
220 // Run first part of pipeline for the imported source file
221
5/8
✓ Branch 11 → 12 taken 2225 times.
✗ Branch 11 → 25 not taken.
✓ Branch 12 → 13 taken 2225 times.
✗ Branch 12 → 25 not taken.
✓ Branch 13 → 14 taken 2225 times.
✗ Branch 13 → 25 not taken.
✓ Branch 19 → 15 taken 2317 times.
✓ Branch 19 → 20 taken 2223 times.
4540 for (SourceFile *sourceFile : dependencies | std::views::values)
222
2/2
✓ Branch 16 → 17 taken 2315 times.
✓ Branch 16 → 25 taken 2 times.
2317 sourceFile->runFrontEnd();
223
224
1/2
✓ Branch 20 → 21 taken 2223 times.
✗ Branch 20 → 26 not taken.
2223 printStatusMessage("Import Collector", IO_AST, IO_AST, compilerOutput.times.importCollector);
225 2230 }
226
227 3442 void SourceFile::runSymbolTableBuilder() {
228 // Skip if restored from the cache or this stage has already been done
229
3/4
✓ Branch 2 → 3 taken 3442 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 1219 times.
✓ Branch 3 → 5 taken 2223 times.
3442 if (restoredFromCache || previousStage >= SYMBOL_TABLE_BUILDER)
230 1219 return;
231
232
1/2
✓ Branch 5 → 6 taken 2223 times.
✗ Branch 5 → 30 not taken.
2223 Timer timer(&compilerOutput.times.symbolTableBuilder);
233
1/2
✓ Branch 6 → 7 taken 2223 times.
✗ Branch 6 → 30 not taken.
2223 timer.start();
234
235 // The symbol tables of all dependencies are present at this point, so we can merge the exported name registries in
236
2/2
✓ Branch 15 → 9 taken 2315 times.
✓ Branch 15 → 16 taken 2223 times.
4538 for (const auto &[importName, sourceFile] : dependencies)
237
1/2
✓ Branch 12 → 13 taken 2315 times.
✗ Branch 12 → 24 not taken.
2315 mergeNameRegistries(*sourceFile, importName);
238
239 // Build symbol table of the current file
240
1/2
✓ Branch 16 → 17 taken 2223 times.
✗ Branch 16 → 30 not taken.
2223 SymbolTableBuilder symbolTableBuilder(resourceManager, this);
241
2/2
✓ Branch 17 → 18 taken 2204 times.
✓ Branch 17 → 25 taken 19 times.
2223 symbolTableBuilder.visit(ast);
242
243 2204 previousStage = SYMBOL_TABLE_BUILDER;
244
1/2
✓ Branch 19 → 20 taken 2204 times.
✗ Branch 19 → 28 not taken.
2204 timer.stop();
245
1/2
✓ Branch 20 → 21 taken 2204 times.
✗ Branch 20 → 26 not taken.
2204 printStatusMessage("Symbol Table Builder", IO_AST, IO_AST, compilerOutput.times.symbolTableBuilder);
246 2223 }
247
248 3422 void SourceFile::runTypeCheckerPre() { // NOLINT(misc-no-recursion)
249 // Skip if restored from the cache or this stage has already been done
250
3/4
✓ Branch 2 → 3 taken 3422 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 1219 times.
✓ Branch 3 → 5 taken 2203 times.
3422 if (restoredFromCache || previousStage >= TYPE_CHECKER_PRE)
251 1219 return;
252
253 // Type-check all dependencies first
254
5/8
✓ Branch 5 → 6 taken 2203 times.
✗ Branch 5 → 24 not taken.
✓ Branch 6 → 7 taken 2203 times.
✗ Branch 6 → 24 not taken.
✓ Branch 7 → 8 taken 2203 times.
✗ Branch 7 → 24 not taken.
✓ Branch 13 → 9 taken 2314 times.
✓ Branch 13 → 14 taken 2203 times.
4517 for (SourceFile *sourceFile : dependencies | std::views::values)
255
1/2
✓ Branch 10 → 11 taken 2314 times.
✗ Branch 10 → 24 not taken.
2314 sourceFile->runTypeCheckerPre();
256
257
1/2
✓ Branch 14 → 15 taken 2203 times.
✗ Branch 14 → 30 not taken.
2203 Timer timer(&compilerOutput.times.typeCheckerPre);
258
1/2
✓ Branch 15 → 16 taken 2203 times.
✗ Branch 15 → 30 not taken.
2203 timer.start();
259
260 // Then type-check the current file
261
1/2
✓ Branch 16 → 17 taken 2203 times.
✗ Branch 16 → 30 not taken.
2203 TypeChecker typeChecker(resourceManager, this, TC_MODE_PRE);
262
2/2
✓ Branch 17 → 18 taken 2189 times.
✓ Branch 17 → 25 taken 14 times.
2203 typeChecker.visit(ast);
263
264 2189 previousStage = TYPE_CHECKER_PRE;
265
1/2
✓ Branch 19 → 20 taken 2189 times.
✗ Branch 19 → 28 not taken.
2189 timer.stop();
266
1/2
✓ Branch 20 → 21 taken 2189 times.
✗ Branch 20 → 26 not taken.
2189 printStatusMessage("Type Checker Pre", IO_AST, IO_AST, compilerOutput.times.typeCheckerPre);
267 2203 }
268
269 8609 void SourceFile::runTypeCheckerPost() { // NOLINT(misc-no-recursion)
270 // Skip if restored from cache, this stage has already been done, or not all dependants finished type checking
271
6/8
✓ Branch 2 → 3 taken 8609 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 8609 times.
✗ Branch 3 → 80 not taken.
✓ Branch 4 → 5 taken 2939 times.
✓ Branch 4 → 6 taken 5670 times.
✓ Branch 7 → 8 taken 2939 times.
✓ Branch 7 → 9 taken 5670 times.
8609 if (restoredFromCache || !haveAllDependantsBeenTypeChecked())
272 2939 return;
273
274
1/2
✓ Branch 9 → 10 taken 5670 times.
✗ Branch 9 → 80 not taken.
5670 Timer timer(&compilerOutput.times.typeCheckerPost);
275
1/2
✓ Branch 10 → 11 taken 5670 times.
✗ Branch 10 → 80 not taken.
5670 timer.start();
276
277 // Start type-checking loop. The type-checker can request a re-execution. The max number of type-checker runs is limited
278
1/2
✓ Branch 11 → 12 taken 5670 times.
✗ Branch 11 → 80 not taken.
5670 TypeChecker typeChecker(resourceManager, this, TC_MODE_POST);
279 5670 unsigned short typeCheckerRuns = 0;
280
2/2
✓ Branch 27 → 13 taken 3222 times.
✓ Branch 27 → 28 taken 5604 times.
8826 while (reVisitRequested) {
281 3222 typeCheckerRuns++;
282 3222 totalTypeCheckerRuns++;
283 3222 reVisitRequested = false;
284
285 // Type-check the current file first. Multiple times, if requested
286 3222 timer.resume();
287
2/2
✓ Branch 14 → 15 taken 3190 times.
✓ Branch 14 → 58 taken 32 times.
3222 typeChecker.visit(ast);
288
1/2
✓ Branch 16 → 17 taken 3190 times.
✗ Branch 16 → 78 not taken.
3190 timer.pause();
289
290 // Then type-check all dependencies
291
5/8
✓ Branch 17 → 18 taken 3190 times.
✗ Branch 17 → 59 not taken.
✓ Branch 18 → 19 taken 3190 times.
✗ Branch 18 → 59 not taken.
✓ Branch 19 → 20 taken 3190 times.
✗ Branch 19 → 59 not taken.
✓ Branch 25 → 21 taken 8122 times.
✓ Branch 25 → 26 taken 3156 times.
11278 for (SourceFile *sourceFile : dependencies | std::views::values)
292
2/2
✓ Branch 22 → 23 taken 8088 times.
✓ Branch 22 → 59 taken 34 times.
8122 sourceFile->runTypeCheckerPost();
293 }
294
295
2/2
✓ Branch 28 → 29 taken 5495 times.
✓ Branch 28 → 78 taken 109 times.
5604 checkForSoftErrors();
296
297 // Check if all dyn variables were type-inferred successfully
298
2/2
✓ Branch 30 → 31 taken 5494 times.
✓ Branch 30 → 78 taken 1 time.
5495 globalScope->ensureSuccessfulTypeInference();
299
300 5494 previousStage = TYPE_CHECKER_POST;
301
1/2
✓ Branch 31 → 32 taken 5494 times.
✗ Branch 31 → 78 not taken.
5494 timer.stop();
302
1/2
✓ Branch 32 → 33 taken 5494 times.
✗ Branch 32 → 60 not taken.
5494 printStatusMessage("Type Checker Post", IO_AST, IO_AST, compilerOutput.times.typeCheckerPost, typeCheckerRuns);
303
304 // Save the JSON version in the compiler output
305
2/4
✓ Branch 33 → 34 taken 5494 times.
✗ Branch 33 → 35 not taken.
✓ Branch 34 → 35 taken 5494 times.
✗ Branch 34 → 42 not taken.
5494 if (cliOptions.dump.dumpSymbolTable || cliOptions.testMode)
306
2/4
✓ Branch 36 → 37 taken 5494 times.
✗ Branch 36 → 64 not taken.
✓ Branch 37 → 38 taken 5494 times.
✗ Branch 37 → 62 not taken.
5494 compilerOutput.symbolTableString = globalScope->getSymbolTableJSON().dump(/*indent=*/2);
307
308 // Dump symbol table
309
1/2
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 55 taken 5494 times.
5494 if (cliOptions.dump.dumpSymbolTable)
310 dumpOutput(compilerOutput.symbolTableString, "Symbol Table", "symbol-table.json");
311 5670 }
312
313 347 void SourceFile::runDependencyGraphVisualizer() {
314 // Only execute if enabled
315
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 347 times.
347 if (restoredFromCache)
316 2 return;
317
2/4
✓ Branch 4 → 5 taken 347 times.
✗ Branch 4 → 7 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 347 times.
347 if (!cliOptions.dump.dumpDependencyGraph && !cliOptions.testMode)
318 return;
319 // Check if this stage has already been done
320
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 345 times.
347 if (previousStage >= DEP_GRAPH_VISUALIZER)
321 2 return;
322
323
1/2
✓ Branch 9 → 10 taken 345 times.
✗ Branch 9 → 47 not taken.
345 Timer timer(&compilerOutput.times.depGraphVisualizer);
324
1/2
✓ Branch 10 → 11 taken 345 times.
✗ Branch 10 → 47 not taken.
345 timer.start();
325
326 // Generate dot code for this source file
327
1/2
✓ Branch 11 → 12 taken 345 times.
✗ Branch 11 → 47 not taken.
345 std::stringstream dotCode;
328
1/2
✓ Branch 12 → 13 taken 345 times.
✗ Branch 12 → 45 not taken.
345 visualizerPreamble(dotCode);
329
1/2
✓ Branch 13 → 14 taken 345 times.
✗ Branch 13 → 45 not taken.
345 DependencyGraphVisualizer depGraphVisualizer(resourceManager, this);
330
1/2
✓ Branch 14 → 15 taken 345 times.
✗ Branch 14 → 43 not taken.
345 depGraphVisualizer.getDependencyGraph(dotCode);
331
1/2
✓ Branch 15 → 16 taken 345 times.
✗ Branch 15 → 43 not taken.
345 dotCode << "}";
332
333 // Dump the serialized AST string and the SVG file
334
1/2
✓ Branch 16 → 17 taken 345 times.
✗ Branch 16 → 34 not taken.
345 compilerOutput.depGraphString = dotCode.str();
335
336
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 27 taken 345 times.
345 if (cliOptions.dump.dumpDependencyGraph)
337 visualizerOutput("Dependency Graph", compilerOutput.depGraphString);
338
339 345 previousStage = DEP_GRAPH_VISUALIZER;
340
1/2
✓ Branch 27 → 28 taken 345 times.
✗ Branch 27 → 43 not taken.
345 timer.stop();
341
1/2
✓ Branch 28 → 29 taken 345 times.
✗ Branch 28 → 41 not taken.
345 printStatusMessage("AST Visualizer", IO_AST, IO_AST, compilerOutput.times.depGraphVisualizer);
342 345 }
343
344 272083 void SourceFile::runIRGenerator() {
345 // Skip if restored from the cache or this stage has already been done
346
3/4
✓ Branch 2 → 3 taken 272083 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 270094 times.
✓ Branch 3 → 5 taken 1989 times.
272083 if (restoredFromCache || previousStage >= IR_GENERATOR)
347 270094 return;
348
349
1/2
✓ Branch 5 → 6 taken 1989 times.
✗ Branch 5 → 60 not taken.
1989 Timer timer(&compilerOutput.times.irGenerator);
350
1/2
✓ Branch 6 → 7 taken 1989 times.
✗ Branch 6 → 60 not taken.
1989 timer.start();
351
352 // Create the LLVM module for this source file
353
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 1987 times.
1989 llvm::LLVMContext &llvmContext = cliOptions.useLTO ? resourceManager.ltoContext : context;
354
1/2
✓ Branch 10 → 11 taken 1989 times.
✗ Branch 10 → 41 not taken.
1989 llvmModule = std::make_unique<llvm::Module>(fileName, llvmContext);
355
356 // Generate this source file
357
1/2
✓ Branch 13 → 14 taken 1989 times.
✗ Branch 13 → 60 not taken.
1989 IRGenerator irGenerator(resourceManager, this);
358
1/2
✓ Branch 14 → 15 taken 1989 times.
✗ Branch 14 → 42 not taken.
1989 irGenerator.visit(ast);
359
360 // Save the ir string in the compiler output
361
2/4
✓ Branch 16 → 17 taken 1989 times.
✗ Branch 16 → 18 not taken.
✓ Branch 17 → 18 taken 1989 times.
✗ Branch 17 → 23 not taken.
1989 if (cliOptions.dump.dumpIR || cliOptions.testMode)
362
1/2
✓ Branch 19 → 20 taken 1989 times.
✗ Branch 19 → 43 not taken.
1989 compilerOutput.irString = IRGenerator::getIRString(llvmModule.get(), cliOptions);
363
364 // Dump unoptimized IR code
365
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 36 taken 1989 times.
1989 if (cliOptions.dump.dumpIR)
366 dumpOutput(compilerOutput.irString, "Unoptimized IR Code", "ir-code.ll");
367
368 1989 previousStage = IR_GENERATOR;
369
1/2
✓ Branch 36 → 37 taken 1989 times.
✗ Branch 36 → 58 not taken.
1989 timer.stop();
370
1/2
✓ Branch 37 → 38 taken 1989 times.
✗ Branch 37 → 56 not taken.
1989 printStatusMessage("IR Generator", IO_AST, IO_IR, compilerOutput.times.irGenerator);
371 1989 }
372
373 271936 void SourceFile::runDefaultIROptimizer() {
374
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 271936 times.
271936 assert(!cliOptions.useLTO);
375
376 // Skip if restored from the cache or this stage has already been done
377
6/8
✓ Branch 4 → 5 taken 271936 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 1842 times.
✓ Branch 5 → 8 taken 270094 times.
✓ Branch 6 → 7 taken 31 times.
✓ Branch 6 → 9 taken 1811 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 31 times.
271936 if (restoredFromCache || previousStage > IR_OPTIMIZER || (previousStage == IR_OPTIMIZER && !cliOptions.testMode))
378 270094 return;
379
380
1/2
✓ Branch 9 → 10 taken 1842 times.
✗ Branch 9 → 60 not taken.
1842 Timer timer(&compilerOutput.times.irOptimizer);
381
1/2
✓ Branch 10 → 11 taken 1842 times.
✗ Branch 10 → 60 not taken.
1842 timer.start();
382
383 // Optimize this source file
384
1/2
✓ Branch 11 → 12 taken 1842 times.
✗ Branch 11 → 60 not taken.
1842 IROptimizer irOptimizer(resourceManager, this);
385
1/2
✓ Branch 12 → 13 taken 1842 times.
✗ Branch 12 → 58 not taken.
1842 irOptimizer.prepare();
386
1/2
✓ Branch 13 → 14 taken 1842 times.
✗ Branch 13 → 58 not taken.
1842 irOptimizer.optimizeDefault();
387
388 // Save the optimized ir string in the compiler output
389
2/4
✓ Branch 14 → 15 taken 1842 times.
✗ Branch 14 → 16 not taken.
✓ Branch 15 → 16 taken 1842 times.
✗ Branch 15 → 21 not taken.
1842 if (cliOptions.dump.dumpIR || cliOptions.testMode)
390
1/2
✓ Branch 17 → 18 taken 1842 times.
✗ Branch 17 → 40 not taken.
1842 compilerOutput.irOptString = IRGenerator::getIRString(llvmModule.get(), cliOptions);
391
392 // Dump optimized IR code
393
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 35 taken 1842 times.
1842 if (cliOptions.dump.dumpIR)
394 dumpOutput(compilerOutput.irOptString, "Optimized IR Code",
395 "ir-code-O" + std::to_string(static_cast<uint8_t>(cliOptions.optLevel)) + ".ll");
396
397 1842 previousStage = IR_OPTIMIZER;
398
1/2
✓ Branch 35 → 36 taken 1842 times.
✗ Branch 35 → 58 not taken.
1842 timer.stop();
399
1/2
✓ Branch 36 → 37 taken 1842 times.
✗ Branch 36 → 56 not taken.
1842 printStatusMessage("IR Optimizer", IO_IR, IO_IR, compilerOutput.times.irOptimizer);
400 1842 }
401
402 2 void SourceFile::runPreLinkIROptimizer() {
403
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 assert(cliOptions.useLTO);
404
405 // Skip if restored from the cache or this stage has already been done
406
2/4
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
2 if (restoredFromCache || previousStage >= IR_OPTIMIZER)
407 return;
408
409
1/2
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 51 not taken.
2 Timer timer(&compilerOutput.times.irOptimizer);
410
1/2
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 51 not taken.
2 timer.start();
411
412 // Optimize this source file
413
1/2
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 51 not taken.
2 IROptimizer irOptimizer(resourceManager, this);
414
1/2
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 49 not taken.
2 irOptimizer.prepare();
415
1/2
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 49 not taken.
2 irOptimizer.optimizePreLink();
416
417 // Save the optimized ir string in the compiler output
418
2/4
✓ Branch 12 → 13 taken 2 times.
✗ Branch 12 → 14 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 19 not taken.
2 if (cliOptions.dump.dumpIR || cliOptions.testMode)
419
1/2
✓ Branch 15 → 16 taken 2 times.
✗ Branch 15 → 36 not taken.
2 compilerOutput.irOptString = IRGenerator::getIRString(llvmModule.get(), cliOptions);
420
421 // Dump optimized IR code
422
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 32 taken 2 times.
2 if (cliOptions.dump.dumpIR)
423 dumpOutput(compilerOutput.irOptString, "Optimized IR Code (pre-link)", "ir-code-lto-pre-link.ll");
424
425
1/2
✓ Branch 32 → 33 taken 2 times.
✗ Branch 32 → 49 not taken.
2 timer.pause();
426 2 }
427
428 2 void SourceFile::runBitcodeLinker() {
429
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 assert(cliOptions.useLTO);
430
431 // Skip if this is not the main source file
432
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1 time.
2 if (!isMainFile)
433 1 return;
434
435 // Skip if restored from the cache or this stage has already been done
436
2/4
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1 time.
1 if (restoredFromCache || previousStage >= IR_OPTIMIZER)
437 return;
438
439
1/2
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 20 not taken.
1 Timer timer(&compilerOutput.times.irOptimizer);
440 1 timer.resume();
441
442 // Link all source files together
443
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 20 not taken.
1 BitcodeLinker linker(resourceManager);
444
1/2
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 18 not taken.
1 linker.link();
445
446
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 18 not taken.
1 timer.pause();
447 1 }
448
449 2 void SourceFile::runPostLinkIROptimizer() {
450
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 assert(cliOptions.useLTO);
451
452 // Skip if this is not the main source file
453
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1 time.
2 if (!isMainFile)
454 1 return;
455
456 // Skip if restored from the cache or this stage has already been done
457
2/4
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1 time.
1 if (restoredFromCache || previousStage >= IR_OPTIMIZER)
458 return;
459
460
1/2
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 57 not taken.
1 Timer timer(&compilerOutput.times.irOptimizer);
461 1 timer.resume();
462
463 // Optimize LTO module
464
1/2
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 57 not taken.
1 IROptimizer irOptimizer(resourceManager, this);
465
1/2
✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 55 not taken.
1 irOptimizer.prepare();
466
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 55 not taken.
1 irOptimizer.optimizePostLink();
467
468 // Save the optimized ir string in the compiler output
469
2/4
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 16 not taken.
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 21 not taken.
1 if (cliOptions.dump.dumpIR || cliOptions.testMode) {
470 1 llvm::Module *module = resourceManager.ltoModule.get();
471
1/2
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 40 not taken.
1 compilerOutput.irOptString = IRGenerator::getIRString(module, cliOptions);
472 }
473
474 // Dump optimized IR code
475
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 34 taken 1 time.
1 if (cliOptions.dump.dumpIR)
476 dumpOutput(compilerOutput.irOptString, "Optimized IR Code (post-Link)", "ir-code-lto-post-link.ll");
477
478 1 previousStage = IR_OPTIMIZER;
479
1/2
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 55 not taken.
1 timer.stop();
480
1/2
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 53 not taken.
1 printStatusMessage("IR Optimizer", IO_IR, IO_IR, compilerOutput.times.irOptimizer);
481 1 }
482
483 272035 void SourceFile::runObjectEmitter() {
484 // Skip if restored from the cache or this stage has already been done
485
3/4
✓ Branch 2 → 3 taken 272035 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 270094 times.
✓ Branch 3 → 5 taken 1941 times.
272035 if (restoredFromCache || previousStage >= OBJECT_EMITTER)
486 270095 return;
487
488 // Skip if LTO is enabled and this is not the main source file
489
4/4
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 8 taken 1939 times.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 1 time.
1941 if (cliOptions.useLTO && !isMainFile)
490 1 return;
491
492
1/2
✓ Branch 8 → 9 taken 1940 times.
✗ Branch 8 → 67 not taken.
1940 Timer timer(&compilerOutput.times.objectEmitter);
493
1/2
✓ Branch 9 → 10 taken 1940 times.
✗ Branch 9 → 67 not taken.
1940 timer.start();
494
495 // Deduce an object file path
496
2/4
✓ Branch 10 → 11 taken 1940 times.
✗ Branch 10 → 45 not taken.
✓ Branch 11 → 12 taken 1940 times.
✗ Branch 11 → 43 not taken.
1940 std::filesystem::path objectFilePath = cliOptions.outputDir / filePath.filename();
497
2/4
✓ Branch 13 → 14 taken 1940 times.
✗ Branch 13 → 48 not taken.
✓ Branch 14 → 15 taken 1940 times.
✗ Branch 14 → 46 not taken.
1940 objectFilePath.replace_extension("o");
498
499 // Emit object for this source file
500
1/2
✓ Branch 16 → 17 taken 1940 times.
✗ Branch 16 → 65 not taken.
1940 const ObjectEmitter objectEmitter(resourceManager, this);
501
1/2
✓ Branch 17 → 18 taken 1940 times.
✗ Branch 17 → 63 not taken.
1940 objectEmitter.emit(objectFilePath);
502
503 // Save assembly string in the compiler output
504
4/6
✓ Branch 18 → 19 taken 1896 times.
✓ Branch 18 → 22 taken 44 times.
✓ Branch 19 → 20 taken 1896 times.
✗ Branch 19 → 21 not taken.
✓ Branch 20 → 21 taken 1896 times.
✗ Branch 20 → 22 not taken.
1940 if (cliOptions.isNativeTarget && (cliOptions.dump.dumpAssembly || cliOptions.testMode))
505
1/2
✓ Branch 21 → 22 taken 1896 times.
✗ Branch 21 → 63 not taken.
1896 objectEmitter.getASMString(compilerOutput.asmString);
506
507 // Dump assembly code
508
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 35 taken 1940 times.
1940 if (cliOptions.dump.dumpAssembly)
509 dumpOutput(compilerOutput.asmString, "Assembly code", "assembly-code.s");
510
511 // Add the object file to the linker objects
512
1/2
✓ Branch 35 → 36 taken 1940 times.
✗ Branch 35 → 63 not taken.
1940 resourceManager.linker.addFileToLinkage(objectFilePath);
513
514 1940 previousStage = OBJECT_EMITTER;
515
1/2
✓ Branch 36 → 37 taken 1940 times.
✗ Branch 36 → 63 not taken.
1940 timer.stop();
516
1/2
✓ Branch 37 → 38 taken 1940 times.
✗ Branch 37 → 61 not taken.
1940 printStatusMessage("Object Emitter", IO_IR, IO_OBJECT_FILE, compilerOutput.times.objectEmitter);
517 1940 }
518
519 272035 void SourceFile::concludeCompilation() {
520 // Skip if restored from the cache or this stage has already been done
521
3/4
✓ Branch 2 → 3 taken 272035 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 270094 times.
✓ Branch 3 → 5 taken 1941 times.
272035 if (restoredFromCache || previousStage >= FINISHED)
522 270094 return;
523
524 // Cache the source file
525
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1941 times.
1941 if (!cliOptions.ignoreCache)
526 resourceManager.cacheManager.cacheSourceFile(this);
527
528 // Save type registry as string in the compiler output
529
4/6
✓ Branch 7 → 8 taken 297 times.
✓ Branch 7 → 14 taken 1644 times.
✓ Branch 8 → 9 taken 297 times.
✗ Branch 8 → 10 not taken.
✓ Branch 9 → 10 taken 297 times.
✗ Branch 9 → 14 not taken.
1941 if (isMainFile && (cliOptions.dump.dumpTypes || cliOptions.testMode))
530
1/2
✓ Branch 10 → 11 taken 297 times.
✗ Branch 10 → 52 not taken.
297 compilerOutput.typesString = TypeRegistry::dump();
531
532 // Dump type registry
533
3/4
✓ Branch 14 → 15 taken 297 times.
✓ Branch 14 → 28 taken 1644 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 28 taken 297 times.
1941 if (isMainFile && cliOptions.dump.dumpTypes)
534 dumpOutput(compilerOutput.typesString, "Type Registry", "type-registry.out");
535
536 // Save cache statistics as string in the compiler output
537
4/6
✓ Branch 28 → 29 taken 297 times.
✓ Branch 28 → 32 taken 1644 times.
✓ Branch 29 → 30 taken 297 times.
✗ Branch 29 → 31 not taken.
✓ Branch 30 → 31 taken 297 times.
✗ Branch 30 → 32 not taken.
1941 if (isMainFile && (cliOptions.dump.dumpCacheStats || cliOptions.testMode))
538 297 dumpCacheStats();
539
540 // Dump lookup cache statistics
541
3/4
✓ Branch 32 → 33 taken 297 times.
✓ Branch 32 → 46 taken 1644 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 46 taken 297 times.
1941 if (isMainFile && cliOptions.dump.dumpCacheStats)
542 dumpOutput(compilerOutput.cacheStats, "Cache Statistics", "cache-stats.out");
543
544
1/2
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 50 taken 1941 times.
1941 if (cliOptions.printDebugOutput)
545 std::cout << "Finished compiling " << fileName << std::endl;
546
547 1941 previousStage = FINISHED;
548 }
549
550 2924 void SourceFile::runFrontEnd() { // NOLINT(misc-no-recursion)
551 2924 runLexer();
552
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2924 times.
2924 CHECK_ABORT_FLAG_V()
553 2924 runParser();
554
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2924 times.
2924 CHECK_ABORT_FLAG_V()
555 2924 runCSTVisualizer();
556
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2924 times.
2924 CHECK_ABORT_FLAG_V()
557 2924 runASTBuilder();
558
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 2924 times.
2924 CHECK_ABORT_FLAG_V()
559 2924 runASTVisualizer();
560
1/2
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 2924 times.
2924 CHECK_ABORT_FLAG_V()
561 2924 runImportCollector();
562
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 2922 times.
2922 CHECK_ABORT_FLAG_V()
563 2922 runSymbolTableBuilder();
564
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2922 times.
2922 CHECK_ABORT_FLAG_V()
565 }
566
567 501 void SourceFile::runMiddleEnd() {
568 // We need two runs here due to generics.
569 // The first run to determine all concrete function/struct/interface substantiations
570 501 runTypeCheckerPre(); // Visit the dependency tree from bottom to top
571
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 487 times.
487 CHECK_ABORT_FLAG_V()
572 // The second run to ensure, also generic scopes are type-checked properly
573 487 runTypeCheckerPost(); // Visit the dependency tree from top to bottom in topological order
574
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 345 times.
345 CHECK_ABORT_FLAG_V()
575 // Visualize dependency graph
576 345 runDependencyGraphVisualizer();
577
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 345 times.
345 CHECK_ABORT_FLAG_V()
578 }
579
580 271738 void SourceFile::runBackEnd() { // NOLINT(misc-no-recursion)
581 // Run backend for all dependencies first
582
5/8
✓ Branch 2 → 3 taken 271738 times.
✗ Branch 2 → 36 not taken.
✓ Branch 3 → 4 taken 271738 times.
✗ Branch 3 → 36 not taken.
✓ Branch 4 → 5 taken 271738 times.
✗ Branch 4 → 36 not taken.
✓ Branch 10 → 6 taken 271408 times.
✓ Branch 10 → 11 taken 271738 times.
543146 for (SourceFile *sourceFile : dependencies | std::views::values)
583
1/2
✓ Branch 7 → 8 taken 271408 times.
✗ Branch 7 → 36 not taken.
271408 sourceFile->runBackEnd();
584
585 271738 runIRGenerator();
586
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 271738 times.
271738 CHECK_ABORT_FLAG_V()
587
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 24 taken 271737 times.
271738 if (cliOptions.useLTO) {
588 1 runPreLinkIROptimizer();
589
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
1 CHECK_ABORT_FLAG_V()
590 1 runBitcodeLinker();
591
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 1 time.
1 CHECK_ABORT_FLAG_V()
592 1 runPostLinkIROptimizer();
593
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 27 taken 1 time.
1 CHECK_ABORT_FLAG_V()
594 } else {
595 271737 runDefaultIROptimizer();
596
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 271737 times.
271737 CHECK_ABORT_FLAG_V()
597 }
598 271738 runObjectEmitter();
599
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 271738 times.
271738 CHECK_ABORT_FLAG_V()
600 271738 concludeCompilation();
601
602
1/2
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 35 taken 271738 times.
271738 if (isMainFile) {
603 resourceManager.totalTimer.stop();
604 if (cliOptions.printDebugOutput)
605 dumpCompilationStats();
606 }
607 }
608
609 4383 void SourceFile::addDependency(SourceFile *sourceFile, const ASTNode *declNode, const std::string &dependencyName,
610 const std::string &path) {
611 // Check if this would cause a circular dependency
612
1/2
✓ Branch 2 → 3 taken 4383 times.
✗ Branch 2 → 36 not taken.
4383 std::stack<const SourceFile *> dependencyCircle;
613
3/4
✓ Branch 3 → 4 taken 4383 times.
✗ Branch 3 → 34 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 17 taken 4382 times.
4383 if (isAlreadyImported(path, dependencyCircle)) {
614 // Build the error message
615
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 32 not taken.
1 std::stringstream errorMessage;
616
3/6
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 30 not taken.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 30 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 30 not taken.
1 errorMessage << "Circular import detected while importing '" << sourceFile->fileName << "':\n\n";
617
2/4
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 23 not taken.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 21 not taken.
1 errorMessage << CommonUtil::getCircularImportMessage(dependencyCircle);
618
2/4
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 27 not taken.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 24 not taken.
1 throw SemanticError(declNode, CIRCULAR_DEPENDENCY, errorMessage.str());
619 1 }
620
621 // Add the dependency
622 4382 sourceFile->isMainFile = false;
623
1/2
✓ Branch 17 → 18 taken 4382 times.
✗ Branch 17 → 34 not taken.
4382 dependencies.emplace(dependencyName, sourceFile);
624
625 // Add the dependant
626
1/2
✓ Branch 18 → 19 taken 4382 times.
✗ Branch 18 → 33 not taken.
4382 sourceFile->dependants.push_back(this);
627 4383 }
628
629 259357 bool SourceFile::imports(const SourceFile *sourceFile) const {
630 1207539 return std::ranges::any_of(dependencies, [=](const auto &dependency) { return dependency.second == sourceFile; });
631 }
632
633 450957 bool SourceFile::isAlreadyImported(const std::string &filePathSearch, // NOLINT(misc-no-recursion)
634 std::stack<const SourceFile *> &circle) const {
635
1/2
✓ Branch 2 → 3 taken 450957 times.
✗ Branch 2 → 28 not taken.
450957 circle.push(this);
636
637 // Check if the current source file corresponds to the path to search
638
4/6
✓ Branch 3 → 4 taken 450957 times.
✗ Branch 3 → 31 not taken.
✓ Branch 4 → 5 taken 450957 times.
✗ Branch 4 → 29 not taken.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 450956 times.
450957 if (std::filesystem::equivalent(filePath, filePathSearch))
639 1 return true;
640
641 // Check dependants recursively
642
2/2
✓ Branch 24 → 10 taken 446574 times.
✓ Branch 24 → 25 taken 450954 times.
1348484 for (const SourceFile *dependant : dependants)
643
3/4
✓ Branch 12 → 13 taken 446574 times.
✗ Branch 12 → 32 not taken.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 446572 times.
446574 if (dependant->isAlreadyImported(filePathSearch, circle))
644 2 return true;
645
646 // If no dependant was found, remove the current source file from the circle to continue with the next sibling
647 450954 circle.pop();
648 450954 return false;
649 }
650
651 11072 SourceFile *SourceFile::requestRuntimeModule(RuntimeModule runtimeModule) {
652 // Check if the module was already imported
653
2/2
✓ Branch 3 → 4 taken 9009 times.
✓ Branch 3 → 6 taken 2063 times.
11072 if (isRuntimeModuleAvailable(runtimeModule))
654 9009 return resourceManager.runtimeModuleManager.getModule(runtimeModule);
655 2063 return resourceManager.runtimeModuleManager.requestModule(this, runtimeModule);
656 }
657
658 13090 bool SourceFile::isRuntimeModuleAvailable(RuntimeModule runtimeModule) const { return importedRuntimeModules & runtimeModule; }
659
660 147068 void SourceFile::addNameRegistryEntry(const std::string &symbolName, uint64_t typeId, SymbolTableEntry *entry, Scope *scope,
661 bool keepNewOnCollision, SymbolTableEntry *importEntry) {
662
6/6
✓ Branch 2 → 3 taken 72622 times.
✓ Branch 2 → 5 taken 74446 times.
✓ Branch 4 → 5 taken 72132 times.
✓ Branch 4 → 6 taken 490 times.
✓ Branch 7 → 8 taken 146578 times.
✓ Branch 7 → 15 taken 490 times.
147068 if (keepNewOnCollision || !exportedNameRegistry.contains(symbolName)) // Overwrite potential existing entry
663 293156 exportedNameRegistry[symbolName] = {symbolName, typeId, entry, scope, importEntry};
664 else // Name collision => we must remove the existing entry
665 490 exportedNameRegistry.erase(symbolName);
666
3/8
✓ Branch 8 → 9 taken 146578 times.
✗ Branch 8 → 22 not taken.
✓ Branch 9 → 10 taken 146578 times.
✗ Branch 9 → 17 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 146578 times.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 21 not taken.
440224 }
667
668 815340 const NameRegistryEntry *SourceFile::getNameRegistryEntry(const std::string &symbolName) const {
669
1/2
✓ Branch 2 → 3 taken 815340 times.
✗ Branch 2 → 13 not taken.
815340 const auto it = exportedNameRegistry.find(symbolName);
670
2/2
✓ Branch 5 → 6 taken 386763 times.
✓ Branch 5 → 7 taken 428577 times.
815340 if (it == exportedNameRegistry.end())
671 386763 return nullptr;
672
673 // Resolve registry entry for the given name
674 428577 const NameRegistryEntry *entry = &it->second;
675
676 // Mark the import entry as used
677
2/2
✓ Branch 8 → 9 taken 58115 times.
✓ Branch 8 → 10 taken 370462 times.
428577 if (entry->importEntry != nullptr)
678 58115 entry->importEntry->used = true;
679
680 428577 return entry;
681 }
682
683 964891 llvm::Type *SourceFile::getLLVMType(const Type *type) {
684 // Check if the type is already in the mapping
685
1/2
✓ Branch 2 → 3 taken 964891 times.
✗ Branch 2 → 13 not taken.
964891 const auto it = typeToLLVMTypeMapping.find(type);
686
2/2
✓ Branch 5 → 6 taken 935907 times.
✓ Branch 5 → 8 taken 28984 times.
964891 if (it != typeToLLVMTypeMapping.end())
687 935907 return it->second;
688
689 // If not, generate the LLVM type
690
1/2
✓ Branch 8 → 9 taken 28984 times.
✗ Branch 8 → 13 not taken.
28984 llvm::Type *llvmType = type->toLLVMType(this);
691
1/2
✓ Branch 9 → 10 taken 28984 times.
✗ Branch 9 → 13 not taken.
28984 typeToLLVMTypeMapping[type] = llvmType;
692 28984 return llvmType;
693 }
694
695 5606 void SourceFile::checkForSoftErrors() const {
696 // Check if there are any soft errors and if so, print them
697
2/2
✓ Branch 3 → 4 taken 111 times.
✓ Branch 3 → 27 taken 5495 times.
5606 if (!resourceManager.errorManager.softErrors.empty()) {
698
1/2
✓ Branch 4 → 5 taken 111 times.
✗ Branch 4 → 37 not taken.
111 std::stringstream errorStream;
699
1/2
✓ Branch 5 → 6 taken 111 times.
✗ Branch 5 → 35 not taken.
111 errorStream << "There are unresolved errors. Please fix them and recompile.";
700
2/2
✓ Branch 21 → 8 taken 173 times.
✓ Branch 21 → 22 taken 111 times.
395 for (const auto &[codeLoc, message] : resourceManager.errorManager.softErrors)
701
2/4
✓ Branch 10 → 11 taken 173 times.
✗ Branch 10 → 28 not taken.
✓ Branch 11 → 12 taken 173 times.
✗ Branch 11 → 28 not taken.
173 errorStream << "\n\n" << message;
702
2/4
✓ Branch 23 → 24 taken 111 times.
✗ Branch 23 → 32 not taken.
✓ Branch 24 → 25 taken 111 times.
✗ Branch 24 → 29 not taken.
111 throw CompilerError(UNRESOLVED_SOFT_ERRORS, errorStream.str());
703 111 }
704 5495 }
705
706 333 void SourceFile::collectAndPrintWarnings() { // NOLINT(misc-no-recursion)
707 // Print warnings for all dependencies
708
5/8
✓ Branch 2 → 3 taken 333 times.
✗ Branch 2 → 31 not taken.
✓ Branch 3 → 4 taken 333 times.
✗ Branch 3 → 31 not taken.
✓ Branch 4 → 5 taken 333 times.
✗ Branch 4 → 31 not taken.
✓ Branch 11 → 6 taken 256 times.
✓ Branch 11 → 12 taken 333 times.
589 for (SourceFile *sourceFile : dependencies | std::views::values)
709
2/2
✓ Branch 7 → 8 taken 16 times.
✓ Branch 7 → 9 taken 240 times.
256 if (!sourceFile->isStdFile)
710
1/2
✓ Branch 8 → 9 taken 16 times.
✗ Branch 8 → 31 not taken.
16 sourceFile->collectAndPrintWarnings();
711 // Collect warnings for this file
712
1/2
✓ Branch 12 → 13 taken 333 times.
✗ Branch 12 → 15 not taken.
333 if (!ignoreWarnings)
713 333 globalScope->collectWarnings(compilerOutput.warnings);
714 // Print warnings for this file
715
2/2
✓ Branch 29 → 17 taken 156 times.
✓ Branch 29 → 30 taken 333 times.
822 for (const CompilerWarning &warning : compilerOutput.warnings)
716
1/2
✓ Branch 19 → 20 taken 156 times.
✗ Branch 19 → 32 not taken.
156 warning.print();
717 333 }
718
719 13264 const SourceFile *SourceFile::getRootSourceFile() const { // NOLINT(misc-no-recursion)
720
2/2
✓ Branch 2 → 3 taken 4409 times.
✓ Branch 2 → 4 taken 8855 times.
13264 return isMainFile ? this : parent->getRootSourceFile();
721 }
722
723 26114 bool SourceFile::isRT(RuntimeModule runtimeModule) const {
724
2/4
✓ Branch 2 → 3 taken 26114 times.
✗ Branch 2 → 38 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 26114 times.
26114 assert(IDENTIFYING_TOP_LEVEL_NAMES.contains(runtimeModule));
725
1/2
✓ Branch 5 → 6 taken 26114 times.
✗ Branch 5 → 38 not taken.
26114 const char *topLevelName = IDENTIFYING_TOP_LEVEL_NAMES.at(runtimeModule);
726
2/4
✓ Branch 8 → 9 taken 26114 times.
✗ Branch 8 → 28 not taken.
✓ Branch 9 → 10 taken 26114 times.
✗ Branch 9 → 26 not taken.
52228 const auto it = exportedNameRegistry.find(topLevelName);
727
2/2
✓ Branch 14 → 15 taken 3602 times.
✓ Branch 14 → 16 taken 22512 times.
26114 if (it == exportedNameRegistry.end())
728 3602 return false;
729
2/4
✓ Branch 18 → 19 taken 22512 times.
✗ Branch 18 → 34 not taken.
✓ Branch 19 → 20 taken 22512 times.
✗ Branch 19 → 32 not taken.
67536 return exportedNameRegistry.at(topLevelName).targetEntry->scope == globalScope.get();
730 }
731
732 8609 bool SourceFile::haveAllDependantsBeenTypeChecked() const {
733 34435 return std::ranges::all_of(dependants, [](const SourceFile *dependant) { return dependant->totalTypeCheckerRuns >= 1; });
734 }
735
736 /**
737 * Acquire all publicly visible symbols from the imported source file and put them in the name registry of the current one.
738 * But only do that for the symbols that are actually defined in the imported source file. Do not allow transitive dependencies.
739 * Here, we also register privately visible symbols to know that the symbol exist. The error handling regarding the visibility
740 * is issued later in the pipeline.
741 *
742 * @param importedSourceFile Imported source file
743 * @param importName First fragment of all fully qualified symbol names from that import
744 */
745 4378 void SourceFile::mergeNameRegistries(const SourceFile &importedSourceFile, const std::string &importName) {
746 // Retrieve import entry
747 4378 SymbolTableEntry *importEntry = globalScope->lookupStrict(importName);
748
3/4
✓ Branch 6 → 7 taken 2063 times.
✓ Branch 6 → 10 taken 2315 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 2063 times.
4378 assert(importEntry != nullptr || importName.starts_with("__")); // Runtime imports start with two underscores
749
750
2/2
✓ Branch 32 → 12 taken 441101 times.
✓ Branch 32 → 33 taken 4378 times.
445479 for (const auto &[originalName, entry] : importedSourceFile.exportedNameRegistry) {
751 // Skip if we introduce a transitive dependency
752
2/2
✓ Branch 16 → 17 taken 341541 times.
✓ Branch 16 → 18 taken 99560 times.
441101 if (entry.targetScope->sourceFile->globalScope != importedSourceFile.globalScope)
753 341541 continue;
754 // Add the fully qualified name
755
1/2
✓ Branch 18 → 19 taken 99560 times.
✗ Branch 18 → 42 not taken.
99560 std::string newName = importName;
756
1/2
✓ Branch 19 → 20 taken 99560 times.
✗ Branch 19 → 40 not taken.
99560 newName += SCOPE_ACCESS_TOKEN;
757
1/2
✓ Branch 20 → 21 taken 99560 times.
✗ Branch 20 → 40 not taken.
99560 newName += originalName;
758
3/8
✓ Branch 21 → 22 taken 99560 times.
✗ Branch 21 → 39 not taken.
✓ Branch 22 → 23 taken 99560 times.
✗ Branch 22 → 34 not taken.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 99560 times.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
99560 exportedNameRegistry.emplace(newName, NameRegistryEntry{newName, entry.typeId, entry.targetEntry, entry.targetScope, importEntry});
759 // Add the shortened name, considering the name collision
760 99560 const bool keepOnCollision = importedSourceFile.alwaysKeepSymbolsOnNameCollision;
761
1/2
✓ Branch 26 → 27 taken 99560 times.
✗ Branch 26 → 40 not taken.
99560 addNameRegistryEntry(originalName, entry.typeId, entry.targetEntry, entry.targetScope, keepOnCollision, importEntry);
762 99560 }
763 4378 }
764
765 297 void SourceFile::dumpCacheStats() {
766
1/2
✓ Branch 2 → 3 taken 297 times.
✗ Branch 2 → 32 not taken.
297 std::stringstream cacheStats;
767
3/6
✓ Branch 3 → 4 taken 297 times.
✗ Branch 3 → 22 not taken.
✓ Branch 4 → 5 taken 297 times.
✗ Branch 4 → 20 not taken.
✓ Branch 5 → 6 taken 297 times.
✗ Branch 5 → 20 not taken.
297 cacheStats << FunctionManager::dumpLookupCacheStatistics() << std::endl;
768
3/6
✓ Branch 7 → 8 taken 297 times.
✗ Branch 7 → 25 not taken.
✓ Branch 8 → 9 taken 297 times.
✗ Branch 8 → 23 not taken.
✓ Branch 9 → 10 taken 297 times.
✗ Branch 9 → 23 not taken.
297 cacheStats << StructManager::dumpLookupCacheStatistics() << std::endl;
769
3/6
✓ Branch 11 → 12 taken 297 times.
✗ Branch 11 → 28 not taken.
✓ Branch 12 → 13 taken 297 times.
✗ Branch 12 → 26 not taken.
✓ Branch 13 → 14 taken 297 times.
✗ Branch 13 → 26 not taken.
297 cacheStats << InterfaceManager::dumpLookupCacheStatistics() << std::endl;
770
1/2
✓ Branch 15 → 16 taken 297 times.
✗ Branch 15 → 29 not taken.
297 compilerOutput.cacheStats = cacheStats.str();
771 297 }
772
773 void SourceFile::dumpCompilationStats() const {
774 const size_t sourceFileCount = resourceManager.sourceFiles.size();
775 const size_t totalLineCount = resourceManager.getTotalLineCount();
776 const size_t totalTypeCount = TypeRegistry::getTypeCount();
777 const size_t allocatedBytes = resourceManager.astNodeAlloc.getTotalAllocatedSize();
778 const size_t allocationCount = resourceManager.astNodeAlloc.getAllocationCount();
779 const size_t totalDuration = resourceManager.totalTimer.getDurationMilliseconds();
780 std::cout << "\nSuccessfully compiled " << std::to_string(sourceFileCount) << " source file(s)";
781 std::cout << " or " << std::to_string(totalLineCount) << " lines in total.\n";
782 std::cout << "Total number of blocks allocated via BlockAllocator: " << CommonUtil::formatBytes(allocatedBytes);
783 std::cout << " in " << std::to_string(allocationCount) << " allocations.\n";
784 #ifndef NDEBUG
785 resourceManager.astNodeAlloc.printAllocatedClassStatistic();
786 #endif
787 std::cout << "Total number of types: " << std::to_string(totalTypeCount) << "\n";
788 std::cout << "Total compile time: " << std::to_string(totalDuration) << " ms\n";
789 }
790
791 void SourceFile::dumpOutput(const std::string &content, const std::string &caption, const std::string &fileSuffix) const {
792 if (cliOptions.dump.dumpToFiles) {
793 // Dump to file
794 const std::string dumpFileName = filePath.stem().string() + "-" + fileSuffix;
795 std::filesystem::path dumpFilePath = cliOptions.outputDir / dumpFileName;
796 dumpFilePath.make_preferred();
797 FileUtil::writeToFile(dumpFilePath, content);
798 } else {
799 // Dump to console
800 std::cout << "\n" << caption << ":\n" << content;
801 }
802
803 // If the abort after dump is requested, set the abort compilation flag
804 if (cliOptions.dump.abortAfterDump) {
805 // If this is an IR dump whilst having optimization enabled, we may not abort when dumping unoptimized IR,
806 // because we also have to dump the optimized IR
807 if (cliOptions.dump.dumpIR && fileSuffix == "ir-code.ll") {
808 resourceManager.abortCompilation = cliOptions.optLevel == OptLevel::O0;
809 } else {
810 resourceManager.abortCompilation = true;
811 }
812 }
813 }
814
815 3771 void SourceFile::visualizerPreamble(std::stringstream &output) const {
816
2/2
✓ Branch 2 → 3 taken 361 times.
✓ Branch 2 → 4 taken 3410 times.
3771 if (isMainFile)
817 361 output << "digraph {\n rankdir=\"TB\";\n";
818 else
819 3410 output << "subgraph {\n";
820
3/6
✓ Branch 6 → 7 taken 3771 times.
✗ Branch 6 → 13 not taken.
✓ Branch 7 → 8 taken 3771 times.
✗ Branch 7 → 11 not taken.
✓ Branch 8 → 9 taken 3771 times.
✗ Branch 8 → 11 not taken.
3771 output << " label=\"" << filePath.generic_string() << "\";\n";
821 3771 }
822
823 void SourceFile::visualizerOutput(std::string outputName, const std::string &output) const {
824 if (cliOptions.dump.dumpToFiles) {
825 // Check if graphviz is installed
826 // GCOV_EXCL_START
827 if (!SystemUtil::isGraphvizInstalled())
828 throw CompilerError(IO_ERROR, "Please check if you have installed Graphviz and added it to the PATH variable");
829 // GCOV_EXCL_STOP
830
831 // Write to a dot file
832 std::ranges::transform(outputName, outputName.begin(), ::tolower);
833 dumpOutput(output, outputName, outputName + ".dot");
834
835 // Generate SVG. This only works if the dot code was dumped into a file
836 std::cout << "\nGenerating SVG file ... ";
837 const std::string dotFileName = filePath.stem().string() + "-" + outputName + ".dot";
838 std::filesystem::path dotFilePath = cliOptions.outputDir / dotFileName;
839 std::filesystem::path svgFilePath = dotFilePath;
840 svgFilePath.replace_extension("svg");
841 dotFilePath.make_preferred();
842 svgFilePath.make_preferred();
843 SystemUtil::exec("dot -T svg -o" + svgFilePath.string() + " " + dotFilePath.string());
844 std::cout << "done.\nSVG file can be found at: " << svgFilePath << "\n";
845 } else {
846 // Dump to console
847 std::cout << "\nSerialized " << outputName << ":\n\n" << output << "\n";
848 }
849
850 // If the abort after dump is requested, set the abort compilation flag
851 if (cliOptions.dump.abortAfterDump)
852 resourceManager.abortCompilation = true;
853 }
854
855 28359 void SourceFile::printStatusMessage(const char *stage, const CompileStageIOType &in, const CompileStageIOType &out,
856 uint64_t stageRuntime, unsigned short stageRuns) const {
857
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 30 taken 28359 times.
28359 if (cliOptions.printDebugOutput) {
858 static constexpr const char *const compilerStageIoTypeName[6] = {"Code", "Tokens", "CST", "AST", "IR", "Obj"};
859 // Build output string
860 std::stringstream outputStr;
861 outputStr << "[" << stage << "] for " << fileName << ": ";
862 outputStr << compilerStageIoTypeName[in] << " --> " << compilerStageIoTypeName[out];
863 outputStr << " (" << std::to_string(stageRuntime) << " ms";
864 if (stageRuns > 0)
865 outputStr << "; " << std::to_string(stageRuns) << " run(s)";
866 outputStr << ")\n";
867 // Print
868 std::cout << outputStr.str();
869 }
870 28359 }
871
872 } // namespace spice::compiler
873