UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

105 lines (91 loc) 3.86 kB
/** * @file Unbounded array detector * @description Detects unbounded array growth patterns */ /** * Detects unbounded array growth patterns * @param {string} content - File content * @param {string} filePath - Path to the file * @returns {Array} Array of unbounded array issues */ function detectUnboundedArrays(content, filePath) { const issues = []; const lines = content.split('\n'); const { PERFORMANCE_PATTERNS } = require('./performancePatterns'); // Pattern to detect truly unbounded array growth const dangerousPatterns = [ // Infinite or very long-running loops with array operations /while\s*\(\s*true\s*\)/, /while\s*\(\s*1\s*\)/, /while\s*\(.*\)\s*{[^}]*\.push\s*\(/m, // Array growth without any break conditions /for\s*\(\s*;\s*;\s*\)/, // infinite for loop ]; // Check for dangerous patterns first let hasDangerousLoop = false; for (const pattern of dangerousPatterns) { if (pattern.test(content)) { hasDangerousLoop = true; break; } } // Only proceed if we found potentially dangerous patterns if (!hasDangerousLoop) { return issues; } lines.forEach((line, index) => { const lineNumber = index + 1; // Only detect actual array growth operations const growthPatterns = [ /\.push\s*\([^)]*\)/, /\.unshift\s*\([^)]*\)/, /\[\s*\w+\.length\s*\]\s*=/ // array[array.length] = value ]; growthPatterns.forEach(pattern => { if (pattern.test(line)) { // Get broader context (20 lines before and after) const contextStart = Math.max(0, index - 20); const contextEnd = Math.min(lines.length, index + 20); const contextLines = lines.slice(contextStart, contextEnd).join('\n'); // Check for signs this is actually bounded const boundedIndicators = [ /for\s*\([^;]+;\s*\w+\s*<\s*\w+\.(length|size)/, // for loop with length check /\.slice\(\d+,\s*\d+\)/, // explicit slice bounds /\.splice\(\d+,\s*\d+\)/, // removing elements /if\s*\([^)]*\.(length|size)\s*[><=]/, // length check condition /maxResults|limit|MAX_|LIMIT_/i, // limit constants /break|return/, // exit conditions /\w+\s*=\s*\[\]/, // array reset ]; const isBounded = boundedIndicators.some(indicator => indicator.test(contextLines)); // Check if it's in an infinite/dangerous loop const infiniteLoopPattern = /while\s*\(\s*(true|1)\s*\)|for\s*\(\s*;\s*;\s*\)/; const inInfiniteLoop = infiniteLoopPattern.test(contextLines); // Only flag if truly unbounded if (inInfiniteLoop && !isBounded) { const patternInfo = PERFORMANCE_PATTERNS['unbounded_array']; const operation = line.match(/\.(push|unshift)/)?.[1] || 'array growth'; issues.push({ type: 'unbounded_array', severity: patternInfo.severity, category: patternInfo.category, location: `${filePath}:${lineNumber}`, line: lineNumber, code: line.trim(), operation: operation, description: `Unbounded array ${operation} in infinite loop — memory leak risk`, summary: `Unbounded array ${operation} in infinite loop`, recommendation: 'Add break conditions or size limits to prevent memory exhaustion', effort: patternInfo.effort, impact: patternInfo.impact, estimatedSavings: 'prevents memory exhaustion and OOM errors' }); } } }); }); return issues; } module.exports = { detectUnboundedArrays };