Fix js-prototype-assignment on declarations

This commit is contained in:
Nathan Shively-Sanders 2018-02-22 12:52:50 -08:00
parent d55aa22d15
commit aa88f71c2e
5 changed files with 156 additions and 11 deletions

View File

@ -17915,15 +17915,34 @@ namespace ts {
function getAssignedClassType(symbol: Symbol) {
const decl = symbol.valueDeclaration;
const assignmentSymbol = decl && decl.parent && isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left);
const assignmentSymbol = decl && decl.parent &&
(isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
if (assignmentSymbol) {
const prototype = forEach(assignmentSymbol.declarations, d => getAssignedJavascriptPrototype(d.parent));
const prototype = forEach(assignmentSymbol.declarations, getAssignedJavascriptPrototype);
if (prototype) {
return checkExpression(prototype);
}
}
}
function getAssignedJavascriptPrototype(node: Node) {
if (!node.parent) {
return false;
}
let parent: Node = node.parent;
while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) {
parent = parent.parent;
}
return parent && isBinaryExpression(parent) &&
isPropertyAccessExpression(parent.left) &&
parent.left.name.escapedText === "prototype" &&
parent.operatorToken.kind === SyntaxKind.EqualsToken &&
isObjectLiteralExpression(parent.right) &&
parent.right;
}
function getInferredClassType(symbol: Symbol) {
const links = getSymbolLinks(symbol);
if (!links.inferredClassType) {

View File

@ -1488,18 +1488,10 @@ namespace ts {
return symbol;
}
const declaration = symbol.valueDeclaration;
const e = getDeclaredJavascriptInitializer(declaration) || getAssignedJavascriptInitializer(declaration) || getAssignedJavascriptPrototype(declaration);
const e = getDeclaredJavascriptInitializer(declaration) || getAssignedJavascriptInitializer(declaration);
return e ? e.symbol : symbol;
}
export function getAssignedJavascriptPrototype(node: Node) {
return isPropertyAccessExpression(node) &&
node.parent && isPropertyAccessExpression(node.parent) && node.parent.name.escapedText === "prototype" &&
node.parent.parent && isBinaryExpression(node.parent.parent) && node.parent.parent.operatorToken.kind === SyntaxKind.EqualsToken &&
node.parent.parent.right.kind === SyntaxKind.ObjectLiteralExpression &&
node.parent.parent.right;
}
export function getDeclaredJavascriptInitializer(node: Node) {
if (node && isVariableDeclaration(node) && node.initializer) {
return getJavascriptInitializer(node.initializer) ||

View File

@ -0,0 +1,52 @@
=== tests/cases/conformance/salsa/module.js ===
var Inner = function() {}
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
Inner.prototype = {
>Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
m() { },
>m : Symbol(m, Decl(module.js, 1, 19))
i: 1
>i : Symbol(i, Decl(module.js, 2, 12))
}
// incremental assignments still work
Inner.prototype.j = 2
>Inner.prototype : Symbol(Inner.j, Decl(module.js, 4, 1))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>j : Symbol(Inner.j, Decl(module.js, 4, 1))
/** @type {string} */
Inner.prototype.k;
>Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
var inner = new Inner()
>inner : Symbol(inner, Decl(module.js, 9, 3))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
inner.m()
>inner.m : Symbol(m, Decl(module.js, 1, 19))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>m : Symbol(m, Decl(module.js, 1, 19))
inner.i
>inner.i : Symbol(i, Decl(module.js, 2, 12))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>i : Symbol(i, Decl(module.js, 2, 12))
inner.j
>inner.j : Symbol(Inner.j, Decl(module.js, 4, 1))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>j : Symbol(Inner.j, Decl(module.js, 4, 1))
inner.k
>inner.k : Symbol(Inner.k, Decl(module.js, 6, 21))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>k : Symbol(Inner.k, Decl(module.js, 6, 21))

View File

@ -0,0 +1,63 @@
=== tests/cases/conformance/salsa/module.js ===
var Inner = function() {}
>Inner : () => void
>function() {} : () => void
Inner.prototype = {
>Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Inner.prototype : any
>Inner : () => void
>prototype : any
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
>m : () => void
i: 1
>i : number
>1 : 1
}
// incremental assignments still work
Inner.prototype.j = 2
>Inner.prototype.j = 2 : 2
>Inner.prototype.j : any
>Inner.prototype : any
>Inner : () => void
>prototype : any
>j : any
>2 : 2
/** @type {string} */
Inner.prototype.k;
>Inner.prototype.k : any
>Inner.prototype : any
>Inner : () => void
>prototype : any
>k : any
var inner = new Inner()
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>new Inner() : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>Inner : () => void
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>m : () => void
inner.i
>inner.i : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>i : number
inner.j
>inner.j : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>j : number
inner.k
>inner.k : string
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>k : string

View File

@ -0,0 +1,19 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @target: es6
// @Filename: module.js
var Inner = function() {}
Inner.prototype = {
m() { },
i: 1
}
// incremental assignments still work
Inner.prototype.j = 2
/** @type {string} */
Inner.prototype.k;
var inner = new Inner()
inner.m()
inner.i
inner.j
inner.k