c-next 0.1.20 → 0.1.22
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/package.json +1 -1
- package/src/codegen/CodeGenerator.ts +9 -6
- package/src/codegen/generators/IOrchestrator.ts +3 -0
- package/src/codegen/generators/expressions/CallExprGenerator.ts +34 -2
- package/src/lib/types/ISymbolInfo.ts +5 -0
- package/src/lib/types/TLanguage.ts +6 -0
- package/src/pipeline/Pipeline.ts +78 -18
- package/src/symbols/CppSymbolCollector.ts +218 -4
package/package.json
CHANGED
|
@@ -3058,9 +3058,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3058
3058
|
}
|
|
3059
3059
|
|
|
3060
3060
|
/**
|
|
3061
|
-
* Check if a type name is a user-defined struct
|
|
3061
|
+
* Issue #322: Check if a type name is a user-defined struct
|
|
3062
|
+
* Part of IOrchestrator interface.
|
|
3062
3063
|
*/
|
|
3063
|
-
|
|
3064
|
+
isStructType(typeName: string): boolean {
|
|
3064
3065
|
return this.typeResolver!.isStructType(typeName);
|
|
3065
3066
|
}
|
|
3066
3067
|
|
|
@@ -7999,10 +8000,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
7999
8000
|
currentIdentifier = memberName; // Track for .length lookups
|
|
8000
8001
|
isGlobalAccess = true; // Mark that we're in a global access chain
|
|
8001
8002
|
// Issue #304: Check if this is a C++ scope symbol (namespace, class, enum)
|
|
8002
|
-
//
|
|
8003
|
-
//
|
|
8004
|
-
//
|
|
8005
|
-
|
|
8003
|
+
// These require :: syntax for member access. Variable symbols (including
|
|
8004
|
+
// object instances like Arduino's extern HardwareSerial Serial;) should
|
|
8005
|
+
// use . syntax, not :: syntax.
|
|
8006
|
+
// Issue #321: Removed || this.cppMode override - it was causing all symbols
|
|
8007
|
+
// to use :: in C++ mode, even object instances that need . syntax.
|
|
8008
|
+
if (this.isCppScopeSymbol(memberName)) {
|
|
8006
8009
|
isCppAccessChain = true;
|
|
8007
8010
|
}
|
|
8008
8011
|
// Check if this first identifier is a register
|
|
@@ -72,6 +72,9 @@ interface IOrchestrator {
|
|
|
72
72
|
/** Check if a function is defined in C-Next (vs C headers) */
|
|
73
73
|
isCNextFunction(name: string): boolean;
|
|
74
74
|
|
|
75
|
+
/** Issue #322: Check if a type is a struct type */
|
|
76
|
+
isStructType(typeName: string): boolean;
|
|
77
|
+
|
|
75
78
|
/** Get the raw type name without C conversion */
|
|
76
79
|
getTypeName(ctx: Parser.TypeContext): string;
|
|
77
80
|
|
|
@@ -147,8 +147,40 @@ const generateFunctionCall = (
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
if (!isCNextFunc) {
|
|
150
|
-
// C function: pass-by-value, just generate the expression
|
|
151
|
-
|
|
150
|
+
// C/C++ function: pass-by-value, just generate the expression
|
|
151
|
+
let argCode = orchestrator.generateExpression(e);
|
|
152
|
+
|
|
153
|
+
// Issue #322: Check if parameter expects a pointer and argument is a struct
|
|
154
|
+
// If so, automatically add & to pass the address
|
|
155
|
+
if (targetParam?.baseType?.endsWith("*")) {
|
|
156
|
+
// Try getExpressionType first
|
|
157
|
+
let argType = orchestrator.getExpressionType(e);
|
|
158
|
+
|
|
159
|
+
// Issue #322: If getExpressionType returns null (e.g., for this.member),
|
|
160
|
+
// fall back to looking up the generated code in the type registry
|
|
161
|
+
if (!argType && !argCode.startsWith("&")) {
|
|
162
|
+
// The argCode is already resolved (e.g., ConfigManager_config)
|
|
163
|
+
// Look it up directly in the type registry
|
|
164
|
+
const typeInfo = input.typeRegistry.get(argCode);
|
|
165
|
+
if (typeInfo) {
|
|
166
|
+
argType = typeInfo.baseType;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Add & if argument is a struct type (not already a pointer)
|
|
171
|
+
// Don't add & if the expression already has & prefix
|
|
172
|
+
// Don't add & if argument is already a pointer or array
|
|
173
|
+
if (
|
|
174
|
+
argType &&
|
|
175
|
+
!argType.endsWith("*") &&
|
|
176
|
+
!argCode.startsWith("&") &&
|
|
177
|
+
!targetParam.isArray &&
|
|
178
|
+
orchestrator.isStructType(argType)
|
|
179
|
+
) {
|
|
180
|
+
argCode = `&${argCode}`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
152
184
|
// Issue #304: Wrap with static_cast if C++ enum class → integer
|
|
153
185
|
return wrapWithCppEnumCast(
|
|
154
186
|
argCode,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import TSymbolKind from "./TSymbolKind";
|
|
2
|
+
import TLanguage from "./TLanguage";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Symbol information for IDE features (autocomplete, hover)
|
|
@@ -23,6 +24,10 @@ interface ISymbolInfo {
|
|
|
23
24
|
line: number;
|
|
24
25
|
/** Array size or bit width */
|
|
25
26
|
size?: number;
|
|
27
|
+
/** Source file path where this symbol is defined */
|
|
28
|
+
sourceFile?: string;
|
|
29
|
+
/** Language of the source file */
|
|
30
|
+
language?: TLanguage;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
export default ISymbolInfo;
|
package/src/pipeline/Pipeline.ts
CHANGED
|
@@ -62,6 +62,8 @@ class Pipeline {
|
|
|
62
62
|
private cppDetected: boolean;
|
|
63
63
|
/** Issue #220: Store SymbolCollector per file for header generation */
|
|
64
64
|
private symbolCollectors: Map<string, SymbolCollector> = new Map();
|
|
65
|
+
/** Issue #321: Track processed headers to avoid cycles during recursive include resolution */
|
|
66
|
+
private processedHeaders: Set<string> = new Set();
|
|
65
67
|
/** Issue #280: Store pass-by-value params per file for header generation */
|
|
66
68
|
private passByValueParamsCollectors: Map<
|
|
67
69
|
string,
|
|
@@ -320,8 +322,17 @@ class Pipeline {
|
|
|
320
322
|
|
|
321
323
|
/**
|
|
322
324
|
* Stage 2: Collect symbols from C/C++ headers
|
|
325
|
+
* Issue #321: Now recursively processes #include directives to handle
|
|
326
|
+
* nested headers (e.g., Arduino's HardwareSerial.h including Stream.h)
|
|
323
327
|
*/
|
|
324
328
|
private async collectHeaderSymbols(file: IDiscoveredFile): Promise<void> {
|
|
329
|
+
// Issue #321: Check if already processed to avoid cycles
|
|
330
|
+
const absolutePath = resolve(file.path);
|
|
331
|
+
if (this.processedHeaders.has(absolutePath)) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
this.processedHeaders.add(absolutePath);
|
|
335
|
+
|
|
325
336
|
// Check cache first
|
|
326
337
|
if (this.cacheManager?.isValid(file.path)) {
|
|
327
338
|
const cached = this.cacheManager.getSymbols(file.path);
|
|
@@ -348,35 +359,84 @@ class Pipeline {
|
|
|
348
359
|
}
|
|
349
360
|
}
|
|
350
361
|
|
|
351
|
-
|
|
362
|
+
// Issue #321: Read original content FIRST to extract includes before preprocessing
|
|
363
|
+
// The preprocessor expands/removes #include directives, so we need the original
|
|
364
|
+
const originalContent = readFileSync(file.path, "utf-8");
|
|
365
|
+
|
|
366
|
+
// Issue #328: Skip headers generated by C-Next Transpiler
|
|
367
|
+
// During incremental migration, generated .h files may be discovered via #include
|
|
368
|
+
// recursion from C++ files. These headers contain the same symbols as their .cnx
|
|
369
|
+
// source files, so including them would cause false symbol conflicts.
|
|
370
|
+
if (originalContent.includes("Generated by C-Next Transpiler")) {
|
|
371
|
+
if (this.config.debugMode) {
|
|
372
|
+
console.log(`[DEBUG] Skipping C-Next generated header: ${file.path}`);
|
|
373
|
+
}
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
352
376
|
|
|
353
|
-
//
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
});
|
|
377
|
+
// Issue #321: Recursively process #include directives in headers
|
|
378
|
+
// This ensures symbols from nested headers (like Arduino's extern HardwareSerial Serial)
|
|
379
|
+
// are properly collected even when included transitively
|
|
380
|
+
const includes = IncludeDiscovery.extractIncludes(originalContent);
|
|
381
|
+
const headerDir = dirname(absolutePath);
|
|
382
|
+
const searchPaths = [headerDir, ...this.config.includeDirs];
|
|
360
383
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
384
|
+
if (this.config.debugMode) {
|
|
385
|
+
console.log(`[DEBUG] Processing includes in ${file.path}:`);
|
|
386
|
+
console.log(`[DEBUG] Search paths: ${searchPaths.join(", ")}`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
for (const includePath of includes) {
|
|
390
|
+
const resolved = IncludeDiscovery.resolveInclude(
|
|
391
|
+
includePath,
|
|
392
|
+
searchPaths,
|
|
393
|
+
);
|
|
394
|
+
if (this.config.debugMode) {
|
|
395
|
+
console.log(
|
|
396
|
+
`[DEBUG] #include "${includePath}" → ${resolved || "NOT FOUND"}`,
|
|
364
397
|
);
|
|
365
|
-
content = readFileSync(file.path, "utf-8");
|
|
366
|
-
} else {
|
|
367
|
-
content = preprocessResult.content;
|
|
368
398
|
}
|
|
369
|
-
|
|
370
|
-
|
|
399
|
+
if (resolved) {
|
|
400
|
+
const includedFile = FileDiscovery.discoverFile(resolved);
|
|
401
|
+
if (
|
|
402
|
+
includedFile &&
|
|
403
|
+
(includedFile.type === EFileType.CHeader ||
|
|
404
|
+
includedFile.type === EFileType.CppHeader)
|
|
405
|
+
) {
|
|
406
|
+
if (this.config.debugMode) {
|
|
407
|
+
console.log(
|
|
408
|
+
`[DEBUG] → Recursively processing ${includedFile.path}`,
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
await this.collectHeaderSymbols(includedFile);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
371
414
|
}
|
|
372
415
|
|
|
416
|
+
// Issue #321: Parse with ORIGINAL content, not preprocessed content
|
|
417
|
+
// The preprocessor expands includes and can lose class definitions.
|
|
418
|
+
// We need the original content to properly detect C++ syntax and parse classes.
|
|
419
|
+
// Note: Preprocessing was previously done here but is no longer needed for symbol collection.
|
|
420
|
+
|
|
373
421
|
// Parse based on file type
|
|
374
422
|
if (file.type === EFileType.CHeader) {
|
|
375
|
-
this.
|
|
423
|
+
if (this.config.debugMode) {
|
|
424
|
+
console.log(`[DEBUG] Parsing C header: ${file.path}`);
|
|
425
|
+
}
|
|
426
|
+
this.parseCHeader(originalContent, file.path);
|
|
376
427
|
} else if (file.type === EFileType.CppHeader) {
|
|
377
428
|
// Issue #211: .hpp files are always C++
|
|
378
429
|
this.cppDetected = true;
|
|
379
|
-
this.
|
|
430
|
+
if (this.config.debugMode) {
|
|
431
|
+
console.log(`[DEBUG] Parsing C++ header: ${file.path}`);
|
|
432
|
+
}
|
|
433
|
+
this.parseCppHeader(originalContent, file.path);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Debug: Show symbols found
|
|
437
|
+
if (this.config.debugMode) {
|
|
438
|
+
const symbols = this.symbolTable.getSymbolsByFile(file.path);
|
|
439
|
+
console.log(`[DEBUG] Found ${symbols.length} symbols in ${file.path}`);
|
|
380
440
|
}
|
|
381
441
|
|
|
382
442
|
// After parsing, cache the results
|
|
@@ -102,6 +102,9 @@ class CppSymbolCollector {
|
|
|
102
102
|
? `${this.currentNamespace}::${name}`
|
|
103
103
|
: name;
|
|
104
104
|
|
|
105
|
+
// Issue #322: Extract function parameters
|
|
106
|
+
const params = this.extractFunctionParameters(declarator);
|
|
107
|
+
|
|
105
108
|
this.symbols.push({
|
|
106
109
|
name: fullName,
|
|
107
110
|
kind: ESymbolKind.Function,
|
|
@@ -111,6 +114,7 @@ class CppSymbolCollector {
|
|
|
111
114
|
sourceLanguage: ESourceLanguage.Cpp,
|
|
112
115
|
isExported: true,
|
|
113
116
|
parent: this.currentNamespace,
|
|
117
|
+
parameters: params.length > 0 ? params : undefined,
|
|
114
118
|
});
|
|
115
119
|
}
|
|
116
120
|
|
|
@@ -214,6 +218,11 @@ class CppSymbolCollector {
|
|
|
214
218
|
? `${this.currentNamespace}::${name}`
|
|
215
219
|
: name;
|
|
216
220
|
|
|
221
|
+
// Issue #322: Extract parameters for function declarations
|
|
222
|
+
const params = isFunction
|
|
223
|
+
? this.extractFunctionParameters(declarator)
|
|
224
|
+
: [];
|
|
225
|
+
|
|
217
226
|
this.symbols.push({
|
|
218
227
|
name: fullName,
|
|
219
228
|
kind: isFunction ? ESymbolKind.Function : ESymbolKind.Variable,
|
|
@@ -224,6 +233,7 @@ class CppSymbolCollector {
|
|
|
224
233
|
isExported: true,
|
|
225
234
|
isDeclaration: isFunction,
|
|
226
235
|
parent: this.currentNamespace,
|
|
236
|
+
parameters: params.length > 0 ? params : undefined,
|
|
227
237
|
});
|
|
228
238
|
}
|
|
229
239
|
}
|
|
@@ -280,10 +290,39 @@ class CppSymbolCollector {
|
|
|
280
290
|
* Collect a single member declaration
|
|
281
291
|
*/
|
|
282
292
|
private collectMemberDeclaration(className: string, memberDecl: any): void {
|
|
283
|
-
|
|
284
|
-
|
|
293
|
+
const line = memberDecl.start?.line ?? 0;
|
|
294
|
+
|
|
295
|
+
// Issue #322: Check for inline function definition within the class
|
|
296
|
+
const funcDef = memberDecl.functionDefinition?.();
|
|
297
|
+
if (funcDef) {
|
|
298
|
+
const declarator = funcDef.declarator?.();
|
|
299
|
+
if (declarator) {
|
|
300
|
+
const funcName = this.extractDeclaratorName(declarator);
|
|
301
|
+
if (funcName) {
|
|
302
|
+
const declSpecSeq = funcDef.declSpecifierSeq?.();
|
|
303
|
+
const returnType = declSpecSeq
|
|
304
|
+
? this.extractTypeFromDeclSpecSeq(declSpecSeq)
|
|
305
|
+
: "void";
|
|
306
|
+
const params = this.extractFunctionParameters(declarator);
|
|
307
|
+
const fullName = `${className}::${funcName}`;
|
|
308
|
+
|
|
309
|
+
this.symbols.push({
|
|
310
|
+
name: fullName,
|
|
311
|
+
kind: ESymbolKind.Function,
|
|
312
|
+
type: returnType,
|
|
313
|
+
sourceFile: this.sourceFile,
|
|
314
|
+
sourceLine: line,
|
|
315
|
+
sourceLanguage: ESourceLanguage.Cpp,
|
|
316
|
+
isExported: true,
|
|
317
|
+
parent: className,
|
|
318
|
+
parameters: params.length > 0 ? params : undefined,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
285
324
|
|
|
286
|
-
// Get member declaration list
|
|
325
|
+
// Get member declaration list (for data members and function declarations)
|
|
287
326
|
const declSpecSeq = memberDecl.declSpecifierSeq?.();
|
|
288
327
|
if (!declSpecSeq) return;
|
|
289
328
|
|
|
@@ -300,8 +339,23 @@ class CppSymbolCollector {
|
|
|
300
339
|
const fieldName = this.extractDeclaratorName(declarator);
|
|
301
340
|
if (!fieldName) continue;
|
|
302
341
|
|
|
303
|
-
//
|
|
342
|
+
// Issue #322: Collect member functions with their parameters
|
|
304
343
|
if (this.declaratorIsFunction(declarator)) {
|
|
344
|
+
const params = this.extractFunctionParameters(declarator);
|
|
345
|
+
const fullName = `${className}::${fieldName}`;
|
|
346
|
+
|
|
347
|
+
this.symbols.push({
|
|
348
|
+
name: fullName,
|
|
349
|
+
kind: ESymbolKind.Function,
|
|
350
|
+
type: fieldType,
|
|
351
|
+
sourceFile: this.sourceFile,
|
|
352
|
+
sourceLine: line,
|
|
353
|
+
sourceLanguage: ESourceLanguage.Cpp,
|
|
354
|
+
isExported: true,
|
|
355
|
+
isDeclaration: true,
|
|
356
|
+
parent: className,
|
|
357
|
+
parameters: params.length > 0 ? params : undefined,
|
|
358
|
+
});
|
|
305
359
|
continue;
|
|
306
360
|
}
|
|
307
361
|
|
|
@@ -508,6 +562,166 @@ class CppSymbolCollector {
|
|
|
508
562
|
return false;
|
|
509
563
|
}
|
|
510
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Issue #322: Extract function parameters from a declarator.
|
|
567
|
+
* Returns an array of parameter info objects with name, type, and pointer flag.
|
|
568
|
+
*/
|
|
569
|
+
private extractFunctionParameters(declarator: any): Array<{
|
|
570
|
+
name: string;
|
|
571
|
+
type: string;
|
|
572
|
+
isConst: boolean;
|
|
573
|
+
isArray: boolean;
|
|
574
|
+
}> {
|
|
575
|
+
const params: Array<{
|
|
576
|
+
name: string;
|
|
577
|
+
type: string;
|
|
578
|
+
isConst: boolean;
|
|
579
|
+
isArray: boolean;
|
|
580
|
+
}> = [];
|
|
581
|
+
|
|
582
|
+
// Find parametersAndQualifiers from the declarator
|
|
583
|
+
let paramsAndQuals: any = null;
|
|
584
|
+
const ptrDecl = declarator.pointerDeclarator?.();
|
|
585
|
+
if (ptrDecl) {
|
|
586
|
+
const noPtr = ptrDecl.noPointerDeclarator?.();
|
|
587
|
+
paramsAndQuals = noPtr?.parametersAndQualifiers?.();
|
|
588
|
+
}
|
|
589
|
+
if (!paramsAndQuals) {
|
|
590
|
+
const noPtr = declarator.noPointerDeclarator?.();
|
|
591
|
+
paramsAndQuals = noPtr?.parametersAndQualifiers?.();
|
|
592
|
+
}
|
|
593
|
+
if (!paramsAndQuals) {
|
|
594
|
+
return params;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Get parameterDeclarationClause
|
|
598
|
+
const paramClause = paramsAndQuals.parameterDeclarationClause?.();
|
|
599
|
+
if (!paramClause) {
|
|
600
|
+
return params;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Get parameterDeclarationList
|
|
604
|
+
const paramList = paramClause.parameterDeclarationList?.();
|
|
605
|
+
if (!paramList) {
|
|
606
|
+
return params;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Iterate over parameterDeclaration entries
|
|
610
|
+
for (const paramDecl of paramList.parameterDeclaration?.() ?? []) {
|
|
611
|
+
const paramInfo = this.extractParameterInfo(paramDecl);
|
|
612
|
+
if (paramInfo) {
|
|
613
|
+
params.push(paramInfo);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return params;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Issue #322: Extract type and name info from a single parameter declaration.
|
|
622
|
+
*/
|
|
623
|
+
private extractParameterInfo(paramDecl: any): {
|
|
624
|
+
name: string;
|
|
625
|
+
type: string;
|
|
626
|
+
isConst: boolean;
|
|
627
|
+
isArray: boolean;
|
|
628
|
+
} | null {
|
|
629
|
+
// Get the type from declSpecifierSeq
|
|
630
|
+
const declSpecSeq = paramDecl.declSpecifierSeq?.();
|
|
631
|
+
if (!declSpecSeq) {
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
let baseType = this.extractTypeFromDeclSpecSeq(declSpecSeq);
|
|
636
|
+
let isConst = false;
|
|
637
|
+
let isPointer = false;
|
|
638
|
+
|
|
639
|
+
// Check for const qualifier
|
|
640
|
+
const declText = declSpecSeq.getText();
|
|
641
|
+
if (declText.includes("const")) {
|
|
642
|
+
isConst = true;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Check for pointer in declarator or abstractDeclarator
|
|
646
|
+
const declarator = paramDecl.declarator?.();
|
|
647
|
+
const abstractDecl = paramDecl.abstractDeclarator?.();
|
|
648
|
+
|
|
649
|
+
if (declarator) {
|
|
650
|
+
// Check if declarator has pointer operator
|
|
651
|
+
if (this.declaratorHasPointer(declarator)) {
|
|
652
|
+
isPointer = true;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
if (abstractDecl) {
|
|
656
|
+
// Abstract declarator (no name) - check for pointer
|
|
657
|
+
if (this.abstractDeclaratorHasPointer(abstractDecl)) {
|
|
658
|
+
isPointer = true;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// If pointer, append * to the type
|
|
663
|
+
if (isPointer) {
|
|
664
|
+
baseType = baseType + "*";
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Get parameter name (may be empty for abstract declarators)
|
|
668
|
+
let paramName = "";
|
|
669
|
+
if (declarator) {
|
|
670
|
+
const name = this.extractDeclaratorName(declarator);
|
|
671
|
+
if (name) {
|
|
672
|
+
paramName = name;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
return {
|
|
677
|
+
name: paramName,
|
|
678
|
+
type: baseType,
|
|
679
|
+
isConst,
|
|
680
|
+
isArray: false, // Could be enhanced to detect arrays
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Issue #322: Check if a declarator contains a pointer operator.
|
|
686
|
+
*/
|
|
687
|
+
private declaratorHasPointer(declarator: any): boolean {
|
|
688
|
+
const ptrDecl = declarator.pointerDeclarator?.();
|
|
689
|
+
if (ptrDecl) {
|
|
690
|
+
// Check for pointerOperator children
|
|
691
|
+
const ptrOps = ptrDecl.pointerOperator?.();
|
|
692
|
+
if (ptrOps && ptrOps.length > 0) {
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
// Also check getText for *
|
|
696
|
+
if (ptrDecl.getText().includes("*")) {
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Issue #322: Check if an abstract declarator (pointer without name) contains a pointer.
|
|
705
|
+
*/
|
|
706
|
+
private abstractDeclaratorHasPointer(abstractDecl: any): boolean {
|
|
707
|
+
// Check for pointerAbstractDeclarator
|
|
708
|
+
const ptrAbstract = abstractDecl.pointerAbstractDeclarator?.();
|
|
709
|
+
if (ptrAbstract) {
|
|
710
|
+
const ptrOps = ptrAbstract.pointerOperator?.();
|
|
711
|
+
if (ptrOps && ptrOps.length > 0) {
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
if (ptrAbstract.getText().includes("*")) {
|
|
715
|
+
return true;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
// Simple check for * in the text
|
|
719
|
+
if (abstractDecl.getText().includes("*")) {
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
|
|
511
725
|
private extractTypeFromDeclSpecSeq(declSpecSeq: any): string {
|
|
512
726
|
const parts: string[] = [];
|
|
513
727
|
|