GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 75.8% 25 / 0 / 33
Functions: 88.9% 8 / 0 / 9
Branches: 50.8% 32 / 0 / 63

src/linter/rules/NamingConventionRule.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "NamingConventionRule.h"
4
5 #include <cctype>
6
7 #include <ast/ASTNodes.h>
8
9 namespace spice::compiler {
10
11 /**
12 * Check whether an identifier is written in camelCase (starts lowercase, no underscores)
13 *
14 * @param input Identifier to check
15 * @return True if the identifier is camelCase
16 */
17 6 static bool isCamelCase(const std::string &input) {
18
4/6
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 9 not taken.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 9 not taken.
✓ Branch 7 → 8 taken 5 times.
✓ Branch 7 → 9 taken 1 time.
6 return !input.empty() && std::islower(static_cast<unsigned char>(input.front())) != 0 && !input.contains('_');
19 }
20
21 /**
22 * Check whether an identifier is written in PascalCase (starts uppercase, no underscores)
23 *
24 * @param input Identifier to check
25 * @return True if the identifier is PascalCase
26 */
27 2 static bool isPascalCase(const std::string &input) {
28
4/6
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 9 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 9 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 1 time.
2 return !input.empty() && std::isupper(static_cast<unsigned char>(input.front())) != 0 && !input.contains('_');
29 }
30
31 /**
32 * Check whether an identifier is written in SNAKE_CASE (all uppercase, underscores)
33 *
34 * @param input Identifier to check
35 * @return True if the identifier is SNAKE_CASE
36 */
37 2 static bool isSnakeCase(const std::string &input) {
38
6/7
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 4 taken 11 times.
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 1 time.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 1 time.
15 return !input.empty() && std::ranges::all_of(input, [](unsigned char c) { return std::isupper(c) || c == '_'; });
39 }
40
41 7 void NamingConventionRule::checkFctDef(FctDefNode *node, std::vector<LintFinding> &findings) {
42 // Operator overloads (e.g. "op.plus") intentionally do not follow camelCase
43
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 6 times.
7 if (node->name->isOperatorOverload())
44 1 return;
45
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 14 taken 5 times.
6 if (!isCamelCase(node->name->name))
46
1/2
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 15 not taken.
1 findings.emplace_back(node->name->codeLoc, id(), LintSeverity::WARNING,
47
2/4
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 21 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 19 not taken.
2 "Function name '" + node->name->name + "' should be camelCase");
48 }
49
50 1 void NamingConventionRule::checkProcDef(ProcDefNode *node, std::vector<LintFinding> &findings) {
51 // Constructors are always named "ctor" by language convention
52
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
1 if (node->isCtor)
53 1 return;
54 if (!isCamelCase(node->name->name))
55 findings.emplace_back(node->name->codeLoc, id(), LintSeverity::WARNING,
56 "Procedure name '" + node->name->name + "' should be camelCase");
57 }
58
59 2 void NamingConventionRule::checkStructDef(StructDefNode *node, std::vector<LintFinding> &findings) {
60
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 11 taken 1 time.
2 if (!isPascalCase(node->structName))
61
1/2
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 12 not taken.
1 findings.emplace_back(node->codeLoc, id(), LintSeverity::WARNING,
62
2/4
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 18 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 16 not taken.
2 "Struct name '" + node->structName + "' should be PascalCase");
63 2 }
64
65 void NamingConventionRule::checkInterfaceDef(InterfaceDefNode *node, std::vector<LintFinding> &findings) {
66 if (!isPascalCase(node->interfaceName))
67 findings.emplace_back(node->codeLoc, id(), LintSeverity::WARNING,
68 "Interface name '" + node->interfaceName + "' should be PascalCase");
69 }
70
71 2 void NamingConventionRule::checkGlobalVarDef(GlobalVarDefNode *node, std::vector<LintFinding> &findings) {
72
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 11 taken 1 time.
2 if (!isSnakeCase(node->varName))
73
1/2
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 12 not taken.
1 findings.emplace_back(node->codeLoc, id(), LintSeverity::WARNING,
74
2/4
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 18 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 16 not taken.
2 "Global variable name '" + node->varName + "' should be SNAKE_CASE");
75 2 }
76
77 } // namespace spice::compiler
78