Skip to content

feat(parser): Draft of scope analysis with types #1533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
31 changes: 7 additions & 24 deletions packages/eslint-plugin/src/rules/no-unused-vars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,24 @@ export default util.createRule({
create(context) {
const rules = baseRule.create(context);

/**
* Mark heritage clause as used
* @param node The node currently being traversed
*/
function markHeritageAsUsed(node: TSESTree.Expression): void {
function markParameterAsUsed(node: TSESTree.Node): void {
switch (node.type) {
case AST_NODE_TYPES.Identifier:
context.markVariableAsUsed(node.name);
break;
case AST_NODE_TYPES.MemberExpression:
markHeritageAsUsed(node.object);
case AST_NODE_TYPES.AssignmentPattern:
markParameterAsUsed(node.left);
break;
case AST_NODE_TYPES.CallExpression:
markHeritageAsUsed(node.callee);
case AST_NODE_TYPES.RestElement:
markParameterAsUsed(node.argument);
break;
}
}

return Object.assign({}, rules, {
'TSTypeReference Identifier'(node: TSESTree.Identifier) {
context.markVariableAsUsed(node.name);
},
TSInterfaceHeritage(node: TSESTree.TSInterfaceHeritage) {
if (node.expression) {
markHeritageAsUsed(node.expression);
}
},
TSClassImplements(node: TSESTree.TSClassImplements) {
if (node.expression) {
markHeritageAsUsed(node.expression);
}
},
'TSParameterProperty Identifier'(node: TSESTree.Identifier) {
TSParameterProperty(node: TSESTree.TSParameterProperty) {
// just assume parameter properties are used
context.markVariableAsUsed(node.name);
markParameterAsUsed(node.parameter);
},
'TSEnumMember Identifier'(node: TSESTree.Identifier) {
context.markVariableAsUsed(node.name);
Expand Down
18 changes: 18 additions & 0 deletions packages/eslint-plugin/src/rules/no-use-before-define.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ function isOuterVariable(
);
}

/**
* Checks whether or not a given variable is a type declaration.
*/
function isType(
variable: TSESLint.Scope.Variable,
reference: TSESLint.Scope.Reference,
): boolean {
const node = variable.defs[0].node as TSESTree.Node;

return (
node.type === AST_NODE_TYPES.TSTypeAliasDeclaration &&
isOuterScope(variable, reference)
);
}

/**
* Checks whether or not a given location is inside of the range of a given node.
*/
Expand Down Expand Up @@ -231,6 +246,9 @@ export default util.createRule<Options, MessageIds>({
if (isOuterClass(variable, reference)) {
return !!options.classes;
}
if (isType(variable, reference)) {
return !!options.typedefs;
}
if (isOuterVariable(variable, reference)) {
return !!options.variables;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ interface B<T> {}
type C<T> = Array<T>
class D<T> {}
`,
`
interface foo<TMessageIds> {}
interface bar<TMessageIds> {}
`,
],
invalid: [
{
Expand Down
47 changes: 42 additions & 5 deletions packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { RuleTester } from '../RuleTester';

const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 6,
ecmaVersion: 10,
sourceType: 'module',
ecmaFeatures: {},
},
env: { es6: true },
parser: '@typescript-eslint/parser',
});

Expand Down Expand Up @@ -35,12 +35,16 @@ class X {
}
`,
// https://github.com/eslint/typescript-eslint-parser/issues/466
`
{
code: `
/*globals document, selector */
const links = document.querySelectorAll( selector ) as NodeListOf<HTMLElement>
`,
`,
env: { browser: true },
},
// https://github.com/eslint/typescript-eslint-parser/issues/437
`
type Result = string
interface Runnable {
run (): Result
toString (): string
Expand All @@ -60,7 +64,7 @@ export class FooBar extends Foo {}
// https://github.com/typescript-eslint/typescript-eslint/issues/18
`
function eachr<Key, Value>(subject: Map<Key, Value>): typeof subject;
function eachr(subject: Object | Array<Value>): typeof subject {
function eachr<Value = string>(subject: Object | Array<Value>): typeof subject {
return subject
}
`,
Expand All @@ -85,6 +89,18 @@ function eachr<Key, Value>(subject: Map<Key, Value>): typeof subject;
var a = { b: () => {} };
a?.b();
`,
// https://github.com/typescript-eslint/typescript-eslint/issues/262
`
export default class Foo {
[key: string]: any;
}
`,
// https://github.com/typescript-eslint/typescript-eslint/issues/262
`
export default interface Foo {
[key: string]: any;
}
`,
],
invalid: [
{
Expand Down Expand Up @@ -120,5 +136,26 @@ function eachr<Key, Value>(subject: Map<Key, Value>): typeof subject;
},
],
},
{
code: 'function foo(subject: Object<Key> | Array<Value>)',
errors: [
{
messageId: 'undef',
data: {
name: 'Key',
},
line: 1,
column: 30,
},
{
messageId: 'undef',
data: {
name: 'Value',
},
line: 1,
column: 43,
},
],
},
],
});
Loading