Remove hack to get target of GetAccessor symbol (#27868)

* Remove hack to get target of GetAccessor symbol

* Add tests and get moveToNewFile to work with binding patterns
This commit is contained in:
Andy 2018-10-22 11:44:06 -07:00 committed by GitHub
parent 02c74987b7
commit d3d4f83f89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 16 deletions

View File

@ -1328,8 +1328,10 @@ Actual: ${stringify(fullActual)}`);
})));
}
public verifyQuickInfoAt(markerName: string, expectedText: string, expectedDocumentation?: string) {
this.goToMarker(markerName);
public verifyQuickInfoAt(markerName: string | Range, expectedText: string, expectedDocumentation?: string) {
if (typeof markerName === "string") this.goToMarker(markerName);
else this.goToRangeStart(markerName);
this.verifyQuickInfoString(expectedText, expectedDocumentation);
}
@ -4221,7 +4223,7 @@ namespace FourSlashInterface {
this.state.verifyQuickInfoString(expectedText, expectedDocumentation);
}
public quickInfoAt(markerName: string, expectedText: string, expectedDocumentation?: string) {
public quickInfoAt(markerName: string | FourSlash.Range, expectedText: string, expectedDocumentation?: string) {
this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation);
}

View File

@ -612,7 +612,7 @@ namespace ts.refactor {
| ImportEqualsDeclaration;
type TopLevelDeclarationStatement = NonVariableTopLevelDeclaration | VariableStatement;
interface TopLevelVariableDeclaration extends VariableDeclaration { parent: VariableDeclarationList & { parent: VariableStatement; }; }
type TopLevelDeclaration = NonVariableTopLevelDeclaration | TopLevelVariableDeclaration;
type TopLevelDeclaration = NonVariableTopLevelDeclaration | TopLevelVariableDeclaration | BindingElement;
function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration {
return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent);
}
@ -653,7 +653,7 @@ namespace ts.refactor {
return cb(statement as FunctionDeclaration | ClassDeclaration | EnumDeclaration | ModuleDeclaration | TypeAliasDeclaration | InterfaceDeclaration | ImportEqualsDeclaration);
case SyntaxKind.VariableStatement:
return forEach((statement as VariableStatement).declarationList.declarations as ReadonlyArray<TopLevelVariableDeclaration>, cb);
return firstDefined((statement as VariableStatement).declarationList.declarations, decl => forEachTopLevelDeclarationInBindingName(decl.name, cb));
case SyntaxKind.ExpressionStatement: {
const { expression } = statement as ExpressionStatement;
@ -663,13 +663,32 @@ namespace ts.refactor {
}
}
}
function forEachTopLevelDeclarationInBindingName<T>(name: BindingName, cb: (node: TopLevelDeclaration) => T): T | undefined {
switch (name.kind) {
case SyntaxKind.Identifier:
return cb(cast(name.parent, (x): x is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(x) || isBindingElement(x)));
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.ObjectBindingPattern:
return firstDefined(name.elements, em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb));
default:
return Debug.assertNever(name);
}
}
function nameOfTopLevelDeclaration(d: TopLevelDeclaration): Identifier | undefined {
return d.kind === SyntaxKind.ExpressionStatement ? d.expression.left.name : tryCast(d.name, isIdentifier);
return isExpressionStatement(d) ? d.expression.left.name : tryCast(d.name, isIdentifier);
}
function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLevelDeclarationStatement {
return isVariableDeclaration(d) ? d.parent.parent : d;
switch (d.kind) {
case SyntaxKind.VariableDeclaration:
return d.parent.parent;
case SyntaxKind.BindingElement:
return getTopLevelDeclarationStatement(
cast(d.parent.parent, (p): p is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(p) || isBindingElement(p)));
default:
return d;
}
}
function addExportToChanges(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, changes: textChanges.ChangeTracker, useEs6Exports: boolean): void {

View File

@ -1337,15 +1337,9 @@ namespace ts {
!bindingElement.propertyName;
}
export function getPropertySymbolFromBindingElement(checker: TypeChecker, bindingElement: ObjectBindingElementWithoutPropertyName) {
export function getPropertySymbolFromBindingElement(checker: TypeChecker, bindingElement: ObjectBindingElementWithoutPropertyName): Symbol | undefined {
const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent);
const propSymbol = typeOfPattern && checker.getPropertyOfType(typeOfPattern, bindingElement.name.text);
if (propSymbol && propSymbol.flags & SymbolFlags.Accessor) {
// See GH#16922
Debug.assert(!!(propSymbol.flags & SymbolFlags.Transient));
return (propSymbol as TransientSymbol).target;
}
return propSymbol;
return typeOfPattern && checker.getPropertyOfType(typeOfPattern, bindingElement.name.text);
}
/**

View File

@ -0,0 +1,26 @@
/// <reference path="fourslash.ts" />
// @noLib: true
// @Filename: /a.ts
////class C {
//// get [|{| "isWriteAccess": true, "isDefinition": true |}g|](): number { return 0; }
////
//// set [|{| "isWriteAccess": true, "isDefinition": true |}s|](value: number) {}
////}
////const { [|{| "isWriteAccess": true, "isDefinition": true |}g|], [|{| "isWriteAccess": true, "isDefinition": true |}s|] } = new C();
const [g0, s0, g1, s1] = test.ranges();
verify.quickInfoAt(g0, "(property) C.g: number");
verify.referenceGroups(g0, [{ definition: "(property) C.g: number", ranges: [g0, g1] }]);
verify.referenceGroups(g1, [
{ definition: "(property) C.g: number", ranges: [g0] },
{ definition: "const g: number", ranges: [g1] },
]);
verify.quickInfoAt(s0, "(property) C.s: number");
verify.referenceGroups(s0, [{ definition: "(property) C.s: number", ranges: [s0, s1] }]);
verify.referenceGroups(s1, [
{ definition: "(property) C.s: number", ranges: [s0] },
{ definition: "const s: number", ranges: [s1] }
]);

View File

@ -322,7 +322,7 @@ declare namespace FourSlashInterface {
/** Verify the quick info available at the current marker. */
quickInfoIs(expectedText: string, expectedDocumentation?: string): void;
/** Goto a marker and call `quickInfoIs`. */
quickInfoAt(markerName: string, expectedText?: string, expectedDocumentation?: string): void;
quickInfoAt(markerName: string | Range, expectedText?: string, expectedDocumentation?: string): void;
/**
* Call `quickInfoAt` for each pair in the object.
* (If the value is an array, it is [expectedText, expectedDocumentation].)

View File

@ -0,0 +1,23 @@
/// <reference path='fourslash.ts' />
// @Filename: /a.ts
////[|export const [x, { p: y }] = [0, { p: 1 }];|]
// @Filename: /b.ts
////import { x, y } from "./a";
verify.noErrors();
verify.moveToNewFile({
newFileContents: {
"/a.ts": "",
"/x.ts":
`export const [x, { p: y }] = [0, { p: 1 }];`,
"/b.ts":
`
import { x, y } from "./x";
`,
},
});

View File

@ -0,0 +1,33 @@
/// <reference path='fourslash.ts' />
// @Filename: /a.ts
////class C {
//// get g() { return 0; }
//// get h() { return 1; }
////}
////[|export const { g, h: i } = new C();|]
// @Filename: /b.ts
////import { g, i } from "./a";
verify.noErrors();
verify.moveToNewFile({
newFileContents: {
"/a.ts":
`export class C {
get g() { return 0; }
get h() { return 1; }
}
`,
"/g.ts":
`import { C } from "./a";
export const { g, h: i } = new C();`,
"/b.ts":
`
import { g, i } from "./g";
`,
},
});