From 5de87e30c66a9c859d0ebc363be8728ea6a98192 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 27 Jan 2016 14:00:33 -0800 Subject: [PATCH 01/13] Allow multiple 'this' property assignments in Salsa Fixes issue #6645 (cherry picked from commit 7259b9fd4aa29ffb83acfffd14f55e6bee8c5d87) --- src/compiler/binder.ts | 3 ++- .../getJavaScriptSemanticDiagnostics23.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/getJavaScriptSemanticDiagnostics23.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index cc81f92fbfc..1b70275b11c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1435,7 +1435,8 @@ namespace ts { // Declare a 'member' in case it turns out the container was an ES5 class if (container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.FunctionDeclaration) { container.symbol.members = container.symbol.members || {}; - declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + // It's acceptable for multiple 'this' assignments of the same identifier to occur + declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property); } } diff --git a/tests/cases/fourslash/getJavaScriptSemanticDiagnostics23.ts b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics23.ts new file mode 100644 index 00000000000..2524e50e668 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics23.ts @@ -0,0 +1,14 @@ +/// + +// @allowJs: true +// @Filename: a.js +//// function Person(age) { +//// if (age >= 18) { +//// this.canVote = true; +//// } else { +//// this.canVote = false; +//// } +//// } + +verify.getSyntacticDiagnostics(`[]`); +verify.getSemanticDiagnostics(`[]`); From 671d83e81adecf37258532fd8e6d061f0d0d888c Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 1 Feb 2016 20:59:37 -0800 Subject: [PATCH 02/13] Treat multiple prototype property assignments as union property declarations (cherry picked from commit a4c6f666862d14e187bb7e09615fdfc0c92ab875) --- src/compiler/checker.ts | 2 +- .../getJavaScriptSemanticDiagnostics24.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/getJavaScriptSemanticDiagnostics24.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e0caf84fa9d..93339901c07 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2845,7 +2845,7 @@ namespace ts { } // Handle module.exports = expr if (declaration.kind === SyntaxKind.BinaryExpression) { - return links.type = checkExpression((declaration).right); + return links.type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right))); } if (declaration.kind === SyntaxKind.PropertyAccessExpression) { // Declarations only exist for property access expressions for certain diff --git a/tests/cases/fourslash/getJavaScriptSemanticDiagnostics24.ts b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics24.ts new file mode 100644 index 00000000000..cf70f883e99 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptSemanticDiagnostics24.ts @@ -0,0 +1,16 @@ +/// + +// @allowJs: true +// @Filename: a.js +//// function Person(age) { +//// if (age >= 18) { +//// this.canVote = true; +//// } else { +//// this.canVote = 23; +//// } +//// } +//// let x = new Person(100); +//// x.canVote/**/; + +goTo.marker(); +verify.quickInfoIs('(property) Person.canVote: boolean | number'); From de2ef72d4f6136223658f5040cc550b2e33bdcf9 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 28 Jan 2016 11:39:19 -0800 Subject: [PATCH 03/13] Use union types in the return type of functions in the error case Fixes #6663 (cherry picked from commit da6e82f639a7cc96887fde34391a9c8c654fa301) --- src/compiler/checker.ts | 3 ++- .../fourslash/getJavaScriptCompletions19.ts | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/getJavaScriptCompletions19.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 93339901c07..c975127a62f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10433,7 +10433,8 @@ namespace ts { } else { error(func, Diagnostics.No_best_common_type_exists_among_return_expressions); - return unknownType; + // Defer to unioning the return types so we get a) downstream errors earlier and b) better Salsa experience + return getUnionType(types); } } diff --git a/tests/cases/fourslash/getJavaScriptCompletions19.ts b/tests/cases/fourslash/getJavaScriptCompletions19.ts new file mode 100644 index 00000000000..5a361930e86 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptCompletions19.ts @@ -0,0 +1,25 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: file.js +//// function fn() { +//// if (foo) { +//// return 0; +//// } else { +//// return '0'; +//// } +//// } +//// let x = fn(); +//// if(typeof x === 'string') { +//// x/*str*/ +//// } else { +//// x/*num*/ +//// } + +goTo.marker('str'); +edit.insert('.'); +verify.completionListContains('substr', undefined, undefined, 'method'); + +goTo.marker('num'); +edit.insert('.'); +verify.completionListContains('toFixed', undefined, undefined, 'method'); From eb27166b0953bec0af10d0565fc2b7b278f6c4cc Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 27 Jan 2016 14:07:32 -0800 Subject: [PATCH 04/13] Parse JSDoc comments for ES6 class constructors and methods Fixes #6646 (cherry picked from commit 1b282cda1de630186e9ad4aa20f30dfd66bb9c9b) --- src/compiler/parser.ts | 4 ++-- .../fourslash/getJavaScriptCompletions16.ts | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/getJavaScriptCompletions16.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 57bd9860d12..1ee74603825 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4778,7 +4778,7 @@ namespace ts { parseExpected(SyntaxKind.ConstructorKeyword); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false, Diagnostics.or_expected); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { @@ -4792,7 +4792,7 @@ namespace ts { const isAsync = !!(method.flags & NodeFlags.Async); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, method); method.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, diagnosticMessage); - return finishNode(method); + return addJSDocComment(finishNode(method)); } function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: PropertyName, questionToken: Node): ClassElement { diff --git a/tests/cases/fourslash/getJavaScriptCompletions16.ts b/tests/cases/fourslash/getJavaScriptCompletions16.ts new file mode 100644 index 00000000000..07c50d3f892 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptCompletions16.ts @@ -0,0 +1,18 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: file.js +//// "use strict"; +//// +//// class Something { +//// +//// /** +//// * @param {number} a +//// */ +//// constructor(a, b) { +//// a./**/ +//// } +//// } + +goTo.marker(); +verify.completionListContains('toFixed', undefined, undefined, 'method'); From 176baf904aead7b7c0f7dd9baa00df95e6709f85 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 1 Feb 2016 21:20:37 -0800 Subject: [PATCH 05/13] Add some tests (cherry picked from commit 3dfd378b7e0cf6fb685c63410439fdd12a672fb9) --- .../fourslash/getJavaScriptCompletions16.ts | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/getJavaScriptCompletions16.ts b/tests/cases/fourslash/getJavaScriptCompletions16.ts index 07c50d3f892..4d4b76d98d6 100644 --- a/tests/cases/fourslash/getJavaScriptCompletions16.ts +++ b/tests/cases/fourslash/getJavaScriptCompletions16.ts @@ -10,9 +10,26 @@ //// * @param {number} a //// */ //// constructor(a, b) { -//// a./**/ +//// a/*body*/ +//// } +//// +//// /** +//// * @param {number} a +//// */ +//// method(a) { +//// a/*method*/ //// } //// } +//// let x = new Something(/*sig*/); -goTo.marker(); +goTo.marker('body'); +edit.insert('.'); +verify.completionListContains('toFixed', undefined, undefined, 'method'); +edit.backspace(); + +goTo.marker('sig'); +verify.currentSignatureHelpIs('Something(a: number, b: any): Something'); + +goTo.marker('method'); +edit.insert('.'); verify.completionListContains('toFixed', undefined, undefined, 'method'); From 96ec9be6655b9095b6c6df4fd97f577a75d9ae00 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 28 Jan 2016 11:02:49 -0800 Subject: [PATCH 06/13] Recognize the RHS of assignments as the JSDoc target expression Fixes #6552 (cherry picked from commit 364b08854bc1face5c9b38301bb83c7346f1ccce) --- src/compiler/parser.ts | 6 +++--- src/compiler/utilities.ts | 14 ++++++++++++- .../fourslash/getJavaScriptCompletions18.ts | 21 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/getJavaScriptCompletions18.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1ee74603825..bd05ceb1bd2 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4051,7 +4051,7 @@ namespace ts { setDecoratorContext(/*val*/ true); } - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseOptionalIdentifier() { @@ -4335,13 +4335,13 @@ namespace ts { const labeledStatement = createNode(SyntaxKind.LabeledStatement, fullStart); labeledStatement.label = expression; labeledStatement.statement = parseStatement(); - return finishNode(labeledStatement); + return addJSDocComment(finishNode(labeledStatement)); } else { const expressionStatement = createNode(SyntaxKind.ExpressionStatement, fullStart); expressionStatement.expression = expression; parseSemicolon(); - return finishNode(expressionStatement); + return addJSDocComment(finishNode(expressionStatement)); } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8bcf89ce1f2..f6810fadf59 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1207,7 +1207,19 @@ namespace ts { node.parent.parent.parent.kind === SyntaxKind.VariableStatement; const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined; - return variableStatementNode && variableStatementNode.jsDocComment; + if (variableStatementNode) { + return variableStatementNode.jsDocComment; + } + + // Also recognize when the node is the RHS of an assignment expression + const isSourceOfAssignmentExpressionStatement = + node.parent && node.parent.parent && + node.parent.kind === SyntaxKind.BinaryExpression && + (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && + node.parent.parent.kind === SyntaxKind.ExpressionStatement; + if (isSourceOfAssignmentExpressionStatement) { + return node.parent.parent.jsDocComment; + } } return undefined; diff --git a/tests/cases/fourslash/getJavaScriptCompletions18.ts b/tests/cases/fourslash/getJavaScriptCompletions18.ts new file mode 100644 index 00000000000..a30d4943f4f --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptCompletions18.ts @@ -0,0 +1,21 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: file.js +//// /** +//// * @param {number} a +//// * @param {string} b +//// */ +//// exports.foo = function(a, b) { +//// a/*a*/; +//// b/*b*/ +//// }; + +goTo.marker('a'); +edit.insert('.'); +verify.completionListContains('toFixed', undefined, undefined, 'method'); + + +goTo.marker('b'); +edit.insert('.'); +verify.completionListContains('substr', undefined, undefined, 'method'); From f84bbcdf59a4ff1c9e4311ecf3eaad7b83bd2b8a Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 28 Jan 2016 15:18:50 -0800 Subject: [PATCH 07/13] Don't show the currently-completing thing at the cursor in JS files Fixes #6693 (cherry picked from commit 124bd517e71353d8c22c0ee63f2e830c0b18004c) --- src/services/services.ts | 23 +++++++++++-------- .../fourslash/getJavaScriptCompletions20.ts | 21 +++++++++++++++++ 2 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 tests/cases/fourslash/getJavaScriptCompletions20.ts diff --git a/src/services/services.ts b/src/services/services.ts index 0016a27acc3..58d5357eddb 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -62,7 +62,7 @@ namespace ts { export interface SourceFile { /* @internal */ version: string; /* @internal */ scriptSnapshot: IScriptSnapshot; - /* @internal */ nameTable: Map; + /* @internal */ nameTable: Map; /* @internal */ getNamedDeclarations(): Map; @@ -808,7 +808,7 @@ namespace ts { public languageVersion: ScriptTarget; public languageVariant: LanguageVariant; public identifiers: Map; - public nameTable: Map; + public nameTable: Map; public resolvedModules: Map; public imports: LiteralExpression[]; public moduleAugmentations: LiteralExpression[]; @@ -1957,8 +1957,6 @@ namespace ts { const text = scriptSnapshot.getText(0, scriptSnapshot.getLength()); const sourceFile = createSourceFile(fileName, text, scriptTarget, setNodeParents); setSourceFileFields(sourceFile, scriptSnapshot, version); - // after full parsing we can use table with interned strings as name table - sourceFile.nameTable = sourceFile.identifiers; return sourceFile; } @@ -3834,7 +3832,7 @@ namespace ts { if (isRightOfDot && isSourceFileJavaScript(sourceFile)) { const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries); - addRange(entries, getJavaScriptCompletionEntries(sourceFile, uniqueNames)); + addRange(entries, getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames)); } else { if (!symbols || symbols.length === 0) { @@ -3867,12 +3865,17 @@ namespace ts { return { isMemberCompletion, isNewIdentifierLocation, entries }; - function getJavaScriptCompletionEntries(sourceFile: SourceFile, uniqueNames: Map): CompletionEntry[] { + function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map): CompletionEntry[] { const entries: CompletionEntry[] = []; const target = program.getCompilerOptions().target; const nameTable = getNameTable(sourceFile); for (const name in nameTable) { + // Skip identifiers produced only from the current location + if (nameTable[name] === position) { + continue; + } + if (!uniqueNames[name]) { uniqueNames[name] = name; const displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks*/ true); @@ -7525,7 +7528,7 @@ namespace ts { } /* @internal */ - export function getNameTable(sourceFile: SourceFile): Map { + export function getNameTable(sourceFile: SourceFile): Map { if (!sourceFile.nameTable) { initializeNameTable(sourceFile); } @@ -7534,7 +7537,7 @@ namespace ts { } function initializeNameTable(sourceFile: SourceFile): void { - const nameTable: Map = {}; + const nameTable: Map = {}; walk(sourceFile); sourceFile.nameTable = nameTable; @@ -7542,7 +7545,7 @@ namespace ts { function walk(node: Node) { switch (node.kind) { case SyntaxKind.Identifier: - nameTable[(node).text] = (node).text; + nameTable[(node).text] = nameTable[(node).text] === undefined ? node.pos : -1; break; case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: @@ -7554,7 +7557,7 @@ namespace ts { node.parent.kind === SyntaxKind.ExternalModuleReference || isArgumentOfElementAccessExpression(node)) { - nameTable[(node).text] = (node).text; + nameTable[(node).text] = nameTable[(node).text] === undefined ? node.pos : -1; } break; default: diff --git a/tests/cases/fourslash/getJavaScriptCompletions20.ts b/tests/cases/fourslash/getJavaScriptCompletions20.ts new file mode 100644 index 00000000000..d254705bb91 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptCompletions20.ts @@ -0,0 +1,21 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: file.js +//// /** +//// * A person +//// * @constructor +//// * @param {string} name - The name of the person. +//// * @param {number} age - The age of the person. +//// */ +//// function Person(name, age) { +//// this.name = name; +//// this.age = age; +//// } +//// +//// +//// Person.getName = 10; +//// Person.getNa/**/ = 10; + +goTo.marker(); +verify.not.memberListContains('getNa'); From c6e18a9fcf3a560e26054e71cbfc4fec6ca1398e Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 28 Jan 2016 16:05:03 -0800 Subject: [PATCH 08/13] Fix case when position === 0 (cherry picked from commit 1231c9e145ef65cf51d5f582abfb71929892c48a) --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 58d5357eddb..058ae3e72cf 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5490,7 +5490,7 @@ namespace ts { const nameTable = getNameTable(sourceFile); - if (lookUp(nameTable, internedName)) { + if (lookUp(nameTable, internedName) !== undefined) { result = result || []; getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); } From f0e70cbf0fc1f9f3b65d36f4ece8db5e6719dde0 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 28 Jan 2016 15:48:18 -0800 Subject: [PATCH 09/13] Don't crash when return type jsdoc tag is malformed Fixes #6662 (cherry picked from commit 5a845bf0fca604a9928ec8762266231ec62fafda) --- src/compiler/checker.ts | 2 +- .../fourslash/getJavaScriptQuickInfo7.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/getJavaScriptQuickInfo7.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c975127a62f..446f426e6d3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10356,7 +10356,7 @@ namespace ts { function getReturnTypeFromJSDocComment(func: SignatureDeclaration | FunctionDeclaration): Type { const returnTag = getJSDocReturnTag(func); - if (returnTag) { + if (returnTag && returnTag.typeExpression) { return getTypeFromTypeNode(returnTag.typeExpression.type); } } diff --git a/tests/cases/fourslash/getJavaScriptQuickInfo7.ts b/tests/cases/fourslash/getJavaScriptQuickInfo7.ts new file mode 100644 index 00000000000..9faf97e7951 --- /dev/null +++ b/tests/cases/fourslash/getJavaScriptQuickInfo7.ts @@ -0,0 +1,19 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: file.js +//// /** +//// * This is a very cool function that is very nice. +//// * @returns something +//// */ +//// function a1() { +//// try { +//// throw new Error('x'); +//// } catch (x) { x--; } +//// return 23; +//// } +//// +//// x - /**/a1() + +goTo.marker(); +verify.quickInfoExists(); \ No newline at end of file From cf0e79a02f8030d791d237bb781311cf48e0d355 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 28 Jan 2016 16:07:06 -0800 Subject: [PATCH 10/13] Add explicit `return undefined;` (cherry picked from commit 1f503f1b27fb52ee5dacd75bd9379908ce6ee68e) --- src/compiler/checker.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 446f426e6d3..a7ebc36c7f3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10359,6 +10359,8 @@ namespace ts { if (returnTag && returnTag.typeExpression) { return getTypeFromTypeNode(returnTag.typeExpression.type); } + + return undefined; } function createPromiseType(promisedType: Type): Type { From a426de3b893a9a14a08964da8b8ae8fbb48b0119 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 1 Feb 2016 10:14:14 -0800 Subject: [PATCH 11/13] Fix lint (cherry picked from commit 95196886f7fb37078ddcbc2b85c8d171fc9e5a6e) --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7ebc36c7f3..c737b7d8987 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10359,7 +10359,7 @@ namespace ts { if (returnTag && returnTag.typeExpression) { return getTypeFromTypeNode(returnTag.typeExpression.type); } - + return undefined; } From 54bc98b22a177f227fdf94a2af36dc792797cd6c Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 1 Feb 2016 21:48:16 -0800 Subject: [PATCH 12/13] Add malformed parameter test (cherry picked from commit b15ff81384f33e17bb8e10e10d5992cd6727e68c) --- tests/cases/fourslash/getJavaScriptQuickInfo7.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/cases/fourslash/getJavaScriptQuickInfo7.ts b/tests/cases/fourslash/getJavaScriptQuickInfo7.ts index 9faf97e7951..5aa8474757d 100644 --- a/tests/cases/fourslash/getJavaScriptQuickInfo7.ts +++ b/tests/cases/fourslash/getJavaScriptQuickInfo7.ts @@ -5,8 +5,9 @@ //// /** //// * This is a very cool function that is very nice. //// * @returns something +//// * @param p anotherthing //// */ -//// function a1() { +//// function a1(p) { //// try { //// throw new Error('x'); //// } catch (x) { x--; } From 73a8ace843bf931c7fa069d6c7ad6f6a10f92237 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Fri, 29 Jan 2016 16:01:41 -0800 Subject: [PATCH 13/13] Fixes bug #6673 #6673 (cherry picked from commit f89ebb8fd80e28e74cdbfb4f3585b3f1d7bdbe39) --- src/compiler/binder.ts | 16 +++++++++--- tests/cases/fourslash/javaScriptModules13.ts | 4 ++- tests/cases/fourslash/javaScriptModules19.ts | 26 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 tests/cases/fourslash/javaScriptModules19.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1b70275b11c..933381afa92 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1384,7 +1384,7 @@ namespace ts { // Export assignment in some sort of block construct bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)); } - else if (boundExpression.kind === SyntaxKind.Identifier) { + else if (boundExpression.kind === SyntaxKind.Identifier && node.kind === SyntaxKind.ExportAssignment) { // An export default clause with an identifier exports all meanings of that identifier declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes); } @@ -1445,8 +1445,16 @@ namespace ts { // Look up the function in the local scope, since prototype assignments should // follow the function declaration - const classId = ((node.left).expression).expression; - const funcSymbol = container.locals[classId.text]; + const leftSideOfAssignment = node.left as PropertyAccessExpression; + const classPrototype = leftSideOfAssignment.expression as PropertyAccessExpression; + const constructorFunction = classPrototype.expression as Identifier; + + // Fix up parent pointers since we're going to use these nodes before we bind into them + leftSideOfAssignment.parent = node; + constructorFunction.parent = classPrototype; + classPrototype.parent = leftSideOfAssignment; + + const funcSymbol = container.locals[constructorFunction.text]; if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function)) { return; } @@ -1457,7 +1465,7 @@ namespace ts { } // Declare the method/property - declareSymbol(funcSymbol.members, funcSymbol, node.left, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + declareSymbol(funcSymbol.members, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes); } function bindCallExpression(node: CallExpression) { diff --git a/tests/cases/fourslash/javaScriptModules13.ts b/tests/cases/fourslash/javaScriptModules13.ts index 4eed369836f..cb3ef36783f 100644 --- a/tests/cases/fourslash/javaScriptModules13.ts +++ b/tests/cases/fourslash/javaScriptModules13.ts @@ -23,4 +23,6 @@ verify.completionListContains('y'); verify.not.completionListContains('invisible'); edit.insert('x.'); -verify.completionListContains('a'); +verify.memberListContains('a', undefined, undefined, 'property'); +edit.insert('a.'); +verify.memberListContains('toFixed', undefined, undefined, 'method'); diff --git a/tests/cases/fourslash/javaScriptModules19.ts b/tests/cases/fourslash/javaScriptModules19.ts new file mode 100644 index 00000000000..91e2439dcc9 --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules19.ts @@ -0,0 +1,26 @@ +/// + +// Assignments to 'module.exports' create an external module + +// @allowJs: true +// @Filename: myMod.js +//// var x = { a: 10 }; +//// module.exports = x; + +// @Filename: isGlobal.js +//// var y = 10; + +// @Filename: consumer.js +//// var x = require('myMod'); +//// /**/; + +goTo.file('consumer.js'); +goTo.marker(); + +verify.completionListContains('y'); +verify.not.completionListContains('invisible'); + +edit.insert('x.'); +verify.memberListContains('a', undefined, undefined, 'property'); +edit.insert('a.'); +verify.memberListContains('toFixed', undefined, undefined, 'method');