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

rieske / trans / 29858613021

21 Jul 2026 06:45PM UTC coverage: 90.602% (-0.1%) from 90.735%
29858613021

Pull #52

github

rieske
Fuzz test and fix issues
Pull Request #52: Fuzz test and fix issues

54 of 72 new or added lines in 7 files covered. (75.0%)

100 existing lines in 4 files now uncovered.

5312 of 5863 relevant lines covered (90.6%)

365676.6 hits per line

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

85.97
/src/semantic_analyzer/SemanticAnalysisVisitor.cpp
1
#include "SemanticAnalysisVisitor.h"
2

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

6
#include "translation_unit/Context.h"
7
#include "types/Type.h"
8
#include "util/Logger.h"
9
#include "util/LogManager.h"
10

11
namespace semantic_analyzer {
12

13
static const translation_unit::Context EXTERNAL_CONTEXT {"external", 0};
14

15
static Logger& err = LogManager::getErrorLogger();
16

17
SemanticAnalysisVisitor::SemanticAnalysisVisitor() {
408✔
18
    type::Type functionType = type::function(type::signedInteger());
408✔
19
    symbolTable.insertFunction("printf", functionType.getFunction(), EXTERNAL_CONTEXT);
1,224✔
20
    symbolTable.insertFunction("scanf", functionType.getFunction(), EXTERNAL_CONTEXT);
1,224✔
21
}
408✔
22

23
SemanticAnalysisVisitor::~SemanticAnalysisVisitor() {
408✔
24
}
408✔
25

26
void SemanticAnalysisVisitor::printSymbolTable() const {
386✔
27
    symbolTable.printTable();
386✔
28
}
386✔
29

30
void SemanticAnalysisVisitor::visit(ast::DeclarationSpecifiers& declarationSpecifiers) {
1,192✔
31
    // FIXME: this would look so much better
32
    /*for (std::string error : declarationSpecifiers.getSemanticErrors()) {
33
     semanticError(error, globalContext);
34
     }*/
35
    if (declarationSpecifiers.getStorageSpecifiers().size() > 1) {
1,192✔
UNCOV
36
        semanticError("multiple storage classes in declaration specifiers",
×
UNCOV
37
                declarationSpecifiers.getStorageSpecifiers().at(1).getContext());
×
38
    }
39
}
1,192✔
40

41
void SemanticAnalysisVisitor::visit(ast::Declaration& declaration) {
514✔
42
    declaration.visitChildren(*this);
514✔
43

44
    auto baseType = declaration.getDeclarationSpecifiers().getTypeSpecifiers().at(0).getType();
514✔
45
    for (const auto& declarator : declaration.getDeclarators()) {
1,150✔
46
        auto type = declarator->getFundamentalType(baseType);
636✔
47
        if (type.isVoid()) {
636✔
48
            semanticError("variable `" + declarator->getName() + "` declared void", declarator->getContext());
2✔
49
        } else if (symbolTable.isAtFileScope() && symbolTable.hasFunction(declarator->getName())) {
634✔
UNCOV
50
            semanticError("symbol `" + declarator->getName() + "` declaration conflicts with function of the same name",
×
UNCOV
51
                    declarator->getContext());
×
52
        } else if (symbolTable.insertSymbol(declarator->getName(), type, declarator->getContext())) {
634✔
53
            declarator->setHolder(symbolTable.lookup(declarator->getName()));
632✔
54
            // TODO: type check initializers
55
            if (declarator->hasInitializer() && symbolTable.isAtFileScope()) {
632✔
56
                long initValue = 0;
28✔
57
                if (declarator->getInitializer()->evaluateConstant(initValue)) {
28✔
58
                    symbolTable.setGlobalInitializer(declarator->getName(), initValue);
28✔
59
                } else {
UNCOV
60
                    semanticError("global initializer is not a constant expression", declarator->getContext());
×
61
                }
62
            }
63
        } else {
64
            semanticError(
2✔
65
                    "symbol `" + declarator->getName() +
4✔
66
                            "` declaration conflicts with previous declaration on " +
4✔
67
                            to_string(symbolTable.lookup(declarator->getName()).getContext()),
4✔
68
                    declarator->getContext());
4✔
69
        }
70
    }
636✔
71
}
514✔
72

73
void SemanticAnalysisVisitor::visit(ast::Declarator& declarator) {
1,316✔
74
    declarator.visitChildren(*this);
1,316✔
75
}
1,316✔
76

77
void SemanticAnalysisVisitor::visit(ast::InitializedDeclarator& declarator) {
636✔
78
    declarator.visitChildren(*this);
636✔
79
}
636✔
80

UNCOV
81
void SemanticAnalysisVisitor::visit(ast::ArrayAccess& arrayAccess) {
×
UNCOV
82
    arrayAccess.visitLeftOperand(*this);
×
UNCOV
83
    arrayAccess.visitRightOperand(*this);
×
84

UNCOV
85
    auto type = arrayAccess.leftOperandType();
×
UNCOV
86
    if (type.isPointer()) {
×
UNCOV
87
        arrayAccess.setLvalue(symbolTable.createTemporarySymbol(type.dereference()));
×
UNCOV
88
        arrayAccess.setResultSymbol(symbolTable.createTemporarySymbol(type.dereference()));
×
89
    } else {
UNCOV
90
        semanticError("invalid type for operator[]\n", arrayAccess.getContext());
×
91
    }
UNCOV
92
}
×
93

94
void SemanticAnalysisVisitor::visit(ast::FunctionCall& functionCall) {
940✔
95
    functionCall.visitOperand(*this);
940✔
96
    functionCall.visitArguments(*this);
940✔
97

98
    // Operand failed to resolve (e.g. undeclared identifier) — error already reported.
99
    if (!functionCall.hasOperandSymbol()) {
940✔
100
        return;
6✔
101
    }
102

103
    const auto calleeName = functionCall.operandSymbol()->getName();
936✔
104
    if (!symbolTable.hasFunction(calleeName)) {
936✔
105
        semanticError("called object `" + calleeName + "` is not a function", functionCall.getContext());
2✔
106
        return;
2✔
107
    }
108

109
    auto functionSymbol = symbolTable.findFunction(calleeName);
934✔
110

111
    functionCall.setSymbol(functionSymbol);
934✔
112

113
    auto& arguments = functionCall.getArgumentList();
934✔
114
    if (arguments.size() == functionSymbol.argumentCount()) {
934✔
115
        auto declaredArguments = functionSymbol.arguments();
114✔
116
        for (std::size_t i { 0 }; i < arguments.size(); ++i) {
310✔
117
            if (!arguments.at(i)->hasResultSymbol()) {
196✔
NEW
UNCOV
118
                return;
×
119
            }
120
            const auto& declaredArgument = declaredArguments.at(i);
196✔
121
            const auto& actualArgument = arguments.at(i)->getResultSymbol();
196✔
122
            typeCheck(actualArgument->getType(), declaredArgument, functionCall.getContext());
196✔
123
        }
124

125
        auto returnType = functionSymbol.returnType();
114✔
126
        if (!returnType.isVoid()) {
114✔
127
            functionCall.setResultSymbol(symbolTable.createTemporarySymbol(returnType));
114✔
128
        }
129
    } else if (functionSymbol.getContext() == EXTERNAL_CONTEXT) {
934✔
130
    // FIXME: using EXTERNAL_CONTEXT as a workaround for printf/scanf external functions until varargs are properly implemented
131
        auto returnType = functionSymbol.returnType();
820✔
132
        if (!returnType.isVoid()) {
820✔
133
            functionCall.setResultSymbol(symbolTable.createTemporarySymbol(returnType));
820✔
134
        }
135
    } else {
820✔
UNCOV
136
        semanticError("no match for function " + functionSymbol.getType().to_string(), functionCall.getContext());
×
137
    }
138
}
936✔
139

140
void SemanticAnalysisVisitor::visit(ast::IdentifierExpression& identifier) {
2,770✔
141
    if (symbolTable.hasSymbol(identifier.getIdentifier())) {
2,770✔
142
        identifier.setResultSymbol(symbolTable.lookup(identifier.getIdentifier()));
2,760✔
143
    } else {
144
        semanticError("symbol `" + identifier.getIdentifier() + "` is not defined", identifier.getContext());
10✔
145
    }
146
}
2,770✔
147

148
void SemanticAnalysisVisitor::visit(ast::ConstantExpression& constant) {
1,328✔
149
    constant.setResultSymbol(symbolTable.createTemporarySymbol(constant.getType()));
1,328✔
150
}
1,328✔
151

152
void SemanticAnalysisVisitor::visit(ast::StringLiteralExpression& stringLiteral) {
824✔
153
    std::string constantSymbol = symbolTable.newConstant(stringLiteral.getValue());
824✔
154
    stringLiteral.setConstantSymbol(constantSymbol);
824✔
155
    stringLiteral.setResultSymbol(symbolTable.createTemporarySymbol(stringLiteral.getType()));
824✔
156
}
824✔
157

158
void SemanticAnalysisVisitor::visit(ast::PostfixExpression& expression) {
26✔
159
    expression.visitOperand(*this);
26✔
160
    if (!expression.hasOperandSymbol()) {
26✔
NEW
UNCOV
161
        return;
×
162
    }
163

164
    expression.setType(expression.operandType());
26✔
165
    auto operandSymbol = *expression.operandSymbol();
26✔
166
    expression.setResultSymbol(operandSymbol);
26✔
167

168
    auto preOperationSymbolName = operandSymbol.getName() + "_pre";
26✔
169
    symbolTable.insertSymbol(preOperationSymbolName, operandSymbol.getType(), operandSymbol.getContext());
26✔
170
    expression.setPreOperationSymbol(symbolTable.lookup(preOperationSymbolName));
26✔
171

172
    if (!expression.isLval()) {
26✔
UNCOV
173
        semanticError("lvalue required as increment operand", expression.getContext());
×
174
    }
175
}
26✔
176

177
void SemanticAnalysisVisitor::visit(ast::PrefixExpression& expression) {
28✔
178
    expression.visitOperand(*this);
28✔
179
    if (!expression.hasOperandSymbol()) {
28✔
NEW
UNCOV
180
        return;
×
181
    }
182

183
    expression.setType(expression.operandType());
28✔
184
    expression.setResultSymbol(*expression.operandSymbol());
28✔
185

186
    if (!expression.isLval()) {
28✔
187
        semanticError("lvalue required as increment operand", expression.getContext());
×
188
    }
189
}
190

191
void SemanticAnalysisVisitor::visit(ast::UnaryExpression& expression) {
544✔
192
    expression.visitOperand(*this);
544✔
193
    if (!expression.hasOperandSymbol()) {
544✔
194
        return;
4✔
195
    }
196

197
    switch (expression.getOperator()->getLexeme().front()) {
540✔
198
    case '&':
328✔
199
        expression.setResultSymbol(symbolTable.createTemporarySymbol(type::pointer(expression.operandType())));
328✔
200
        break;
328✔
201
    case '*':
90✔
202
        if (expression.operandType().isPointer()) {
90✔
203
            expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.operandType().dereference()));
90✔
204
            expression.setLvalueSymbol(symbolTable.createTemporarySymbol(expression.operandType()));
90✔
205
        } else {
206
            semanticError("invalid type argument of ‘unary *’ :" + expression.operandType().to_string(), expression.getContext());
×
207
        }
208
        break;
90✔
209
    case '+':
4✔
210
        expression.setResultSymbol(*expression.operandSymbol());
4✔
211
        break;
4✔
212
    case '-':
88✔
213
        expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.operandType()));
88✔
214
        break;
88✔
215
    case '!':
30✔
216
        expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
30✔
217
        expression.setTruthyLabel(symbolTable.newLabel());
30✔
218
        expression.setFalsyLabel(symbolTable.newLabel());
30✔
219
        break;
30✔
220
    default:
×
221
        throw std::runtime_error { "Unidentified increment operator: " + expression.getOperator()->getLexeme() };
×
222
    }
223
}
224

UNCOV
225
void SemanticAnalysisVisitor::visit(ast::TypeCast& expression) {
×
UNCOV
226
    expression.visitOperand(*this);
×
NEW
UNCOV
227
    if (!expression.hasOperandSymbol()) {
×
NEW
UNCOV
228
        return;
×
229
    }
230

UNCOV
231
    expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.getType().getType()));
×
232
}
233

234
void SemanticAnalysisVisitor::visit(ast::ArithmeticExpression& expression) {
118✔
235
    expression.visitLeftOperand(*this);
118✔
236
    expression.visitRightOperand(*this);
118✔
237
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
118✔
NEW
UNCOV
238
        return;
×
239
    }
240

241
    typeCheck(
118✔
242
            expression.leftOperandType(),
236✔
243
            expression.rightOperandType(),
236✔
244
            expression.getContext());
236✔
245
    // FIXME: type conversion
246
    expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.leftOperandType()));
118✔
247
}
248

249
void SemanticAnalysisVisitor::visit(ast::ShiftExpression& expression) {
20✔
250
    expression.visitLeftOperand(*this);
20✔
251
    expression.visitRightOperand(*this);
20✔
252
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
20✔
NEW
253
        return;
×
254
    }
255

256
    if (expression.rightOperandType().isPrimitive() && !expression.rightOperandType().getPrimitive().isFloating()) {
20✔
257
        expression.setResultSymbol(symbolTable.createTemporarySymbol(expression.leftOperandType()));
20✔
258
    } else {
UNCOV
259
        semanticError("argument of type int required for shift expression", expression.getContext());
×
260
    }
261
}
262

263
void SemanticAnalysisVisitor::visit(ast::ComparisonExpression& expression) {
186✔
264
    expression.visitLeftOperand(*this);
186✔
265
    expression.visitRightOperand(*this);
186✔
266
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
186✔
NEW
UNCOV
267
        return;
×
268
    }
269

270
    typeCheck(
186✔
271
            expression.leftOperandType(),
372✔
272
            expression.rightOperandType(),
372✔
273
            expression.getContext());
372✔
274

275
    expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
186✔
276
    expression.setTruthyLabel(symbolTable.newLabel());
186✔
277
    expression.setFalsyLabel(symbolTable.newLabel());
186✔
278
}
279

280
void SemanticAnalysisVisitor::visit(ast::BitwiseExpression& expression) {
16✔
281
    expression.visitLeftOperand(*this);
16✔
282
    expression.visitRightOperand(*this);
16✔
283
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
16✔
NEW
UNCOV
284
        return;
×
285
    }
286
    expression.setType(expression.leftOperandType());
16✔
287

288
    typeCheck(
16✔
289
            expression.leftOperandType(),
32✔
290
            expression.rightOperandType(),
32✔
291
            expression.getContext());
32✔
292

293
    expression.setResultSymbol(
16✔
294
            symbolTable.createTemporarySymbol(expression.getType()));
32✔
295
}
296

297
void SemanticAnalysisVisitor::visit(ast::LogicalAndExpression& expression) {
12✔
298
    expression.visitLeftOperand(*this);
12✔
299
    expression.visitRightOperand(*this);
12✔
300
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
12✔
NEW
UNCOV
301
        return;
×
302
    }
303

304
    typeCheck(
12✔
305
            expression.leftOperandType(),
24✔
306
            expression.rightOperandType(),
24✔
307
            expression.getContext());
24✔
308

309
    expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
12✔
310
    expression.setExitLabel(symbolTable.newLabel());
12✔
311
}
312

313
void SemanticAnalysisVisitor::visit(ast::LogicalOrExpression& expression) {
12✔
314
    expression.visitLeftOperand(*this);
12✔
315
    expression.visitRightOperand(*this);
12✔
316
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
12✔
NEW
UNCOV
317
        return;
×
318
    }
319

320
    typeCheck(
12✔
321
            expression.leftOperandType(),
24✔
322
            expression.rightOperandType(),
24✔
323
            expression.getContext());
24✔
324

325
    expression.setResultSymbol(symbolTable.createTemporarySymbol(type::signedInteger()));
12✔
326
    expression.setExitLabel(symbolTable.newLabel());
12✔
327
}
328

329
void SemanticAnalysisVisitor::visit(ast::AssignmentExpression& expression) {
488✔
330
    expression.visitLeftOperand(*this);
488✔
331
    expression.visitRightOperand(*this);
488✔
332
    if (!expression.hasLeftOperandSymbol() || !expression.hasRightOperandSymbol()) {
488✔
333
        return;
4✔
334
    }
335

336
    if (expression.isLval()) {
484✔
337
        typeCheck(
480✔
338
                expression.leftOperandType(),
960✔
339
                expression.rightOperandType(),
960✔
340
                expression.getContext());
960✔
341

342
        expression.setResultSymbol(*expression.leftOperandSymbol());
480✔
343
    } else {
344
        semanticError("lvalue required on the left side of assignment", expression.getContext());
12✔
345
    }
346
}
347

348
void SemanticAnalysisVisitor::visit(ast::ExpressionList& expression) {
2✔
349
    expression.visitLeftOperand(*this);
2✔
350
    expression.visitRightOperand(*this);
2✔
351
    if (!expression.hasRightOperandSymbol()) {
2✔
NEW
UNCOV
352
        return;
×
353
    }
354
    // Comma operator: value and type of the right operand
355
    expression.setType(expression.rightOperandType());
2✔
356
    expression.setResultSymbol(*expression.rightOperandSymbol());
2✔
357
}
358

359
void SemanticAnalysisVisitor::visit(ast::Operator&) {
×
360
}
×
361

UNCOV
362
void SemanticAnalysisVisitor::visit(ast::JumpStatement& statement) {
×
UNCOV
363
    throw std::runtime_error { "not implemented" };
×
364
}
365

366
void SemanticAnalysisVisitor::visit(ast::ReturnStatement& statement) {
486✔
367
    statement.returnExpression->accept(*this);
486✔
368
}
486✔
369

370
void SemanticAnalysisVisitor::visit(ast::VoidReturnStatement& statement) {
22✔
371
}
22✔
372

373
void SemanticAnalysisVisitor::visit(ast::IfStatement& statement) {
24✔
374
    statement.testExpression->accept(*this);
24✔
375
    statement.body->accept(*this);
24✔
376

377
    statement.setFalsyLabel(symbolTable.newLabel());
24✔
378
}
24✔
379

380
void SemanticAnalysisVisitor::visit(ast::IfElseStatement& statement) {
18✔
381
    statement.testExpression->accept(*this);
18✔
382
    statement.truthyBody->accept(*this);
18✔
383
    statement.falsyBody->accept(*this);
18✔
384

385
    statement.setFalsyLabel(symbolTable.newLabel());
18✔
386
    statement.setExitLabel(symbolTable.newLabel());
18✔
387
}
18✔
388

389
void SemanticAnalysisVisitor::visit(ast::LoopStatement& loop) {
58✔
390
    loop.header->accept(*this);
58✔
391
    loop.body->accept(*this);
58✔
392
}
58✔
393

394
void SemanticAnalysisVisitor::visit(ast::ForLoopHeader& loopHeader) {
36✔
395
    if (loopHeader.initialization) {
36✔
396
        loopHeader.initialization->accept(*this);
22✔
397
    }
398
    if (loopHeader.clause) {
36✔
399
        loopHeader.clause->accept(*this);
26✔
400
    }
401
    if (loopHeader.increment) {
36✔
402
        loopHeader.increment->accept(*this);
24✔
403
    }
404

405
    loopHeader.setLoopEntry(symbolTable.newLabel());
36✔
406
    loopHeader.setLoopExit(symbolTable.newLabel());
36✔
407
}
36✔
408

409
void SemanticAnalysisVisitor::visit(ast::WhileLoopHeader& loopHeader) {
22✔
410
    loopHeader.clause->accept(*this);
22✔
411

412
    loopHeader.setLoopEntry(symbolTable.newLabel());
22✔
413
    loopHeader.setLoopExit(symbolTable.newLabel());
22✔
414
}
22✔
415

416
void SemanticAnalysisVisitor::visit(ast::Pointer&) {
68✔
417
}
68✔
418

419
void SemanticAnalysisVisitor::visit(ast::Identifier&) {
804✔
420
}
804✔
421

UNCOV
422
void SemanticAnalysisVisitor::visit(ast::ArrayDeclarator& declaration) {
×
UNCOV
423
    declaration.subscriptExpression->accept(*this);
×
UNCOV
424
    throw std::runtime_error { "not implemented" };
×
425
}
426

427
void SemanticAnalysisVisitor::visit(ast::FunctionDeclarator& declarator) {
504✔
428
    declarator.visitFormalArguments(*this);
504✔
429

430
    argumentNames.clear();
504✔
431
    std::vector<type::Type> arguments;
504✔
432
    for (auto& argumentDeclaration : declarator.getFormalArguments()) {
678✔
433
        arguments.push_back(argumentDeclaration.getType());
174✔
434
        argumentNames.push_back(argumentDeclaration.getName());
174✔
435
    }
436

437
    // FIXME: return type is not known at this point!
438
    type::Type functionType = type::function(type::signedInteger(), arguments);
504✔
439
    if (symbolTable.hasGlobalVariable(declarator.getName())) {
504✔
440
        semanticError("function `" + declarator.getName() + "` conflicts with global variable of the same name",
2✔
441
                declarator.getContext());
4✔
442
        return;
2✔
443
    }
444
    FunctionEntry functionEntry = symbolTable.insertFunction(
445
            declarator.getName(),
1,004✔
446
            functionType.getFunction(),
1,004✔
447
            declarator.getContext());
1,506✔
448

449
    if (functionEntry.getContext() != declarator.getContext()) {
502✔
450
        semanticError("function `" + declarator.getName() + "` definition conflicts with previous one on "
×
UNCOV
451
                + to_string(functionEntry.getContext()), declarator.getContext());
×
452
    }
453
}
506✔
454

455
void SemanticAnalysisVisitor::visit(ast::FormalArgument& argument) {
174✔
456
    argument.visitSpecifiers(*this);
174✔
457
    argument.visitDeclarator(*this);
174✔
458
    if (argument.getType().isVoid()) {
174✔
UNCOV
459
        semanticError("function argument ‘" + argument.getName() + "’ declared void", argument.getDeclarationContext());
×
460
    }
461
}
174✔
462

463
void SemanticAnalysisVisitor::visit(ast::FunctionDefinition& function) {
504✔
464
    function.visitReturnType(*this);
504✔
465
    function.visitDeclarator(*this);
504✔
466

467
    if (!symbolTable.hasFunction(function.getName())) {
504✔
468
        return;
2✔
469
    }
470
    function.setSymbol(symbolTable.findFunction(function.getName()));
502✔
471
    symbolTable.startFunction(function.getName(), argumentNames);
502✔
472
    // Parameters and outermost body declarations share one scope (C); do not enterBlockScope.
473
    function.visitBodyChildren(*this);
502✔
474
    function.setArguments(symbolTable.getCurrentScopeArguments());
502✔
475
    function.setLocalVariables(symbolTable.getCurrentScopeSymbols());
502✔
476
    symbolTable.endFunction();
502✔
477
}
478

479
void SemanticAnalysisVisitor::visit(ast::Block& block) {
130✔
480
    symbolTable.enterBlockScope();
130✔
481
    block.visitChildren(*this);
130✔
482
    symbolTable.exitBlockScope();
130✔
483
}
130✔
484

485
void SemanticAnalysisVisitor::typeCheck(const type::Type& typeFrom, const type::Type& typeTo,
1,020✔
486
        const translation_unit::Context& context)
487
{
488
    if (!typeTo.canAssignFrom(typeFrom)) {
1,020✔
UNCOV
489
        semanticError("type mismatch: can't convert " + typeFrom.to_string() + " to " + typeTo.to_string(), context);
×
490
    }
491
}
1,020✔
492

493
void SemanticAnalysisVisitor::semanticError(std::string message, const translation_unit::Context& context) {
22✔
494
    containsSemanticErrors = true;
22✔
495
    err << context << ": error: " << message << "\n";
22✔
496
}
22✔
497

498
bool SemanticAnalysisVisitor::successfulSemanticAnalysis() const {
408✔
499
    return !containsSemanticErrors;
408✔
500
}
501

502
std::map<std::string, std::string> SemanticAnalysisVisitor::getConstants() const {
386✔
503
    return symbolTable.getConstants();
386✔
504
}
505

506
std::vector<ValueEntry> SemanticAnalysisVisitor::getGlobalVariables() const {
386✔
507
    return symbolTable.getGlobalVariables();
386✔
508
}
509

510
} // namespace semantic_analyzer
511

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc