auto-cr-rules
Version:
Extensible static analysis rule set for the auto-cr automated code review toolkit
159 lines (158 loc) • 5.84 kB
JavaScript
;
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;
}
};