diff --git a/src/services/completions.ts b/src/services/completions.ts index 3e02ba7c20237..f0ad156956d82 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1504,6 +1504,8 @@ namespace ts.Completions { : KeywordCompletionFilters.TypeKeywords; } + const variableDeclaration = getVariableDeclaration(location); + filterMutate(symbols, symbol => { if (!isSourceFile(location)) { // export = /**/ here we want to get all meanings, so any symbol is ok @@ -1511,6 +1513,12 @@ namespace ts.Completions { return true; } + // Filter out variables from their own initializers + // `const a = /* no 'a' here */` + if (variableDeclaration && symbol.valueDeclaration === variableDeclaration) { + return false; + } + symbol = skipAlias(symbol, typeChecker); // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace) @@ -1529,6 +1537,19 @@ namespace ts.Completions { }); } + function getVariableDeclaration(property: Node): VariableDeclaration | undefined { + const variableDeclaration = findAncestor(property, node => + isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) + ? "quit" + : isVariableDeclaration(node)); + + return variableDeclaration as VariableDeclaration | undefined; + } + + function isArrowFunctionBody(node: Node) { + return node.parent && isArrowFunction(node.parent) && node.parent.body === node; + }; + function isTypeOnlyCompletion(): boolean { return insideJsDocTagTypeExpression || !isContextTokenValueLocation(contextToken) && diff --git a/tests/cases/fourslash/commentsClassMembers.ts b/tests/cases/fourslash/commentsClassMembers.ts index 1e17f0327fe7e..3cc9b27172958 100644 --- a/tests/cases/fourslash/commentsClassMembers.ts +++ b/tests/cases/fourslash/commentsClassMembers.ts @@ -201,7 +201,8 @@ verify.completions( ], }, { marker: ["29", "33", "38", "109"], includes: locals }, - { marker: ["35", "40", "87"], includes: locals, isNewIdentifierLocation: true }, + { marker: ["35", "40"], includes: locals, isNewIdentifierLocation: true }, + { marker: ["87"], includes: locals.filter(local => local === 'i1_s_p') , isNewIdentifierLocation: true }, { marker: "31", includes: { name: "b", text: "(parameter) b: number", documentation: "number to add" } }, { marker: "42", includes: { name: "value", text: "(parameter) value: number", documentation: "this is value" }, isNewIdentifierLocation: true }, { marker: ["45", "52", "59"], includes: { name: "b", text: "(parameter) b: number" } }, diff --git a/tests/cases/fourslash/completionListBuilderLocations_VariableDeclarations.ts b/tests/cases/fourslash/completionListBuilderLocations_VariableDeclarations.ts index af119f40be57f..eaad02afcc52f 100644 --- a/tests/cases/fourslash/completionListBuilderLocations_VariableDeclarations.ts +++ b/tests/cases/fourslash/completionListBuilderLocations_VariableDeclarations.ts @@ -26,8 +26,15 @@ ////var y = 10; y=/*var12*/ +// first declaration verify.completions({ - marker: test.markers(), + marker: ["var1"], + exact: completion.globalsPlus(["y", "C"]), + isNewIdentifierLocation: true +}); + +verify.completions({ + marker: ["var2", "var3", "var4", "var5", "var6", "var7", "var8", "var9", "var10", "var11", "var12"], exact: completion.globalsPlus(["x", "y", "C"]), isNewIdentifierLocation: true }); diff --git a/tests/cases/fourslash/completionListInObjectLiteral5.ts b/tests/cases/fourslash/completionListInObjectLiteral5.ts new file mode 100644 index 0000000000000..eb245d748bf41 --- /dev/null +++ b/tests/cases/fourslash/completionListInObjectLiteral5.ts @@ -0,0 +1,26 @@ +/// + +////const o = 'something' +////const obj = { +//// prop: o/*1*/, +//// pro() { +//// const obj1 = { +//// p:{ +//// s: { +//// h: { +//// hh: o/*2*/ +//// }, +//// someFun() { +//// o/*3*/ +//// } +//// } +//// } +//// } +//// }, +//// o/*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'] }); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListIsGlobalCompletion.ts b/tests/cases/fourslash/completionListIsGlobalCompletion.ts index 91cd1a0f9c7e5..7184e50499e00 100644 --- a/tests/cases/fourslash/completionListIsGlobalCompletion.ts +++ b/tests/cases/fourslash/completionListIsGlobalCompletion.ts @@ -41,12 +41,13 @@ verify.completions( { marker: ["1", "3", "6", "8", "12", "14"], exact: undefined, isGlobalCompletion: false }, { marker: "2", exact: ["a.ts", "file.ts"], isGlobalCompletion: false, isNewIdentifierLocation: true }, { marker: ["4", "19"], exact: [], isGlobalCompletion: false }, - { marker: ["5", "11", "18"], exact: globals, isGlobalCompletion: true }, + { marker: ["5", "11"], exact: globals, isGlobalCompletion: true }, + { marker: ["18"], exact: globals.filter(name => name !== 'user'), isGlobalCompletion: true }, { marker: "7", exact: completion.globalsInsideFunction(x), isGlobalCompletion: true }, { marker: "9", exact: ["x", "y"], isGlobalCompletion: false }, { marker: "10", exact: completion.classElementKeywords, isGlobalCompletion: false, isNewIdentifierLocation: true }, - { marker: "13", exact: globals, isGlobalCompletion: false }, - { marker: "15", exact: globals, isGlobalCompletion: true, isNewIdentifierLocation: true }, - { marker: "16", exact: [...x, completion.globalThisEntry, ...completion.globalsVars, completion.undefinedVarEntry], isGlobalCompletion: false }, + { marker: "13", exact: globals.filter(name => name !== 'z'), isGlobalCompletion: false }, + { marker: "15", exact: globals.filter(name => name !== 'x'), isGlobalCompletion: true, isNewIdentifierLocation: true }, + { marker: "16", exact: [...x, completion.globalThisEntry, ...completion.globalsVars, completion.undefinedVarEntry].filter(name => name !== 'user'), isGlobalCompletion: false }, { marker: "17", exact: completion.globalKeywords, isGlobalCompletion: false }, ); diff --git a/tests/cases/fourslash/completionListWithMeanings.ts b/tests/cases/fourslash/completionListWithMeanings.ts index 034607d08c021..82c69d43a48de 100644 --- a/tests/cases/fourslash/completionListWithMeanings.ts +++ b/tests/cases/fourslash/completionListWithMeanings.ts @@ -36,10 +36,20 @@ const types: ReadonlyArray = [ ...completion.typeKeywords, ]; +const filterValuesByName = (name: string) => { + return values.filter(entry => { + if (typeof entry === 'string') { + return entry !== name; + } + + return entry.name !== name; + }) +} + verify.completions( - { marker: "valueExpr", exact: values, isNewIdentifierLocation: true }, + { marker: "valueExpr", exact: filterValuesByName('tt'), isNewIdentifierLocation: true }, { marker: "typeExpr", exact: types, }, - { marker: "valueExprInObjectLiteral", exact: values }, + { marker: "valueExprInObjectLiteral", exact: filterValuesByName('yy') }, { marker: "membertypeExpr", exact: [{ name: "point3", text: "interface m3.point3" }] }, { marker: "membervalueExpr", exact: [{ name: "zz2", text: "var m3.zz2: number" }] }, ); diff --git a/tests/cases/fourslash/completionListWithoutVariableinitializer.ts b/tests/cases/fourslash/completionListWithoutVariableinitializer.ts new file mode 100644 index 0000000000000..7ef57ca66e196 --- /dev/null +++ b/tests/cases/fourslash/completionListWithoutVariableinitializer.ts @@ -0,0 +1,62 @@ +/// + +//// const a = a/*1*/; +//// const b = a && b/*2*/; +//// const c = [{ prop: [c/*3*/] }]; +//// const d = () => { d/*4*/ }; +//// const e = () => expression/*5*/ +//// const f = { prop() { e/*6*/ } }; +//// const fn = (p = /*7*/) => {} +//// const { g, h = /*8*/ } = { ... } +//// const [ g1, h1 = /*9*/ ] = [ ... ] + +verify.completions({ + marker: ["1"], + excludes: ["a"], + isNewIdentifierLocation: true, +}); + +verify.completions({ + marker: ["2"], + excludes: ["b"], + includes: ["a"], +}); + +verify.completions({ + marker: ["3"], + excludes: ["c"], + includes: ["a", "b"], + isNewIdentifierLocation: true, +}); + +verify.completions({ + marker: ["4"], + includes: ["a", "b", "c", "d"], +}); + +verify.completions({ + marker: ["5"], + includes: ["a", "b", "c", "d", "e"], +}); + +verify.completions({ + marker: ["6"], + includes: ["a", "b", "c", "d", "e"], +}); + +verify.completions({ + marker: ["7"], + includes: ["a", "b", "c", "d", "e"], + excludes: ["fn"], +}); + +verify.completions({ + marker: ["8"], + includes: ["a", "b", "c", "d", "e", "fn"], +}); + +verify.completions({ + marker: ["9"], + includes: ["a", "b", "c", "d", "e", "fn"], +}); + diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts index ec54418c77935..40aa223b7eced 100644 --- a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts +++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts @@ -12,6 +12,11 @@ //// }; verify.completions({ - marker: test.markers(), - exact: completion.globalsPlus(["foo", "bar", "obj1", "obj2"]), + marker: ["1"], + exact: completion.globalsPlus(["foo", "bar", "obj2"]), +}); + +verify.completions({ + marker: ["2"], + exact: completion.globalsPlus(["foo", "bar", "obj1"]), }); diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts index 0a6fad60b293e..70c1f60055425 100644 --- a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts +++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts @@ -7,5 +7,5 @@ verify.completions({ marker: ["1"], - exact: completion.globalsPlus(["foo", "bar", "obj"]) + exact: completion.globalsPlus(["foo", "bar"]), }); diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts index 35daa6185a3f1..a720bcc1dc6b2 100644 --- a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts +++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts @@ -7,5 +7,5 @@ verify.completions({ marker: ["1"], - exact: completion.globalsPlus(["foo", "bar", "obj"]) + exact: completion.globalsPlus(["foo", "bar"]), }); diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts index 74ded23477463..979b0b2afe767 100644 --- a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts +++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts @@ -4,10 +4,11 @@ //// export const exportedConstant = 0; // @Filename: /b.ts +//// const foo = 'foo' //// const obj = { exp/**/ verify.completions({ - marker: "", - exact: completion.globalsPlus(["obj"]), - preferences: { includeCompletionsForModuleExports: true } -}); \ No newline at end of file + marker: "", + exact: completion.globalsPlus(["foo"]), + preferences: { includeCompletionsForModuleExports: true }, +}); diff --git a/tests/cases/fourslash/completionTypeAssertion.ts b/tests/cases/fourslash/completionTypeAssertion.ts index bb5c6f8abda29..fbfe72ac455cc 100644 --- a/tests/cases/fourslash/completionTypeAssertion.ts +++ b/tests/cases/fourslash/completionTypeAssertion.ts @@ -1,5 +1,6 @@ /// -//// var x = this as/*1*/ +//// var x = 'something' +//// var y = this as/*1*/ verify.completions({marker: "1", exact: completion.globalsPlus(["x"]) }) diff --git a/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts b/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts index 503758461489b..00d5ef2c6e0d6 100644 --- a/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts +++ b/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts @@ -28,6 +28,8 @@ // 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", "4", "5", "6"], exact } + { marker: ["1",], exact: exact.filter(name => name !== 'p1'), isNewIdentifierLocation: true }, + { marker: ["2", "3"], exact: exact.filter(name => name !== 'p2') }, + { marker: ["4"], exact: exact.filter(name => name !== 'p3' ) }, + { marker: ["5", "6"], exact: exact.filter(name => name !== 'p4') }, ); diff --git a/tests/cases/fourslash/tsxCompletionOnOpeningTagWithoutJSX1.ts b/tests/cases/fourslash/tsxCompletionOnOpeningTagWithoutJSX1.ts index c7f3b3f26bebb..256c4280f856d 100644 --- a/tests/cases/fourslash/tsxCompletionOnOpeningTagWithoutJSX1.ts +++ b/tests/cases/fourslash/tsxCompletionOnOpeningTagWithoutJSX1.ts @@ -1,6 +1,7 @@ /// //@Filename: file.tsx -//// var x =