Skip to content

Make object literal properties new identifier locations when not contextually typed #42612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ namespace ts.Completions {

// Get all entities in the current scope.
completionKind = CompletionKind.Global;
isNewIdentifierLocation = isNewIdentifierDefinitionLocation(contextToken);
isNewIdentifierLocation = isNewIdentifierDefinitionLocation();

if (previousToken !== contextToken) {
Debug.assert(!!previousToken, "Expected 'contextToken' to be defined when different from 'previousToken'.");
Expand Down Expand Up @@ -1849,18 +1849,19 @@ namespace ts.Completions {
return false;
}

function isNewIdentifierDefinitionLocation(previousToken: Node | undefined): boolean {
if (previousToken) {
const containingNodeKind = previousToken.parent.kind;
function isNewIdentifierDefinitionLocation(): boolean {
if (contextToken) {
const containingNodeKind = contextToken.parent.kind;
// Previous token may have been a keyword that was converted to an identifier.
switch (keywordForNode(previousToken)) {
switch (keywordForNode(contextToken)) {
case SyntaxKind.CommaToken:
return containingNodeKind === SyntaxKind.CallExpression // func( a, |
|| containingNodeKind === SyntaxKind.Constructor // constructor( a, | /* public, protected, private keywords are allowed here, so show completion */
|| containingNodeKind === SyntaxKind.NewExpression // new C(a, |
|| containingNodeKind === SyntaxKind.ArrayLiteralExpression // [a, |
|| containingNodeKind === SyntaxKind.BinaryExpression // const x = (a, |
|| containingNodeKind === SyntaxKind.FunctionType; // var x: (s: string, list|
|| containingNodeKind === SyntaxKind.FunctionType // var x: (s: string, list|
|| containingNodeKind === SyntaxKind.ObjectLiteralExpression; // const obj = { x, |

case SyntaxKind.OpenParenToken:
return containingNodeKind === SyntaxKind.CallExpression // func( |
Expand All @@ -1882,7 +1883,8 @@ namespace ts.Completions {
return containingNodeKind === SyntaxKind.ModuleDeclaration; // module A.|

case SyntaxKind.OpenBraceToken:
return containingNodeKind === SyntaxKind.ClassDeclaration; // class A{ |
return containingNodeKind === SyntaxKind.ClassDeclaration // class A { |
|| containingNodeKind === SyntaxKind.ObjectLiteralExpression; // const obj = { |

case SyntaxKind.EqualsToken:
return containingNodeKind === SyntaxKind.VariableDeclaration // const x = a|
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/completionListInObjectLiteral5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@
verify.completions({ marker: ["1"], excludes: ['obj'], includes: ['o'] });
verify.completions({ marker: ["2"], excludes: ['obj1'], includes: ['o', 'obj'] });
verify.completions({ marker: ["3"], includes: ['o', 'obj', 'obj1'] });
verify.completions({ marker: ["4"], includes: ['o'], excludes: ['obj'] });
verify.completions({ marker: ["4"], includes: ['o'], excludes: ['obj'], isNewIdentifierLocation: true });
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
//// f15({f/*15*/});
//// f16({f/*16*/});

//// f1({ f1, /*17*/ });

const locals = [
...(() => {
const symbols = [];
Expand All @@ -56,11 +58,13 @@ const locals = [
];
verify.completions(
// Non-contextual, any, unknown, object, Record<string, ..>, [key: string]: .., Type parameter, etc..
{ marker: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], exact: completion.globalsPlus(locals)},
{ marker: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], exact: completion.globalsPlus(locals), isNewIdentifierLocation: true },
// Has named property
{ marker: ["12", "13"], exact: "typed"},
{ marker: ["12", "13"], exact: "typed", isNewIdentifierLocation: false },
// Has both StringIndexType and named property
{ marker: ["14"], exact: "prop", isNewIdentifierLocation: true},
{ marker: ["14"], exact: "prop", isNewIdentifierLocation: true },
// NumberIndexType
{ marker: ["15", "16"], exact: [], isNewIdentifierLocation: true},
{ marker: ["15", "16"], exact: [], isNewIdentifierLocation: true },
// After comma
{ marker: ["17"], exact: completion.globalsPlus(locals), isNewIdentifierLocation: true },
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
verify.completions({
marker: "",
exact: completion.globalsPlus(["foo"]),
isNewIdentifierLocation: true,
preferences: { includeCompletionsForModuleExports: true },
});
1 change: 1 addition & 0 deletions tests/cases/fourslash/completionsGenericUnconstrained.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

verify.completions({
marker: "",
isNewIdentifierLocation: true,
includes: [{
name: "Object",
sortText: completion.SortText.GlobalsOrKeywords
Expand Down
6 changes: 4 additions & 2 deletions tests/cases/fourslash/completionsSelfDeclaring2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

verify.completions({
marker: "1",
exact: completion.globalsPlus(["f1", "f2"])
exact: completion.globalsPlus(["f1", "f2"]),
isNewIdentifierLocation: true
});

verify.completions({
marker: "2",
exact: ["xyz"]
exact: ["xyz"],
isNewIdentifierLocation: false
});