Skip to content

Commit 85c6d34

Browse files
committed
add basic support for contextual object literal completions
1 parent 57fa018 commit 85c6d34

File tree

2 files changed

+51
-32
lines changed

2 files changed

+51
-32
lines changed

src/services/services.ts

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,7 +1574,7 @@ module ts {
15741574
// invalid identifer name. We need to check if whatever was inside the quotes is actually a valid identifier name.
15751575
displayName = displayName.substring(1, displayName.length - 1);
15761576
}
1577-
1577+
15781578
var isValid = isIdentifierStart(displayName.charCodeAt(0), target);
15791579
for (var i = 1, n = displayName.length; isValid && i < n; i++) {
15801580
isValid = isValid && isIdentifierPart(displayName.charCodeAt(i), target);
@@ -1748,6 +1748,36 @@ module ts {
17481748
return !(declaration && declaration.flags & NodeFlags.Private && containingClass !== declaration.parent);
17491749
}
17501750

1751+
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
1752+
if (!existingMembers || existingMembers.length === 0) {
1753+
return contextualMemberSymbols;
1754+
}
1755+
1756+
var existingMemberNames: Map<boolean> = {};
1757+
forEach(existingMembers, m => {
1758+
if (m.kind !== SyntaxKind.PropertyAssignment) {
1759+
// Ignore ommited expressions for missing members in the object literal
1760+
return;
1761+
}
1762+
1763+
if (position <= m.getEnd() && position >= m.getStart()) {
1764+
// If this is the current item we are editing right now, do not filter it out
1765+
return;
1766+
}
1767+
1768+
existingMemberNames[m.name.text] = true;
1769+
});
1770+
1771+
var filteredMembers: Symbol[] = [];
1772+
forEach(contextualMemberSymbols, s=> {
1773+
if (!existingMemberNames[s.name]) {
1774+
filteredMembers.push(s);
1775+
}
1776+
});
1777+
1778+
return filteredMembers;
1779+
}
1780+
17511781
synchronizeHostData();
17521782

17531783
filename = TypeScript.switchToForwardSlashes(filename);
@@ -1855,34 +1885,23 @@ module ts {
18551885

18561886
// Object literal expression, look up possible property names from contextual type
18571887
if (containingObjectLiteral) {
1858-
var searchPosition = Math.min(position, TypeScript.end(containingObjectLiteral));
1859-
var path = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, searchPosition);
1860-
// Get the object literal node
1888+
var objectLiteral = mappedNode.kind === SyntaxKind.ObjectLiteral ? <ObjectLiteral>mappedNode : <ObjectLiteral>getAncestor(mappedNode, SyntaxKind.ObjectLiteral);
18611889

1862-
while (node && node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) {
1863-
node = node.parent;
1864-
}
1865-
1866-
if (!node || node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) {
1867-
// AST Path look up did not result in the same node as Fidelity Syntax Tree look up.
1868-
// Once we remove AST this will no longer be a problem.
1869-
return null;
1870-
}
1890+
Debug.assert(objectLiteral);
18711891

18721892
isMemberCompletion = true;
18731893

1874-
//// Try to get the object members form contextual typing
1875-
//var contextualMembers = compiler.getContextualMembersFromAST(node, document);
1876-
//if (contextualMembers && contextualMembers.symbols && contextualMembers.symbols.length > 0) {
1877-
// // get existing members
1878-
// var existingMembers = compiler.getVisibleMemberSymbolsFromAST(node, document);
1879-
1880-
// // Add filtterd items to the completion list
1881-
// getCompletionEntriesFromSymbols({
1882-
// symbols: filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position),
1883-
// enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol
1884-
// }, entries);
1885-
//}
1894+
var contextualType = typeInfoResolver.getContextualType(objectLiteral);
1895+
if (!contextualType) {
1896+
return undefined;
1897+
}
1898+
1899+
var contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType);
1900+
if (contextualTypeMembers && contextualTypeMembers.length > 0) {
1901+
// Add filtterd items to the completion list
1902+
var filteredMembers = filterContextualMembersList(contextualTypeMembers, objectLiteral.properties);
1903+
getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession);
1904+
}
18861905
}
18871906
// Get scope memebers
18881907
else {

tests/cases/fourslash/memberCompletionOnTypeParameters.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
/// <reference path='fourslash.ts'/>
2-
3-
////interface IFoo {
4-
//// x: number;
5-
//// y: string;
6-
////}
7-
////
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface IFoo {
4+
//// x: number;
5+
//// y: string;
6+
////}
7+
////
88
////function foo<S, T extends IFoo, U extends T, V extends U>() {
99
//// var s:S, t: T, u: U, v: V;
1010
//// s./*S*/; // no constraint, no completion

0 commit comments

Comments
 (0)