diff --git a/src/definition.js b/src/definition.js index faef938..8c8d338 100644 --- a/src/definition.js +++ b/src/definition.js @@ -28,7 +28,7 @@ import Variable from './variable'; * @class Definition */ export default class Definition { - constructor(type, name, node, parent, index, kind) { + constructor(type, name, node, parent, index, kind, inner) { /** * @member {String} Definition#type - type of the occurrence (e.g. "Parameter", "Variable", ...). */ @@ -53,6 +53,10 @@ export default class Definition { * @member {String?} Definition#kind - the kind of the declaration statement. */ this.kind = kind; + /** + * @member {Variable} Definition#inner - the reference to the inner scope variable. + */ + this.inner = inner; } } diff --git a/src/referencer.js b/src/referencer.js index bd81080..4f94e7e 100644 --- a/src/referencer.js +++ b/src/referencer.js @@ -233,17 +233,7 @@ export default class Referencer extends esrecurse.Visitor { } visitClass(node) { - if (node.type === Syntax.ClassDeclaration) { - this.currentScope().__define(node.id, - new Definition( - Variable.ClassName, - node.id, - node, - null, - null, - null - )); - } + var innerVariable; // FIXME: Maybe consider TDZ. this.visit(node.superClass); @@ -251,7 +241,7 @@ export default class Referencer extends esrecurse.Visitor { this.scopeManager.__nestClassScope(node); if (node.id) { - this.currentScope().__define(node.id, + innerVariable = this.currentScope().__define(node.id, new Definition( Variable.ClassName, node.id, @@ -261,6 +251,19 @@ export default class Referencer extends esrecurse.Visitor { this.visit(node.body); this.close(node); + + if (node.type === Syntax.ClassDeclaration) { + this.currentScope().__define(node.id, + new Definition( + Variable.ClassName, + node.id, + node, + null, + null, + null, + innerVariable + )); + } } visitProperty(node) { diff --git a/src/scope.js b/src/scope.js index 0e4d8c2..09dd3d4 100644 --- a/src/scope.js +++ b/src/scope.js @@ -352,11 +352,13 @@ export default class Scope { if (node) { variable.identifiers.push(node); } + + return variable; } __define(node, def) { if (node && node.type === Syntax.Identifier) { - this.__defineGeneric( + return this.__defineGeneric( node.name, this.set, this.variables, @@ -504,7 +506,7 @@ export class GlobalScope extends Scope { __defineImplicit(node, def) { if (node && node.type === Syntax.Identifier) { - this.__defineGeneric( + return this.__defineGeneric( node.name, this.implicit.set, this.implicit.variables, diff --git a/test/es6-class.js b/test/es6-class.js index 8c6ffac..dac5b7e 100644 --- a/test/es6-class.js +++ b/test/es6-class.js @@ -191,6 +191,47 @@ describe('ES6 class', function() { expect(scope.references[0].identifier.name).to.be.equal('shoe'); expect(scope.references[1].identifier.name).to.be.equal('Shoe'); }); + + it('reference in class', function() { + const ast = parse(` + class Foo { + constructor() { + Foo; + } + } + `); + + + const scopeManager = analyze(ast, {ecmaVersion: 6}); + expect(scopeManager.scopes).to.have.length(3); + + let scope = scopeManager.scopes[0]; + expect(scope.type).to.be.equal('global'); + expect(scope.block.type).to.be.equal('Program'); + expect(scope.isStrict).to.be.false; + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal('Foo'); + expect(scope.variables[0].defs).to.have.length(1); + + let classDef = scope.variables[0].defs[0] + + scope = scopeManager.scopes[1]; + expect(scope.type).to.be.equal('class'); + expect(scope.block.type).to.be.equal('ClassDeclaration'); + expect(scope.isStrict).to.be.true; + expect(scope.variables).to.have.length(1); + expect(classDef.inner).to.be.equal(scope.variables[0]); + expect(scope.references).to.have.length(0); + + scope = scopeManager.scopes[2]; + expect(scope.type).to.be.equal('function'); + expect(scope.block.type).to.be.equal('FunctionExpression'); + expect(scope.isStrict).to.be.true; + expect(scope.variables).to.have.length(1); + expect(scope.variables[0].name).to.be.equal('arguments'); + expect(scope.references).to.have.length(1); + expect(scope.references[0].identifier.name).to.be.equal('Foo'); + }); }); // vim: set sw=4 ts=4 et tw=80 :