UNPKG

auto-cr-rules

Version:

Extensible static analysis rule set for the auto-cr automated code review toolkit

159 lines (158 loc) 5.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.noSwallowedErrors = void 0; var types_1 = require("../types"); exports.noSwallowedErrors = (0, types_1.defineRule)('no-swallowed-errors', { tag: 'base', severity: types_1.RuleSeverity.Warning }, function (_a) { var _b, _c; var ast = _a.ast, helpers = _a.helpers, messages = _a.messages, source = _a.source; var moduleStart = (_c = (_b = ast.span) === null || _b === void 0 ? void 0 : _b.start) !== null && _c !== void 0 ? _c : 0; var lineIndex = buildLineIndex(source); visitTryStatements(ast, function (tryStatement) { var _a, _b, _c, _d, _e; var catchBlock = (_b = (_a = tryStatement.handler) === null || _a === void 0 ? void 0 : _a.body) !== null && _b !== void 0 ? _b : null; var finallyBlock = (_c = tryStatement.finalizer) !== null && _c !== void 0 ? _c : null; var catchHasExecutable = catchBlock ? hasExecutableStatements(catchBlock.stmts) : false; var finallyHasExecutable = finallyBlock ? hasExecutableStatements(finallyBlock.stmts) : false; if (catchHasExecutable || finallyHasExecutable) { return; } var reportSpan = (_e = (_d = catchBlock === null || catchBlock === void 0 ? void 0 : catchBlock.span) !== null && _d !== void 0 ? _d : finallyBlock === null || finallyBlock === void 0 ? void 0 : finallyBlock.span) !== null && _e !== void 0 ? _e : tryStatement.span; var charIndex = bytePosToCharIndex(source, moduleStart, reportSpan.start); var computedLine = resolveLine(lineIndex, charIndex); var fallbackLine = determineFallbackLine({ source: source, computedLine: computedLine, hasCatch: Boolean(catchBlock), hasFinally: Boolean(finallyBlock), }); var line = selectLineNumber(computedLine, fallbackLine); helpers.reportViolation({ description: messages.swallowedError(), line: line, span: reportSpan, }, reportSpan); }); }); var buildLineIndex = function (source) { var offsets = [0]; for (var index = 0; index < source.length; index += 1) { if (source[index] === '\n') { offsets.push(index + 1); } } return { offsets: offsets }; }; var resolveLine = function (_a, position) { var offsets = _a.offsets; var low = 0; var high = offsets.length - 1; while (low <= high) { var mid = Math.floor((low + high) / 2); var current = offsets[mid]; if (current === position) { return mid + 1; } if (current < position) { low = mid + 1; } else { high = mid - 1; } } return high + 1; }; var readUtf8Character = function (source, index, code) { if (code <= 0x7f) { return { bytes: 1, nextIndex: index + 1 }; } if (code <= 0x7ff) { return { bytes: 2, nextIndex: index + 1 }; } if (code >= 0xd800 && code <= 0xdbff && index + 1 < source.length) { var next = source.charCodeAt(index + 1); if (next >= 0xdc00 && next <= 0xdfff) { return { bytes: 4, nextIndex: index + 2 }; } } return { bytes: 3, nextIndex: index + 1 }; }; var bytePosToCharIndex = function (source, moduleStart, bytePos) { var target = Math.max(bytePos - moduleStart, 0); if (target === 0) { return 0; } var index = 0; var byteOffset = 0; while (index < source.length) { var code = source.charCodeAt(index); var _a = readUtf8Character(source, index, code), bytes = _a.bytes, nextIndex = _a.nextIndex; if (byteOffset + bytes > target) { return index; } byteOffset += bytes; index = nextIndex; } return source.length; }; var determineFallbackLine = function (_a) { var source = _a.source, computedLine = _a.computedLine, hasCatch = _a.hasCatch, hasFinally = _a.hasFinally; if (hasCatch) { return findKeywordLine(source, computedLine, /\bcatch\b/); } if (hasFinally) { return findKeywordLine(source, computedLine, /\bfinally\b/); } return findKeywordLine(source, computedLine, /\btry\b/); }; var findKeywordLine = function (source, computedLine, pattern) { var lines = source.split(/\r?\n/); var startIndex = Math.max((computedLine !== null && computedLine !== void 0 ? computedLine : 1) - 1, 0); for (var index = startIndex; index < lines.length; index += 1) { if (pattern.test(lines[index])) { return index + 1; } } return undefined; }; var selectLineNumber = function (computed, fallback) { if (fallback === undefined) { return computed; } if (computed === undefined) { return fallback; } if (computed < fallback) { return fallback; } return computed; }; var visitTryStatements = function (ast, callback) { var queue = [ast]; while (queue.length > 0) { var current = queue.pop(); if (!current || typeof current !== 'object') { continue; } var candidate = current; if (candidate.type === 'TryStatement') { callback(candidate); } for (var _i = 0, _a = Object.values(candidate); _i < _a.length; _i++) { var value = _a[_i]; queue.push(value); } } }; var hasExecutableStatements = function (statements) { return statements.some(isExecutableStatement); }; var isExecutableStatement = function (statement) { switch (statement.type) { case 'EmptyStatement': return false; case 'BlockStatement': return hasExecutableStatements(statement.stmts); default: return true; } };