diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9bd51f0c763..f91cf107749 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -635,7 +635,6 @@ namespace ts { function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: string) { let symbol = createSymbol(symbolFlags, name); addDeclarationToSymbol(symbol, node, symbolFlags); - return symbol; } function bindBlockScopedDeclaration(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { @@ -889,6 +888,11 @@ namespace ts { case SpecialPropertyAssignmentKind.ThisProperty: bindThisPropertyAssignment(node); break; + case SpecialPropertyAssignmentKind.None: + // Nothing to do + break; + default: + Debug.fail("Unknown special property assignment kind"); } } return checkStrictModeBinaryExpression(node); @@ -1080,19 +1084,19 @@ namespace ts { // The function is now a constructor rather than a normal function if (!funcSymbol.inferredConstructor) { + // Have the binder set up all the related class symbols for us declareSymbol(container.locals, funcSymbol, funcSymbol.valueDeclaration, SymbolFlags.Class, SymbolFlags.None); - // funcSymbol.flags = (funcSymbol.flags | SymbolFlags.Class) & ~SymbolFlags.Function; - funcSymbol.members = funcSymbol.members || {}; + // funcSymbol.members = funcSymbol.members || {}; funcSymbol.members["__constructor"] = funcSymbol; funcSymbol.inferredConstructor = true; } - // Declare the 'prototype' member of the function - let prototypeSymbol = declareSymbol(funcSymbol.exports, funcSymbol, (node.left).expression, SymbolFlags.ObjectLiteral | SymbolFlags.Property, SymbolFlags.None); + // Get the exports of the class so we can add the method to it + let funcExports = declareSymbol(funcSymbol.exports, funcSymbol, (node.left).expression, SymbolFlags.ObjectLiteral | SymbolFlags.Property, SymbolFlags.None); - // Declare the property on the prototype symbol - declareSymbol(prototypeSymbol.members, prototypeSymbol, node.left, SymbolFlags.Method, SymbolFlags.None); - // and on the class type + // Declare the method + declareSymbol(funcExports.members, funcExports, node.left, SymbolFlags.Method, SymbolFlags.None); + // and on the members of the function so it appears in 'prototype' declareSymbol(funcSymbol.members, funcSymbol, node.left, SymbolFlags.Method, SymbolFlags.PropertyExcludes); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fb7040a96ab..18a878ae91b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2577,9 +2577,11 @@ namespace ts { return links.type = checkExpression((declaration).right); } if (declaration.kind === SyntaxKind.PropertyAccessExpression) { + // Declarations only exist for property access expressions for certain + // special assignment kinds if (declaration.parent.kind === SyntaxKind.BinaryExpression) { // Handle exports.p = expr or this.p = expr or className.prototype.method = expr - return links.type = checkExpression((declaration.parent).right); + return links.type = checkExpressionCached((declaration.parent).right); } else { // Declaration for className.prototype in inferred JS class @@ -3860,6 +3862,7 @@ namespace ts { break; case SyntaxKind.PropertyAccessExpression: + // Inferred class method result = getSignaturesOfType(checkExpressionCached((node.parent).right), SignatureKind.Call); break; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cb72e87bb94..603f5a3d93c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1093,64 +1093,6 @@ namespace ts { return SpecialPropertyAssignmentKind.None; } - /** - * Returns true if the node is an assignment to a property on the identifier 'exports'. - * This function does not test if the node is in a JavaScript file or not. - */ - export function isExportsPropertyAssignment(expression: Node): boolean { - // of the form 'exports.name = expr' where 'name' and 'expr' are arbitrary - return isInJavaScriptFile(expression) && - (expression.kind === SyntaxKind.BinaryExpression) && - ((expression).operatorToken.kind === SyntaxKind.EqualsToken) && - ((expression).left.kind === SyntaxKind.PropertyAccessExpression) && - (((expression).left).expression.kind === SyntaxKind.Identifier) && - (((((expression).left).expression)).text === "exports"); - } - - /** - * Returns true if the node is an assignment to the property access expression 'module.exports'. - * This function does not test if the node is in a JavaScript file or not. - */ - export function isModuleExportsAssignment(expression: Node): boolean { - // of the form 'module.exports = expr' where 'expr' is arbitrary - return isInJavaScriptFile(expression) && - (expression.kind === SyntaxKind.BinaryExpression) && - ((expression).operatorToken.kind === SyntaxKind.EqualsToken) && - ((expression).left.kind === SyntaxKind.PropertyAccessExpression) && - (((expression).left).expression.kind === SyntaxKind.Identifier) && - (((((expression).left).expression)).text === "module") && - (((expression).left).name.text === "exports"); - } - - /** - * Returns true if this expression is an assignment to the given named property - */ - function isAssignmentToProperty(expression: Node, name?: string): expression is BinaryExpression { - return (expression.kind === SyntaxKind.BinaryExpression) && - ((expression).operatorToken.kind === SyntaxKind.EqualsToken) && - isNamedPropertyAccess((expression).left, name); - } - - /** - * Returns true if this expression is a PropertyAccessExpression where the property name is the provided name - */ - function isNamedPropertyAccess(expression: Node, name?: string): expression is PropertyAccessExpression { - return expression.kind === SyntaxKind.PropertyAccessExpression && - (!name || (expression).name.text === name); - } - - /** - * Returns true if the node is an assignment in the form 'id1.prototype.id2 = expr' where id1 and id2 - * are any identifier. - * This function does not test if the node is in a JavaScript file or not. - */ - export function isPrototypePropertyAssignment(expression: Node): expression is BinaryExpression { - return isAssignmentToProperty(expression) && - isNamedPropertyAccess(expression.left) && - isNamedPropertyAccess((expression.left).expression, "prototype") && - ((expression.left).expression).expression.kind === SyntaxKind.Identifier; - } - export function getExternalModuleName(node: Node): Expression { if (node.kind === SyntaxKind.ImportDeclaration) { return (node).moduleSpecifier; diff --git a/tests/cases/fourslash/javaScriptPrototype4.ts b/tests/cases/fourslash/javaScriptPrototype4.ts index f78bf52438b..3ed723740b4 100644 --- a/tests/cases/fourslash/javaScriptPrototype4.ts +++ b/tests/cases/fourslash/javaScriptPrototype4.ts @@ -23,7 +23,6 @@ verify.completionListContains('qua', undefined, undefined, 'warning'); // Check members of function.prototype edit.insert('prototype.'); -debug.printMemberListMembers(); verify.completionListContains('foo', undefined, undefined, 'method'); verify.completionListContains('bar', undefined, undefined, 'method'); verify.completionListContains('qua', undefined, undefined, 'warning');