From b8329a05c3ea5611e34581f0704b80eef3e461c6 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sun, 22 Jan 2017 10:45:23 -0800 Subject: [PATCH 01/14] basic support for declaring properties on funcitons --- src/compiler/binder.ts | 30 +++++++++++++++++++ src/compiler/checker.ts | 29 +++++++++++------- src/compiler/types.ts | 4 ++- src/compiler/utilities.ts | 9 ++++++ .../fourslash/renameJsPropertyAssignment.ts | 11 +++++++ 5 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 tests/cases/fourslash/renameJsPropertyAssignment.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 712c96a49f9..da1ba466530 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -265,6 +265,7 @@ namespace ts { return "export="; case SpecialPropertyAssignmentKind.ExportsProperty: case SpecialPropertyAssignmentKind.ThisProperty: + case SpecialPropertyAssignmentKind.Property: // exports.x = ... or this.y = ... return ((node as BinaryExpression).left as PropertyAccessExpression).name.text; case SpecialPropertyAssignmentKind.PrototypeProperty: @@ -1921,6 +1922,9 @@ namespace ts { case SpecialPropertyAssignmentKind.ThisProperty: bindThisPropertyAssignment(node); break; + case SpecialPropertyAssignmentKind.Property: + bindPropertyAssignment(node); + break; case SpecialPropertyAssignmentKind.None: // Nothing to do break; @@ -2225,6 +2229,32 @@ namespace ts { declareSymbol(funcSymbol.members, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes); } + function bindPropertyAssignment(node: BinaryExpression) { + // We saw a node of the form 'x.y = z'. Declare a 'member' y on x if x was a function. + + // Look up the function in the local scope, since prototype assignments should + // follow the function declaration + const leftSideOfAssignment = node.left as PropertyAccessExpression; + const target = leftSideOfAssignment.expression as Identifier; + + // Fix up parent pointers since we're going to use these nodes before we bind into them + leftSideOfAssignment.parent = node; + target.parent = leftSideOfAssignment; + + const funcSymbol = container.locals[target.text]; + if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) { + return; + } + + // Set up the members collection if it doesn't exist already + if (!funcSymbol.exports) { + funcSymbol.exports = createMap(); + } + + // Declare the method/property + declareSymbol(funcSymbol.exports, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + } + function bindCallExpression(node: CallExpression) { // We're only inspecting call expressions to detect CommonJS modules, so we can skip // this check if we've already seen the module indicator diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bd8ff7568f3..78f67ae438f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4580,7 +4580,7 @@ namespace ts { // Combinations of function, class, enum and module let members = emptySymbols; let constructSignatures: Signature[] = emptyArray; - if (symbol.flags & SymbolFlags.HasExports) { + if (symbol.exports) { members = getExportsOfSymbol(symbol); } if (symbol.flags & SymbolFlags.Class) { @@ -19871,22 +19871,29 @@ namespace ts { return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined; } + function getSpecialPropertyAssignmentSymbolFromEntityName(entityName: EntityName | PropertyAccessExpression) { + const specialPropertyAssignmentKind = getSpecialPropertyAssignmentKind(entityName.parent.parent); + switch (specialPropertyAssignmentKind) { + case SpecialPropertyAssignmentKind.ExportsProperty: + case SpecialPropertyAssignmentKind.PrototypeProperty: + return getSymbolOfNode(entityName.parent); + case SpecialPropertyAssignmentKind.ThisProperty: + case SpecialPropertyAssignmentKind.ModuleExports: + case SpecialPropertyAssignmentKind.Property: + return getSymbolOfNode(entityName.parent.parent); + } + } + function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol | undefined { if (isDeclarationName(entityName)) { return getSymbolOfNode(entityName.parent); } if (isInJavaScriptFile(entityName) && entityName.parent.kind === SyntaxKind.PropertyAccessExpression) { - const specialPropertyAssignmentKind = getSpecialPropertyAssignmentKind(entityName.parent.parent); - switch (specialPropertyAssignmentKind) { - case SpecialPropertyAssignmentKind.ExportsProperty: - case SpecialPropertyAssignmentKind.PrototypeProperty: - return getSymbolOfNode(entityName.parent); - case SpecialPropertyAssignmentKind.ThisProperty: - case SpecialPropertyAssignmentKind.ModuleExports: - return getSymbolOfNode(entityName.parent.parent); - default: - // Fall through if it is not a special property assignment + // Check if this is a special property assignment + const specialPropertyAssignmentSymbol = getSpecialPropertyAssignmentSymbolFromEntityName(entityName); + if (specialPropertyAssignmentSymbol) { + return specialPropertyAssignmentSymbol; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c16c199d3eb..8fa47183a7e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3133,7 +3133,9 @@ /// className.prototype.name = expr PrototypeProperty, /// this.name = expr - ThisProperty + ThisProperty, + // F.name = expr + Property } export interface FileExtensionInfo { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b7cc0f0de6d..5cd0746b039 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1374,6 +1374,10 @@ namespace ts { return false; } + export function isValidSpecialPropertyAssignmentParent(parentSymbol: Symbol) { + return parentSymbol && (parentSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(parentSymbol)); + } + /// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property /// assignments we treat as special in the binder export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind { @@ -1398,6 +1402,10 @@ namespace ts { // module.exports = expr return SpecialPropertyAssignmentKind.ModuleExports; } + else { + // F.x = expr + return SpecialPropertyAssignmentKind.Property; + } } else if (lhs.expression.kind === SyntaxKind.ThisKeyword) { return SpecialPropertyAssignmentKind.ThisProperty; @@ -1417,6 +1425,7 @@ namespace ts { } } + return SpecialPropertyAssignmentKind.None; } diff --git a/tests/cases/fourslash/renameJsPropertyAssignment.ts b/tests/cases/fourslash/renameJsPropertyAssignment.ts new file mode 100644 index 00000000000..fd1ba47569d --- /dev/null +++ b/tests/cases/fourslash/renameJsPropertyAssignment.ts @@ -0,0 +1,11 @@ +/// + +// @allowJs: true +// @Filename: a.js +////function bar() { +////} +////bar.[|foo|] = "foo"; +////console.log(bar./**/[|foo|]); + +goTo.marker(); +verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false); \ No newline at end of file From 39b3ecb78c40b88bc277fbdf537e94b46005efc6 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sun, 22 Jan 2017 10:45:23 -0800 Subject: [PATCH 02/14] Handel defining properties on function and class expressions in .js files --- src/compiler/binder.ts | 16 +++++++++--- src/compiler/checker.ts | 7 +++-- src/compiler/utilities.ts | 8 ++---- .../reference/multipleDeclarations.symbols | 26 +++++++++++-------- .../reference/multipleDeclarations.types | 14 +++++----- .../fourslash/getJavaScriptCompletions20.ts | 2 +- .../fourslash/renameJsPropertyAssignment2.ts | 11 ++++++++ .../fourslash/renameJsPropertyAssignment3.ts | 11 ++++++++ .../cases/fourslash/renameJsThisProperty05.ts | 15 +++++++++++ .../cases/fourslash/renameJsThisProperty06.ts | 15 +++++++++++ 10 files changed, 94 insertions(+), 31 deletions(-) create mode 100644 tests/cases/fourslash/renameJsPropertyAssignment2.ts create mode 100644 tests/cases/fourslash/renameJsPropertyAssignment3.ts create mode 100644 tests/cases/fourslash/renameJsThisProperty05.ts create mode 100644 tests/cases/fourslash/renameJsThisProperty06.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index da1ba466530..50e69414907 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2215,8 +2215,12 @@ namespace ts { constructorFunction.parent = classPrototype; classPrototype.parent = leftSideOfAssignment; - const funcSymbol = container.locals.get(constructorFunction.text); - if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) { + let funcSymbol = container.locals.get(constructorFunction.text); + if (isDeclarationOfFunctionOrClassExpression(funcSymbol)) { + funcSymbol = (funcSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; + } + + if (!funcSymbol || !(funcSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class))) { return; } @@ -2241,8 +2245,12 @@ namespace ts { leftSideOfAssignment.parent = node; target.parent = leftSideOfAssignment; - const funcSymbol = container.locals[target.text]; - if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) { + let funcSymbol = container.locals.get(target.text); + if (isDeclarationOfFunctionOrClassExpression(funcSymbol)) { + funcSymbol = (funcSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; + } + + if (!funcSymbol || !(funcSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class))) { return; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 78f67ae438f..b7c81c1e0ab 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13886,10 +13886,13 @@ namespace ts { // in a JS file // Note:JS inferred classes might come from a variable declaration instead of a function declaration. // In this case, using getResolvedSymbol directly is required to avoid losing the members from the declaration. - const funcSymbol = node.expression.kind === SyntaxKind.Identifier ? + let funcSymbol = node.expression.kind === SyntaxKind.Identifier ? getResolvedSymbol(node.expression as Identifier) : checkExpression(node.expression).symbol; - if (funcSymbol && funcSymbol.members && (funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) { + if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { + funcSymbol = getSymbolOfNode((funcSymbol.valueDeclaration).initializer); + } + if (funcSymbol && funcSymbol.members && funcSymbol.flags & SymbolFlags.Function) { return getInferredClassType(funcSymbol); } else if (compilerOptions.noImplicitAny) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5cd0746b039..40bfc2302dc 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1366,18 +1366,14 @@ namespace ts { * Returns true if the node is a variable declaration whose initializer is a function expression. * This function does not test if the node is in a JavaScript file or not. */ - export function isDeclarationOfFunctionExpression(s: Symbol) { + export function isDeclarationOfFunctionOrClassExpression(s: Symbol) { if (s.valueDeclaration && s.valueDeclaration.kind === SyntaxKind.VariableDeclaration) { const declaration = s.valueDeclaration as VariableDeclaration; - return declaration.initializer && declaration.initializer.kind === SyntaxKind.FunctionExpression; + return declaration.initializer && (declaration.initializer.kind === SyntaxKind.FunctionExpression || declaration.initializer.kind === SyntaxKind.ClassExpression); } return false; } - export function isValidSpecialPropertyAssignmentParent(parentSymbol: Symbol) { - return parentSymbol && (parentSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(parentSymbol)); - } - /// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property /// assignments we treat as special in the binder export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind { diff --git a/tests/baselines/reference/multipleDeclarations.symbols b/tests/baselines/reference/multipleDeclarations.symbols index 9e49c2fc00c..4fc8f8a5f28 100644 --- a/tests/baselines/reference/multipleDeclarations.symbols +++ b/tests/baselines/reference/multipleDeclarations.symbols @@ -30,7 +30,7 @@ class X { >this : Symbol(X, Decl(input.js, 5, 1)) this.mistake = 'frankly, complete nonsense'; ->this.mistake : Symbol(X.mistake, Decl(input.js, 12, 5)) +>this.mistake : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) >this : Symbol(X, Decl(input.js, 5, 1)) >mistake : Symbol(X.mistake, Decl(input.js, 8, 35)) } @@ -38,7 +38,7 @@ class X { >m : Symbol(X.m, Decl(input.js, 10, 5)) } mistake() { ->mistake : Symbol(X.mistake, Decl(input.js, 12, 5)) +>mistake : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) } } let x = new X(); @@ -46,9 +46,11 @@ let x = new X(); >X : Symbol(X, Decl(input.js, 5, 1)) X.prototype.mistake = false; ->X.prototype.mistake : Symbol(X.mistake, Decl(input.js, 12, 5)) +>X.prototype.mistake : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) +>X.prototype : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) >X : Symbol(X, Decl(input.js, 5, 1)) >prototype : Symbol(X.prototype) +>mistake : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) x.m(); >x.m : Symbol(X.m, Decl(input.js, 10, 5)) @@ -56,15 +58,15 @@ x.m(); >m : Symbol(X.m, Decl(input.js, 10, 5)) x.mistake; ->x.mistake : Symbol(X.mistake, Decl(input.js, 12, 5)) +>x.mistake : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) >x : Symbol(x, Decl(input.js, 16, 3)) ->mistake : Symbol(X.mistake, Decl(input.js, 12, 5)) +>mistake : Symbol(X.mistake, Decl(input.js, 12, 5), Decl(input.js, 16, 16)) class Y { >Y : Symbol(Y, Decl(input.js, 19, 10)) mistake() { ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) } m() { >m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) @@ -80,15 +82,17 @@ class Y { >this : Symbol(Y, Decl(input.js, 19, 10)) this.mistake = 'even more nonsense'; ->this.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35)) +>this.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) >this : Symbol(Y, Decl(input.js, 19, 10)) ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) } } Y.prototype.mistake = true; ->Y.prototype.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35)) +>Y.prototype.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) +>Y.prototype : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) >Y : Symbol(Y, Decl(input.js, 19, 10)) >prototype : Symbol(Y.prototype) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) let y = new Y(); >y : Symbol(y, Decl(input.js, 31, 3)) @@ -100,7 +104,7 @@ y.m(); >m : Symbol(Y.m, Decl(input.js, 22, 5), Decl(input.js, 25, 19)) y.mistake(); ->y.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35)) +>y.mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) >y : Symbol(y, Decl(input.js, 31, 3)) ->mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35)) +>mistake : Symbol(Y.mistake, Decl(input.js, 20, 9), Decl(input.js, 26, 35), Decl(input.js, 29, 1)) diff --git a/tests/baselines/reference/multipleDeclarations.types b/tests/baselines/reference/multipleDeclarations.types index 195bdc2ad0d..b82cdbe05ed 100644 --- a/tests/baselines/reference/multipleDeclarations.types +++ b/tests/baselines/reference/multipleDeclarations.types @@ -43,16 +43,16 @@ class X { this.mistake = 'frankly, complete nonsense'; >this.mistake = 'frankly, complete nonsense' : "frankly, complete nonsense" ->this.mistake : () => void +>this.mistake : any >this : this ->mistake : () => void +>mistake : any >'frankly, complete nonsense' : "frankly, complete nonsense" } m() { >m : () => void } mistake() { ->mistake : () => void +>mistake : any } } let x = new X(); @@ -62,11 +62,11 @@ let x = new X(); X.prototype.mistake = false; >X.prototype.mistake = false : false ->X.prototype.mistake : () => void +>X.prototype.mistake : any >X.prototype : X >X : typeof X >prototype : X ->mistake : () => void +>mistake : any >false : false x.m(); @@ -76,9 +76,9 @@ x.m(); >m : () => void x.mistake; ->x.mistake : () => void +>x.mistake : any >x : X ->mistake : () => void +>mistake : any class Y { >Y : Y diff --git a/tests/cases/fourslash/getJavaScriptCompletions20.ts b/tests/cases/fourslash/getJavaScriptCompletions20.ts index 3ca27fa288a..ec2bcef161b 100644 --- a/tests/cases/fourslash/getJavaScriptCompletions20.ts +++ b/tests/cases/fourslash/getJavaScriptCompletions20.ts @@ -18,4 +18,4 @@ //// Person.getNa/**/ = 10; goTo.marker(); -verify.not.completionListContains('getNa'); +verify.completionListContains('getName'); diff --git a/tests/cases/fourslash/renameJsPropertyAssignment2.ts b/tests/cases/fourslash/renameJsPropertyAssignment2.ts new file mode 100644 index 00000000000..39831d4ae1b --- /dev/null +++ b/tests/cases/fourslash/renameJsPropertyAssignment2.ts @@ -0,0 +1,11 @@ +/// + +// @allowJs: true +// @Filename: a.js +////class Minimatch { +////} +////Minimatch.[|staticProperty|] = "string"; +////console.log(Minimatch./**/[|staticProperty|]); + +goTo.marker(); +verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false); \ No newline at end of file diff --git a/tests/cases/fourslash/renameJsPropertyAssignment3.ts b/tests/cases/fourslash/renameJsPropertyAssignment3.ts new file mode 100644 index 00000000000..5871010d6f4 --- /dev/null +++ b/tests/cases/fourslash/renameJsPropertyAssignment3.ts @@ -0,0 +1,11 @@ +/// + +// @allowJs: true +// @Filename: a.js +////var C = class { +////} +////C.[|staticProperty|] = "string"; +////console.log(C./**/[|staticProperty|]); + +goTo.marker(); +verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false); \ No newline at end of file diff --git a/tests/cases/fourslash/renameJsThisProperty05.ts b/tests/cases/fourslash/renameJsThisProperty05.ts new file mode 100644 index 00000000000..c1408d6aff1 --- /dev/null +++ b/tests/cases/fourslash/renameJsThisProperty05.ts @@ -0,0 +1,15 @@ +/// + +// @allowJs: true +// @Filename: a.js +////class C { +//// constructor(y) { +//// this.x = y; +//// } +////} +////C.prototype.[|z|] = 1; +////var t = new C(12); +////t./**/[|z|] = 11; + +goTo.marker(); +verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false); diff --git a/tests/cases/fourslash/renameJsThisProperty06.ts b/tests/cases/fourslash/renameJsThisProperty06.ts new file mode 100644 index 00000000000..63a16b68a4f --- /dev/null +++ b/tests/cases/fourslash/renameJsThisProperty06.ts @@ -0,0 +1,15 @@ +/// + +// @allowJs: true +// @Filename: a.js +////var C = class { +//// constructor(y) { +//// this.x = y; +//// } +////} +////C.prototype.[|z|] = 1; +////var t = new C(12); +////t./**/[|z|] = 11; + +goTo.marker(); +verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false); From e8a2173feed58a7646092fae0b12fece032878ab Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sun, 22 Jan 2017 10:45:23 -0800 Subject: [PATCH 03/14] Use variable name for class and function expressions names --- src/compiler/checker.ts | 4 +- .../reference/classExpression3.symbols | 6 +-- .../reference/classExpression3.types | 16 ++++---- .../reference/classExpression4.symbols | 6 +-- .../reference/classExpression4.types | 24 +++++------ .../reference/classExpressionES63.symbols | 6 +-- .../reference/classExpressionES63.types | 16 ++++---- .../functionsInClassExpressions.symbols | 24 +++++------ .../functionsInClassExpressions.types | 4 +- .../implementsInClassExpression.symbols | 2 +- .../implementsInClassExpression.types | 4 +- .../staticPropertyNameConflicts.errors.txt | 40 +++++++++---------- .../transformsElideNullUndefinedType.types | 8 ++-- 13 files changed, 81 insertions(+), 79 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b7c81c1e0ab..69831917381 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2171,13 +2171,15 @@ namespace ts { return type.flags & TypeFlags.StringLiteral ? `"${escapeString((type).text)}"` : (type).text; } - function getNameOfSymbol(symbol: Symbol): string { if (symbol.declarations && symbol.declarations.length) { const declaration = symbol.declarations[0]; if (declaration.name) { return declarationNameToString(declaration.name); } + if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { + return declarationNameToString((declaration.parent).name); + } switch (declaration.kind) { case SyntaxKind.ClassExpression: return "(Anonymous class)"; diff --git a/tests/baselines/reference/classExpression3.symbols b/tests/baselines/reference/classExpression3.symbols index bc1b263a000..fbd5f7b5331 100644 --- a/tests/baselines/reference/classExpression3.symbols +++ b/tests/baselines/reference/classExpression3.symbols @@ -3,7 +3,7 @@ let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; >C : Symbol(C, Decl(classExpression3.ts, 0, 3)) >a : Symbol((Anonymous class).a, Decl(classExpression3.ts, 0, 43)) >b : Symbol((Anonymous class).b, Decl(classExpression3.ts, 0, 53)) ->c : Symbol((Anonymous class).c, Decl(classExpression3.ts, 0, 63)) +>c : Symbol(C.c, Decl(classExpression3.ts, 0, 63)) let c = new C(); >c : Symbol(c, Decl(classExpression3.ts, 1, 3)) @@ -20,7 +20,7 @@ c.b; >b : Symbol((Anonymous class).b, Decl(classExpression3.ts, 0, 53)) c.c; ->c.c : Symbol((Anonymous class).c, Decl(classExpression3.ts, 0, 63)) +>c.c : Symbol(C.c, Decl(classExpression3.ts, 0, 63)) >c : Symbol(c, Decl(classExpression3.ts, 1, 3)) ->c : Symbol((Anonymous class).c, Decl(classExpression3.ts, 0, 63)) +>c : Symbol(C.c, Decl(classExpression3.ts, 0, 63)) diff --git a/tests/baselines/reference/classExpression3.types b/tests/baselines/reference/classExpression3.types index 51798f300d4..713407fa8d4 100644 --- a/tests/baselines/reference/classExpression3.types +++ b/tests/baselines/reference/classExpression3.types @@ -1,7 +1,7 @@ === tests/cases/conformance/classes/classExpressions/classExpression3.ts === let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; ->C : typeof (Anonymous class) ->class extends class extends class { a = 1 } { b = 2 } { c = 3 } : typeof (Anonymous class) +>C : typeof C +>class extends class extends class { a = 1 } { b = 2 } { c = 3 } : typeof C >class extends class { a = 1 } { b = 2 } : (Anonymous class) >class { a = 1 } : (Anonymous class) >a : number @@ -12,22 +12,22 @@ let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; >3 : 3 let c = new C(); ->c : (Anonymous class) ->new C() : (Anonymous class) ->C : typeof (Anonymous class) +>c : C +>new C() : C +>C : typeof C c.a; >c.a : number ->c : (Anonymous class) +>c : C >a : number c.b; >c.b : number ->c : (Anonymous class) +>c : C >b : number c.c; >c.c : number ->c : (Anonymous class) +>c : C >c : number diff --git a/tests/baselines/reference/classExpression4.symbols b/tests/baselines/reference/classExpression4.symbols index 4df5302cecc..47a03bc4c96 100644 --- a/tests/baselines/reference/classExpression4.symbols +++ b/tests/baselines/reference/classExpression4.symbols @@ -3,7 +3,7 @@ let C = class { >C : Symbol(C, Decl(classExpression4.ts, 0, 3)) foo() { ->foo : Symbol((Anonymous class).foo, Decl(classExpression4.ts, 0, 15)) +>foo : Symbol(C.foo, Decl(classExpression4.ts, 0, 15)) return new C(); >C : Symbol(C, Decl(classExpression4.ts, 0, 3)) @@ -11,7 +11,7 @@ let C = class { }; let x = (new C).foo(); >x : Symbol(x, Decl(classExpression4.ts, 5, 3)) ->(new C).foo : Symbol((Anonymous class).foo, Decl(classExpression4.ts, 0, 15)) +>(new C).foo : Symbol(C.foo, Decl(classExpression4.ts, 0, 15)) >C : Symbol(C, Decl(classExpression4.ts, 0, 3)) ->foo : Symbol((Anonymous class).foo, Decl(classExpression4.ts, 0, 15)) +>foo : Symbol(C.foo, Decl(classExpression4.ts, 0, 15)) diff --git a/tests/baselines/reference/classExpression4.types b/tests/baselines/reference/classExpression4.types index 066f169ae74..849a7459bbe 100644 --- a/tests/baselines/reference/classExpression4.types +++ b/tests/baselines/reference/classExpression4.types @@ -1,22 +1,22 @@ === tests/cases/conformance/classes/classExpressions/classExpression4.ts === let C = class { ->C : typeof (Anonymous class) ->class { foo() { return new C(); }} : typeof (Anonymous class) +>C : typeof C +>class { foo() { return new C(); }} : typeof C foo() { ->foo : () => (Anonymous class) +>foo : () => C return new C(); ->new C() : (Anonymous class) ->C : typeof (Anonymous class) +>new C() : C +>C : typeof C } }; let x = (new C).foo(); ->x : (Anonymous class) ->(new C).foo() : (Anonymous class) ->(new C).foo : () => (Anonymous class) ->(new C) : (Anonymous class) ->new C : (Anonymous class) ->C : typeof (Anonymous class) ->foo : () => (Anonymous class) +>x : C +>(new C).foo() : C +>(new C).foo : () => C +>(new C) : C +>new C : C +>C : typeof C +>foo : () => C diff --git a/tests/baselines/reference/classExpressionES63.symbols b/tests/baselines/reference/classExpressionES63.symbols index 4e52d5ee9dd..f74b2893f73 100644 --- a/tests/baselines/reference/classExpressionES63.symbols +++ b/tests/baselines/reference/classExpressionES63.symbols @@ -3,7 +3,7 @@ let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; >C : Symbol(C, Decl(classExpressionES63.ts, 0, 3)) >a : Symbol((Anonymous class).a, Decl(classExpressionES63.ts, 0, 43)) >b : Symbol((Anonymous class).b, Decl(classExpressionES63.ts, 0, 53)) ->c : Symbol((Anonymous class).c, Decl(classExpressionES63.ts, 0, 63)) +>c : Symbol(C.c, Decl(classExpressionES63.ts, 0, 63)) let c = new C(); >c : Symbol(c, Decl(classExpressionES63.ts, 1, 3)) @@ -20,7 +20,7 @@ c.b; >b : Symbol((Anonymous class).b, Decl(classExpressionES63.ts, 0, 53)) c.c; ->c.c : Symbol((Anonymous class).c, Decl(classExpressionES63.ts, 0, 63)) +>c.c : Symbol(C.c, Decl(classExpressionES63.ts, 0, 63)) >c : Symbol(c, Decl(classExpressionES63.ts, 1, 3)) ->c : Symbol((Anonymous class).c, Decl(classExpressionES63.ts, 0, 63)) +>c : Symbol(C.c, Decl(classExpressionES63.ts, 0, 63)) diff --git a/tests/baselines/reference/classExpressionES63.types b/tests/baselines/reference/classExpressionES63.types index c5c8de91c17..f597edab9db 100644 --- a/tests/baselines/reference/classExpressionES63.types +++ b/tests/baselines/reference/classExpressionES63.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/classExpressions/classExpressionES63.ts === let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; ->C : typeof (Anonymous class) ->class extends class extends class { a = 1 } { b = 2 } { c = 3 } : typeof (Anonymous class) +>C : typeof C +>class extends class extends class { a = 1 } { b = 2 } { c = 3 } : typeof C >class extends class { a = 1 } { b = 2 } : (Anonymous class) >class { a = 1 } : (Anonymous class) >a : number @@ -12,22 +12,22 @@ let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; >3 : 3 let c = new C(); ->c : (Anonymous class) ->new C() : (Anonymous class) ->C : typeof (Anonymous class) +>c : C +>new C() : C +>C : typeof C c.a; >c.a : number ->c : (Anonymous class) +>c : C >a : number c.b; >c.b : number ->c : (Anonymous class) +>c : C >b : number c.c; >c.c : number ->c : (Anonymous class) +>c : C >c : number diff --git a/tests/baselines/reference/functionsInClassExpressions.symbols b/tests/baselines/reference/functionsInClassExpressions.symbols index a1da3a3175c..4aa62da8e33 100644 --- a/tests/baselines/reference/functionsInClassExpressions.symbols +++ b/tests/baselines/reference/functionsInClassExpressions.symbols @@ -4,24 +4,24 @@ let Foo = class { constructor() { this.bar++; ->this.bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) ->this : Symbol((Anonymous class), Decl(functionsInClassExpressions.ts, 0, 9)) ->bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this.bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this : Symbol(Foo, Decl(functionsInClassExpressions.ts, 0, 9)) +>bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) } bar = 0; ->bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) inc = () => { ->inc : Symbol((Anonymous class).inc, Decl(functionsInClassExpressions.ts, 4, 12)) +>inc : Symbol(Foo.inc, Decl(functionsInClassExpressions.ts, 4, 12)) this.bar++; ->this.bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) ->this : Symbol((Anonymous class), Decl(functionsInClassExpressions.ts, 0, 9)) ->bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this.bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this : Symbol(Foo, Decl(functionsInClassExpressions.ts, 0, 9)) +>bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) } m() { return this.bar; } ->m : Symbol((Anonymous class).m, Decl(functionsInClassExpressions.ts, 7, 5)) ->this.bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) ->this : Symbol((Anonymous class), Decl(functionsInClassExpressions.ts, 0, 9)) ->bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>m : Symbol(Foo.m, Decl(functionsInClassExpressions.ts, 7, 5)) +>this.bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this : Symbol(Foo, Decl(functionsInClassExpressions.ts, 0, 9)) +>bar : Symbol(Foo.bar, Decl(functionsInClassExpressions.ts, 3, 5)) } diff --git a/tests/baselines/reference/functionsInClassExpressions.types b/tests/baselines/reference/functionsInClassExpressions.types index b00f3df3490..7352f6e6b12 100644 --- a/tests/baselines/reference/functionsInClassExpressions.types +++ b/tests/baselines/reference/functionsInClassExpressions.types @@ -1,7 +1,7 @@ === tests/cases/compiler/functionsInClassExpressions.ts === let Foo = class { ->Foo : typeof (Anonymous class) ->class { constructor() { this.bar++; } bar = 0; inc = () => { this.bar++; } m() { return this.bar; }} : typeof (Anonymous class) +>Foo : typeof Foo +>class { constructor() { this.bar++; } bar = 0; inc = () => { this.bar++; } m() { return this.bar; }} : typeof Foo constructor() { this.bar++; diff --git a/tests/baselines/reference/implementsInClassExpression.symbols b/tests/baselines/reference/implementsInClassExpression.symbols index 48a44d91e9c..bf3b3ef9337 100644 --- a/tests/baselines/reference/implementsInClassExpression.symbols +++ b/tests/baselines/reference/implementsInClassExpression.symbols @@ -11,5 +11,5 @@ let cls = class implements Foo { >Foo : Symbol(Foo, Decl(implementsInClassExpression.ts, 0, 0)) doThing() { } ->doThing : Symbol((Anonymous class).doThing, Decl(implementsInClassExpression.ts, 4, 32)) +>doThing : Symbol(cls.doThing, Decl(implementsInClassExpression.ts, 4, 32)) } diff --git a/tests/baselines/reference/implementsInClassExpression.types b/tests/baselines/reference/implementsInClassExpression.types index d3647c30ff1..0734f8b8b78 100644 --- a/tests/baselines/reference/implementsInClassExpression.types +++ b/tests/baselines/reference/implementsInClassExpression.types @@ -7,8 +7,8 @@ interface Foo { } let cls = class implements Foo { ->cls : typeof (Anonymous class) ->class implements Foo { doThing() { }} : typeof (Anonymous class) +>cls : typeof cls +>class implements Foo { doThing() { }} : typeof cls >Foo : Foo doThing() { } diff --git a/tests/baselines/reference/staticPropertyNameConflicts.errors.txt b/tests/baselines/reference/staticPropertyNameConflicts.errors.txt index 4c051ace0ac..1b22bbbf759 100644 --- a/tests/baselines/reference/staticPropertyNameConflicts.errors.txt +++ b/tests/baselines/reference/staticPropertyNameConflicts.errors.txt @@ -9,17 +9,17 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(41,12): error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function 'StaticCallerFn'. tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(47,12): error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function 'StaticArguments'. tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(52,12): error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function 'StaticArgumentsFn'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(62,12): error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(67,12): error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(73,12): error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(78,12): error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(84,12): error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function '(Anonymous class)'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(62,12): error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'StaticName_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(67,12): error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'StaticNameFn_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(73,12): error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function 'StaticLength_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(78,12): error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function 'StaticLengthFn_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(84,12): error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'StaticPrototype_Anonymous'. tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(89,12): error TS2300: Duplicate identifier 'prototype'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(89,12): error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(95,12): error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(100,12): error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(106,12): error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function '(Anonymous class)'. -tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(111,12): error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function '(Anonymous class)'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(89,12): error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'StaticPrototypeFn_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(95,12): error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function 'StaticCaller_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(100,12): error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function 'StaticCallerFn_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(106,12): error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function 'StaticArguments_Anonymous'. +tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(111,12): error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function 'StaticArgumentsFn_Anonymous'. tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(121,16): error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'StaticName'. tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(128,16): error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'StaticNameFn'. tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameConflicts.ts(136,16): error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function 'StaticLength'. @@ -119,14 +119,14 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon var StaticName_Anonymous = class { static name: number; // error ~~~~ -!!! error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'StaticName_Anonymous'. name: string; // ok } var StaticNameFn_Anonymous = class { static name() {} // error ~~~~ -!!! error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'StaticNameFn_Anonymous'. name() {} // ok } @@ -134,14 +134,14 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon var StaticLength_Anonymous = class { static length: number; // error ~~~~~~ -!!! error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function 'StaticLength_Anonymous'. length: string; // ok } var StaticLengthFn_Anonymous = class { static length() {} // error ~~~~~~ -!!! error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'length' conflicts with built-in property 'Function.length' of constructor function 'StaticLengthFn_Anonymous'. length() {} // ok } @@ -149,7 +149,7 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon var StaticPrototype_Anonymous = class { static prototype: number; // error ~~~~~~~~~ -!!! error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'StaticPrototype_Anonymous'. prototype: string; // ok } @@ -158,7 +158,7 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon ~~~~~~~~~ !!! error TS2300: Duplicate identifier 'prototype'. ~~~~~~~~~ -!!! error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'prototype' conflicts with built-in property 'Function.prototype' of constructor function 'StaticPrototypeFn_Anonymous'. prototype() {} // ok } @@ -166,14 +166,14 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon var StaticCaller_Anonymous = class { static caller: number; // error ~~~~~~ -!!! error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function 'StaticCaller_Anonymous'. caller: string; // ok } var StaticCallerFn_Anonymous = class { static caller() {} // error ~~~~~~ -!!! error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'caller' conflicts with built-in property 'Function.caller' of constructor function 'StaticCallerFn_Anonymous'. caller() {} // ok } @@ -181,14 +181,14 @@ tests/cases/conformance/classes/propertyMemberDeclarations/staticPropertyNameCon var StaticArguments_Anonymous = class { static arguments: number; // error ~~~~~~~~~ -!!! error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function 'StaticArguments_Anonymous'. arguments: string; // ok } var StaticArgumentsFn_Anonymous = class { static arguments() {} // error ~~~~~~~~~ -!!! error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function '(Anonymous class)'. +!!! error TS2699: Static property 'arguments' conflicts with built-in property 'Function.arguments' of constructor function 'StaticArgumentsFn_Anonymous'. arguments() {} // ok } diff --git a/tests/baselines/reference/transformsElideNullUndefinedType.types b/tests/baselines/reference/transformsElideNullUndefinedType.types index 7f48d8a00e9..ffc26ddaa60 100644 --- a/tests/baselines/reference/transformsElideNullUndefinedType.types +++ b/tests/baselines/reference/transformsElideNullUndefinedType.types @@ -140,14 +140,14 @@ class C5 { } var C6 = class { constructor(p12: null) { } } ->C6 : typeof (Anonymous class) ->class { constructor(p12: null) { } } : typeof (Anonymous class) +>C6 : typeof C6 +>class { constructor(p12: null) { } } : typeof C6 >p12 : null >null : null var C7 = class { constructor(p13: undefined) { } } ->C7 : typeof (Anonymous class) ->class { constructor(p13: undefined) { } } : typeof (Anonymous class) +>C7 : typeof C7 +>class { constructor(p13: undefined) { } } : typeof C7 >p13 : undefined declare function fn(); From 793d8be6e02a2881b6d7d09cdd662b17ca1b56e7 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 30 Jan 2017 16:42:12 -0800 Subject: [PATCH 04/14] Check for undefined symbols --- src/compiler/binder.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 50e69414907..e462898a0ce 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2216,7 +2216,7 @@ namespace ts { classPrototype.parent = leftSideOfAssignment; let funcSymbol = container.locals.get(constructorFunction.text); - if (isDeclarationOfFunctionOrClassExpression(funcSymbol)) { + if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { funcSymbol = (funcSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; } @@ -2246,7 +2246,7 @@ namespace ts { target.parent = leftSideOfAssignment; let funcSymbol = container.locals.get(target.text); - if (isDeclarationOfFunctionOrClassExpression(funcSymbol)) { + if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { funcSymbol = (funcSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; } From 0aa8a6e4a5d54de2f7312915717f7037e65960af Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 13 Feb 2017 20:54:47 -0800 Subject: [PATCH 05/14] Consolidate bindProperty logic in one function --- src/compiler/binder.ts | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1453ed2522a..b76700bd497 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1928,7 +1928,7 @@ namespace ts { bindThisPropertyAssignment(node); break; case SpecialPropertyAssignmentKind.Property: - bindPropertyAssignment(node); + bindStaticPropertyAssignment(node); break; case SpecialPropertyAssignmentKind.None: // Nothing to do @@ -2220,25 +2220,10 @@ namespace ts { constructorFunction.parent = classPrototype; classPrototype.parent = leftSideOfAssignment; - let funcSymbol = container.locals.get(constructorFunction.text); - if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { - funcSymbol = (funcSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; - } - - if (!funcSymbol || !(funcSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class))) { - return; - } - - // Set up the members collection if it doesn't exist already - if (!funcSymbol.members) { - funcSymbol.members = createMap(); - } - - // Declare the method/property - declareSymbol(funcSymbol.members, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + bindPropertyAssignment(constructorFunction.text, leftSideOfAssignment, /*isPrototypeProperty*/ true); } - function bindPropertyAssignment(node: BinaryExpression) { + function bindStaticPropertyAssignment(node: BinaryExpression) { // We saw a node of the form 'x.y = z'. Declare a 'member' y on x if x was a function. // Look up the function in the local scope, since prototype assignments should @@ -2250,22 +2235,26 @@ namespace ts { leftSideOfAssignment.parent = node; target.parent = leftSideOfAssignment; - let funcSymbol = container.locals.get(target.text); - if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { - funcSymbol = (funcSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; + bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false); + } + + function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) { + let targetSymbol = container.locals.get(functionName); + if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) { + targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; } - if (!funcSymbol || !(funcSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class))) { + if (!targetSymbol || !(targetSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class))) { return; } // Set up the members collection if it doesn't exist already - if (!funcSymbol.exports) { - funcSymbol.exports = createMap(); - } + const symbolTable = isPrototypeProperty ? + (targetSymbol.members || (targetSymbol.members = createMap())): + (targetSymbol.exports || (targetSymbol.exports = createMap())); // Declare the method/property - declareSymbol(funcSymbol.exports, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + declareSymbol(symbolTable, targetSymbol, propertyAccessExpression, SymbolFlags.Property, SymbolFlags.PropertyExcludes); } function bindCallExpression(node: CallExpression) { From 90eef8940ee5bdc584cd82e4773ba083152c199f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 13 Feb 2017 20:54:57 -0800 Subject: [PATCH 06/14] accept baseline change --- .../cases/fourslash/findAllRefsForVariableInExtendsClause01.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/findAllRefsForVariableInExtendsClause01.ts b/tests/cases/fourslash/findAllRefsForVariableInExtendsClause01.ts index d40cb009f1e..a61f925c97e 100644 --- a/tests/cases/fourslash/findAllRefsForVariableInExtendsClause01.ts +++ b/tests/cases/fourslash/findAllRefsForVariableInExtendsClause01.ts @@ -3,4 +3,4 @@ ////var [|{| "isWriteAccess": true, "isDefinition": true |}Base|] = class { }; ////class C extends [|Base|] { } -verify.singleReferenceGroup("var Base: typeof (Anonymous class)"); +verify.singleReferenceGroup("var Base: typeof Base"); From 9897c6949256a6281326b87746d4933a437dad12 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 13 Feb 2017 11:18:56 -0800 Subject: [PATCH 07/14] wip --- src/services/codefixes/fixAddMissingMember.ts | 74 +++++++++++++++++++ src/services/codefixes/fixes.ts | 1 + src/services/codefixes/helpers.ts | 12 ++- ...codeFixUndeclaredPropertyNumericLiteral.ts | 17 +++++ 4 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 src/services/codefixes/fixAddMissingMember.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts new file mode 100644 index 00000000000..c51c63bdc27 --- /dev/null +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -0,0 +1,74 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code], + getCodeActions: getActionsForAddMissingMember + }); + + function getActionsForAddMissingMember(context: CodeFixContext): CodeAction[] | undefined { + + const sourceFile = context.sourceFile; + const start = context.span.start; + // This is the identifier in the case of a class declaration + // or the class keyword token in the case of a class expression. + const token = getTokenAtPosition(sourceFile, start); + const checker = context.program.getTypeChecker(); + + if(!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { + return undefined; + } + + if((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { + return undefined; + } + 1 + 1; + + let typeString: string = 'any'; + // if binary expression, try to infer type for LHS, else use any + if(token.parent.parent.kind === SyntaxKind.BinaryExpression) + { + const binaryExpression = token.parent.parent as BinaryExpression; + binaryExpression.operatorToken; + + const type = checker.getTypeAtLocation(binaryExpression.right); + typeString = checker.typeToString(type); + } + + const classDeclaration = getContainingClass(token); + const startPos = classDeclaration.members.pos; + return [{ + description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `${token.getFullText(sourceFile)}: ${typeString};` + }] + }] + }]; + } + + + + + // x needs to be a `this` construct. ie + // this.. + // Want to infer type of x when possible. ie: + // * assignment, + // * function call argument: foo(this.x) where foo(x: SomeType) + // * expression with a type assertion: this.x as MyFavoriteType + // * access expression: this.x.push("asdf") ... probably an array? + // * + // What if there are multiple usages of this.x? Create intersection over all usages? + + // needs to be in a class + // inferred type might be error. then add any. + // either make indexable of the inferred type + // add named member of the inferred type. +} + +// // class C { +// // constructor() { +// // this.x = 1; +// // } +// // } \ No newline at end of file diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 3bd173e04f6..76be34c67cd 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -1,4 +1,5 @@ /// +/// /// /// /// diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 7bee4f5a0ed..60efdef1e81 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -32,7 +32,7 @@ namespace ts.codefix { const declaration = declarations[0] as Declaration; const name = declaration.name ? declaration.name.getText() : undefined; - const visibility = getVisibilityPrefix(getModifierFlags(declaration)); + const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration)); switch (declaration.kind) { case SyntaxKind.GetAccessor: @@ -138,11 +138,15 @@ namespace ts.codefix { } } - function getMethodBodyStub(newLineChar: string) { - return ` {${newLineChar}throw new Error('Method not implemented.');${newLineChar}}${newLineChar}`; + export function getStubbedMethod(visibility: string, name: string, signature: string = '()', newlineChar: string): string { + return `${visibility}${name}${signature}${getMethodBodyStub(newlineChar)}`; } - function getVisibilityPrefix(flags: ModifierFlags): string { + function getMethodBodyStub(newlineChar: string) { + return ` {${newlineChar}throw new Error('Method not implemented.');${newlineChar}}${newlineChar}`; + } + + function getVisibilityPrefixWithSpace(flags: ModifierFlags): string { if (flags & ModifierFlags.Public) { return "public "; } diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts new file mode 100644 index 00000000000..bb11d9e76e1 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts @@ -0,0 +1,17 @@ +/// + +//// [|class A { +//// constructor() { +//// this.x = 10; +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + x: number; + + constructor() { + this.x = 10; + } +} +`); \ No newline at end of file From 92e4c6b7dbab5fa2de5fce40a36bf4bae9dcb208 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 14 Feb 2017 17:20:04 -0800 Subject: [PATCH 08/14] Get Widened Type --- src/compiler/checker.ts | 1 + src/compiler/diagnosticMessages.json | 8 +++ src/compiler/types.ts | 1 + src/services/codefixes/fixAddMissingMember.ts | 54 +++++++++++-------- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 704812b0185..c593fcd6737 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -83,6 +83,7 @@ namespace ts { getSignaturesOfType, getIndexTypeOfType, getBaseTypes, + getWidenedType, getTypeFromTypeNode, getParameterType: getTypeAtPosition, getReturnTypeOfSignature, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ec6067751a2..a01676207be 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3303,6 +3303,14 @@ "category": "Message", "code": 90015 }, + "Add declaration for missing property '{0}'": { + "category": "Message", + "code": 90016 + }, + "Add index accessor for missing property '{0}'": { + "category": "Message", + "code": 90017 + }, "Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": { "category": "Error", "code": 8017 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index bdc4eea98da..2b121627b45 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2382,6 +2382,7 @@ getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type; getBaseTypes(type: InterfaceType): BaseType[]; + getWidenedType(type: Type): Type; getReturnTypeOfSignature(signature: Signature): Type; /** * Gets the type of a parameter at a given position in a signature. diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index c51c63bdc27..24fc6b16abb 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -12,32 +12,41 @@ namespace ts.codefix { // This is the identifier in the case of a class declaration // or the class keyword token in the case of a class expression. const token = getTokenAtPosition(sourceFile, start); - const checker = context.program.getTypeChecker(); - if(!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { + const classDeclaration = getContainingClass(token); + if (!classDeclaration) { return undefined; } - if((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { + const startPos = classDeclaration.members.pos; + + if (!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { return undefined; } - 1 + 1; + + if ((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { + return undefined; + } + + // if function call, synthesize function declaration + if(token.parent.parent.kind == SyntaxKind.CallExpression) { + + } let typeString: string = 'any'; + // if binary expression, try to infer type for LHS, else use any - if(token.parent.parent.kind === SyntaxKind.BinaryExpression) - { + if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { const binaryExpression = token.parent.parent as BinaryExpression; binaryExpression.operatorToken; - - const type = checker.getTypeAtLocation(binaryExpression.right); + + const checker = context.program.getTypeChecker(); + const type = checker.getWidenedType(checker.getTypeAtLocation(binaryExpression.right)); typeString = checker.typeToString(type); } - const classDeclaration = getContainingClass(token); - const startPos = classDeclaration.members.pos; return [{ - description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class), + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]), changes: [{ fileName: sourceFile.fileName, textChanges: [{ @@ -45,14 +54,19 @@ namespace ts.codefix { newText: `${token.getFullText(sourceFile)}: ${typeString};` }] }] + }, + { + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_accessor_for_missing_property_0), [token.getText()]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `[name: string]: ${typeString};` + }] + }] }]; } - - - - // x needs to be a `this` construct. ie - // this.. // Want to infer type of x when possible. ie: // * assignment, // * function call argument: foo(this.x) where foo(x: SomeType) @@ -65,10 +79,4 @@ namespace ts.codefix { // inferred type might be error. then add any. // either make indexable of the inferred type // add named member of the inferred type. -} - -// // class C { -// // constructor() { -// // this.x = 1; -// // } -// // } \ No newline at end of file +} \ No newline at end of file From f047a6ea31d284d9d5b5a532ab41d30791921826 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 14 Feb 2017 17:27:07 -0800 Subject: [PATCH 09/14] wip testing --- src/harness/fourslash.ts | 28 ++++++++++++------- .../codeFixUndeclaredPropertyObjectLiteral.ts | 17 +++++++++++ tests/cases/fourslash/fourslash.ts | 2 +- tests/cases/fourslash/unusedImports2FS.ts | 2 +- .../fourslash/unusedLocalsInFunction3.ts | 2 +- 5 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 34aa9580d6d..a722cb20724 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2122,7 +2122,7 @@ namespace FourSlash { * Because codefixes are only applied on the working file, it is unsafe * to apply this more than once (consider a refactoring across files). */ - public verifyRangeAfterCodeFix(expectedText: string, errorCode?: number, includeWhiteSpace?: boolean) { + public verifyRangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number) { const ranges = this.getRanges(); if (ranges.length !== 1) { this.raiseError("Exactly one range should be specified in the testfile."); @@ -2130,7 +2130,7 @@ namespace FourSlash { const fileName = this.activeFile.fileName; - this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName, errorCode)); + this.applyCodeAction(fileName, this.getCodeFixActions(fileName, errorCode), index); const actualText = this.rangeText(ranges[0]); @@ -2155,7 +2155,7 @@ namespace FourSlash { public verifyFileAfterCodeFix(expectedContents: string, fileName?: string) { fileName = fileName ? fileName : this.activeFile.fileName; - this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName)); + this.applyCodeAction(fileName, this.getCodeFixActions(fileName)); const actualContents: string = this.getFileContent(fileName); if (this.removeWhitespace(actualContents) !== this.removeWhitespace(expectedContents)) { @@ -2193,12 +2193,20 @@ namespace FourSlash { return actions; } - private applyCodeFixActions(fileName: string, actions: ts.CodeAction[]): void { - if (!(actions && actions.length === 1)) { - this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`); + private applyCodeAction(fileName: string, actions: ts.CodeAction[], index?: number): void { + if (index === undefined) { + if (!(actions && actions.length === 1)) { + this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`); + } + index = 0; } - - const fileChanges = ts.find(actions[0].changes, change => change.fileName === fileName); + else { + if (!(actions && actions.length >= index + 1)) { + this.raiseError(`Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`); + } + } + + const fileChanges = ts.find(actions[index].changes, change => change.fileName === fileName); if (!fileChanges) { this.raiseError("The CodeFix found doesn't provide any changes in this file."); } @@ -3535,8 +3543,8 @@ namespace FourSlashInterface { this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true); } - public rangeAfterCodeFix(expectedText: string, errorCode?: number, includeWhiteSpace?: boolean): void { - this.state.verifyRangeAfterCodeFix(expectedText, errorCode, includeWhiteSpace); + public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void { + this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index); } public importFixAtPosition(expectedTextArray: string[], errorCode?: number): void { diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts new file mode 100644 index 00000000000..bc19f792fb3 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts @@ -0,0 +1,17 @@ +/// + +//// [|class A { +//// constructor() { +//// this.x = { a: 10, b: "hello" }; +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + x: { a: number, b: string }; + + constructor() { + this.x = 10; + } +} +`); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 661d7cba6a4..fda5b1a30cd 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -225,7 +225,7 @@ declare namespace FourSlashInterface { noMatchingBracePositionInCurrentFile(bracePosition: number): void; DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; noDocCommentTemplate(): void; - rangeAfterCodeFix(expectedText: string, errorCode?: number, includeWhiteSpace?: boolean): void; + rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number): void; importFixAtPosition(expectedTextArray: string[], errorCode?: number): void; navigationBar(json: any): void; diff --git a/tests/cases/fourslash/unusedImports2FS.ts b/tests/cases/fourslash/unusedImports2FS.ts index 53875693362..8865dea56a6 100644 --- a/tests/cases/fourslash/unusedImports2FS.ts +++ b/tests/cases/fourslash/unusedImports2FS.ts @@ -16,4 +16,4 @@ //// //// } -verify.rangeAfterCodeFix(`import {Calculator} from "./file1"`, /*errorCode*/ undefined, /*includeWhiteSpace*/ true); +verify.rangeAfterCodeFix(`import {Calculator} from "./file1"`, /*includeWhiteSpace*/ true, /*errorCode*/ undefined); diff --git a/tests/cases/fourslash/unusedLocalsInFunction3.ts b/tests/cases/fourslash/unusedLocalsInFunction3.ts index 7aa9b20a33c..0164873acd8 100644 --- a/tests/cases/fourslash/unusedLocalsInFunction3.ts +++ b/tests/cases/fourslash/unusedLocalsInFunction3.ts @@ -7,4 +7,4 @@ //// z+1; ////} -verify.rangeAfterCodeFix("var x,z = 1;", 6133); +verify.rangeAfterCodeFix("var x,z = 1;", /*includeWhiteSpace*/ undefined, 6133); From 18cba86e747d507f0a4ec979cc19cbebb8df02e2 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 14 Feb 2017 18:10:21 -0800 Subject: [PATCH 10/14] add tests --- .../codeFixUndeclaredClassInstance.ts | 22 +++++++++++++++++++ ...ixUndeclaredClassInstanceWithTypeParams.ts | 22 +++++++++++++++++++ ...codeFixUndeclaredPropertyNumericLiteral.ts | 2 +- .../codeFixUndeclaredPropertyObjectLiteral.ts | 8 +++---- tests/cases/fourslash/fourslash.ts | 2 +- 5 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/codeFixUndeclaredClassInstance.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredClassInstanceWithTypeParams.ts diff --git a/tests/cases/fourslash/codeFixUndeclaredClassInstance.ts b/tests/cases/fourslash/codeFixUndeclaredClassInstance.ts new file mode 100644 index 00000000000..024ec144092 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredClassInstance.ts @@ -0,0 +1,22 @@ +/// + +//// class A { +//// a: number; +//// b: string; +//// constructor(public x: any) {} +//// } +//// [|class B { +//// constructor() { +//// this.x = new A(3); +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class B { + x: A; + + constructor() { + this.x = new A(3); + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredClassInstanceWithTypeParams.ts b/tests/cases/fourslash/codeFixUndeclaredClassInstanceWithTypeParams.ts new file mode 100644 index 00000000000..34e359feea8 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredClassInstanceWithTypeParams.ts @@ -0,0 +1,22 @@ +/// + +//// class A { +//// a: number; +//// b: string; +//// constructor(public x: T) {} +//// } +//// [|class B { +//// constructor() { +//// this.x = new A(3); +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class B { + x: A; + + constructor() { + this.x = new A(3); + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts index bb11d9e76e1..eaae355904b 100644 --- a/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts @@ -14,4 +14,4 @@ class A { this.x = 10; } } -`); \ No newline at end of file +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts index bc19f792fb3..3f5c5f99887 100644 --- a/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts @@ -8,10 +8,10 @@ verify.rangeAfterCodeFix(` class A { - x: { a: number, b: string }; - + x: { a: number; b: string; }; + constructor() { - this.x = 10; + this.x = { a: 10, b: "hello" }; } } -`); \ No newline at end of file +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index fda5b1a30cd..34afb71ec85 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -225,7 +225,7 @@ declare namespace FourSlashInterface { noMatchingBracePositionInCurrentFile(bracePosition: number): void; DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; noDocCommentTemplate(): void; - rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number): void; + rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void; importFixAtPosition(expectedTextArray: string[], errorCode?: number): void; navigationBar(json: any): void; From 9110461294c4e660a7be5fd7b3e2dbe8bd8b2db4 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 15 Feb 2017 14:24:25 -0800 Subject: [PATCH 11/14] use getBaseTypeOfLiteralType --- src/compiler/checker.ts | 2 +- src/compiler/types.ts | 2 +- src/services/codefixes/fixAddMissingMember.ts | 20 +++++++++++++++++-- src/services/tsconfig.json | 1 + 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c593fcd6737..426704a3435 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -83,7 +83,7 @@ namespace ts { getSignaturesOfType, getIndexTypeOfType, getBaseTypes, - getWidenedType, + getBaseTypeOfLiteralType, getTypeFromTypeNode, getParameterType: getTypeAtPosition, getReturnTypeOfSignature, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2b121627b45..52c9cecd8e8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2382,7 +2382,7 @@ getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type; getBaseTypes(type: InterfaceType): BaseType[]; - getWidenedType(type: Type): Type; + getBaseTypeOfLiteralType(type: Type): Type; getReturnTypeOfSignature(signature: Signature): Type; /** * Gets the type of a parameter at a given position in a signature. diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 24fc6b16abb..fbb8b3a483b 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -30,6 +30,22 @@ namespace ts.codefix { // if function call, synthesize function declaration if(token.parent.parent.kind == SyntaxKind.CallExpression) { + const callExpression = token.parent.parent as CallExpression; + if(callExpression.typeArguments) { + /** + * We can't in general know which arguments should use the type of the expression + * or the type of the type argument in the declaration. Consider + * ``` + * class A { + * constructor(a: number){ + * this.foo(a,1,true); + * } + * } + * ``` + */ + return undefined; + } + } @@ -41,8 +57,8 @@ namespace ts.codefix { binaryExpression.operatorToken; const checker = context.program.getTypeChecker(); - const type = checker.getWidenedType(checker.getTypeAtLocation(binaryExpression.right)); - typeString = checker.typeToString(type); + const widenedType = checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)); + typeString = checker.typeToString(widenedType); } return [{ diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index b4e8289f367..d88cf137afa 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -78,6 +78,7 @@ "formatting/smartIndenter.ts", "formatting/tokenRange.ts", "codeFixProvider.ts", + "codefixes/fixAddMissingMember.ts", "codefixes/fixExtendsInterfaceBecomesImplements.ts", "codefixes/fixClassIncorrectlyImplementsInterface.ts", "codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", From cf3b4d6b0092ca174ccd519b9016c7921e77747c Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 15 Feb 2017 15:15:09 -0800 Subject: [PATCH 12/14] cleanup --- src/harness/fourslash.ts | 2 +- src/services/codefixes/fixAddMissingMember.ts | 163 +++++++----------- src/services/codefixes/helpers.ts | 8 +- 3 files changed, 71 insertions(+), 102 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index a722cb20724..49d1336c874 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2205,7 +2205,7 @@ namespace FourSlash { this.raiseError(`Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`); } } - + const fileChanges = ts.find(actions[index].changes, change => change.fileName === fileName); if (!fileChanges) { this.raiseError("The CodeFix found doesn't provide any changes in this file."); diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index fbb8b3a483b..ac03f606d59 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -1,98 +1,67 @@ -/* @internal */ -namespace ts.codefix { - registerCodeFix({ - errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code], - getCodeActions: getActionsForAddMissingMember - }); - - function getActionsForAddMissingMember(context: CodeFixContext): CodeAction[] | undefined { - - const sourceFile = context.sourceFile; - const start = context.span.start; - // This is the identifier in the case of a class declaration - // or the class keyword token in the case of a class expression. - const token = getTokenAtPosition(sourceFile, start); - - const classDeclaration = getContainingClass(token); - if (!classDeclaration) { - return undefined; - } - - const startPos = classDeclaration.members.pos; - - if (!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { - return undefined; - } - - if ((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { - return undefined; - } - - // if function call, synthesize function declaration - if(token.parent.parent.kind == SyntaxKind.CallExpression) { - const callExpression = token.parent.parent as CallExpression; - if(callExpression.typeArguments) { - /** - * We can't in general know which arguments should use the type of the expression - * or the type of the type argument in the declaration. Consider - * ``` - * class A { - * constructor(a: number){ - * this.foo(a,1,true); - * } - * } - * ``` - */ - return undefined; - } - - - } - - let typeString: string = 'any'; - - // if binary expression, try to infer type for LHS, else use any - if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { - const binaryExpression = token.parent.parent as BinaryExpression; - binaryExpression.operatorToken; - - const checker = context.program.getTypeChecker(); - const widenedType = checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)); - typeString = checker.typeToString(widenedType); - } - - return [{ - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]), - changes: [{ - fileName: sourceFile.fileName, - textChanges: [{ - span: { start: startPos, length: 0 }, - newText: `${token.getFullText(sourceFile)}: ${typeString};` - }] - }] - }, - { - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_accessor_for_missing_property_0), [token.getText()]), - changes: [{ - fileName: sourceFile.fileName, - textChanges: [{ - span: { start: startPos, length: 0 }, - newText: `[name: string]: ${typeString};` - }] - }] - }]; - } - - // Want to infer type of x when possible. ie: - // * assignment, - // * function call argument: foo(this.x) where foo(x: SomeType) - // * expression with a type assertion: this.x as MyFavoriteType - // * access expression: this.x.push("asdf") ... probably an array? - // * - // What if there are multiple usages of this.x? Create intersection over all usages? - - // needs to be in a class - // inferred type might be error. then add any. - // either make indexable of the inferred type - // add named member of the inferred type. +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code], + getCodeActions: getActionsForAddMissingMember + }); + + function getActionsForAddMissingMember(context: CodeFixContext): CodeAction[] | undefined { + + const sourceFile = context.sourceFile; + const start = context.span.start; + // This is the identifier of the missing property. eg: + // this.missing = 1; + // ^^^^^^^ + const token = getTokenAtPosition(sourceFile, start); + + if (token.kind != SyntaxKind.Identifier) { + return undefined; + } + + const classDeclaration = getContainingClass(token); + if (!classDeclaration) { + return undefined; + } + + if (!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { + return undefined; + } + + if ((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { + return undefined; + } + + let typeString = "any"; + + if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { + const binaryExpression = token.parent.parent as BinaryExpression; + + const checker = context.program.getTypeChecker(); + const widenedType = checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)); + typeString = checker.typeToString(widenedType); + } + + const startPos = classDeclaration.members.pos; + + return [{ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `${token.getFullText(sourceFile)}: ${typeString};` + }] + }] + }, + { + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_accessor_for_missing_property_0), [token.getText()]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `[name: string]: ${typeString};` + }] + }] + }]; + } } \ No newline at end of file diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 60efdef1e81..3eab994f84c 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -58,7 +58,7 @@ namespace ts.codefix { if (declarations.length === 1) { Debug.assert(signatures.length === 1); const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call); - return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`; + return getStubbedMethod(visibility, name, sigString, newlineChar); } let result = ""; @@ -78,7 +78,7 @@ namespace ts.codefix { bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker); } const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call); - result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`; + result += getStubbedMethod(visibility, name, sigString, newlineChar); return result; default: @@ -138,8 +138,8 @@ namespace ts.codefix { } } - export function getStubbedMethod(visibility: string, name: string, signature: string = '()', newlineChar: string): string { - return `${visibility}${name}${signature}${getMethodBodyStub(newlineChar)}`; + export function getStubbedMethod(visibility: string, name: string, sigString = "()", newlineChar: string): string { + return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`; } function getMethodBodyStub(newlineChar: string) { From 7fd711c81dd472a9acf535e099060e5698227f91 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 16 Feb 2017 13:10:03 -0800 Subject: [PATCH 13/14] Handle undefined import name --- src/services/findAllReferences.ts | 2 +- tests/cases/fourslash/findAllRefsForDefaultExport.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 111ea98417d..24d7d648272 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -154,7 +154,7 @@ namespace ts.FindAllReferences { const importDecl = importSpecifier.parent as ts.ImportDeclaration; Debug.assert(importDecl.moduleSpecifier === importSpecifier); const defaultName = importDecl.importClause.name; - const defaultReferencedSymbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(defaultName)); + const defaultReferencedSymbol = defaultName && checker.getAliasedSymbol(checker.getSymbolAtLocation(defaultName)); if (symbol === defaultReferencedSymbol) { return defaultName.text; } diff --git a/tests/cases/fourslash/findAllRefsForDefaultExport.ts b/tests/cases/fourslash/findAllRefsForDefaultExport.ts index c518bb8f59e..98e74e281ad 100644 --- a/tests/cases/fourslash/findAllRefsForDefaultExport.ts +++ b/tests/cases/fourslash/findAllRefsForDefaultExport.ts @@ -7,5 +7,8 @@ ////import [|{| "isWriteAccess": true, "isDefinition": true |}g|] from "./a"; /////*ref*/[|g|](); +// @Filename: c.ts +////import { f } from "./a"; + verify.singleReferenceGroup("function f(): void"); verify.goToDefinition("ref", "def"); From 1b6cf97766f48bd4a8072b31f6de8c0f02984da8 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 16 Feb 2017 13:37:35 -0800 Subject: [PATCH 14/14] widen type, index signature, and add tests --- src/compiler/checker.ts | 1 + src/compiler/diagnosticMessages.json | 2 +- src/compiler/types.ts | 1 + src/services/codefixes/fixAddMissingMember.ts | 4 ++-- ...xUndeclaredIndexSignatureNumericLiteral.ts | 17 ++++++++++++++ ...FixUndeclaredPropertyFunctionEmptyClass.ts | 20 +++++++++++++++++ ...UndeclaredPropertyFunctionNonEmptyClass.ts | 22 +++++++++++++++++++ .../codeFixUndeclaredPropertyObjectLiteral.ts | 10 +++++---- ...edPropertyObjectLiteralStrictNullChecks.ts | 21 ++++++++++++++++++ .../codeFixUndeclaredPropertyThisType.ts | 17 ++++++++++++++ 10 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyFunctionEmptyClass.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyFunctionNonEmptyClass.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteralStrictNullChecks.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyThisType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 426704a3435..ceae9739c40 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -84,6 +84,7 @@ namespace ts { getIndexTypeOfType, getBaseTypes, getBaseTypeOfLiteralType, + getWidenedType, getTypeFromTypeNode, getParameterType: getTypeAtPosition, getReturnTypeOfSignature, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a01676207be..04fb3a10d54 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3307,7 +3307,7 @@ "category": "Message", "code": 90016 }, - "Add index accessor for missing property '{0}'": { + "Add index signature for missing property '{0}'": { "category": "Message", "code": 90017 }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 52c9cecd8e8..e5d726199ca 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2383,6 +2383,7 @@ getIndexTypeOfType(type: Type, kind: IndexKind): Type; getBaseTypes(type: InterfaceType): BaseType[]; getBaseTypeOfLiteralType(type: Type): Type; + getWidenedType(type: Type): Type; getReturnTypeOfSignature(signature: Signature): Type; /** * Gets the type of a parameter at a given position in a signature. diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index ac03f606d59..6ae2ba3f51c 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -37,7 +37,7 @@ namespace ts.codefix { const binaryExpression = token.parent.parent as BinaryExpression; const checker = context.program.getTypeChecker(); - const widenedType = checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)); + const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right))); typeString = checker.typeToString(widenedType); } @@ -54,7 +54,7 @@ namespace ts.codefix { }] }, { - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_accessor_for_missing_property_0), [token.getText()]), + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]), changes: [{ fileName: sourceFile.fileName, textChanges: [{ diff --git a/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts new file mode 100644 index 00000000000..2e49a8184eb --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredIndexSignatureNumericLiteral.ts @@ -0,0 +1,17 @@ +/// + +//// [|class A { +//// constructor() { +//// this.x = 10; +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + [name: string]: number; + + constructor() { + this.x = 10; + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 1); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyFunctionEmptyClass.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyFunctionEmptyClass.ts new file mode 100644 index 00000000000..6f0a5de3557 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyFunctionEmptyClass.ts @@ -0,0 +1,20 @@ +/// + +//// [|class A { +//// constructor() { +//// this.x = function(x: number, y?: A){ +//// return x > 0 ? x : y; +//// } +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + x: (x: number, y?: A) => A; + constructor() { + this.x = function(x: number, y?: A){ + return x > 0 ? x : y; + } + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyFunctionNonEmptyClass.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyFunctionNonEmptyClass.ts new file mode 100644 index 00000000000..b05fb0d42b5 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyFunctionNonEmptyClass.ts @@ -0,0 +1,22 @@ +/// + +//// [|class A { +//// y: number; +//// constructor(public a: number) { +//// this.x = function(x: number, y?: A){ +//// return x > 0 ? x : y; +//// } +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + x: (x: number, y?: A) => number | A; + y: number; + constructor(public a: number) { + this.x = function(x: number, y?: A){ + return x > 0 ? x : y; + } + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts index 3f5c5f99887..a2647c5a21e 100644 --- a/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteral.ts @@ -2,16 +2,18 @@ //// [|class A { //// constructor() { -//// this.x = { a: 10, b: "hello" }; +//// let e: any = 10; +//// this.x = { a: 10, b: "hello", c: undefined, d: null, e: e }; //// } //// }|] verify.rangeAfterCodeFix(` class A { - x: { a: number; b: string; }; + x: { a: number; b: string; c: any; d: any; e: any; }; constructor() { - this.x = { a: 10, b: "hello" }; + let e: any = 10; + this.x = { a: 10, b: "hello", c: undefined, d: null, e: e }; } } -`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteralStrictNullChecks.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteralStrictNullChecks.ts new file mode 100644 index 00000000000..0b0ab8cdd59 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyObjectLiteralStrictNullChecks.ts @@ -0,0 +1,21 @@ +/// + +// @strictNullChecks: true + +//// [|class A { +//// constructor() { +//// let e: any = 10; +//// this.x = { a: 10, b: "hello", c: undefined, d: null, e: e }; +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + x: { a: number; b: string; c: undefined; d: null; e: any; }; + + constructor() { + let e: any = 10; + this.x = { a: 10, b: "hello", c: undefined, d: null, e: e }; + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyThisType.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyThisType.ts new file mode 100644 index 00000000000..56f9b34d809 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyThisType.ts @@ -0,0 +1,17 @@ +/// + +//// [|class A { +//// constructor() { +//// this.mythis = this; +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + mythis: this; + + constructor() { + this.mythis = this; + } +} +`, /*includeWhiteSpace*/ false, /*errorCode*/ undefined, /*index*/ 0);