Fix type param and interface declaration scoping (babel/babel-eslint#449)
This commit is contained in:
parent
700f62e28e
commit
1c5400a670
@ -180,18 +180,6 @@ function monkeypatch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function visitTypeParameters(typeParameters) {
|
|
||||||
var params = typeParameters.params;
|
|
||||||
|
|
||||||
// visit bounds on polymorphpic types, eg; `Foo` in `fn<T: Foo>(a: T): T`
|
|
||||||
for (var i = 0; i < params.length; i++) {
|
|
||||||
var param = params[i];
|
|
||||||
if (param.typeAnnotation) {
|
|
||||||
visitTypeAnnotation.call(this, param.typeAnnotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkIdentifierOrVisit(node) {
|
function checkIdentifierOrVisit(node) {
|
||||||
if (node.typeAnnotation) {
|
if (node.typeAnnotation) {
|
||||||
visitTypeAnnotation.call(this, node.typeAnnotation);
|
visitTypeAnnotation.call(this, node.typeAnnotation);
|
||||||
@ -209,6 +197,9 @@ function monkeypatch() {
|
|||||||
for (var j = 0; j < node.typeParameters.params.length; j++) {
|
for (var j = 0; j < node.typeParameters.params.length; j++) {
|
||||||
var name = node.typeParameters.params[j];
|
var name = node.typeParameters.params[j];
|
||||||
scope.__define(name, new Definition("TypeParameter", name, name));
|
scope.__define(name, new Definition("TypeParameter", name, name));
|
||||||
|
if (name.typeAnnotation) {
|
||||||
|
checkIdentifierOrVisit.call(this, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
scope.__define = function() {
|
scope.__define = function() {
|
||||||
return parentScope.__define.apply(parentScope, arguments);
|
return parentScope.__define.apply(parentScope, arguments);
|
||||||
@ -222,7 +213,7 @@ function monkeypatch() {
|
|||||||
visitDecorators.call(this, node);
|
visitDecorators.call(this, node);
|
||||||
var typeParamScope;
|
var typeParamScope;
|
||||||
if (node.typeParameters) {
|
if (node.typeParameters) {
|
||||||
typeParamScope = nestTypeParamScope(this.scopeManager, node);
|
typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
||||||
}
|
}
|
||||||
// visit flow type: ClassImplements
|
// visit flow type: ClassImplements
|
||||||
if (node.implements) {
|
if (node.implements) {
|
||||||
@ -264,8 +255,7 @@ function monkeypatch() {
|
|||||||
referencer.prototype.visitFunction = function(node) {
|
referencer.prototype.visitFunction = function(node) {
|
||||||
var typeParamScope;
|
var typeParamScope;
|
||||||
if (node.typeParameters) {
|
if (node.typeParameters) {
|
||||||
typeParamScope = nestTypeParamScope(this.scopeManager, node);
|
typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
||||||
visitTypeParameters.call(this, node.typeParameters);
|
|
||||||
}
|
}
|
||||||
if (node.returnType) {
|
if (node.returnType) {
|
||||||
checkIdentifierOrVisit.call(this, node.returnType);
|
checkIdentifierOrVisit.call(this, node.returnType);
|
||||||
@ -328,11 +318,27 @@ function monkeypatch() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
referencer.prototype.InterfaceDeclaration = function(node) {
|
||||||
|
createScopeVariable.call(this, node, node.id);
|
||||||
|
var typeParamScope;
|
||||||
|
if (node.typeParameters) {
|
||||||
|
typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
||||||
|
}
|
||||||
|
// TODO: Handle mixins
|
||||||
|
for (var i = 0; i < node.extends.length; i++) {
|
||||||
|
visitTypeAnnotation.call(this, node.extends[i]);
|
||||||
|
}
|
||||||
|
visitTypeAnnotation.call(this, node.body);
|
||||||
|
if (typeParamScope) {
|
||||||
|
this.close(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
referencer.prototype.TypeAlias = function(node) {
|
referencer.prototype.TypeAlias = function(node) {
|
||||||
createScopeVariable.call(this, node, node.id);
|
createScopeVariable.call(this, node, node.id);
|
||||||
var typeParamScope;
|
var typeParamScope;
|
||||||
if (node.typeParameters) {
|
if (node.typeParameters) {
|
||||||
typeParamScope = nestTypeParamScope(this.scopeManager, node);
|
typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
||||||
}
|
}
|
||||||
if (node.right) {
|
if (node.right) {
|
||||||
visitTypeAnnotation.call(this, node.right);
|
visitTypeAnnotation.call(this, node.right);
|
||||||
@ -352,7 +358,7 @@ function monkeypatch() {
|
|||||||
|
|
||||||
var typeParamScope;
|
var typeParamScope;
|
||||||
if (node.typeParameters) {
|
if (node.typeParameters) {
|
||||||
typeParamScope = nestTypeParamScope(this.scopeManager, node);
|
typeParamScope = nestTypeParamScope.call(this, this.scopeManager, node);
|
||||||
}
|
}
|
||||||
if (typeParamScope) {
|
if (typeParamScope) {
|
||||||
this.close(node);
|
this.close(node);
|
||||||
|
|||||||
@ -222,16 +222,73 @@ describe("verify", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("type parameter bounds", () => {
|
it("interface declaration", () => {
|
||||||
|
verifyAndAssertMessages(
|
||||||
|
unpad(`
|
||||||
|
interface Foo {};
|
||||||
|
interface Bar {
|
||||||
|
foo: Foo,
|
||||||
|
};
|
||||||
|
`),
|
||||||
|
{ "no-unused-vars": 1, "no-undef": 1 },
|
||||||
|
[ "2:11 'Bar' is defined but never used. no-unused-vars" ]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("type parameter bounds (classes)", () => {
|
||||||
|
verifyAndAssertMessages(
|
||||||
|
unpad(`
|
||||||
|
import type {Foo, Foo2} from 'foo';
|
||||||
|
import Base from 'base';
|
||||||
|
class Log<T1: Foo, T2: Foo2, T3, T4> extends Base<T3> {
|
||||||
|
messages: {[T1]: T2};
|
||||||
|
}
|
||||||
|
new Log();
|
||||||
|
`),
|
||||||
|
{ "no-unused-vars": 1, "no-undef": 1 },
|
||||||
|
[ "3:34 'T4' is defined but never used. no-unused-vars" ]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("type parameter bounds (interfaces)", () => {
|
||||||
|
verifyAndAssertMessages(
|
||||||
|
unpad(`
|
||||||
|
import type {Foo, Foo2, Bar} from '';
|
||||||
|
interface Log<T1: Foo, T2: Foo2, T3, T4> extends Bar<T3> {
|
||||||
|
messages: {[T1]: T2};
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
{ "no-unused-vars": 1, "no-undef": 1 },
|
||||||
|
[ "2:11 'Log' is defined but never used. no-unused-vars",
|
||||||
|
"2:38 'T4' is defined but never used. no-unused-vars" ]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("type parameter bounds (type aliases)", () => {
|
||||||
|
verifyAndAssertMessages(
|
||||||
|
unpad(`
|
||||||
|
import type {Foo, Foo2, Foo3} from 'foo';
|
||||||
|
type Log<T1: Foo, T2: Foo2, T3> = {
|
||||||
|
messages: {[T1]: T2};
|
||||||
|
delay: Foo3;
|
||||||
|
};
|
||||||
|
`),
|
||||||
|
{ "no-unused-vars": 1, "no-undef": 1 },
|
||||||
|
[ "2:6 'Log' is defined but never used. no-unused-vars",
|
||||||
|
"2:29 'T3' is defined but never used. no-unused-vars" ]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("type parameter bounds (functions)", () => {
|
||||||
verifyAndAssertMessages(
|
verifyAndAssertMessages(
|
||||||
unpad(`
|
unpad(`
|
||||||
import type Foo from 'foo';
|
import type Foo from 'foo';
|
||||||
import type Foo2 from 'foo';
|
import type Foo2 from 'foo';
|
||||||
function log<T1: Foo, T2: Foo2>(a: T1, b: T2) { return a + b; }
|
function log<T1: Foo, T2: Foo2, T3, T4>(a: T1, b: T2): T3 { return a + b; }
|
||||||
log(1, 2);
|
log(1, 2);
|
||||||
`),
|
`),
|
||||||
{ "no-unused-vars": 1, "no-undef": 1 },
|
{ "no-unused-vars": 1, "no-undef": 1 },
|
||||||
[]
|
[ "3:37 'T4' is defined but never used. no-unused-vars" ]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user