diff --git a/src/services/completions.ts b/src/services/completions.ts
index c55783b060a72..77c12920f2f41 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -160,6 +160,8 @@ import {
isImportKeyword,
isImportSpecifier,
isInComment,
+ isIndexSignatureDeclaration,
+ isInferTypeNode,
isInitializedProperty,
isInJSFile,
isInRightSideOfInternalImportEqualsDeclaration,
@@ -226,6 +228,7 @@ import {
isTypeOfExpression,
isTypeOnlyImportDeclaration,
isTypeOnlyImportOrExportDeclaration,
+ isTypeParameterDeclaration,
isTypeReferenceType,
isValidTypeOnlyAliasUseSite,
isVariableDeclaration,
@@ -283,6 +286,7 @@ import {
ObjectType,
ObjectTypeDeclaration,
or,
+ ParameterDeclaration,
ParenthesizedTypeNode,
positionBelongsToNode,
positionIsASICandidate,
@@ -350,6 +354,7 @@ import {
TypeLiteralNode,
TypeNode,
TypeOnlyImportDeclaration,
+ TypeParameterDeclaration,
TypeQueryNode,
TypeReferenceNode,
unescapeLeadingUnderscores,
@@ -2048,7 +2053,7 @@ export function getCompletionEntriesFromSymbols(
isRightOfOpenTag?: boolean,
): UniqueNameSet {
const start = timestamp();
- const variableDeclaration = getVariableDeclaration(location);
+ const variableOrParameterDeclaration = getVariableOrParameterDeclaration(contextToken);
const useSemicolons = probablyUsesSemicolons(sourceFile);
const typeChecker = program.getTypeChecker();
// Tracks unique names.
@@ -2121,10 +2126,27 @@ export function getCompletionEntriesFromSymbols(
}
// Filter out variables from their own initializers
// `const a = /* no 'a' here */`
- if (variableDeclaration && symbol.valueDeclaration === variableDeclaration) {
+ if (tryCast(variableOrParameterDeclaration, isVariableDeclaration) && symbol.valueDeclaration === variableOrParameterDeclaration) {
return false;
}
+ // Filter out parameters from their own initializers
+ // `function f(a = /* no 'a' and 'b' here */, b) { }` or
+ // `function f(a: T) { }`
+ const symbolDeclaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
+ if (variableOrParameterDeclaration && symbolDeclaration && (
+ (isTypeParameterDeclaration(variableOrParameterDeclaration) && isTypeParameterDeclaration(symbolDeclaration)) ||
+ (isParameter(variableOrParameterDeclaration) && isParameter(symbolDeclaration))
+ )) {
+ const symbolDeclarationPos = symbolDeclaration.pos;
+ const parameters = isParameter(variableOrParameterDeclaration) ? variableOrParameterDeclaration.parent.parameters :
+ isInferTypeNode(variableOrParameterDeclaration.parent) ? undefined :
+ variableOrParameterDeclaration.parent.typeParameters;
+ if (symbolDeclarationPos >= variableOrParameterDeclaration.pos && parameters && symbolDeclarationPos < parameters.end) {
+ return false;
+ }
+ }
+
// External modules can have global export declarations that will be
// available as global keywords in all scopes. But if the external module
// already has an explicit export and user only wants to user explicit
@@ -5084,17 +5106,22 @@ function isModuleSpecifierMissingOrEmpty(specifier: ModuleReference | Expression
return !tryCast(isExternalModuleReference(specifier) ? specifier.expression : specifier, isStringLiteralLike)?.text;
}
-function getVariableDeclaration(property: Node): VariableDeclaration | undefined {
- const variableDeclaration = findAncestor(property, node =>
+function getVariableOrParameterDeclaration(contextToken: Node | undefined) {
+ if (!contextToken) return;
+
+ const declaration = findAncestor(contextToken, node =>
isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node)
? "quit"
- : isVariableDeclaration(node));
-
- return variableDeclaration as VariableDeclaration | undefined;
+ : isVariableDeclaration(node) || ((isParameter(node) || isTypeParameterDeclaration(node)) && !isIndexSignatureDeclaration(node.parent)));
+ return declaration as ParameterDeclaration | TypeParameterDeclaration | VariableDeclaration | undefined;
}
function isArrowFunctionBody(node: Node) {
- return node.parent && isArrowFunction(node.parent) && node.parent.body === node;
+ return node.parent && isArrowFunction(node.parent) &&
+ (node.parent.body === node ||
+ // const a = () => /**/;
+ node.kind === SyntaxKind.EqualsGreaterThanToken
+ );
}
/** True if symbol is a type or a module containing at least one type. */
diff --git a/tests/cases/fourslash/completionListInClosedFunction02.ts b/tests/cases/fourslash/completionListInClosedFunction02.ts
index bfda6646fd736..77522ca225914 100644
--- a/tests/cases/fourslash/completionListInClosedFunction02.ts
+++ b/tests/cases/fourslash/completionListInClosedFunction02.ts
@@ -7,6 +7,5 @@
verify.completions({
marker: "1",
- // Note: `c: typeof c` would be a compile error
- includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"],
+ includes: ["foo", "x", "y", "z", "bar", "a", "b"],
});
diff --git a/tests/cases/fourslash/completionListInClosedFunction03.ts b/tests/cases/fourslash/completionListInClosedFunction03.ts
index 3ee7cd43d2496..85a0bc3d8a6ec 100644
--- a/tests/cases/fourslash/completionListInClosedFunction03.ts
+++ b/tests/cases/fourslash/completionListInClosedFunction03.ts
@@ -9,5 +9,5 @@
verify.completions({
marker: "1",
// Note: `c = c` would be a compile error
- includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"],
+ includes: ["foo", "x", "y", "z", "bar", "a", "b"],
});
diff --git a/tests/cases/fourslash/completionListInClosedFunction04.ts b/tests/cases/fourslash/completionListInClosedFunction04.ts
index 225cbbb1a2062..5dfbc5347f380 100644
--- a/tests/cases/fourslash/completionListInClosedFunction04.ts
+++ b/tests/cases/fourslash/completionListInClosedFunction04.ts
@@ -9,5 +9,5 @@
verify.completions({
marker: "1",
// Note: `b = b` or `b = c` would be a compile error
- includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"],
+ includes: ["foo", "x", "y", "z", "bar", "a"],
});
diff --git a/tests/cases/fourslash/completionListInClosedFunction05.ts b/tests/cases/fourslash/completionListInClosedFunction05.ts
index 11c1600934983..161c6ed3bda62 100644
--- a/tests/cases/fourslash/completionListInClosedFunction05.ts
+++ b/tests/cases/fourslash/completionListInClosedFunction05.ts
@@ -8,7 +8,6 @@
verify.completions({
marker: "1",
- // Note: `v = v` would be a compile error
- includes: ["foo", "x", "y", "z", "bar", "a", "b", "c", "v"],
+ includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"],
isNewIdentifierLocation: true,
});
diff --git a/tests/cases/fourslash/completionListInTypeParameterOfClassExpression1.ts b/tests/cases/fourslash/completionListInTypeParameterOfClassExpression1.ts
index 7435289eb5246..15f150cef62c1 100644
--- a/tests/cases/fourslash/completionListInTypeParameterOfClassExpression1.ts
+++ b/tests/cases/fourslash/completionListInTypeParameterOfClassExpression1.ts
@@ -7,4 +7,4 @@
////var C4 = class D{}
verify.completions({ marker: ["0", "1", "2", "3"], exact: undefined });
-verify.completions({ marker: "4", exact: completion.globalTypesPlus(["D", "T"]) });
+verify.completions({ marker: "4", exact: completion.globalTypesPlus(["D"]) });
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction02.ts b/tests/cases/fourslash/completionListInUnclosedFunction02.ts
index b46d51d2f69f6..d7183b3f694da 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction02.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction02.ts
@@ -3,5 +3,4 @@
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof /*1*/
-// Note: Ideally `c` wouldn't be included since it hasn't been initialized yet.
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"]})
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b"]})
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction03.ts b/tests/cases/fourslash/completionListInUnclosedFunction03.ts
index b094fe2e725d9..1aec54cf35269 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction03.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction03.ts
@@ -4,5 +4,4 @@
//// function bar(a: number, b: string, c: typeof /*1*/
////}
-// Note: Ideally `c` wouldn't be included since it hasn't been initialized yet.
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"]})
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b"]})
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction04.ts b/tests/cases/fourslash/completionListInUnclosedFunction04.ts
index 543b1bd321386..20a9b4efd7af8 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction04.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction04.ts
@@ -3,5 +3,4 @@
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof x = /*1*/
-// Note: Ideally `c` wouldn't be included since it hasn't been initialized yet.
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"]})
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b"]})
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction05.ts b/tests/cases/fourslash/completionListInUnclosedFunction05.ts
index 82d3611001d35..c077c5eb1e2da 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction05.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction05.ts
@@ -4,5 +4,4 @@
//// function bar(a: number, b: string, c: typeof x = /*1*/
////}
-// Note: Ideally `c` wouldn't be included since it hasn't been initialized yet.
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"]})
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b"]})
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction06.ts b/tests/cases/fourslash/completionListInUnclosedFunction06.ts
index 21b1349a60762..712ae4bae051c 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction06.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction06.ts
@@ -4,5 +4,4 @@
//// function bar(a: number, b: string = /*1*/, c: typeof x = "hello"
////
-// Note: Ideally `c` wouldn't be included since it hasn't been initialized yet.
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"]})
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a"]})
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction07.ts b/tests/cases/fourslash/completionListInUnclosedFunction07.ts
index 7863d9dd1f36c..dffb285559b9a 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction07.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction07.ts
@@ -4,5 +4,4 @@
//// function bar(a: number, b: string = /*1*/, c: typeof x = "hello"
////}
-// Note: Ideally `c` wouldn't be included since it hasn't been initialized yet.
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"]})
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a"]})
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction08.ts b/tests/cases/fourslash/completionListInUnclosedFunction08.ts
index c0616881bd6a9..090ef27227410 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction08.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction08.ts
@@ -4,5 +4,4 @@
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = /*1*/
-// Note: "v" questionable since we're in its initializer
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c", "v"], isNewIdentifierLocation: true });
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"], isNewIdentifierLocation: true });
diff --git a/tests/cases/fourslash/completionListInUnclosedFunction09.ts b/tests/cases/fourslash/completionListInUnclosedFunction09.ts
index 14827b1a891cd..b87a43eece085 100644
--- a/tests/cases/fourslash/completionListInUnclosedFunction09.ts
+++ b/tests/cases/fourslash/completionListInUnclosedFunction09.ts
@@ -5,5 +5,4 @@
//// var v = /*1*/
////}
-// Note: "v" questionable since we're in its initializer
-verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c", "v"], isNewIdentifierLocation: true });
+verify.completions({ marker: "1", includes: ["foo", "x", "y", "z", "bar", "a", "b", "c"], isNewIdentifierLocation: true });
diff --git a/tests/cases/fourslash/completionListWithoutVariableinitializer.ts b/tests/cases/fourslash/completionListWithoutVariableinitializer.ts
index 7ef57ca66e196..5d2a95b743cca 100644
--- a/tests/cases/fourslash/completionListWithoutVariableinitializer.ts
+++ b/tests/cases/fourslash/completionListWithoutVariableinitializer.ts
@@ -46,8 +46,7 @@ verify.completions({
verify.completions({
marker: ["7"],
- includes: ["a", "b", "c", "d", "e"],
- excludes: ["fn"],
+ includes: ["a", "b", "c", "d", "e", "fn"],
});
verify.completions({
@@ -59,4 +58,3 @@ verify.completions({
marker: ["9"],
includes: ["a", "b", "c", "d", "e", "fn"],
});
-
diff --git a/tests/cases/fourslash/noCompletionsForCurrentOrLaterParameters.ts b/tests/cases/fourslash/noCompletionsForCurrentOrLaterParameters.ts
new file mode 100644
index 0000000000000..6ed833c16f428
--- /dev/null
+++ b/tests/cases/fourslash/noCompletionsForCurrentOrLaterParameters.ts
@@ -0,0 +1,47 @@
+///
+
+//// function f1(a = /*1*/, b) { }
+//// function f2(a = a/*2*/, b) { }
+//// function f3(a = a + /*3*/, b = a/*4*/, c = /*5*/) { }
+//// function f3(a) {
+//// function f4(b = /*6*/, c) { }
+//// }
+//// const f5 = (a, b = (c = /*7*/, e) => { }, d = b) => { }
+////
+//// type A1 = K
+//// type A2 = K
+
+verify.completions({
+ marker: ["1", "2"],
+ excludes: ["a", "b"],
+})
+verify.completions({
+ marker: ["3"],
+ excludes: ["a", "b"],
+})
+
+verify.completions({
+ marker: ["4"],
+ includes: ["a"],
+})
+
+verify.completions({
+ marker: ["5"],
+ includes: ["a", "b"],
+})
+
+verify.completions({
+ marker: ["6"],
+ excludes: ["b", "c"],
+ includes: ["a"],
+})
+
+verify.completions({
+ marker: ["7"],
+ includes: ["a", "b", "d"],
+})
+
+verify.completions({
+ marker: ["T1", "T2"],
+ excludes: ["K", "L"],
+})