UNPKG

superaugment

Version:

Enterprise-grade MCP server with world-class C++ analysis, robust error handling, and production-ready architecture for VS Code Augment

476 lines 18.4 kB
/** * Enhanced C++ Analyzer with Tree-sitter AST Support * * Provides comprehensive C++ code analysis using Tree-sitter for accurate * syntax parsing, semantic analysis, and advanced code understanding. */ import Parser from 'tree-sitter'; import Cpp from 'tree-sitter-cpp'; // import { readFile } from 'fs/promises'; // Unused import // import { join, dirname, basename, extname } from 'path'; // Unused imports import { FileSystemManager } from '../utils/FileSystemManager.js'; import { logger } from '../utils/logger.js'; import { AnalysisError, ErrorCode, } from '../errors/ErrorTypes.js'; /** * Enhanced C++ Analyzer using Tree-sitter */ export class EnhancedCppAnalyzer { parser; fileSystemManager; constructor() { this.parser = new Parser(); this.parser.setLanguage(Cpp); this.fileSystemManager = new FileSystemManager(); } /** * Perform comprehensive C++ analysis */ async analyzeFile(filePath, options = {}) { try { logger.info(`Starting enhanced C++ analysis for: ${filePath}`); const content = await this.fileSystemManager.readFileContent(filePath); const tree = this.parser.parse(content); const result = { metrics: await this.analyzeMetrics(tree, content), structure: await this.analyzeStructure(tree, content), dependencies: await this.analyzeDependencies(tree, content, filePath), modernCpp: await this.analyzeModernCpp(tree, content, options.cppStandard || 'cpp17'), performance: options.includePerformance ? await this.analyzePerformance(tree, content) : { hotspots: [], optimizations: [], score: 0 }, memory: options.includeMemory ? await this.analyzeMemory(tree, content) : { issues: [], smartPointerUsage: { uniquePtr: 0, sharedPtr: 0, weakPtr: 0, rawPointers: 0, recommendations: [] }, raii: { score: 0, violations: [], recommendations: [] }, score: 0 }, security: options.includeSecurity ? await this.analyzeSecurity(tree, content) : { vulnerabilities: [], recommendations: [], score: 0 }, }; // Add CUDA analysis if requested and CUDA code detected if (options.includeCuda && this.detectCudaCode(content)) { result.cuda = await this.analyzeCuda(tree, content); } logger.info(`Enhanced C++ analysis completed for: ${filePath}`); return result; } catch (error) { throw new AnalysisError(`Enhanced C++ analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath, options } }, error instanceof Error ? error : undefined); } } /** * Analyze code metrics using AST */ async analyzeMetrics(tree, content) { const lines = content.split('\n'); let codeLines = 0; let commentLines = 0; let blankLines = 0; for (const line of lines) { const trimmed = line.trim(); if (trimmed === '') { blankLines++; } else if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) { commentLines++; } else { codeLines++; } } const complexity = this.calculateComplexity(tree); return { totalLines: lines.length, codeLines, commentLines, blankLines, complexity, }; } /** * Calculate complexity metrics from AST */ calculateComplexity(tree) { // This is a simplified implementation // In a real implementation, we would traverse the AST to calculate accurate metrics const cyclomaticComplexity = this.calculateCyclomaticComplexity(tree); const cognitiveComplexity = this.calculateCognitiveComplexity(tree); const halstead = this.calculateHalsteadMetrics(tree); const maintainabilityIndex = this.calculateMaintainabilityIndex(cyclomaticComplexity, halstead); return { cyclomatic: cyclomaticComplexity, cognitive: cognitiveComplexity, halstead, maintainabilityIndex, }; } /** * Calculate cyclomatic complexity from AST */ calculateCyclomaticComplexity(tree) { let complexity = 1; // Base complexity // Traverse the AST to count decision points const traverse = (node) => { switch (node.type) { case 'if_statement': case 'while_statement': case 'for_statement': case 'do_statement': case 'switch_statement': case 'case_statement': case 'conditional_expression': complexity++; break; case 'logical_and_expression': case 'logical_or_expression': complexity++; break; } // Recursively traverse child nodes for (let i = 0; i < node.childCount; i++) { traverse(node.child(i)); } }; traverse(tree.rootNode); return complexity; } /** * Calculate cognitive complexity */ calculateCognitiveComplexity(tree) { let complexity = 0; const traverse = (node, currentNesting) => { let increment = 0; let newNesting = currentNesting; switch (node.type) { case 'if_statement': case 'while_statement': case 'for_statement': case 'do_statement': increment = 1 + currentNesting; newNesting = currentNesting + 1; break; case 'switch_statement': increment = 1 + currentNesting; newNesting = currentNesting + 1; break; case 'case_statement': increment = 1; break; case 'conditional_expression': increment = 1 + currentNesting; break; case 'logical_and_expression': case 'logical_or_expression': increment = 1; break; case 'catch_clause': increment = 1 + currentNesting; newNesting = currentNesting + 1; break; case 'lambda_expression': increment = 1; newNesting = currentNesting + 1; break; } complexity += increment; // Recursively traverse child nodes for (let i = 0; i < node.childCount; i++) { traverse(node.child(i), newNesting); } }; traverse(tree.rootNode, 0); return complexity; } /** * Calculate Halstead metrics */ calculateHalsteadMetrics(tree) { const operators = new Set(); const operands = new Set(); let operatorCount = 0; let operandCount = 0; const operatorTypes = new Set([ '+', '-', '*', '/', '%', '=', '==', '!=', '<', '>', '<=', '>=', '&&', '||', '!', '&', '|', '^', '~', '<<', '>>', '++', '--', '+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', 'if', 'else', 'while', 'for', 'do', 'switch', 'case', 'default', 'return', 'break', 'continue', 'goto', 'try', 'catch', 'throw' ]); const traverse = (node) => { const nodeText = node.text; // Count operators if (operatorTypes.has(node.type) || operatorTypes.has(nodeText)) { operators.add(nodeText); operatorCount++; } // Count operands (identifiers, literals) else if (node.type === 'identifier' || node.type === 'number_literal' || node.type === 'string_literal' || node.type === 'character_literal') { operands.add(nodeText); operandCount++; } // Recursively traverse child nodes for (let i = 0; i < node.childCount; i++) { traverse(node.child(i)); } }; traverse(tree.rootNode); const n1 = operators.size; // Unique operators const n2 = operands.size; // Unique operands const N1 = operatorCount; // Total operators const N2 = operandCount; // Total operands const vocabulary = n1 + n2; const length = N1 + N2; const volume = length * Math.log2(vocabulary || 1); const difficulty = (n1 / 2) * (N2 / (n2 || 1)); const effort = difficulty * volume; const timeToProgram = effort / 18; // Seconds const bugsDelivered = volume / 3000; return { vocabulary, length, volume: Math.round(volume * 100) / 100, difficulty: Math.round(difficulty * 100) / 100, effort: Math.round(effort * 100) / 100, timeToProgram: Math.round(timeToProgram * 100) / 100, bugsDelivered: Math.round(bugsDelivered * 1000) / 1000, }; } /** * Calculate maintainability index */ calculateMaintainabilityIndex(cyclomaticComplexity, halstead, linesOfCode = 100) { // Maintainability Index = 171 - 5.2 * ln(Halstead Volume) - 0.23 * (Cyclomatic Complexity) - 16.2 * ln(Lines of Code) const halsteadVolume = halstead.volume || 1; const logVolume = Math.log(halsteadVolume); const logLoc = Math.log(linesOfCode || 1); const maintainabilityIndex = 171 - 5.2 * logVolume - 0.23 * cyclomaticComplexity - 16.2 * logLoc; // Normalize to 0-100 scale return Math.max(0, Math.min(100, maintainabilityIndex)); } /** * Detect CUDA code in content */ detectCudaCode(content) { const cudaKeywords = [ '__global__', '__device__', '__host__', 'cudaMalloc', 'cudaFree', 'cudaMemcpy', 'blockIdx', 'threadIdx', 'blockDim', 'gridDim', '<<<', '>>>' ]; return cudaKeywords.some(keyword => content.includes(keyword)); } // Structural analysis methods async analyzeStructure(tree, _content) { const structure = { namespaces: [], classes: [], functions: [], variables: [], enums: [], templates: [], macros: [], }; const traverse = (node) => { switch (node.type) { case 'namespace_definition': structure.namespaces.push(this.extractNamespace(node)); break; case 'class_specifier': case 'struct_specifier': structure.classes.push(this.extractClass(node)); break; case 'function_definition': case 'function_declarator': structure.functions.push(this.extractFunction(node)); break; case 'declaration': const variable = this.extractVariable(node); if (variable) structure.variables.push(variable); break; case 'enum_specifier': structure.enums.push(this.extractEnum(node)); break; case 'template_declaration': structure.templates.push(this.extractTemplate(node)); break; case 'preproc_def': case 'preproc_function_def': structure.macros.push(this.extractMacro(node)); break; } // Recursively traverse child nodes for (let i = 0; i < node.childCount; i++) { traverse(node.child(i)); } }; traverse(tree.rootNode); return structure; } async analyzeDependencies(tree, _content, filePath) { const systemIncludes = []; const userIncludes = []; const traverse = (node) => { if (node.type === 'preproc_include') { const includeText = node.text; const match = includeText.match(/#include\s*[<"](.*)[>"]/); if (match && match[1]) { const includePath = match[1]; if (includeText.includes('<')) { systemIncludes.push(includePath); } else { userIncludes.push(includePath); } } } for (let i = 0; i < node.childCount; i++) { traverse(node.child(i)); } }; traverse(tree.rootNode); return { systemIncludes, userIncludes, dependencyGraph: [{ file: filePath, includes: [...systemIncludes, ...userIncludes], includedBy: [], depth: 0 }], circularDependencies: [], // Would require cross-file analysis }; } async analyzeModernCpp(_tree, _content, cppStandard) { // Implementation would detect modern C++ features usage return { cppStandard, featuresUsed: [], recommendations: [], score: 0, }; } async analyzePerformance(_tree, _content) { // Implementation would identify performance hotspots return { hotspots: [], optimizations: [], score: 0, }; } async analyzeMemory(_tree, _content) { // Implementation would analyze memory management patterns return { issues: [], smartPointerUsage: { uniquePtr: 0, sharedPtr: 0, weakPtr: 0, rawPointers: 0, recommendations: [], }, raii: { score: 0, violations: [], recommendations: [], }, score: 0, }; } async analyzeSecurity(_tree, _content) { // Implementation would identify security vulnerabilities return { vulnerabilities: [], recommendations: [], score: 0, }; } async analyzeCuda(_tree, _content) { // Implementation would analyze CUDA-specific patterns return { kernels: [], memoryTransfers: [], optimizations: [], score: 0, }; } // Extraction methods for structural analysis extractNamespace(node) { const nameNode = node.childForFieldName('name'); return { name: nameNode?.text || 'anonymous', line: node.startPosition.row + 1, column: node.startPosition.column, nested: false, // Would need parent analysis members: [], // Would need member analysis }; } extractClass(node) { const nameNode = node.childForFieldName('name'); return { name: nameNode?.text || 'anonymous', line: node.startPosition.row + 1, column: node.startPosition.column, type: node.type === 'struct_specifier' ? 'struct' : 'class', inheritance: [], // Would need inheritance analysis members: [], // Would need member analysis isTemplate: false, // Would need template analysis accessSpecifiers: [], // Would need access specifier analysis }; } extractFunction(node) { const nameNode = node.childForFieldName('declarator')?.childForFieldName('declarator'); return { name: nameNode?.text || 'anonymous', line: node.startPosition.row + 1, column: node.startPosition.column, returnType: 'unknown', // Would need type analysis parameters: [], // Would need parameter analysis isStatic: false, // Would need modifier analysis isVirtual: false, isConst: false, isNoexcept: false, isTemplate: false, complexity: 1, // Would calculate from body bodyLines: node.endPosition.row - node.startPosition.row, }; } extractVariable(node) { // Simplified variable extraction const declarator = node.childForFieldName('declarator'); if (!declarator) return null; return { name: declarator.text || 'unknown', type: 'unknown', // Would need type analysis line: node.startPosition.row + 1, column: node.startPosition.column, isGlobal: false, // Would need scope analysis isStatic: false, isConst: false, isConstexpr: false, }; } extractEnum(node) { const nameNode = node.childForFieldName('name'); return { name: nameNode?.text || 'anonymous', line: node.startPosition.row + 1, column: node.startPosition.column, isScoped: false, // Would need analysis values: [], // Would need value analysis }; } extractTemplate(node) { return { name: 'template', // Would need name analysis line: node.startPosition.row + 1, column: node.startPosition.column, type: 'function', // Would need type analysis parameters: [], // Would need parameter analysis specializations: [], // Would need specialization analysis }; } extractMacro(node) { const nameNode = node.childForFieldName('name'); return { name: nameNode?.text || 'unknown', line: node.startPosition.row + 1, column: node.startPosition.column, body: node.text, isFunctionLike: node.type === 'preproc_function_def', }; } } //# sourceMappingURL=EnhancedCppAnalyzer.js.map