Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
19 changes: 17 additions & 2 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1892,13 +1892,27 @@ namespace ts.Completions {

if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
const instantiatedType = tryGetObjectLiteralContextualType(objectLikeContainer, typeChecker);

// Check completions for Object property value shorthand
if (instantiatedType === undefined) {
return GlobalsSearch.Fail;
if (objectLikeContainer.flags & NodeFlags.InWithStatement) {
return GlobalsSearch.Fail;
}
return GlobalsSearch.Continue;
}
const completionsType = typeChecker.getContextualType(objectLikeContainer, ContextFlags.Completions);
isNewIdentifierLocation = hasIndexSignature(completionsType || instantiatedType);
const hasStringIndexType = (completionsType || instantiatedType).getStringIndexType();
const hasNumberIndextype = (completionsType || instantiatedType).getNumberIndexType();
isNewIdentifierLocation = !!hasStringIndexType || !!hasNumberIndextype;
typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker);
existingMembers = objectLikeContainer.properties;

if (typeMembers.length === 0) {
// Edge case: If NumberIndexType exists
if (!hasNumberIndextype) {
return GlobalsSearch.Continue;
}
}
}
else {
Debug.assert(objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern);
Expand Down Expand Up @@ -2312,6 +2326,7 @@ namespace ts.Completions {
}

return isDeclarationName(contextToken)
&& !isShorthandPropertyAssignment(contextToken.parent)
&& !isJsxAttribute(contextToken.parent)
// Don't block completions if we're in `class C /**/`, because we're *past* the end of the identifier and might want to complete `extends`.
// If `contextToken !== previousToken`, this is `class C ex/**/`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
/// <reference path='fourslash.ts' />

// @Filename: a.ts
//// var [x/*variable1*/

// @Filename: b.ts
//// var [x, y/*variable2*/

// @Filename: c.ts
//// var [./*variable3*/

// @Filename: d.ts
//// var [x, ...z/*variable4*/

// @Filename: e.ts
//// var {x/*variable5*/

// @Filename: f.ts
//// var {x, y/*variable6*/

// @Filename: g.ts
//// function func1({ a/*parameter1*/

// @Filename: h.ts
//// function func2({ a, b/*parameter2*/

verify.completions({ marker: test.markers(), exact: undefined });
verify.completions({ marker: test.markers(), exact: undefined });
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/// <reference path="fourslash.ts"/>

//// declare const foo: number;
//// interface Empty {}
//// interface Typed { typed: number; }

//// declare function f1(obj): void;
//// declare function f2(obj: any): void;
//// declare function f3(obj: unknown): void;
//// declare function f4(obj: object): void;
//// declare function f5(obj: Record<string, any>): void;
//// declare function f6(obj: { [key: string]: number }): void;
//// declare function f7<T>(obj: T): void;
//// declare function f8<T extends object>(obj: T): void;
//// declare function f9<T extends {}>(obj: T): void;
//// declare function f10<T extends Empty>(obj: T): void;
//// declare function f11<T extends (Empty | Record<string, any> | {})>(obj: T): void;
//// declare function f12(obj: Object): void;
//// declare function f13<T extends Object>(obj: T): void;
//// declare function f14(obj: Typed): void;
//// declare function f15<T extends (Empty | Object | Typed)>(obj: T): void;
//// declare function f16(obj: Record<number, any>): void;
//// declare function f17(obj: { [key: string]: number, prop: number }): void;
//// declare function f18(obj: { [key: number]: number }): void;

//// f1({f/*1*/});
//// f2({f/*2*/});
//// f3({f/*3*/});
//// f4({f/*4*/});
//// f5({f/*5*/});
//// f6({f/*6*/});
//// f7({f/*7*/});
//// f8({f/*8*/});
//// f9({f/*9*/});
//// f10({f/*10*/});
//// f11({f/*11*/});
//// f12({f/*12*/});
//// f13({f/*13*/});
//// f14({f/*14*/});
//// f15({f/*15*/});
//// f16({f/*16*/});
//// f17({f/*17*/});
//// f18({f/*18*/});

verify.completions(
{ marker: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], includes: ["foo"]},
{ marker: ["12", "13", "14", "15"], excludes: ["foo"]},
{ marker: ["16", "17", "18"], excludes: ["foo"], isNewIdentifierLocation: true},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// <reference path="fourslash.ts"/>

//// const foo = 1;
//// const bar = 2;

//// const obj1 = {
//// foo b/*1*/
//// };

//// const obj2: any = {
//// foo b/*2*/
//// };

verify.completions({
marker: test.markers(),
includes: ["bar"]
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference path="fourslash.ts"/>

//// const foo = 1;
//// const bar = 2;
//// const obj = {
//// foo b/*1*/

verify.completions({
marker: ["1"],
includes: ["bar"]
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference path="fourslash.ts"/>

//// const foo = 1;
//// const bar = 2;
//// const obj: any = {
//// foo b/*1*/

verify.completions({
marker: ["1"],
includes: ["bar"]
});
5 changes: 4 additions & 1 deletion tests/cases/fourslash/completionsGenericUnconstrained.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@

verify.completions({
marker: "",
exact: []
includes: [{
name: "Object",
sortText: completion.SortText.GlobalsOrKeywords
}]
});
5 changes: 4 additions & 1 deletion tests/cases/fourslash/completionsSelfDeclaring2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

verify.completions({
marker: "1",
exact: []
includes: [{
name: "Object",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit of a pain, but can we try to keep using exact in all these tests? Hopefully in this case it’s just exact: completion.globals. exact is useful in some of these other tests for ensuring that locals get sorted before globals, which is important to this feature. I’m almost on the fence about whether globals should show up here at all (who wants to declare something like const obj = { Object, Date, setTimeout }?), but I think as long as they get sorted below locals, it’s fine.

Copy link
Contributor Author

@orange4glace orange4glace Nov 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! I'll fix it after I find out how I can do this elegantly. :)

I’m almost on the fence about whether globals should show up here at all

I agree with that by the way.

Copy link
Contributor Author

@orange4glace orange4glace Dec 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sortText: completion.SortText.GlobalsOrKeywords
}]
});

verify.completions({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
// 5, 6: Literal member completion after member name with empty member expression.
const exact = ["p1", "p2", "p3", "p4", ...completion.globalsPlus(["ObjectLiterals"])];
verify.completions(
{ marker: ["1"], exact, isNewIdentifierLocation: true },
{ marker: ["2", "3", "5", "6"], exact },
{ marker: "4", exact: undefined },
{ marker: ["1",], exact, isNewIdentifierLocation: true },
{ marker: ["2", "3", "4", "5", "6"], exact }
);