c-next 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +726 -0
- package/bin/cnext.js +5 -0
- package/grammar/C.g4 +1112 -0
- package/grammar/CNext.g4 +817 -0
- package/grammar/CPP14Lexer.g4 +282 -0
- package/grammar/CPP14Parser.g4 +1072 -0
- package/package.json +85 -0
- package/src/analysis/DivisionByZeroAnalyzer.ts +378 -0
- package/src/analysis/FunctionCallAnalyzer.ts +526 -0
- package/src/analysis/InitializationAnalyzer.ts +725 -0
- package/src/analysis/NullCheckAnalyzer.ts +427 -0
- package/src/analysis/types/IDivisionByZeroError.ts +25 -0
- package/src/analysis/types/IFunctionCallError.ts +17 -0
- package/src/analysis/types/IInitializationError.ts +55 -0
- package/src/analysis/types/INullCheckError.ts +25 -0
- package/src/codegen/CodeGenerator.ts +7945 -0
- package/src/codegen/CommentExtractor.ts +240 -0
- package/src/codegen/CommentFormatter.ts +155 -0
- package/src/codegen/HeaderGenerator.ts +265 -0
- package/src/codegen/TypeResolver.ts +365 -0
- package/src/codegen/types/ECommentType.ts +10 -0
- package/src/codegen/types/IComment.ts +21 -0
- package/src/codegen/types/ICommentError.ts +15 -0
- package/src/codegen/types/TOverflowBehavior.ts +6 -0
- package/src/codegen/types/TParameterInfo.ts +13 -0
- package/src/codegen/types/TTypeConstants.ts +94 -0
- package/src/codegen/types/TTypeInfo.ts +22 -0
- package/src/index.ts +518 -0
- package/src/lib/IncludeDiscovery.ts +131 -0
- package/src/lib/InputExpansion.ts +121 -0
- package/src/lib/PlatformIODetector.ts +162 -0
- package/src/lib/transpiler.ts +439 -0
- package/src/lib/types/ITranspileResult.ts +80 -0
- package/src/parser/c/grammar/C.interp +338 -0
- package/src/parser/c/grammar/C.tokens +229 -0
- package/src/parser/c/grammar/CLexer.interp +415 -0
- package/src/parser/c/grammar/CLexer.tokens +229 -0
- package/src/parser/c/grammar/CLexer.ts +750 -0
- package/src/parser/c/grammar/CListener.ts +976 -0
- package/src/parser/c/grammar/CParser.ts +9663 -0
- package/src/parser/c/grammar/CVisitor.ts +626 -0
- package/src/parser/cpp/grammar/CPP14Lexer.interp +478 -0
- package/src/parser/cpp/grammar/CPP14Lexer.tokens +264 -0
- package/src/parser/cpp/grammar/CPP14Lexer.ts +848 -0
- package/src/parser/cpp/grammar/CPP14Parser.interp +492 -0
- package/src/parser/cpp/grammar/CPP14Parser.tokens +264 -0
- package/src/parser/cpp/grammar/CPP14Parser.ts +19961 -0
- package/src/parser/cpp/grammar/CPP14ParserListener.ts +2120 -0
- package/src/parser/cpp/grammar/CPP14ParserVisitor.ts +1354 -0
- package/src/parser/grammar/CNext.interp +340 -0
- package/src/parser/grammar/CNext.tokens +214 -0
- package/src/parser/grammar/CNextLexer.interp +374 -0
- package/src/parser/grammar/CNextLexer.tokens +214 -0
- package/src/parser/grammar/CNextLexer.ts +668 -0
- package/src/parser/grammar/CNextListener.ts +1020 -0
- package/src/parser/grammar/CNextParser.ts +9239 -0
- package/src/parser/grammar/CNextVisitor.ts +654 -0
- package/src/preprocessor/Preprocessor.ts +301 -0
- package/src/preprocessor/ToolchainDetector.ts +225 -0
- package/src/preprocessor/types/IPreprocessResult.ts +39 -0
- package/src/preprocessor/types/IToolchain.ts +27 -0
- package/src/project/FileDiscovery.ts +236 -0
- package/src/project/Project.ts +425 -0
- package/src/project/types/IProjectConfig.ts +64 -0
- package/src/symbols/CNextSymbolCollector.ts +326 -0
- package/src/symbols/CSymbolCollector.ts +457 -0
- package/src/symbols/CppSymbolCollector.ts +362 -0
- package/src/symbols/SymbolTable.ts +312 -0
- package/src/symbols/types/IConflict.ts +20 -0
- package/src/types/ESourceLanguage.ts +10 -0
- package/src/types/ESymbolKind.ts +20 -0
- package/src/types/ISymbol.ts +45 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Null Check Analyzer
|
|
3
|
+
* Enforces NULL safety for C library interop (ADR-047)
|
|
4
|
+
*
|
|
5
|
+
* C-Next eliminates null bugs by design. This analyzer provides a controlled
|
|
6
|
+
* exception for C interop: NULL comparisons are allowed ONLY for whitelisted
|
|
7
|
+
* stream I/O functions (fgets, fputs, etc.), and the comparison is REQUIRED.
|
|
8
|
+
*
|
|
9
|
+
* Rules:
|
|
10
|
+
* - C stream functions returning nullable pointers must be NULL-checked
|
|
11
|
+
* - NULL keyword only valid in equality comparison context (= or !=)
|
|
12
|
+
* - Cannot store nullable return in C-Next variable
|
|
13
|
+
* - Forbidden functions (fopen, malloc) are not supported in v1
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { ParseTreeWalker } from "antlr4ng";
|
|
17
|
+
import { CNextListener } from "../parser/grammar/CNextListener";
|
|
18
|
+
import * as Parser from "../parser/grammar/CNextParser";
|
|
19
|
+
import { INullCheckError } from "./types/INullCheckError";
|
|
20
|
+
|
|
21
|
+
export { INullCheckError };
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Metadata for C library functions that can return NULL
|
|
25
|
+
*/
|
|
26
|
+
interface ICLibraryFunction {
|
|
27
|
+
header: string;
|
|
28
|
+
nullMeaning: string;
|
|
29
|
+
docsUrl: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Whitelisted stream I/O functions that can return NULL
|
|
34
|
+
* These are the only functions where NULL comparison is allowed
|
|
35
|
+
*/
|
|
36
|
+
const C_STREAM_FUNCTIONS: Map<string, ICLibraryFunction> = new Map([
|
|
37
|
+
[
|
|
38
|
+
"fgets",
|
|
39
|
+
{
|
|
40
|
+
header: "stdio.h",
|
|
41
|
+
nullMeaning: "EOF reached or read error occurred",
|
|
42
|
+
docsUrl: "https://en.cppreference.com/w/c/io/fgets",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
"fputs",
|
|
47
|
+
{
|
|
48
|
+
header: "stdio.h",
|
|
49
|
+
nullMeaning: "Write error occurred (returns EOF, not NULL)",
|
|
50
|
+
docsUrl: "https://en.cppreference.com/w/c/io/fputs",
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
"fgetc",
|
|
55
|
+
{
|
|
56
|
+
header: "stdio.h",
|
|
57
|
+
nullMeaning: "EOF reached or read error occurred (returns EOF)",
|
|
58
|
+
docsUrl: "https://en.cppreference.com/w/c/io/fgetc",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
[
|
|
62
|
+
"fputc",
|
|
63
|
+
{
|
|
64
|
+
header: "stdio.h",
|
|
65
|
+
nullMeaning: "Write error occurred (returns EOF)",
|
|
66
|
+
docsUrl: "https://en.cppreference.com/w/c/io/fputc",
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
"gets",
|
|
71
|
+
{
|
|
72
|
+
header: "stdio.h",
|
|
73
|
+
nullMeaning: "EOF reached or read error (DEPRECATED - use fgets)",
|
|
74
|
+
docsUrl: "https://en.cppreference.com/w/c/io/gets",
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Forbidden functions that return pointers but aren't supported in v1
|
|
81
|
+
* These require ADR-103 (stream handling) infrastructure
|
|
82
|
+
*/
|
|
83
|
+
const FORBIDDEN_NULLABLE_FUNCTIONS: Map<string, string> = new Map([
|
|
84
|
+
["fopen", "File handling will be available via ADR-103 (stream handling)"],
|
|
85
|
+
["fclose", "File handling will be available via ADR-103 (stream handling)"],
|
|
86
|
+
["malloc", "Dynamic allocation is forbidden by ADR-003"],
|
|
87
|
+
["calloc", "Dynamic allocation is forbidden by ADR-003"],
|
|
88
|
+
["realloc", "Dynamic allocation is forbidden by ADR-003"],
|
|
89
|
+
["free", "Dynamic allocation is forbidden by ADR-003"],
|
|
90
|
+
["getenv", "Environment access requires ADR-103 infrastructure"],
|
|
91
|
+
["strstr", "Returns pointer into string - use indexOf pattern instead"],
|
|
92
|
+
["strchr", "Returns pointer into string - use indexOf pattern instead"],
|
|
93
|
+
["strrchr", "Returns pointer into string - use indexOf pattern instead"],
|
|
94
|
+
["memchr", "Returns pointer into memory - not supported"],
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Listener that walks the parse tree and checks NULL usage
|
|
99
|
+
*/
|
|
100
|
+
class NullCheckListener extends CNextListener {
|
|
101
|
+
private analyzer: NullCheckAnalyzer;
|
|
102
|
+
|
|
103
|
+
/** Whether we're currently inside an equality comparison (= or !=) */
|
|
104
|
+
private inEqualityComparison = false;
|
|
105
|
+
|
|
106
|
+
/** Track the function name in the current equality comparison (if any) */
|
|
107
|
+
private equalityComparisonFuncName: string | null = null;
|
|
108
|
+
|
|
109
|
+
/** Track if the current equality comparison contains NULL */
|
|
110
|
+
private equalityComparisonHasNull = false;
|
|
111
|
+
|
|
112
|
+
constructor(analyzer: NullCheckAnalyzer) {
|
|
113
|
+
super();
|
|
114
|
+
this.analyzer = analyzer;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ========================================================================
|
|
118
|
+
// Equality Comparison Context
|
|
119
|
+
// ========================================================================
|
|
120
|
+
|
|
121
|
+
override enterEqualityExpression = (
|
|
122
|
+
ctx: Parser.EqualityExpressionContext,
|
|
123
|
+
): void => {
|
|
124
|
+
// Check if this is actually a comparison (has = or !=)
|
|
125
|
+
// The grammar has equalityExpression : relationalExpression (('=' | '!=') relationalExpression)*
|
|
126
|
+
const children = ctx.children ?? [];
|
|
127
|
+
|
|
128
|
+
// Look for comparison operators
|
|
129
|
+
for (const child of children) {
|
|
130
|
+
const text = child.getText();
|
|
131
|
+
if (text === "=" || text === "!=") {
|
|
132
|
+
this.inEqualityComparison = true;
|
|
133
|
+
this.equalityComparisonFuncName = null;
|
|
134
|
+
this.equalityComparisonHasNull = false;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
override exitEqualityExpression = (
|
|
141
|
+
ctx: Parser.EqualityExpressionContext,
|
|
142
|
+
): void => {
|
|
143
|
+
// Check if this was a comparison (has = or !=)
|
|
144
|
+
const children = ctx.children ?? [];
|
|
145
|
+
let isComparison = false;
|
|
146
|
+
for (const child of children) {
|
|
147
|
+
const text = child.getText();
|
|
148
|
+
if (text === "=" || text === "!=") {
|
|
149
|
+
isComparison = true;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (isComparison) {
|
|
155
|
+
// If we had a stream function in this comparison, it's OK
|
|
156
|
+
// (the function was used correctly in a NULL check)
|
|
157
|
+
this.inEqualityComparison = false;
|
|
158
|
+
this.equalityComparisonFuncName = null;
|
|
159
|
+
this.equalityComparisonHasNull = false;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// ========================================================================
|
|
164
|
+
// Function Calls
|
|
165
|
+
// ========================================================================
|
|
166
|
+
|
|
167
|
+
override enterPostfixExpression = (
|
|
168
|
+
ctx: Parser.PostfixExpressionContext,
|
|
169
|
+
): void => {
|
|
170
|
+
const primary = ctx.primaryExpression();
|
|
171
|
+
if (!primary?.IDENTIFIER()) return;
|
|
172
|
+
|
|
173
|
+
const funcName = primary.IDENTIFIER()!.getText();
|
|
174
|
+
const ops = ctx.postfixOp();
|
|
175
|
+
|
|
176
|
+
// Check if it's a function call (has argument list or parens)
|
|
177
|
+
const isCall = ops.some((op) => {
|
|
178
|
+
const text = op.getText();
|
|
179
|
+
return text.startsWith("(");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (!isCall) return;
|
|
183
|
+
|
|
184
|
+
const line = ctx.start?.line ?? 0;
|
|
185
|
+
const column = ctx.start?.column ?? 0;
|
|
186
|
+
|
|
187
|
+
// Check forbidden functions (always an error)
|
|
188
|
+
if (FORBIDDEN_NULLABLE_FUNCTIONS.has(funcName)) {
|
|
189
|
+
this.analyzer.reportForbiddenFunction(funcName, line, column);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Check stream functions
|
|
194
|
+
if (C_STREAM_FUNCTIONS.has(funcName)) {
|
|
195
|
+
if (this.inEqualityComparison) {
|
|
196
|
+
// Track that we found a stream function in this comparison
|
|
197
|
+
this.equalityComparisonFuncName = funcName;
|
|
198
|
+
} else {
|
|
199
|
+
// Stream function used outside of NULL comparison - error
|
|
200
|
+
this.analyzer.reportMissingNullCheck(funcName, line, column);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// ========================================================================
|
|
206
|
+
// NULL Literal
|
|
207
|
+
// ========================================================================
|
|
208
|
+
|
|
209
|
+
override enterLiteral = (ctx: Parser.LiteralContext): void => {
|
|
210
|
+
const text = ctx.getText();
|
|
211
|
+
|
|
212
|
+
// Check for uppercase NULL (C library NULL)
|
|
213
|
+
if (text === "NULL") {
|
|
214
|
+
const line = ctx.start?.line ?? 0;
|
|
215
|
+
const column = ctx.start?.column ?? 0;
|
|
216
|
+
|
|
217
|
+
if (this.inEqualityComparison) {
|
|
218
|
+
// NULL in comparison context - OK
|
|
219
|
+
this.equalityComparisonHasNull = true;
|
|
220
|
+
} else {
|
|
221
|
+
// NULL outside comparison - error
|
|
222
|
+
this.analyzer.reportInvalidNullUsage(line, column);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// ========================================================================
|
|
228
|
+
// Variable Assignment (check for storing stream function result)
|
|
229
|
+
// ========================================================================
|
|
230
|
+
|
|
231
|
+
override enterVariableDeclaration = (
|
|
232
|
+
ctx: Parser.VariableDeclarationContext,
|
|
233
|
+
): void => {
|
|
234
|
+
// Check if initialization contains a stream function call
|
|
235
|
+
// Grammar: type IDENTIFIER ('<-' expression)?
|
|
236
|
+
const expr = ctx.expression();
|
|
237
|
+
if (!expr) return;
|
|
238
|
+
|
|
239
|
+
const funcName = this.extractFunctionCallName(expr);
|
|
240
|
+
if (funcName && C_STREAM_FUNCTIONS.has(funcName)) {
|
|
241
|
+
const varName = ctx.IDENTIFIER().getText();
|
|
242
|
+
const line = ctx.start?.line ?? 0;
|
|
243
|
+
const column = ctx.start?.column ?? 0;
|
|
244
|
+
this.analyzer.reportInvalidStorage(varName, funcName, line, column);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
override enterAssignmentStatement = (
|
|
249
|
+
ctx: Parser.AssignmentStatementContext,
|
|
250
|
+
): void => {
|
|
251
|
+
// Check if RHS contains a stream function call
|
|
252
|
+
const expr = ctx.expression();
|
|
253
|
+
const funcName = this.extractFunctionCallName(expr);
|
|
254
|
+
|
|
255
|
+
if (funcName && C_STREAM_FUNCTIONS.has(funcName)) {
|
|
256
|
+
const target = ctx.assignmentTarget();
|
|
257
|
+
const varName = target.getText();
|
|
258
|
+
const line = ctx.start?.line ?? 0;
|
|
259
|
+
const column = ctx.start?.column ?? 0;
|
|
260
|
+
this.analyzer.reportInvalidStorage(varName, funcName, line, column);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Extract function call name from an expression (if it's a simple call)
|
|
266
|
+
*/
|
|
267
|
+
private extractFunctionCallName(
|
|
268
|
+
ctx: Parser.ExpressionContext,
|
|
269
|
+
): string | null {
|
|
270
|
+
// Simple heuristic: look for identifier followed by parens in text
|
|
271
|
+
// This could be improved with deeper AST analysis
|
|
272
|
+
const text = ctx.getText();
|
|
273
|
+
|
|
274
|
+
for (const funcName of C_STREAM_FUNCTIONS.keys()) {
|
|
275
|
+
if (text.includes(`${funcName}(`)) {
|
|
276
|
+
return funcName;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Analyzes C-Next AST for NULL safety violations
|
|
286
|
+
*/
|
|
287
|
+
export class NullCheckAnalyzer {
|
|
288
|
+
private errors: INullCheckError[] = [];
|
|
289
|
+
|
|
290
|
+
/** Included headers (for context) */
|
|
291
|
+
private includedHeaders: Set<string> = new Set();
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Analyze a parsed program for NULL safety errors
|
|
295
|
+
* @param tree The parsed program AST
|
|
296
|
+
* @returns Array of NULL check errors
|
|
297
|
+
*/
|
|
298
|
+
public analyze(tree: Parser.ProgramContext): INullCheckError[] {
|
|
299
|
+
this.errors = [];
|
|
300
|
+
this.includedHeaders = new Set();
|
|
301
|
+
|
|
302
|
+
// Collect included headers
|
|
303
|
+
this.collectIncludes(tree);
|
|
304
|
+
|
|
305
|
+
// Walk tree and check NULL usage
|
|
306
|
+
const listener = new NullCheckListener(this);
|
|
307
|
+
ParseTreeWalker.DEFAULT.walk(listener, tree);
|
|
308
|
+
|
|
309
|
+
return this.errors;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Collect included headers for context
|
|
314
|
+
*/
|
|
315
|
+
private collectIncludes(tree: Parser.ProgramContext): void {
|
|
316
|
+
for (const include of tree.includeDirective()) {
|
|
317
|
+
const text = include.getText();
|
|
318
|
+
const match = text.match(/#include\s*[<"]([^>"]+)[>"]/);
|
|
319
|
+
if (match) {
|
|
320
|
+
this.includedHeaders.add(match[1]);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Check if stdio.h is included (required for stream functions)
|
|
327
|
+
*/
|
|
328
|
+
public hasStdioIncluded(): boolean {
|
|
329
|
+
return this.includedHeaders.has("stdio.h");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Report error: stream function used without NULL check
|
|
334
|
+
*/
|
|
335
|
+
public reportMissingNullCheck(
|
|
336
|
+
funcName: string,
|
|
337
|
+
line: number,
|
|
338
|
+
column: number,
|
|
339
|
+
): void {
|
|
340
|
+
this.errors.push({
|
|
341
|
+
code: "E0901",
|
|
342
|
+
functionName: funcName,
|
|
343
|
+
line,
|
|
344
|
+
column,
|
|
345
|
+
message: `C library function '${funcName}' can return NULL - must check result`,
|
|
346
|
+
helpText: `Use: if (${funcName}(...) != NULL) { ... }`,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Report error: forbidden function not supported in v1
|
|
352
|
+
*/
|
|
353
|
+
public reportForbiddenFunction(
|
|
354
|
+
funcName: string,
|
|
355
|
+
line: number,
|
|
356
|
+
column: number,
|
|
357
|
+
): void {
|
|
358
|
+
const reason =
|
|
359
|
+
FORBIDDEN_NULLABLE_FUNCTIONS.get(funcName) ?? "Not supported in v1";
|
|
360
|
+
this.errors.push({
|
|
361
|
+
code: "E0902",
|
|
362
|
+
functionName: funcName,
|
|
363
|
+
line,
|
|
364
|
+
column,
|
|
365
|
+
message: `C library function '${funcName}' returns a pointer - not supported in C-Next v1`,
|
|
366
|
+
helpText: reason,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Report error: NULL used outside comparison context
|
|
372
|
+
*/
|
|
373
|
+
public reportInvalidNullUsage(line: number, column: number): void {
|
|
374
|
+
this.errors.push({
|
|
375
|
+
code: "E0903",
|
|
376
|
+
functionName: "NULL",
|
|
377
|
+
line,
|
|
378
|
+
column,
|
|
379
|
+
message: "NULL can only be used in comparison context",
|
|
380
|
+
helpText: "Use: if (func(...) != NULL) or if (func(...) = NULL)",
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Report error: trying to store stream function result in variable
|
|
386
|
+
*/
|
|
387
|
+
public reportInvalidStorage(
|
|
388
|
+
varName: string,
|
|
389
|
+
funcName: string,
|
|
390
|
+
line: number,
|
|
391
|
+
column: number,
|
|
392
|
+
): void {
|
|
393
|
+
this.errors.push({
|
|
394
|
+
code: "E0904",
|
|
395
|
+
functionName: funcName,
|
|
396
|
+
line,
|
|
397
|
+
column,
|
|
398
|
+
message: `Cannot store '${funcName}' return value in variable '${varName}'`,
|
|
399
|
+
helpText: `C library pointer returns cannot be stored. Use direct comparison: if (${funcName}(...) != NULL)`,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Get metadata for a C stream function (for VS Code tooltips)
|
|
405
|
+
*/
|
|
406
|
+
public static getStreamFunctionInfo(
|
|
407
|
+
funcName: string,
|
|
408
|
+
): ICLibraryFunction | null {
|
|
409
|
+
return C_STREAM_FUNCTIONS.get(funcName) ?? null;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Check if a function is a whitelisted stream function
|
|
414
|
+
*/
|
|
415
|
+
public static isStreamFunction(funcName: string): boolean {
|
|
416
|
+
return C_STREAM_FUNCTIONS.has(funcName);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Check if a function is forbidden (returns pointer, not supported)
|
|
421
|
+
*/
|
|
422
|
+
public static isForbiddenFunction(funcName: string): boolean {
|
|
423
|
+
return FORBIDDEN_NULLABLE_FUNCTIONS.has(funcName);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export default NullCheckAnalyzer;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error reported when division by zero is detected (ADR-051)
|
|
3
|
+
*
|
|
4
|
+
* Error codes:
|
|
5
|
+
* - E0800: Division by literal zero
|
|
6
|
+
* - E0801: Division by const that evaluates to zero
|
|
7
|
+
* - E0802: Modulo by literal zero
|
|
8
|
+
* - E0803: Modulo by const that evaluates to zero
|
|
9
|
+
*/
|
|
10
|
+
export interface IDivisionByZeroError {
|
|
11
|
+
/** Error code (E0800-E0803) */
|
|
12
|
+
code: string;
|
|
13
|
+
/** Operator used ('/' or '%') */
|
|
14
|
+
operator: string;
|
|
15
|
+
/** Line number where the error occurred */
|
|
16
|
+
line: number;
|
|
17
|
+
/** Column number where the error occurred */
|
|
18
|
+
column: number;
|
|
19
|
+
/** Human-readable error message */
|
|
20
|
+
message: string;
|
|
21
|
+
/** Optional help text with suggested fix */
|
|
22
|
+
helpText?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default IDivisionByZeroError;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error reported when a function is called before it's defined (ADR-030)
|
|
3
|
+
*/
|
|
4
|
+
export interface IFunctionCallError {
|
|
5
|
+
/** Error code (E0422) */
|
|
6
|
+
code: string;
|
|
7
|
+
/** Name of the function that was called */
|
|
8
|
+
functionName: string;
|
|
9
|
+
/** Line number where the call occurred */
|
|
10
|
+
line: number;
|
|
11
|
+
/** Column number where the call occurred */
|
|
12
|
+
column: number;
|
|
13
|
+
/** Human-readable error message */
|
|
14
|
+
message: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default IFunctionCallError;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialization analysis error types
|
|
3
|
+
* Used for Rust-style "use before initialization" detection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Information about where a variable was declared
|
|
8
|
+
*/
|
|
9
|
+
export interface IDeclarationInfo {
|
|
10
|
+
/** Variable name */
|
|
11
|
+
name: string;
|
|
12
|
+
/** Line where variable was declared */
|
|
13
|
+
line: number;
|
|
14
|
+
/** Column where variable was declared */
|
|
15
|
+
column: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Error for using a variable before initialization
|
|
20
|
+
*/
|
|
21
|
+
export interface IInitializationError {
|
|
22
|
+
/** Error code (E0381 matches Rust's error code) */
|
|
23
|
+
code: "E0381";
|
|
24
|
+
/** The variable or field that was used before initialization */
|
|
25
|
+
variable: string;
|
|
26
|
+
/** Line where the uninitialized use occurred */
|
|
27
|
+
line: number;
|
|
28
|
+
/** Column where the uninitialized use occurred */
|
|
29
|
+
column: number;
|
|
30
|
+
/** Declaration info for the variable */
|
|
31
|
+
declaration: IDeclarationInfo;
|
|
32
|
+
/** Whether this is a "may be uninitialized" (conditional) or "definitely uninitialized" */
|
|
33
|
+
mayBeUninitialized: boolean;
|
|
34
|
+
/** Human-readable message */
|
|
35
|
+
message: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Format an initialization error into a Rust-style error message
|
|
40
|
+
*/
|
|
41
|
+
export function formatInitializationError(error: IInitializationError): string {
|
|
42
|
+
const certainty = error.mayBeUninitialized ? "possibly " : "";
|
|
43
|
+
return `error[${error.code}]: use of ${certainty}uninitialized variable '${error.variable}'
|
|
44
|
+
--> line ${error.line}:${error.column}
|
|
45
|
+
|
|
|
46
|
+
${error.declaration.line} | ${error.declaration.name}
|
|
47
|
+
| - variable declared here
|
|
48
|
+
...
|
|
49
|
+
${error.line} | ${error.variable}
|
|
50
|
+
| ^ use of ${certainty}uninitialized '${error.variable}'
|
|
51
|
+
|
|
|
52
|
+
= help: consider initializing '${error.variable}'`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default IInitializationError;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error reported when NULL safety rules are violated (ADR-047)
|
|
3
|
+
*
|
|
4
|
+
* Error codes:
|
|
5
|
+
* - E0901: C library function can return NULL - must check result
|
|
6
|
+
* - E0902: C library function returns pointer - not supported in v1
|
|
7
|
+
* - E0903: NULL can only be used in comparison context
|
|
8
|
+
* - E0904: Cannot store C function pointer return in variable
|
|
9
|
+
*/
|
|
10
|
+
export interface INullCheckError {
|
|
11
|
+
/** Error code (E0901-E0904) */
|
|
12
|
+
code: string;
|
|
13
|
+
/** Name of the function or literal involved */
|
|
14
|
+
functionName: string;
|
|
15
|
+
/** Line number where the error occurred */
|
|
16
|
+
line: number;
|
|
17
|
+
/** Column number where the error occurred */
|
|
18
|
+
column: number;
|
|
19
|
+
/** Human-readable error message */
|
|
20
|
+
message: string;
|
|
21
|
+
/** Optional help text with suggested fix */
|
|
22
|
+
helpText?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default INullCheckError;
|