linguclaw 0.4.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/LICENSE +21 -0
- package/README.md +161 -0
- package/dist/agent-system.d.ts +196 -0
- package/dist/agent-system.d.ts.map +1 -0
- package/dist/agent-system.js +738 -0
- package/dist/agent-system.js.map +1 -0
- package/dist/alphabeta.d.ts +54 -0
- package/dist/alphabeta.d.ts.map +1 -0
- package/dist/alphabeta.js +193 -0
- package/dist/alphabeta.js.map +1 -0
- package/dist/browser.d.ts +62 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +224 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +565 -0
- package/dist/cli.js.map +1 -0
- package/dist/code-parser.d.ts +39 -0
- package/dist/code-parser.d.ts.map +1 -0
- package/dist/code-parser.js +385 -0
- package/dist/code-parser.js.map +1 -0
- package/dist/config.d.ts +66 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +232 -0
- package/dist/config.js.map +1 -0
- package/dist/core/engine.d.ts +359 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +127 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/daemon.d.ts +29 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +212 -0
- package/dist/daemon.js.map +1 -0
- package/dist/email-receiver.d.ts +63 -0
- package/dist/email-receiver.d.ts.map +1 -0
- package/dist/email-receiver.js +553 -0
- package/dist/email-receiver.js.map +1 -0
- package/dist/git-integration.d.ts +180 -0
- package/dist/git-integration.d.ts.map +1 -0
- package/dist/git-integration.js +850 -0
- package/dist/git-integration.js.map +1 -0
- package/dist/inbox.d.ts +84 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +198 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/cpp.d.ts +51 -0
- package/dist/languages/cpp.d.ts.map +1 -0
- package/dist/languages/cpp.js +930 -0
- package/dist/languages/cpp.js.map +1 -0
- package/dist/languages/csharp.d.ts +79 -0
- package/dist/languages/csharp.d.ts.map +1 -0
- package/dist/languages/csharp.js +1776 -0
- package/dist/languages/csharp.js.map +1 -0
- package/dist/languages/go.d.ts +50 -0
- package/dist/languages/go.d.ts.map +1 -0
- package/dist/languages/go.js +882 -0
- package/dist/languages/go.js.map +1 -0
- package/dist/languages/java.d.ts +47 -0
- package/dist/languages/java.d.ts.map +1 -0
- package/dist/languages/java.js +649 -0
- package/dist/languages/java.js.map +1 -0
- package/dist/languages/python.d.ts +47 -0
- package/dist/languages/python.d.ts.map +1 -0
- package/dist/languages/python.js +655 -0
- package/dist/languages/python.js.map +1 -0
- package/dist/languages/rust.d.ts +61 -0
- package/dist/languages/rust.d.ts.map +1 -0
- package/dist/languages/rust.js +1064 -0
- package/dist/languages/rust.js.map +1 -0
- package/dist/logger.d.ts +20 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +133 -0
- package/dist/logger.js.map +1 -0
- package/dist/longterm-memory.d.ts +47 -0
- package/dist/longterm-memory.d.ts.map +1 -0
- package/dist/longterm-memory.js +300 -0
- package/dist/longterm-memory.js.map +1 -0
- package/dist/memory.d.ts +42 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +274 -0
- package/dist/memory.js.map +1 -0
- package/dist/messaging.d.ts +103 -0
- package/dist/messaging.d.ts.map +1 -0
- package/dist/messaging.js +645 -0
- package/dist/messaging.js.map +1 -0
- package/dist/multi-provider.d.ts +69 -0
- package/dist/multi-provider.d.ts.map +1 -0
- package/dist/multi-provider.js +484 -0
- package/dist/multi-provider.js.map +1 -0
- package/dist/orchestrator.d.ts +65 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +441 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/plugins.d.ts +52 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +215 -0
- package/dist/plugins.js.map +1 -0
- package/dist/prism-orchestrator.d.ts +26 -0
- package/dist/prism-orchestrator.d.ts.map +1 -0
- package/dist/prism-orchestrator.js +191 -0
- package/dist/prism-orchestrator.js.map +1 -0
- package/dist/prism.d.ts +46 -0
- package/dist/prism.d.ts.map +1 -0
- package/dist/prism.js +188 -0
- package/dist/prism.js.map +1 -0
- package/dist/privacy.d.ts +23 -0
- package/dist/privacy.d.ts.map +1 -0
- package/dist/privacy.js +220 -0
- package/dist/privacy.js.map +1 -0
- package/dist/proactive.d.ts +30 -0
- package/dist/proactive.d.ts.map +1 -0
- package/dist/proactive.js +260 -0
- package/dist/proactive.js.map +1 -0
- package/dist/refactoring-engine.d.ts +100 -0
- package/dist/refactoring-engine.d.ts.map +1 -0
- package/dist/refactoring-engine.js +717 -0
- package/dist/refactoring-engine.js.map +1 -0
- package/dist/resilience.d.ts +43 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +200 -0
- package/dist/resilience.js.map +1 -0
- package/dist/safety.d.ts +40 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +133 -0
- package/dist/safety.js.map +1 -0
- package/dist/sandbox.d.ts +33 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +173 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/scheduler.d.ts +72 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +374 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/semantic-memory.d.ts +70 -0
- package/dist/semantic-memory.d.ts.map +1 -0
- package/dist/semantic-memory.js +430 -0
- package/dist/semantic-memory.js.map +1 -0
- package/dist/skills.d.ts +97 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +575 -0
- package/dist/skills.js.map +1 -0
- package/dist/static/dashboard.html +853 -0
- package/dist/static/hub.html +772 -0
- package/dist/static/index.html +818 -0
- package/dist/static/logo.svg +24 -0
- package/dist/static/workflow-editor.html +913 -0
- package/dist/tools.d.ts +67 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +303 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +295 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +90 -0
- package/dist/types.js.map +1 -0
- package/dist/web.d.ts +76 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +2139 -0
- package/dist/web.js.map +1 -0
- package/dist/workflow-engine.d.ts +114 -0
- package/dist/workflow-engine.d.ts.map +1 -0
- package/dist/workflow-engine.js +855 -0
- package/dist/workflow-engine.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* C++ Language Support for LinguClaw
|
|
4
|
+
* Advanced C++ parser with template and memory management analysis
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CppLanguageSupport = exports.CppAnalyzer = exports.CppParser = void 0;
|
|
8
|
+
class CppParser {
|
|
9
|
+
source = '';
|
|
10
|
+
lines = [];
|
|
11
|
+
parse(source, filePath) {
|
|
12
|
+
this.source = source;
|
|
13
|
+
this.lines = source.split('\n');
|
|
14
|
+
try {
|
|
15
|
+
const ast = this.parseCpp(source, filePath);
|
|
16
|
+
return {
|
|
17
|
+
ast,
|
|
18
|
+
errors: this.findSyntaxErrors(),
|
|
19
|
+
warnings: this.findPreprocessorIssues(),
|
|
20
|
+
tokens: [],
|
|
21
|
+
comments: this.extractComments(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return this.fallbackParse(filePath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
parseCpp(source, filePath) {
|
|
29
|
+
const root = {
|
|
30
|
+
type: 'TranslationUnit',
|
|
31
|
+
id: `${filePath}:0:0`,
|
|
32
|
+
location: this.createLocation(filePath, 0, 0, this.lines.length, 0),
|
|
33
|
+
children: [],
|
|
34
|
+
metadata: { language: 'cpp' },
|
|
35
|
+
};
|
|
36
|
+
// Parse preprocessor directives
|
|
37
|
+
const preprocessor = this.parsePreprocessor(source, filePath);
|
|
38
|
+
root.children.push(...preprocessor);
|
|
39
|
+
// Parse declarations
|
|
40
|
+
const declarations = this.parseDeclarations(source, filePath);
|
|
41
|
+
root.children.push(...declarations);
|
|
42
|
+
return root;
|
|
43
|
+
}
|
|
44
|
+
parsePreprocessor(source, filePath) {
|
|
45
|
+
const directives = [];
|
|
46
|
+
const directiveRegex = /^#(\w+)(?:\s+(.+))?$/gm;
|
|
47
|
+
let match;
|
|
48
|
+
while ((match = directiveRegex.exec(source)) !== null) {
|
|
49
|
+
const directive = match[1];
|
|
50
|
+
const value = match[2]?.trim();
|
|
51
|
+
const lineNum = source.substring(0, match.index).split('\n').length;
|
|
52
|
+
const node = {
|
|
53
|
+
type: 'PreprocessorDirective',
|
|
54
|
+
id: `${filePath}:${lineNum}:0`,
|
|
55
|
+
location: this.createLocation(filePath, lineNum, 0, lineNum, match[0].length),
|
|
56
|
+
children: [],
|
|
57
|
+
metadata: {
|
|
58
|
+
directive,
|
|
59
|
+
value,
|
|
60
|
+
isInclude: directive === 'include',
|
|
61
|
+
isDefine: directive === 'define',
|
|
62
|
+
isIfdef: directive === 'ifdef' || directive === 'ifndef',
|
|
63
|
+
isPragma: directive === 'pragma',
|
|
64
|
+
includePath: directive === 'include' ? this.extractIncludePath(value || '') : undefined,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
directives.push(node);
|
|
68
|
+
}
|
|
69
|
+
return directives;
|
|
70
|
+
}
|
|
71
|
+
extractIncludePath(value) {
|
|
72
|
+
const match = value.match(/[<"](.+)[>"]/);
|
|
73
|
+
return match ? match[1] : value;
|
|
74
|
+
}
|
|
75
|
+
parseDeclarations(source, filePath) {
|
|
76
|
+
const declarations = [];
|
|
77
|
+
const lines = source.split('\n');
|
|
78
|
+
let i = 0;
|
|
79
|
+
while (i < lines.length) {
|
|
80
|
+
const line = lines[i].trim();
|
|
81
|
+
// Skip empty lines and comments
|
|
82
|
+
if (!line || line.startsWith('//') || line.startsWith('#')) {
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// Namespace
|
|
87
|
+
if (line.startsWith('namespace ')) {
|
|
88
|
+
const nsDecl = this.parseNamespace(lines, i, filePath);
|
|
89
|
+
if (nsDecl) {
|
|
90
|
+
declarations.push(nsDecl.node);
|
|
91
|
+
i = nsDecl.endIndex + 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Class/Struct/Union
|
|
96
|
+
if (this.isClassDeclaration(line)) {
|
|
97
|
+
const classDecl = this.parseClass(lines, i, filePath);
|
|
98
|
+
if (classDecl) {
|
|
99
|
+
declarations.push(classDecl.node);
|
|
100
|
+
i = classDecl.endIndex + 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Function
|
|
105
|
+
if (this.isFunctionDeclaration(line)) {
|
|
106
|
+
const funcDecl = this.parseFunction(lines, i, filePath);
|
|
107
|
+
if (funcDecl) {
|
|
108
|
+
declarations.push(funcDecl.node);
|
|
109
|
+
i = funcDecl.endIndex + 1;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Variable declaration
|
|
114
|
+
if (this.isVariableDeclaration(line)) {
|
|
115
|
+
const varDecl = this.parseVariableDeclaration(lines, i, filePath);
|
|
116
|
+
if (varDecl) {
|
|
117
|
+
declarations.push(varDecl.node);
|
|
118
|
+
i = varDecl.endIndex + 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Template
|
|
123
|
+
if (line.startsWith('template<')) {
|
|
124
|
+
const templateDecl = this.parseTemplate(lines, i, filePath);
|
|
125
|
+
if (templateDecl) {
|
|
126
|
+
declarations.push(templateDecl.node);
|
|
127
|
+
i = templateDecl.endIndex + 1;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Enum
|
|
132
|
+
if (line.startsWith('enum ')) {
|
|
133
|
+
const enumDecl = this.parseEnum(lines, i, filePath);
|
|
134
|
+
if (enumDecl) {
|
|
135
|
+
declarations.push(enumDecl.node);
|
|
136
|
+
i = enumDecl.endIndex + 1;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Using/Type alias
|
|
141
|
+
if (line.startsWith('using ') || line.startsWith('typedef ')) {
|
|
142
|
+
const aliasDecl = this.parseTypeAlias(lines, i, filePath);
|
|
143
|
+
if (aliasDecl) {
|
|
144
|
+
declarations.push(aliasDecl.node);
|
|
145
|
+
i = aliasDecl.endIndex + 1;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Extern
|
|
150
|
+
if (line.startsWith('extern ')) {
|
|
151
|
+
const externDecl = this.parseExtern(lines, i, filePath);
|
|
152
|
+
if (externDecl) {
|
|
153
|
+
declarations.push(externDecl.node);
|
|
154
|
+
i = externDecl.endIndex + 1;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
i++;
|
|
159
|
+
}
|
|
160
|
+
return declarations;
|
|
161
|
+
}
|
|
162
|
+
isClassDeclaration(line) {
|
|
163
|
+
return /^(?:class|struct|union)(?:\s+\w+|$)/.test(line) ||
|
|
164
|
+
/^(?:template\s*<[^>]+>\s+)?(?:class|struct)/.test(line);
|
|
165
|
+
}
|
|
166
|
+
isFunctionDeclaration(line) {
|
|
167
|
+
// Matches function signatures but not variable declarations with initializers
|
|
168
|
+
return /(?:^|::)(\w+)\s*\([^)]*\)\s*(?:const|volatile|&|&&|\{|->|noexcept)?\s*$/.test(line) ||
|
|
169
|
+
/^(?:inline|virtual|static|explicit|constexpr|consteval)\s+/.test(line);
|
|
170
|
+
}
|
|
171
|
+
isVariableDeclaration(line) {
|
|
172
|
+
return /^(?:const|constexpr|static|extern|volatile|mutable|thread_local)?\s*[\w:<>,\s*&*]+\s+\w+\s*(?:=|;)/.test(line) ||
|
|
173
|
+
/^[\w:<>,\s*&*]+\s+\w+\s*\{[^}]*\}/.test(line);
|
|
174
|
+
}
|
|
175
|
+
parseNamespace(lines, startIdx, filePath) {
|
|
176
|
+
const line = lines[startIdx].trim();
|
|
177
|
+
const match = line.match(/namespace\s+(\w+)?/);
|
|
178
|
+
if (!match)
|
|
179
|
+
return null;
|
|
180
|
+
const name = match[1] || 'anonymous';
|
|
181
|
+
let endIdx = startIdx;
|
|
182
|
+
let braceCount = 0;
|
|
183
|
+
for (let i = startIdx; i < lines.length; i++) {
|
|
184
|
+
for (const char of lines[i]) {
|
|
185
|
+
if (char === '{')
|
|
186
|
+
braceCount++;
|
|
187
|
+
if (char === '}')
|
|
188
|
+
braceCount--;
|
|
189
|
+
}
|
|
190
|
+
if (braceCount === 0 && i > startIdx) {
|
|
191
|
+
endIdx = i;
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const body = lines.slice(startIdx + 1, endIdx);
|
|
196
|
+
const nested = this.parseDeclarations(body.join('\n'), filePath);
|
|
197
|
+
const node = {
|
|
198
|
+
type: 'NamespaceDeclaration',
|
|
199
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
200
|
+
location: this.createLocation(filePath, startIdx + 1, 0, endIdx + 1, lines[endIdx]?.length || 0),
|
|
201
|
+
children: nested,
|
|
202
|
+
metadata: {
|
|
203
|
+
name,
|
|
204
|
+
isAnonymous: !match[1],
|
|
205
|
+
isInline: line.includes('inline'),
|
|
206
|
+
isNested: false,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
return { node, endIndex: endIdx };
|
|
210
|
+
}
|
|
211
|
+
parseClass(lines, startIdx, filePath) {
|
|
212
|
+
const line = lines[startIdx].trim();
|
|
213
|
+
// Handle template prefix
|
|
214
|
+
let templatePrefix = '';
|
|
215
|
+
let actualLine = line;
|
|
216
|
+
if (line.startsWith('template')) {
|
|
217
|
+
// Find the actual class line
|
|
218
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
219
|
+
if (lines[i].includes('class') || lines[i].includes('struct')) {
|
|
220
|
+
actualLine = lines[i].trim();
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const match = actualLine.match(/(class|struct|union)\s+(?:\w+\s+)?(\w+)(?:<([^>]+)>)?(?:\s*:\s*([^{]+))?/);
|
|
226
|
+
if (!match)
|
|
227
|
+
return null;
|
|
228
|
+
const kind = match[1];
|
|
229
|
+
const name = match[2];
|
|
230
|
+
const templateParams = match[3];
|
|
231
|
+
const inheritance = match[4];
|
|
232
|
+
let endIdx = startIdx;
|
|
233
|
+
let braceCount = 0;
|
|
234
|
+
for (let i = startIdx; i < lines.length; i++) {
|
|
235
|
+
for (const char of lines[i]) {
|
|
236
|
+
if (char === '{')
|
|
237
|
+
braceCount++;
|
|
238
|
+
if (char === '}')
|
|
239
|
+
braceCount--;
|
|
240
|
+
}
|
|
241
|
+
if (braceCount === 0 && i > startIdx) {
|
|
242
|
+
endIdx = i;
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const body = lines.slice(startIdx, endIdx + 1).join('\n');
|
|
247
|
+
const members = this.parseClassMembers(body, filePath);
|
|
248
|
+
const node = {
|
|
249
|
+
type: kind === 'class' ? 'ClassDeclaration' : kind === 'struct' ? 'StructDeclaration' : 'UnionDeclaration',
|
|
250
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
251
|
+
location: this.createLocation(filePath, startIdx + 1, 0, endIdx + 1, lines[endIdx]?.length || 0),
|
|
252
|
+
children: members,
|
|
253
|
+
metadata: {
|
|
254
|
+
name,
|
|
255
|
+
templateParameters: templateParams ? templateParams.split(',').map(p => p.trim()) : [],
|
|
256
|
+
isTemplate: !!templateParams,
|
|
257
|
+
isStruct: kind === 'struct',
|
|
258
|
+
isUnion: kind === 'union',
|
|
259
|
+
inheritance: this.parseInheritance(inheritance),
|
|
260
|
+
accessSpecifiers: this.extractAccessSpecifiers(body),
|
|
261
|
+
hasVirtualDestructor: body.includes('~' + name) && body.includes('virtual'),
|
|
262
|
+
isAbstract: body.includes('= 0') || body.includes('=0'),
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
return { node, endIndex: endIdx };
|
|
266
|
+
}
|
|
267
|
+
parseClassMembers(body, filePath) {
|
|
268
|
+
const members = [];
|
|
269
|
+
const lines = body.split('\n');
|
|
270
|
+
// Simple member extraction - this could be more sophisticated
|
|
271
|
+
for (let i = 0; i < lines.length; i++) {
|
|
272
|
+
const line = lines[i].trim();
|
|
273
|
+
// Access specifiers
|
|
274
|
+
if (line.match(/^(public|private|protected):/)) {
|
|
275
|
+
members.push({
|
|
276
|
+
type: 'AccessSpecifier',
|
|
277
|
+
id: `${filePath}:${i + 1}:0`,
|
|
278
|
+
location: this.createLocation(filePath, i + 1, 0, i + 1, line.length),
|
|
279
|
+
children: [],
|
|
280
|
+
metadata: { access: line.replace(':', '') },
|
|
281
|
+
});
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// Member variables
|
|
285
|
+
const varMatch = line.match(/([\w:<>,\s&*]+)\s+(\w+)\s*(?:=\s*([^;]+))?;/);
|
|
286
|
+
if (varMatch && !line.includes('(')) {
|
|
287
|
+
members.push({
|
|
288
|
+
type: 'FieldDeclaration',
|
|
289
|
+
id: `${filePath}:${i + 1}:0`,
|
|
290
|
+
location: this.createLocation(filePath, i + 1, 0, i + 1, line.length),
|
|
291
|
+
children: [],
|
|
292
|
+
metadata: {
|
|
293
|
+
name: varMatch[2],
|
|
294
|
+
type: varMatch[1].trim(),
|
|
295
|
+
initializer: varMatch[3]?.trim(),
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
// Member functions
|
|
300
|
+
const funcMatch = line.match(/(?:virtual\s+)?(?:static\s+)?(?:const\s+)?([\w:<>,\s&*]+)\s+(\w+)\s*\(([^)]*)\)\s*(?:const|override|final|noexcept)?\s*(?:=\s*0)?/);
|
|
301
|
+
if (funcMatch && line.includes('(')) {
|
|
302
|
+
members.push({
|
|
303
|
+
type: 'MethodDeclaration',
|
|
304
|
+
id: `${filePath}:${i + 1}:0`,
|
|
305
|
+
location: this.createLocation(filePath, i + 1, 0, i + 1, line.length),
|
|
306
|
+
children: [],
|
|
307
|
+
metadata: {
|
|
308
|
+
name: funcMatch[2],
|
|
309
|
+
returnType: funcMatch[1].trim(),
|
|
310
|
+
parameters: funcMatch[3],
|
|
311
|
+
isVirtual: line.includes('virtual'),
|
|
312
|
+
isPureVirtual: line.includes('= 0') || line.includes('=0'),
|
|
313
|
+
isOverride: line.includes('override'),
|
|
314
|
+
isFinal: line.includes('final'),
|
|
315
|
+
isConst: line.includes('const'),
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
// Constructors
|
|
320
|
+
const ctorMatch = line.match(/(\w+)\s*\(([^)]*)\)(?:\s*:\s*([^{]+))?/);
|
|
321
|
+
if (ctorMatch && !line.match(/^[\w:]+\s+\w+\s*\(/)) {
|
|
322
|
+
// Heuristic: if name matches class and not a return type pattern
|
|
323
|
+
members.push({
|
|
324
|
+
type: 'ConstructorDeclaration',
|
|
325
|
+
id: `${filePath}:${i + 1}:0`,
|
|
326
|
+
location: this.createLocation(filePath, i + 1, 0, i + 1, line.length),
|
|
327
|
+
children: [],
|
|
328
|
+
metadata: {
|
|
329
|
+
parameters: ctorMatch[2],
|
|
330
|
+
initializerList: ctorMatch[3],
|
|
331
|
+
isExplicit: line.includes('explicit'),
|
|
332
|
+
isDefault: line.includes('= default'),
|
|
333
|
+
isDeleted: line.includes('= delete'),
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return members;
|
|
339
|
+
}
|
|
340
|
+
parseFunction(lines, startIdx, filePath) {
|
|
341
|
+
const line = lines[startIdx].trim();
|
|
342
|
+
// Handle template functions
|
|
343
|
+
let templateParams;
|
|
344
|
+
let actualStart = startIdx;
|
|
345
|
+
if (line.startsWith('template<')) {
|
|
346
|
+
templateParams = line.match(/template<(.+)>/)?.[1];
|
|
347
|
+
actualStart = startIdx + 1;
|
|
348
|
+
}
|
|
349
|
+
const actualLine = lines[actualStart]?.trim() || line;
|
|
350
|
+
// Match function signature
|
|
351
|
+
const match = actualLine.match(/(?:template<[^>]+>\s*)?(?:(\w+)::)?(?:~)?(\w+)\s*\(([^)]*)\)(?:\s*->\s*([^{]+))?/);
|
|
352
|
+
if (!match && !actualLine.includes('('))
|
|
353
|
+
return null;
|
|
354
|
+
// Find function body
|
|
355
|
+
let endIdx = actualStart;
|
|
356
|
+
let braceCount = 0;
|
|
357
|
+
let hasBody = false;
|
|
358
|
+
for (let i = actualStart; i < lines.length; i++) {
|
|
359
|
+
const currentLine = lines[i];
|
|
360
|
+
// Check for function try block
|
|
361
|
+
if (currentLine.includes('try') && i === actualStart) {
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
for (const char of currentLine) {
|
|
365
|
+
if (char === '{') {
|
|
366
|
+
braceCount++;
|
|
367
|
+
hasBody = true;
|
|
368
|
+
}
|
|
369
|
+
if (char === '}')
|
|
370
|
+
braceCount--;
|
|
371
|
+
}
|
|
372
|
+
if (hasBody && braceCount === 0) {
|
|
373
|
+
endIdx = i;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
// Function declaration without body
|
|
377
|
+
if (currentLine.includes(';') && !hasBody && i > actualStart) {
|
|
378
|
+
endIdx = i;
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const isDestructor = actualLine.includes('~');
|
|
383
|
+
const isOperator = actualLine.match(/operator\s*\W+/);
|
|
384
|
+
const node = {
|
|
385
|
+
type: 'FunctionDeclaration',
|
|
386
|
+
id: `${filePath}:${actualStart + 1}:0`,
|
|
387
|
+
location: this.createLocation(filePath, actualStart + 1, 0, endIdx + 1, lines[endIdx]?.length || 0),
|
|
388
|
+
children: [],
|
|
389
|
+
metadata: {
|
|
390
|
+
name: isDestructor ? 'destructor' : isOperator ? 'operator' : match?.[2] || 'unknown',
|
|
391
|
+
isTemplate: !!templateParams,
|
|
392
|
+
templateParameters: templateParams ? templateParams.split(',').map(p => p.trim()) : [],
|
|
393
|
+
isDestructor,
|
|
394
|
+
isOperator: !!isOperator,
|
|
395
|
+
isConstexpr: actualLine.includes('constexpr'),
|
|
396
|
+
isConsteval: actualLine.includes('consteval'),
|
|
397
|
+
isNoexcept: actualLine.includes('noexcept'),
|
|
398
|
+
isInline: actualLine.includes('inline'),
|
|
399
|
+
isStatic: actualLine.includes('static'),
|
|
400
|
+
isExtern: actualLine.includes('extern'),
|
|
401
|
+
hasBody,
|
|
402
|
+
trailingReturn: match?.[4]?.trim(),
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
return { node, endIndex: endIdx };
|
|
406
|
+
}
|
|
407
|
+
parseVariableDeclaration(lines, startIdx, filePath) {
|
|
408
|
+
const line = lines[startIdx].trim();
|
|
409
|
+
// Match variable declarations including modern C++ features
|
|
410
|
+
const match = line.match(/^(?:(const|constexpr|static|extern|volatile|mutable|thread_local|inline)\s+)*([\w:<>,\s&*]+?)\s+(\w+)(?:\[(\d+)\])?\s*(?:=\s*([^;{]+|\{[^}]*\}))?(?:;|$)/);
|
|
411
|
+
if (!match)
|
|
412
|
+
return null;
|
|
413
|
+
const node = {
|
|
414
|
+
type: 'VariableDeclaration',
|
|
415
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
416
|
+
location: this.createLocation(filePath, startIdx + 1, 0, startIdx + 1, line.length),
|
|
417
|
+
children: [],
|
|
418
|
+
metadata: {
|
|
419
|
+
name: match[3],
|
|
420
|
+
type: match[2].trim(),
|
|
421
|
+
isConst: line.includes('const') && !line.includes('const&') && !line.includes('const*'),
|
|
422
|
+
isConstexpr: line.includes('constexpr'),
|
|
423
|
+
isStatic: line.includes('static'),
|
|
424
|
+
isExtern: line.includes('extern'),
|
|
425
|
+
isMutable: line.includes('mutable'),
|
|
426
|
+
isThreadLocal: line.includes('thread_local'),
|
|
427
|
+
isArray: !!match[4],
|
|
428
|
+
arraySize: match[4] ? parseInt(match[4]) : undefined,
|
|
429
|
+
initializer: match[5]?.trim(),
|
|
430
|
+
isBraceInit: match[5]?.startsWith('{'),
|
|
431
|
+
isAuto: match[2].trim() === 'auto',
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
return { node, endIndex: startIdx };
|
|
435
|
+
}
|
|
436
|
+
parseTemplate(lines, startIdx, filePath) {
|
|
437
|
+
const line = lines[startIdx].trim();
|
|
438
|
+
const match = line.match(/template<(.+)>/);
|
|
439
|
+
if (!match)
|
|
440
|
+
return null;
|
|
441
|
+
// The actual declaration follows the template
|
|
442
|
+
let endIdx = startIdx;
|
|
443
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
444
|
+
if (lines[i].includes('{') || lines[i].includes(';')) {
|
|
445
|
+
endIdx = i;
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const node = {
|
|
450
|
+
type: 'TemplateDeclaration',
|
|
451
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
452
|
+
location: this.createLocation(filePath, startIdx + 1, 0, endIdx + 1, lines[endIdx]?.length || 0),
|
|
453
|
+
children: [],
|
|
454
|
+
metadata: {
|
|
455
|
+
parameters: match[1].split(',').map(p => {
|
|
456
|
+
const param = p.trim();
|
|
457
|
+
const typenameMatch = param.match(/(?:typename|class)\s+(\w+)/);
|
|
458
|
+
const typeMatch = param.match(/(\w+)\s+(\w+)/);
|
|
459
|
+
return {
|
|
460
|
+
kind: param.startsWith('typename') ? 'typename' :
|
|
461
|
+
param.startsWith('class') ? 'class' : 'type',
|
|
462
|
+
name: typenameMatch?.[1] || typeMatch?.[2] || param,
|
|
463
|
+
defaultValue: param.includes('=') ? param.split('=')[1].trim() : undefined,
|
|
464
|
+
};
|
|
465
|
+
}),
|
|
466
|
+
isVariadic: match[1].includes('...'),
|
|
467
|
+
requiresClause: lines.slice(startIdx, endIdx).join(' ').match(/requires\s+(.+)/)?.[1],
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
return { node, endIndex: endIdx };
|
|
471
|
+
}
|
|
472
|
+
parseEnum(lines, startIdx, filePath) {
|
|
473
|
+
const line = lines[startIdx].trim();
|
|
474
|
+
const match = line.match(/enum\s+(?:class\s+)?(\w+)(?:\s*:\s*(\w+))?/);
|
|
475
|
+
if (!match)
|
|
476
|
+
return null;
|
|
477
|
+
let endIdx = startIdx;
|
|
478
|
+
let braceCount = 0;
|
|
479
|
+
for (let i = startIdx; i < lines.length; i++) {
|
|
480
|
+
for (const char of lines[i]) {
|
|
481
|
+
if (char === '{')
|
|
482
|
+
braceCount++;
|
|
483
|
+
if (char === '}')
|
|
484
|
+
braceCount--;
|
|
485
|
+
}
|
|
486
|
+
if (braceCount === 0 && i > startIdx) {
|
|
487
|
+
endIdx = i;
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const body = lines.slice(startIdx, endIdx + 1).join('\n');
|
|
492
|
+
const values = this.extractEnumValues(body);
|
|
493
|
+
const node = {
|
|
494
|
+
type: 'EnumDeclaration',
|
|
495
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
496
|
+
location: this.createLocation(filePath, startIdx + 1, 0, endIdx + 1, lines[endIdx]?.length || 0),
|
|
497
|
+
children: [],
|
|
498
|
+
metadata: {
|
|
499
|
+
name: match[1],
|
|
500
|
+
isScoped: line.includes('enum class') || line.includes('enum struct'),
|
|
501
|
+
underlyingType: match[2],
|
|
502
|
+
values,
|
|
503
|
+
hasAssignedValues: body.includes('='),
|
|
504
|
+
},
|
|
505
|
+
};
|
|
506
|
+
return { node, endIndex: endIdx };
|
|
507
|
+
}
|
|
508
|
+
extractEnumValues(body) {
|
|
509
|
+
const values = [];
|
|
510
|
+
const valueRegex = /(\w+)\s*(?:=\s*([^,]+))?/g;
|
|
511
|
+
let match;
|
|
512
|
+
while ((match = valueRegex.exec(body)) !== null) {
|
|
513
|
+
if (!['enum', 'class', 'struct'].includes(match[1])) {
|
|
514
|
+
values.push({
|
|
515
|
+
name: match[1],
|
|
516
|
+
value: match[2]?.trim(),
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return values;
|
|
521
|
+
}
|
|
522
|
+
parseTypeAlias(lines, startIdx, filePath) {
|
|
523
|
+
const line = lines[startIdx].trim();
|
|
524
|
+
// Using alias
|
|
525
|
+
const usingMatch = line.match(/using\s+(\w+)\s*=\s*(.+);/);
|
|
526
|
+
if (usingMatch) {
|
|
527
|
+
const node = {
|
|
528
|
+
type: 'TypeAliasDeclaration',
|
|
529
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
530
|
+
location: this.createLocation(filePath, startIdx + 1, 0, startIdx + 1, line.length),
|
|
531
|
+
children: [],
|
|
532
|
+
metadata: {
|
|
533
|
+
name: usingMatch[1],
|
|
534
|
+
target: usingMatch[2],
|
|
535
|
+
isUsing: true,
|
|
536
|
+
isTemplateAlias: line.includes('template'),
|
|
537
|
+
},
|
|
538
|
+
};
|
|
539
|
+
return { node, endIndex: startIdx };
|
|
540
|
+
}
|
|
541
|
+
// Typedef
|
|
542
|
+
const typedefMatch = line.match(/typedef\s+([\w<>,\s&*]+)\s+(\w+);/);
|
|
543
|
+
if (typedefMatch) {
|
|
544
|
+
const node = {
|
|
545
|
+
type: 'TypeAliasDeclaration',
|
|
546
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
547
|
+
location: this.createLocation(filePath, startIdx + 1, 0, startIdx + 1, line.length),
|
|
548
|
+
children: [],
|
|
549
|
+
metadata: {
|
|
550
|
+
name: typedefMatch[2],
|
|
551
|
+
target: typedefMatch[1].trim(),
|
|
552
|
+
isUsing: false,
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
return { node, endIndex: startIdx };
|
|
556
|
+
}
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
parseExtern(lines, startIdx, filePath) {
|
|
560
|
+
const line = lines[startIdx].trim();
|
|
561
|
+
const match = line.match(/extern\s+"(\w+)"\s*\{/);
|
|
562
|
+
if (!match) {
|
|
563
|
+
// Single extern declaration
|
|
564
|
+
const singleMatch = line.match(/extern\s+([\w<>,\s&*]+)\s+(\w+)\s*;/);
|
|
565
|
+
if (singleMatch) {
|
|
566
|
+
const node = {
|
|
567
|
+
type: 'ExternDeclaration',
|
|
568
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
569
|
+
location: this.createLocation(filePath, startIdx + 1, 0, startIdx + 1, line.length),
|
|
570
|
+
children: [],
|
|
571
|
+
metadata: {
|
|
572
|
+
language: 'C',
|
|
573
|
+
isBlock: false,
|
|
574
|
+
},
|
|
575
|
+
};
|
|
576
|
+
return { node, endIndex: startIdx };
|
|
577
|
+
}
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
let endIdx = startIdx;
|
|
581
|
+
let braceCount = 0;
|
|
582
|
+
for (let i = startIdx; i < lines.length; i++) {
|
|
583
|
+
for (const char of lines[i]) {
|
|
584
|
+
if (char === '{')
|
|
585
|
+
braceCount++;
|
|
586
|
+
if (char === '}')
|
|
587
|
+
braceCount--;
|
|
588
|
+
}
|
|
589
|
+
if (braceCount === 0 && i > startIdx) {
|
|
590
|
+
endIdx = i;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const node = {
|
|
595
|
+
type: 'ExternDeclaration',
|
|
596
|
+
id: `${filePath}:${startIdx + 1}:0`,
|
|
597
|
+
location: this.createLocation(filePath, startIdx + 1, 0, endIdx + 1, lines[endIdx]?.length || 0),
|
|
598
|
+
children: [],
|
|
599
|
+
metadata: {
|
|
600
|
+
language: match[1],
|
|
601
|
+
isBlock: true,
|
|
602
|
+
},
|
|
603
|
+
};
|
|
604
|
+
return { node, endIndex: endIdx };
|
|
605
|
+
}
|
|
606
|
+
parseInheritance(inheritance) {
|
|
607
|
+
if (!inheritance)
|
|
608
|
+
return [];
|
|
609
|
+
const result = [];
|
|
610
|
+
const parts = inheritance.split(',');
|
|
611
|
+
for (const part of parts) {
|
|
612
|
+
const trimmed = part.trim();
|
|
613
|
+
const virtual = trimmed.includes('virtual');
|
|
614
|
+
const visibility = trimmed.match(/(public|private|protected)/)?.[1] || 'private';
|
|
615
|
+
const className = trimmed.replace(/virtual|public|private|protected/g, '').trim();
|
|
616
|
+
if (className) {
|
|
617
|
+
result.push({ class: className, visibility, isVirtual: virtual });
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return result;
|
|
621
|
+
}
|
|
622
|
+
extractAccessSpecifiers(body) {
|
|
623
|
+
const specifiers = [];
|
|
624
|
+
const regex = /(public|private|protected):/g;
|
|
625
|
+
let match;
|
|
626
|
+
while ((match = regex.exec(body)) !== null) {
|
|
627
|
+
specifiers.push(match[1]);
|
|
628
|
+
}
|
|
629
|
+
return specifiers;
|
|
630
|
+
}
|
|
631
|
+
findSyntaxErrors() {
|
|
632
|
+
const errors = [];
|
|
633
|
+
let braceCount = 0;
|
|
634
|
+
let parenCount = 0;
|
|
635
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
636
|
+
const line = this.lines[i];
|
|
637
|
+
// Skip preprocessor lines and comments
|
|
638
|
+
if (line.trim().startsWith('#') || line.trim().startsWith('//'))
|
|
639
|
+
continue;
|
|
640
|
+
for (const char of line) {
|
|
641
|
+
if (char === '{')
|
|
642
|
+
braceCount++;
|
|
643
|
+
if (char === '}')
|
|
644
|
+
braceCount--;
|
|
645
|
+
if (char === '(')
|
|
646
|
+
parenCount++;
|
|
647
|
+
if (char === ')')
|
|
648
|
+
parenCount--;
|
|
649
|
+
}
|
|
650
|
+
if (braceCount < 0) {
|
|
651
|
+
errors.push({ message: 'Unexpected }', line: i + 1, severity: 'error' });
|
|
652
|
+
braceCount = 0;
|
|
653
|
+
}
|
|
654
|
+
if (parenCount < 0) {
|
|
655
|
+
errors.push({ message: 'Unexpected )', line: i + 1, severity: 'error' });
|
|
656
|
+
parenCount = 0;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (braceCount > 0) {
|
|
660
|
+
errors.push({ message: `Unclosed braces: ${braceCount}`, line: this.lines.length, severity: 'error' });
|
|
661
|
+
}
|
|
662
|
+
return errors;
|
|
663
|
+
}
|
|
664
|
+
findPreprocessorIssues() {
|
|
665
|
+
const warnings = [];
|
|
666
|
+
// Check for common issues
|
|
667
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
668
|
+
const line = this.lines[i];
|
|
669
|
+
// Missing header guard
|
|
670
|
+
if (i === 0 && !line.includes('#ifndef') && !line.includes('#pragma once')) {
|
|
671
|
+
// Only for .h/.hpp files
|
|
672
|
+
if (line.includes('.h') || line.includes('.hpp')) {
|
|
673
|
+
warnings.push({
|
|
674
|
+
message: 'Missing header guard (consider using #pragma once or #ifndef)',
|
|
675
|
+
line: 1,
|
|
676
|
+
severity: 'warning',
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
// Deprecated macros
|
|
681
|
+
if (line.includes('malloc') || line.includes('free') || line.includes('sprintf')) {
|
|
682
|
+
warnings.push({
|
|
683
|
+
message: 'Using C-style memory/string functions, consider C++ alternatives',
|
|
684
|
+
line: i + 1,
|
|
685
|
+
severity: 'info',
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return warnings;
|
|
690
|
+
}
|
|
691
|
+
extractComments() {
|
|
692
|
+
const comments = [];
|
|
693
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
694
|
+
const line = this.lines[i];
|
|
695
|
+
// Single line comments
|
|
696
|
+
const singleIdx = line.indexOf('//');
|
|
697
|
+
if (singleIdx !== -1) {
|
|
698
|
+
comments.push({
|
|
699
|
+
type: 'Line',
|
|
700
|
+
value: line.substring(singleIdx + 2).trim(),
|
|
701
|
+
line: i + 1,
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
// Block comments
|
|
706
|
+
const blockRegex = /\/\*[\s\S]*?\*\//g;
|
|
707
|
+
let match;
|
|
708
|
+
while ((match = blockRegex.exec(this.source)) !== null) {
|
|
709
|
+
const lineNum = this.source.substring(0, match.index).split('\n').length;
|
|
710
|
+
comments.push({
|
|
711
|
+
type: 'Block',
|
|
712
|
+
value: match[0].substring(2, match[0].length - 2).trim(),
|
|
713
|
+
line: lineNum,
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
return comments;
|
|
717
|
+
}
|
|
718
|
+
createLocation(file, startLine, startCol, endLine, endCol) {
|
|
719
|
+
return {
|
|
720
|
+
file,
|
|
721
|
+
startLine,
|
|
722
|
+
startColumn: startCol,
|
|
723
|
+
endLine,
|
|
724
|
+
endColumn: endCol,
|
|
725
|
+
byteOffset: 0,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
fallbackParse(filePath) {
|
|
729
|
+
return {
|
|
730
|
+
ast: this.parseCpp(this.source, filePath),
|
|
731
|
+
errors: this.findSyntaxErrors(),
|
|
732
|
+
warnings: this.findPreprocessorIssues(),
|
|
733
|
+
tokens: [],
|
|
734
|
+
comments: this.extractComments(),
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
exports.CppParser = CppParser;
|
|
739
|
+
class CppAnalyzer {
|
|
740
|
+
analyze(ast, context) {
|
|
741
|
+
const symbolTable = this.buildSymbolTable(ast);
|
|
742
|
+
const memoryAnalysis = this.analyzeMemoryManagement(ast);
|
|
743
|
+
const templateAnalysis = this.analyzeTemplates(ast);
|
|
744
|
+
const securityIssues = this.findSecurityIssues(ast);
|
|
745
|
+
return {
|
|
746
|
+
symbols: symbolTable,
|
|
747
|
+
callGraph: this.buildCallGraph(ast),
|
|
748
|
+
dataFlow: { definitions: new Map(), uses: new Map(), taintedSources: [], sinks: [] },
|
|
749
|
+
controlFlow: { nodes: [], edges: [], loops: [], branches: [] },
|
|
750
|
+
typeInference: new Map(),
|
|
751
|
+
metrics: this.calculateMetrics(ast),
|
|
752
|
+
suggestions: [
|
|
753
|
+
...memoryAnalysis.suggestions,
|
|
754
|
+
...templateAnalysis.suggestions,
|
|
755
|
+
...securityIssues.map(i => ({
|
|
756
|
+
type: 'security',
|
|
757
|
+
severity: i.severity,
|
|
758
|
+
message: i.description,
|
|
759
|
+
remediation: i.remediation,
|
|
760
|
+
})),
|
|
761
|
+
],
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
buildSymbolTable(ast) {
|
|
765
|
+
return {
|
|
766
|
+
variables: new Map(),
|
|
767
|
+
functions: new Map(),
|
|
768
|
+
classes: new Map(),
|
|
769
|
+
modules: new Map(),
|
|
770
|
+
imports: [],
|
|
771
|
+
exports: [],
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
analyzeMemoryManagement(ast) {
|
|
775
|
+
const suggestions = [];
|
|
776
|
+
let rawPointerCount = 0;
|
|
777
|
+
let newCount = 0;
|
|
778
|
+
let deleteCount = 0;
|
|
779
|
+
let uniquePtrCount = 0;
|
|
780
|
+
let sharedPtrCount = 0;
|
|
781
|
+
const traverse = (node) => {
|
|
782
|
+
// Check for raw pointers
|
|
783
|
+
if (node.type === 'VariableDeclaration') {
|
|
784
|
+
const type = node.metadata.type || '';
|
|
785
|
+
if (type.includes('*') && !type.includes('const*') && !type.includes('const *')) {
|
|
786
|
+
rawPointerCount++;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
// Check for new/delete
|
|
790
|
+
if (node.type === 'MethodInvocation' || node.type === 'FunctionCall') {
|
|
791
|
+
const method = node.metadata.method || node.metadata.name || '';
|
|
792
|
+
if (method === 'new' || method.includes('::operator new'))
|
|
793
|
+
newCount++;
|
|
794
|
+
if (method === 'delete' || method === 'delete[]')
|
|
795
|
+
deleteCount++;
|
|
796
|
+
}
|
|
797
|
+
// Check for smart pointers
|
|
798
|
+
const type = node.metadata.type || '';
|
|
799
|
+
if (type.includes('unique_ptr'))
|
|
800
|
+
uniquePtrCount++;
|
|
801
|
+
if (type.includes('shared_ptr'))
|
|
802
|
+
sharedPtrCount++;
|
|
803
|
+
node.children.forEach(traverse);
|
|
804
|
+
};
|
|
805
|
+
traverse(ast);
|
|
806
|
+
// Memory management suggestions
|
|
807
|
+
if (newCount > 0 && deleteCount === 0) {
|
|
808
|
+
suggestions.push({
|
|
809
|
+
type: 'memory',
|
|
810
|
+
severity: 'warning',
|
|
811
|
+
message: `Using 'new' ${newCount} times without corresponding 'delete' - potential memory leak`,
|
|
812
|
+
remediation: 'Use smart pointers (std::unique_ptr, std::shared_ptr) or RAII containers',
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
if (rawPointerCount > 0 && uniquePtrCount + sharedPtrCount === 0) {
|
|
816
|
+
suggestions.push({
|
|
817
|
+
type: 'modernization',
|
|
818
|
+
severity: 'info',
|
|
819
|
+
message: `Using ${rawPointerCount} raw pointers - consider smart pointers`,
|
|
820
|
+
remediation: 'Replace raw pointers with std::unique_ptr for ownership, std::shared_ptr for shared ownership',
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
return { suggestions };
|
|
824
|
+
}
|
|
825
|
+
analyzeTemplates(ast) {
|
|
826
|
+
const suggestions = [];
|
|
827
|
+
let templateCount = 0;
|
|
828
|
+
let deepNesting = 0;
|
|
829
|
+
const traverse = (node, depth = 0) => {
|
|
830
|
+
if (node.type === 'TemplateDeclaration') {
|
|
831
|
+
templateCount++;
|
|
832
|
+
if (depth > 2) {
|
|
833
|
+
deepNesting++;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
node.children.forEach(child => traverse(child, depth + 1));
|
|
837
|
+
};
|
|
838
|
+
traverse(ast);
|
|
839
|
+
if (deepNesting > 0) {
|
|
840
|
+
suggestions.push({
|
|
841
|
+
type: 'complexity',
|
|
842
|
+
severity: 'warning',
|
|
843
|
+
message: `Deep template nesting detected (${deepNesting} instances)`,
|
|
844
|
+
remediation: 'Consider using type aliases or concepts to simplify template instantiation',
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
return { suggestions };
|
|
848
|
+
}
|
|
849
|
+
findSecurityIssues(ast) {
|
|
850
|
+
const issues = [];
|
|
851
|
+
const traverse = (node) => {
|
|
852
|
+
// Check for unsafe functions
|
|
853
|
+
if (node.type === 'MethodInvocation' || node.type === 'FunctionCall') {
|
|
854
|
+
const method = node.metadata.method || node.metadata.name || '';
|
|
855
|
+
// Buffer overflow risks
|
|
856
|
+
const unsafeFunctions = ['strcpy', 'strcat', 'sprintf', 'gets', 'scanf'];
|
|
857
|
+
if (unsafeFunctions.some(f => method.includes(f))) {
|
|
858
|
+
issues.push({
|
|
859
|
+
id: 'CPP001',
|
|
860
|
+
severity: 'critical',
|
|
861
|
+
category: 'memory-safety',
|
|
862
|
+
location: node.location,
|
|
863
|
+
description: `Using unsafe C function: ${method} - buffer overflow risk`,
|
|
864
|
+
remediation: 'Use safe alternatives: strncpy, strncat, snprintf, fgets',
|
|
865
|
+
falsePositiveLikelihood: 0.1,
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
// Memory management issues
|
|
869
|
+
if (method === 'malloc' || method === 'calloc' || method === 'realloc') {
|
|
870
|
+
const parent = node.parent;
|
|
871
|
+
if (!parent || parent.type !== 'VariableDeclaration') {
|
|
872
|
+
issues.push({
|
|
873
|
+
id: 'CPP002',
|
|
874
|
+
severity: 'medium',
|
|
875
|
+
category: 'memory-safety',
|
|
876
|
+
location: node.location,
|
|
877
|
+
description: 'C-style memory allocation without immediate assignment',
|
|
878
|
+
remediation: 'Use new/delete or smart pointers',
|
|
879
|
+
falsePositiveLikelihood: 0.3,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
// Check for missing virtual destructor
|
|
885
|
+
if (node.type === 'ClassDeclaration') {
|
|
886
|
+
const hasVirtualMethod = node.children.some(c => c.type === 'MethodDeclaration' && c.metadata.isVirtual);
|
|
887
|
+
const hasVirtualDestructor = node.metadata.hasVirtualDestructor;
|
|
888
|
+
if (hasVirtualMethod && !hasVirtualDestructor) {
|
|
889
|
+
issues.push({
|
|
890
|
+
id: 'CPP003',
|
|
891
|
+
severity: 'high',
|
|
892
|
+
category: 'memory-safety',
|
|
893
|
+
location: node.location,
|
|
894
|
+
description: `Class ${node.metadata.name} has virtual methods but non-virtual destructor`,
|
|
895
|
+
remediation: 'Add virtual ~ClassName() = default; or mark class as final',
|
|
896
|
+
falsePositiveLikelihood: 0.2,
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
node.children.forEach(traverse);
|
|
901
|
+
};
|
|
902
|
+
traverse(ast);
|
|
903
|
+
return issues;
|
|
904
|
+
}
|
|
905
|
+
buildCallGraph(ast) {
|
|
906
|
+
return { nodes: [], edges: [], entryPoints: [], deadCode: [] };
|
|
907
|
+
}
|
|
908
|
+
calculateMetrics(ast) {
|
|
909
|
+
return {
|
|
910
|
+
linesOfCode: 0,
|
|
911
|
+
logicalLines: 0,
|
|
912
|
+
commentLines: 0,
|
|
913
|
+
blankLines: 0,
|
|
914
|
+
cyclomaticComplexity: 0,
|
|
915
|
+
cognitiveComplexity: 0,
|
|
916
|
+
halsteadMetrics: { operators: 0, operands: 0, uniqueOperators: 0, uniqueOperands: 0, volume: 0, difficulty: 0, effort: 0, timeToProgram: 0, bugsDelivered: 0 },
|
|
917
|
+
maintainabilityIndex: 0,
|
|
918
|
+
duplicateRate: 0,
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
exports.CppAnalyzer = CppAnalyzer;
|
|
923
|
+
exports.CppLanguageSupport = {
|
|
924
|
+
id: 'cpp',
|
|
925
|
+
name: 'C++',
|
|
926
|
+
extensions: ['.cpp', '.cc', '.cxx', '.hpp', '.h', '.hh', '.hxx'],
|
|
927
|
+
parser: new CppParser(),
|
|
928
|
+
analyzer: new CppAnalyzer(),
|
|
929
|
+
};
|
|
930
|
+
//# sourceMappingURL=cpp.js.map
|