Handel defining properties on function and class expressions in .js files
This commit is contained in:
parent
b8329a05c3
commit
39b3ecb78c
10 changed files with 94 additions and 31 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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((<VariableDeclaration>funcSymbol.valueDeclaration).initializer);
|
||||
}
|
||||
if (funcSymbol && funcSymbol.members && funcSymbol.flags & SymbolFlags.Function) {
|
||||
return getInferredClassType(funcSymbol);
|
||||
}
|
||||
else if (compilerOptions.noImplicitAny) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,4 +18,4 @@
|
|||
//// Person.getNa/**/ = 10;
|
||||
|
||||
goTo.marker();
|
||||
verify.not.completionListContains('getNa');
|
||||
verify.completionListContains('getName');
|
||||
|
|
11
tests/cases/fourslash/renameJsPropertyAssignment2.ts
Normal file
11
tests/cases/fourslash/renameJsPropertyAssignment2.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////class Minimatch {
|
||||
////}
|
||||
////Minimatch.[|staticProperty|] = "string";
|
||||
////console.log(Minimatch./**/[|staticProperty|]);
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false);
|
11
tests/cases/fourslash/renameJsPropertyAssignment3.ts
Normal file
11
tests/cases/fourslash/renameJsPropertyAssignment3.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////var C = class {
|
||||
////}
|
||||
////C.[|staticProperty|] = "string";
|
||||
////console.log(C./**/[|staticProperty|]);
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false);
|
15
tests/cases/fourslash/renameJsThisProperty05.ts
Normal file
15
tests/cases/fourslash/renameJsThisProperty05.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @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);
|
15
tests/cases/fourslash/renameJsThisProperty06.ts
Normal file
15
tests/cases/fourslash/renameJsThisProperty06.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @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);
|
Loading…
Reference in a new issue