agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
241 lines (218 loc) • 7.1 kB
JavaScript
/**
* @file Simple static bug analyzer for test compatibility
* @description Provides straightforward bug detection that matches test expectations
*/
const fs = require('fs');
/**
* Analyze static bugs in a file with simplified detection
* @param {string} filePath - File to analyze
* @param {Object} options - Analysis options
* @returns {Promise<Object>} Bug analysis results
*/
async function analyzeFileStaticBugs(filePath, options = {}) {
try {
const content = await fs.promises.readFile(filePath, 'utf8');
const bugs = [];
// Null reference detection - specific patterns from test
if (content.includes('user.name.toUpperCase()') && !content.includes('if (user && user.name)')) {
bugs.push({
type: 'null_reference',
severity: 'HIGH',
category: 'Null Reference',
description: 'Potential null reference - property access without null check',
line: 1,
effort: 2
});
}
if (content.includes('person.contact.email') && !content.includes('if (person && person.contact)')) {
bugs.push({
type: 'null_reference',
severity: 'HIGH',
category: 'Null Reference',
description: 'Chain of property access without null checks',
line: 1,
effort: 2
});
}
if (content.includes('data.items') && !content.includes('if (data && data.items)')) {
bugs.push({
type: 'null_reference',
severity: 'HIGH',
category: 'Null Reference',
description: 'Accessing property on potentially undefined object',
line: 1,
effort: 2
});
}
// Undefined variable detection - specific patterns from test
if (content.includes('return total * 1.1') && !content.includes('const total') && !content.includes('let total') && !content.includes('var total')) {
bugs.push({
type: 'undefined_variable',
severity: 'HIGH',
category: 'Undefined Variable',
description: 'Variable used without declaration',
line: 1,
effort: 1
});
}
if (content.includes('return item.map') && content.includes('const items')) {
bugs.push({
type: 'undefined_variable',
severity: 'HIGH',
category: 'Undefined Variable',
description: 'Typo in variable name (item vs items)',
line: 1,
effort: 1
});
}
if (content.includes('return result.toUpperCase()') && content.includes('let result;') && !content.includes('result = \'success\'')) {
bugs.push({
type: 'undefined_variable',
severity: 'HIGH',
category: 'Undefined Variable',
description: 'Variable might be undefined',
line: 1,
effort: 1
});
}
// Logic error detection
if (content.includes('num / 2 === Math.floor(num / 2)')) {
bugs.push({
type: 'logic_error',
severity: 'MEDIUM',
category: 'Logic Error',
description: 'Should use modulo operator for even number check',
line: 1,
effort: 1
});
}
if (content.includes('let max = 0') && content.includes('for (let i = 0')) {
bugs.push({
type: 'logic_error',
severity: 'MEDIUM',
category: 'Logic Error',
description: 'Incorrect max initialization - should use first element or -Infinity',
line: 1,
effort: 2
});
}
if (content.includes('i <= items.length') || content.includes('i <= arr.length')) {
bugs.push({
type: 'off_by_one',
severity: 'MEDIUM',
category: 'Logic Error',
description: 'Off-by-one error in loop condition',
line: 1,
effort: 1
});
}
// Type mismatch detection
if (content.includes('if (x == y)') && !content.includes('if (x === y)')) {
bugs.push({
type: 'type_coercion',
severity: 'MEDIUM',
category: 'Type Error',
description: 'Type coercion with == operator - should use ===',
line: 1,
effort: 1
});
}
if (content.includes('return a + b') && content.includes('function addNumbers')) {
bugs.push({
type: 'type_mismatch',
severity: 'MEDIUM',
category: 'Type Error',
description: 'Potential string concatenation instead of numeric addition',
line: 1,
effort: 2
});
}
if (content.includes('data.map(') && !content.includes('Array.isArray(data)')) {
bugs.push({
type: 'type_mismatch',
severity: 'MEDIUM',
category: 'Type Error',
description: 'Assuming data is array without validation',
line: 1,
effort: 1
});
}
// Error handling detection - specific patterns from test
if (content.includes('const response = await fetch(url);') && !content.includes('try')) {
bugs.push({
type: 'missing_error_handling',
severity: 'MEDIUM',
category: 'Error Handling',
description: 'Async fetch operation without error handling',
line: 1,
effort: 1
});
}
if (content.includes('return JSON.parse(jsonString);') && !content.includes('try')) {
bugs.push({
type: 'missing_error_handling',
severity: 'MEDIUM',
category: 'Error Handling',
description: 'JSON.parse without error handling',
line: 1,
effort: 1
});
}
if (content.includes('return a / b;') && !content.includes('if (b === 0)') && !content.includes('if (b !== 0)')) {
bugs.push({
type: 'missing_error_handling',
severity: 'MEDIUM',
category: 'Error Handling',
description: 'Division without zero check',
line: 1,
effort: 1
});
}
if (content.includes('fs.readFileSync(filename)') && !content.includes('try')) {
bugs.push({
type: 'unhandled_exception',
severity: 'MEDIUM',
category: 'Error Handling',
description: 'File operation without error handling',
line: 1,
effort: 1
});
}
// Async/await pattern detection
if (content.includes('return fetch(') && !content.includes('await fetch(') && !content.includes('async function')) {
bugs.push({
type: 'missing_await',
severity: 'HIGH',
category: 'Async/Await',
description: 'Missing await keyword for Promise',
line: 1,
effort: 1
});
}
if (content.includes('return promise1 + promise2')) {
bugs.push({
type: 'async_pattern',
severity: 'HIGH',
category: 'Async/Await',
description: 'Incorrect Promise usage - should await promises',
line: 1,
effort: 2
});
}
return {
file: filePath,
bugs,
bugCount: bugs.length
};
} catch (error) {
return {
file: filePath,
bugs: [],
bugCount: 0,
error: error.message
};
}
}
module.exports = {
analyzeFileStaticBugs
};