diff --git a/src/services/completions.ts b/src/services/completions.ts index 9fe0703647..1206030437 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1506,15 +1506,6 @@ namespace ts.Completions { return GlobalsSearch.Success; } - // Set SortText to OptionalMember if it is an optinoal member - function setSortTextToOptionalMember() { - symbols.forEach(m => { - if (SymbolDisplay.getSymbolModifiers(m) === "optional") { - symbolToSortTextMap[getSymbolId(m)] = symbolToSortTextMap[getSymbolId(m)] || SortText.OptionalMember; - } - }); - } - /** * Aggregates relevant symbols for completion in import clauses and export clauses * whose declarations have a module specifier; for instance, symbols will be aggregated for @@ -1884,7 +1875,7 @@ namespace ts.Completions { return contextualMemberSymbols; } - const membersDeclaredBySpreadAssignment: Symbol[] = []; + const membersDeclaredBySpreadAssignment = createMap(); const existingMemberNames = createUnderscoreEscapedMap(); for (const m of existingMembers) { // Ignore omitted expressions for missing members @@ -1911,7 +1902,9 @@ namespace ts.Completions { const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, expression); const properties = type && (type).properties; if (properties) { - membersDeclaredBySpreadAssignment.push(...properties); + properties.forEach(property => { + membersDeclaredBySpreadAssignment.set(property.name, true); + }); } } else if (isBindingElement(m) && m.propertyName) { @@ -1932,18 +1925,28 @@ namespace ts.Completions { } const filteredSymbols = contextualMemberSymbols.filter(m => !existingMemberNames.get(m.escapedName)); - setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment, contextualMemberSymbols); + setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment, filteredSymbols); return filteredSymbols; } + // Set SortText to OptionalMember if it is an optinoal member + function setSortTextToOptionalMember() { + symbols.forEach(m => { + if (m.flags & SymbolFlags.Optional) { + symbolToSortTextMap[getSymbolId(m)] = symbolToSortTextMap[getSymbolId(m)] || SortText.OptionalMember; + } + }); + } + // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment - function setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment: Symbol[], contextualMemberSymbols: Symbol[]): void { - for (const fulfilledSymbol of membersDeclaredBySpreadAssignment) { - for (const contextualMemberSymbol of contextualMemberSymbols) { - if (contextualMemberSymbol.name === fulfilledSymbol.name) { - symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] = SortText.MemberDeclaredBySpreadAssignment; - } + function setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment: Map, contextualMemberSymbols: Symbol[]): void { + if (membersDeclaredBySpreadAssignment.size === 0) { + return; + } + for (const contextualMemberSymbol of contextualMemberSymbols) { + if (membersDeclaredBySpreadAssignment.has(contextualMemberSymbol.name)) { + symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] = SortText.MemberDeclaredBySpreadAssignment; } } } @@ -1999,7 +2002,7 @@ namespace ts.Completions { */ function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray): Symbol[] { const seenNames = createUnderscoreEscapedMap(); - const membersDeclaredBySpreadAssignment: Symbol[] = []; + const membersDeclaredBySpreadAssignment = createMap(); for (const attr of attributes) { // If this is the current item we are editing right now, do not filter it out if (isCurrentlyEditingNode(attr)) { @@ -2015,7 +2018,9 @@ namespace ts.Completions { const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, expression); const properties = type && (type).properties; if (properties) { - membersDeclaredBySpreadAssignment.push(...properties); + properties.forEach(property => { + membersDeclaredBySpreadAssignment.set(property.name, true); + }); } } } diff --git a/tests/cases/fourslash/completionsAtIncompleteObjectLiteralProperty.ts b/tests/cases/fourslash/completionsAtIncompleteObjectLiteralProperty.ts index 130b70de94..3682b31004 100644 --- a/tests/cases/fourslash/completionsAtIncompleteObjectLiteralProperty.ts +++ b/tests/cases/fourslash/completionsAtIncompleteObjectLiteralProperty.ts @@ -10,5 +10,5 @@ verify.completions({ marker: "", - exact: ["abc"], + exact: [{ name: 'abc', kind: 'property', kindModifiers: 'declare,optional', sortText: completion.SortText.OptionalMember }], }); diff --git a/tests/cases/fourslash/completionsOptionalMethod.ts b/tests/cases/fourslash/completionsOptionalMethod.ts index 4c70e31606..a08882a2cc 100644 --- a/tests/cases/fourslash/completionsOptionalMethod.ts +++ b/tests/cases/fourslash/completionsOptionalMethod.ts @@ -5,4 +5,7 @@ ////declare const x: { m?(): void }; ////x./**/ -verify.completions({ marker: "", exact: "m" }); +verify.completions({ + marker: "", + exact: { name: 'm', kind: 'method', kindModifiers: 'declare,optional', sortText: completion.SortText.OptionalMember } +});