@maniascript/mslint
Version:
ManiaScript linter
83 lines (82 loc) • 3.24 kB
JavaScript
import {} from '../linter/rule.js';
import { Scope, ScopeType, Variable } from '@maniascript/parser';
const DEFAULT_EXCEPTIONS = [];
export const noUnusedVariables = {
meta: {
id: 'no-unused-variables',
description: 'Forbid unused variables',
recommended: true,
settings: {
exceptions: DEFAULT_EXCEPTIONS
}
},
create(context) {
const exceptions = Array.isArray(context.settings['exceptions']) ? context.settings['exceptions'] : DEFAULT_EXCEPTIONS;
function getReportMessage(name, variable, isWrite) {
let type = '';
if (variable.isFunctionParameter) {
type = 'Function parameter';
}
else if (variable.isGlobal) {
type = 'Global variable';
}
else if (variable.isForValue) {
type = 'For value';
}
else if (variable.isForeachKey) {
type = 'Foreach key';
}
else if (variable.isForeachValue) {
type = 'Foreach value';
}
else {
type = 'Variable';
}
let action = '';
if (isWrite) {
action = 'never read';
}
else {
action = 'never used';
}
return `${type} '${name}' is ${action}`;
}
function findUnusedVariables(context, scope) {
if (scope.type !== ScopeType.LabelDeclaration && !scope.couldReferenceVariableInLabel) {
let hasForeachKey = false;
let useForeachKey = true;
for (const [name, variable] of scope.variables) {
if (variable.isForeachKey) {
hasForeachKey = true;
}
if (!variable.isForValue && // Allow unused for value
(!variable.isForeachValue || !hasForeachKey || !useForeachKey) && // Allow unused foreach value if the key is used
!exceptions.includes(name)) {
if (variable.references.length === 0) {
if (variable.isForeachKey) {
useForeachKey = false;
}
context.report(variable.node, getReportMessage(name, variable, false));
}
else if (!variable.isTrait && variable.references.every((reference) => reference.isWrite())) {
if (variable.isForeachKey) {
useForeachKey = false;
}
context.report(variable.node, getReportMessage(name, variable, true));
}
}
}
}
for (const child of scope.children) {
findUnusedVariables(context, child);
}
}
return {
'Program:exit': () => {
const scope = context.getScope();
if (scope !== null)
findUnusedVariables(context, scope);
}
};
}
};