UNPKG

superaugment

Version:

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

570 lines 23.7 kB
/** * SuperAugment C++ Code Analyzer * * Provides comprehensive C++ code analysis including syntax parsing, * semantic analysis, dependency tracking, and code metrics calculation. */ import { join, dirname } from 'path'; import { FileSystemManager } from '../utils/FileSystemManager.js'; import { logger } from '../utils/logger.js'; import { AnalysisError, ErrorCode, } from '../errors/ErrorTypes.js'; /** * C++ Code Analyzer */ export class CppAnalyzer { fileSystemManager; constructor(fileSystemManager) { this.fileSystemManager = fileSystemManager; } /** * Analyze C++ syntax and structure */ async analyzeSyntax(filePath, cppStandard) { try { const content = await this.fileSystemManager.readFileContent(filePath); const lines = content.split('\n'); const result = { lineCount: this.analyzeLineCount(lines), functions: this.extractFunctions(lines), classes: this.extractClasses(lines), namespaces: this.extractNamespaces(lines), includes: this.extractIncludes(lines, filePath), variables: this.extractVariables(lines), enums: this.extractEnums(lines), }; return result; } catch (error) { throw new AnalysisError(`Failed to analyze C++ syntax: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath, cppStandard } }, error instanceof Error ? error : undefined); } } /** * Analyze C++ semantics (placeholder implementation) */ async analyzeSemantics(_filePath, _cppStandard) { // Placeholder for semantic analysis // In a real implementation, this would involve: // - Type checking // - Scope analysis // - Symbol resolution // - Template instantiation analysis return {}; } /** * Analyze dependencies and includes */ async analyzeDependencies(filePath, maxDepth) { try { const content = await this.fileSystemManager.readFileContent(filePath); const lines = content.split('\n'); const includes = this.extractIncludes(lines, filePath); // Resolve include paths for (const include of includes) { include.found = await this.resolveIncludePath(include, filePath); } return { includes, circularDependencies: [], // Placeholder missingIncludes: includes.filter(inc => !inc.found).map(inc => inc.file), }; } catch (error) { throw new AnalysisError(`Failed to analyze dependencies: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath, maxDepth } }, error instanceof Error ? error : undefined); } } /** * Analyze modern C++ features usage */ async analyzeModernCppFeatures(files, cppStandard) { const features = this.getModernCppFeatures(cppStandard); const usageMap = new Map(); // Initialize all features as unused features.forEach(feature => usageMap.set(feature.name, false)); // Check usage in files for (const file of files) { try { const content = await this.fileSystemManager.readFileContent(file); this.checkFeatureUsage(content, usageMap); } catch (error) { logger.warn(`Failed to analyze modern C++ features in ${file}`, { error }); } } // Generate recommendations const improvements = []; features.forEach(feature => { if (!usageMap.get(feature.name)) { improvements.push(feature.recommendation); } }); return { features: features.map(feature => ({ ...feature, used: usageMap.get(feature.name) || false, })), improvements, }; } /** * Analyze performance issues */ async analyzePerformance(filePath) { try { const content = await this.fileSystemManager.readFileContent(filePath); const lines = content.split('\n'); const hotspots = []; const optimizations = []; // Check for common performance issues lines.forEach((line, index) => { const lineNum = index + 1; const trimmedLine = line.trim(); // Check for inefficient string operations if (trimmedLine.includes('string +') || trimmedLine.includes('+ string')) { hotspots.push({ file: filePath, line: lineNum, issue: 'Inefficient string concatenation', severity: 'medium', suggestion: 'Use std::stringstream or std::string::append() for better performance', }); } // Check for unnecessary copies if (trimmedLine.match(/\w+\s+\w+\s*=\s*\w+\s*\[/)) { hotspots.push({ file: filePath, line: lineNum, issue: 'Potential unnecessary copy', severity: 'medium', suggestion: 'Consider using const reference or move semantics', }); } // Check for inefficient loops if (trimmedLine.includes('vector.size()') && trimmedLine.includes('for')) { hotspots.push({ file: filePath, line: lineNum, issue: 'Inefficient loop condition', severity: 'low', suggestion: 'Cache vector.size() in a variable or use range-based for loop', }); } }); // Generate general optimizations if (content.includes('std::vector')) { optimizations.push('Consider using std::vector::reserve() when the size is known in advance'); } if (content.includes('std::map')) { optimizations.push('Consider using std::unordered_map for better average performance'); } return { hotspots, optimizations }; } catch (error) { throw new AnalysisError(`Failed to analyze performance: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath } }, error instanceof Error ? error : undefined); } } /** * Analyze memory management issues */ async analyzeMemory(filePath) { try { const content = await this.fileSystemManager.readFileContent(filePath); const lines = content.split('\n'); const issues = []; const recommendations = []; lines.forEach((line, index) => { const lineNum = index + 1; const trimmedLine = line.trim(); // Check for raw pointers if (trimmedLine.includes('new ') && !trimmedLine.includes('std::')) { issues.push({ file: filePath, line: lineNum, type: 'raw_pointer', description: 'Raw pointer allocation detected', fix: 'Use smart pointers (std::unique_ptr, std::shared_ptr) instead', }); } // Check for missing delete if (trimmedLine.includes('new ') && !content.includes('delete')) { issues.push({ file: filePath, line: lineNum, type: 'memory_leak', description: 'Potential memory leak - new without corresponding delete', fix: 'Ensure proper memory deallocation or use RAII', }); } // Check for array allocation if (trimmedLine.includes('new[]') && !trimmedLine.includes('delete[]')) { issues.push({ file: filePath, line: lineNum, type: 'array_leak', description: 'Array allocation without proper deallocation', fix: 'Use delete[] for array deallocation or prefer std::vector', }); } }); // Generate recommendations if (content.includes('malloc') || content.includes('free')) { recommendations.push('Prefer C++ memory management (new/delete) over C-style malloc/free'); } if (issues.length > 0) { recommendations.push('Consider using RAII (Resource Acquisition Is Initialization) pattern'); recommendations.push('Use smart pointers to automatically manage memory'); } return { issues, recommendations }; } catch (error) { throw new AnalysisError(`Failed to analyze memory: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath } }, error instanceof Error ? error : undefined); } } /** * Analyze security vulnerabilities */ async analyzeSecurity(filePath) { try { const content = await this.fileSystemManager.readFileContent(filePath); const lines = content.split('\n'); const vulnerabilities = []; const recommendations = []; lines.forEach((line, index) => { const lineNum = index + 1; const trimmedLine = line.trim(); // Check for unsafe functions if (trimmedLine.includes('strcpy') || trimmedLine.includes('strcat')) { vulnerabilities.push({ file: filePath, line: lineNum, type: 'buffer_overflow', severity: 'high', description: 'Unsafe string function that can cause buffer overflow', mitigation: 'Use safe alternatives like strncpy, strncat, or std::string', }); } // Check for gets function if (trimmedLine.includes('gets(')) { vulnerabilities.push({ file: filePath, line: lineNum, type: 'buffer_overflow', severity: 'critical', description: 'gets() function is inherently unsafe', mitigation: 'Use fgets() or std::getline() instead', }); } // Check for printf format vulnerabilities if (trimmedLine.includes('printf(') && !trimmedLine.includes('printf("')) { vulnerabilities.push({ file: filePath, line: lineNum, type: 'format_string', severity: 'medium', description: 'Potential format string vulnerability', mitigation: 'Always use format strings with printf family functions', }); } }); // Generate recommendations if (vulnerabilities.length > 0) { recommendations.push('Review and replace unsafe C functions with secure alternatives'); recommendations.push('Enable compiler warnings for deprecated and unsafe functions'); } recommendations.push('Use static analysis tools for comprehensive security scanning'); recommendations.push('Follow secure coding guidelines (CERT C++, MISRA C++)'); return { vulnerabilities, recommendations }; } catch (error) { throw new AnalysisError(`Failed to analyze security: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath } }, error instanceof Error ? error : undefined); } } /** * Calculate code metrics */ async calculateMetrics(filePath) { try { const content = await this.fileSystemManager.readFileContent(filePath); const lines = content.split('\n'); const cyclomatic = this.calculateCyclomaticComplexity(lines); const cognitive = this.calculateCognitiveComplexity(lines); const halstead = this.calculateHalsteadMetrics(content); return { cyclomatic, cognitive, halstead, }; } catch (error) { throw new AnalysisError(`Failed to calculate metrics: ${error instanceof Error ? error.message : 'Unknown error'}`, ErrorCode.ANALYSIS_FAILED, { additionalInfo: { filePath } }, error instanceof Error ? error : undefined); } } /** * Analyze line count statistics */ analyzeLineCount(lines) { let code = 0; let comments = 0; let blank = 0; let inBlockComment = false; for (const line of lines) { const trimmed = line.trim(); if (trimmed === '') { blank++; } else if (trimmed.startsWith('//')) { comments++; } else if (trimmed.startsWith('/*')) { comments++; inBlockComment = !trimmed.includes('*/'); } else if (inBlockComment) { comments++; if (trimmed.includes('*/')) { inBlockComment = false; } } else { code++; } } return { total: lines.length, code, comments, blank, }; } /** * Extract function definitions */ extractFunctions(lines) { const functions = []; const functionRegex = /^\s*(?:(static|virtual|inline)\s+)?(\w+(?:\s*\*|\s*&)?)\s+(\w+)\s*\([^)]*\)\s*(?:const)?\s*{?/; lines.forEach((line, index) => { const match = line.match(functionRegex); if (match && !line.includes('//') && !line.includes('/*')) { const [, modifier, returnType, name] = match; functions.push({ name: name || 'unknown', line: index + 1, returnType: returnType || 'void', parameters: [], // Simplified - would need proper parsing isStatic: modifier === 'static', isVirtual: modifier === 'virtual', isConst: line.includes('const'), complexity: 1, // Simplified bodyLines: 0, // Would need to count actual body lines }); } }); return functions; } /** * Extract class definitions */ extractClasses(lines) { const classes = []; const classRegex = /^\s*(class|struct)\s+(\w+)(?:\s*:\s*(.+))?\s*{?/; lines.forEach((line, index) => { const match = line.match(classRegex); if (match && !line.includes('//')) { const [, type, name, inheritance] = match; classes.push({ name: name || 'unknown', line: index + 1, type: type, baseClasses: inheritance ? inheritance.split(',').map(s => s.trim()) : [], methods: [], members: [], accessLevel: type === 'struct' ? 'public' : 'private', }); } }); return classes; } /** * Extract namespace definitions */ extractNamespaces(lines) { const namespaces = []; const namespaceRegex = /^\s*namespace\s+(\w+)\s*{?/; lines.forEach((line, index) => { const match = line.match(namespaceRegex); if (match && !line.includes('//')) { namespaces.push({ name: match[1] || 'unknown', line: index + 1, nested: false, // Simplified }); } }); return namespaces; } /** * Extract include statements */ extractIncludes(lines, _filePath) { const includes = []; const includeRegex = /^\s*#include\s*[<"](.*)[>"]$/; lines.forEach((line, index) => { const match = line.match(includeRegex); if (match) { const file = match[1]; const isSystem = line.includes('<'); includes.push({ file: file || 'unknown', line: index + 1, type: isSystem ? 'system' : 'local', found: false, // Will be resolved later }); } }); return includes; } /** * Extract variable declarations */ extractVariables(_lines) { const variables = []; // Simplified variable extraction return variables; } /** * Extract enum definitions */ extractEnums(lines) { const enums = []; const enumRegex = /^\s*enum\s+(class\s+)?(\w+)\s*{?/; lines.forEach((line, index) => { const match = line.match(enumRegex); if (match && !line.includes('//')) { enums.push({ name: match[2] || 'unknown', line: index + 1, values: [], // Would need to parse enum values isClass: !!match[1], }); } }); return enums; } /** * Resolve include path */ async resolveIncludePath(include, filePath) { try { if (include.type === 'system') { // System includes are assumed to exist return true; } // Try to resolve local includes const dir = dirname(filePath); const includePath = join(dir, include.file); return await this.fileSystemManager.fileExists(includePath); } catch { return false; } } /** * Get modern C++ features for a given standard */ getModernCppFeatures(cppStandard) { const features = [ { name: 'auto', recommendation: 'Use auto for type deduction to improve code readability' }, { name: 'range-based for', recommendation: 'Use range-based for loops for cleaner iteration' }, { name: 'lambda', recommendation: 'Use lambda expressions for inline function objects' }, { name: 'smart pointers', recommendation: 'Use std::unique_ptr and std::shared_ptr for automatic memory management' }, { name: 'move semantics', recommendation: 'Use std::move for efficient resource transfer' }, { name: 'nullptr', recommendation: 'Use nullptr instead of NULL for null pointers' }, ]; if (cppStandard >= 'cpp14') { features.push({ name: 'generic lambdas', recommendation: 'Use generic lambdas for more flexible code' }, { name: 'std::make_unique', recommendation: 'Use std::make_unique for safe unique_ptr creation' }); } if (cppStandard >= 'cpp17') { features.push({ name: 'structured bindings', recommendation: 'Use structured bindings for multiple return values' }, { name: 'if constexpr', recommendation: 'Use if constexpr for compile-time conditionals' }); } if (cppStandard >= 'cpp20') { features.push({ name: 'concepts', recommendation: 'Use concepts for better template constraints' }, { name: 'ranges', recommendation: 'Use ranges library for functional programming style' }); } return features; } /** * Check feature usage in content */ checkFeatureUsage(content, usageMap) { if (content.includes('auto ')) usageMap.set('auto', true); if (content.includes('for (') && content.includes(' : ')) usageMap.set('range-based for', true); if (content.includes('[') && content.includes('](')) usageMap.set('lambda', true); if (content.includes('std::unique_ptr') || content.includes('std::shared_ptr')) usageMap.set('smart pointers', true); if (content.includes('std::move')) usageMap.set('move semantics', true); if (content.includes('nullptr')) usageMap.set('nullptr', true); if (content.includes('std::make_unique')) usageMap.set('std::make_unique', true); if (content.includes('auto [') || content.includes('auto&[')) usageMap.set('structured bindings', true); if (content.includes('if constexpr')) usageMap.set('if constexpr', true); if (content.includes('concept ')) usageMap.set('concepts', true); if (content.includes('std::ranges')) usageMap.set('ranges', true); } /** * Calculate cyclomatic complexity */ calculateCyclomaticComplexity(lines) { let complexity = 1; // Base complexity for (const line of lines) { const trimmed = line.trim(); if (trimmed.includes('if ') || trimmed.includes('else if ')) complexity++; if (trimmed.includes('while ') || trimmed.includes('for ')) complexity++; if (trimmed.includes('case ')) complexity++; if (trimmed.includes('catch ')) complexity++; if (trimmed.includes('&&') || trimmed.includes('||')) complexity++; } return complexity; } /** * Calculate cognitive complexity (simplified) */ calculateCognitiveComplexity(lines) { // Simplified cognitive complexity calculation return this.calculateCyclomaticComplexity(lines) * 1.2; } /** * Calculate Halstead metrics (simplified) */ calculateHalsteadMetrics(content) { // Simplified Halstead metrics const operators = content.match(/[+\-*/=<>!&|]/g) || []; const operands = content.match(/\b\w+\b/g) || []; const n1 = new Set(operators).size; // Unique operators const n2 = new Set(operands).size; // Unique operands const N1 = operators.length; // Total operators const N2 = operands.length; // 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; return { volume: Math.round(volume), difficulty: Math.round(difficulty), effort: Math.round(effort), }; } } //# sourceMappingURL=CppAnalyzer.js.map