Skip to content

Commit f1a4565

Browse files
author
Andy
authored
Ensure getSymbolKind matches getSymbolDisplayPartsDocumentationAndSymbolKind (#23634)
* Ensure getSymbolKind matches getSymbolDisplayPartsDocumentationAndSymbolKind * Fix for property access
1 parent 49c807e commit f1a4565

File tree

4 files changed

+37
-26
lines changed

4 files changed

+37
-26
lines changed

src/harness/fourslash.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -916,8 +916,7 @@ namespace FourSlash {
916916
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source);
917917
assert.equal(ts.displayPartsToString(actualDetails.displayParts), text);
918918
assert.equal(ts.displayPartsToString(actualDetails.documentation), documentation || "");
919-
// TODO: GH#23587
920-
// assert.equal(actualDetails.kind, actual.kind);
919+
assert.equal(actualDetails.kind, actual.kind);
921920
assert.equal(actualDetails.kindModifiers, actual.kindModifiers);
922921
assert.equal(actualDetails.source && ts.displayPartsToString(actualDetails.source), sourceDisplay);
923922
}

src/services/symbolDisplay.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ namespace ts.SymbolDisplay {
99

1010
const flags = getCombinedLocalAndExportSymbolFlags(symbol);
1111
if (flags & SymbolFlags.Class) {
12-
return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
13-
ScriptElementKind.localClassElement : ScriptElementKind.classElement;
12+
const callExpressionLike = getCallExpressionLike(climbParentPropertyAccesses(location), symbol);
13+
return callExpressionLike && shouldUseConstructSignatures(callExpressionLike) ? ScriptElementKind.constructorImplementationElement
14+
: getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ? ScriptElementKind.localClassElement : ScriptElementKind.classElement;
1415
}
1516
if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement;
1617
if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement;
@@ -146,31 +147,15 @@ namespace ts.SymbolDisplay {
146147
let signature: Signature;
147148
type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol.exportSymbol || symbol, location);
148149

149-
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) {
150-
const right = (<PropertyAccessExpression>location.parent).name;
151-
// Either the location is on the right of a property access, or on the left and the right is missing
152-
if (right === location || (right && right.getFullWidth() === 0)) {
153-
location = location.parent;
154-
}
155-
}
150+
location = climbParentPropertyAccesses(location);
156151

157152
// try get the call/construct signature from the type if it matches
158-
let callExpressionLike: CallExpression | NewExpression | JsxOpeningLikeElement;
159-
if (isCallOrNewExpression(location)) {
160-
callExpressionLike = location;
161-
}
162-
else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
163-
callExpressionLike = <CallExpression | NewExpression>location.parent;
164-
}
165-
else if (location.parent && isJsxOpeningLikeElement(location.parent) && isFunctionLike(symbol.valueDeclaration)) {
166-
callExpressionLike = location.parent;
167-
}
168-
153+
const callExpressionLike = getCallExpressionLike(location, symbol);
169154
if (callExpressionLike) {
170155
const candidateSignatures: Signature[] = [];
171156
signature = typeChecker.getResolvedSignature(callExpressionLike, candidateSignatures);
172157

173-
const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression || (isCallExpression(callExpressionLike) && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword);
158+
const useConstructSignatures = shouldUseConstructSignatures(callExpressionLike);
174159

175160
const allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures();
176161

@@ -651,4 +636,31 @@ namespace ts.SymbolDisplay {
651636
return true;
652637
});
653638
}
639+
640+
type CallExpressionLike = CallExpression | NewExpression | JsxOpeningLikeElement | undefined;
641+
function getCallExpressionLike(location: Node, symbol: Symbol): CallExpressionLike {
642+
if (isCallOrNewExpression(location)) {
643+
return location;
644+
}
645+
else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
646+
return <CallExpression | NewExpression>location.parent;
647+
}
648+
else if (location.parent && isJsxOpeningLikeElement(location.parent) && isFunctionLike(symbol.valueDeclaration)) {
649+
return location.parent;
650+
}
651+
}
652+
function shouldUseConstructSignatures(callExpressionLike: CallExpressionLike): boolean {
653+
return callExpressionLike.kind === SyntaxKind.NewExpression || (isCallExpression(callExpressionLike) && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword);
654+
}
655+
656+
function climbParentPropertyAccesses(node: Node): Node {
657+
if (node.parent && isPropertyAccessExpression(node.parent)) {
658+
const { name } = node.parent;
659+
// Either the location is on the right of a property access, or on the left and the right is missing
660+
if (node === name || (name && name.getFullWidth() === 0)) {
661+
return node.parent;
662+
}
663+
}
664+
return node;
665+
}
654666
}

tests/cases/fourslash/completionsRecommended_import.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ goTo.eachMarker(["b0", "b1"], (_, idx) => {
2323
{ name: "Cls", source: "/a" },
2424
idx === 0 ? "constructor Cls(): Cls" : "class Cls",
2525
"",
26-
"class",
26+
idx === 0 ? "constructor" : "class",
2727
undefined,
2828
/*hasAction*/ true, {
2929
includeExternalModuleExports: true,

tests/cases/fourslash/completionsRecommended_local.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ goTo.eachMarker(["c0", "c1"], (_, idx) => {
2424
"Cls",
2525
idx === 0 ? "constructor Cls(): Cls" : "class Cls",
2626
"",
27-
"class",
27+
idx === 0 ? "constructor" : "class",
2828
undefined,
2929
undefined, {
3030
isRecommended: true,
@@ -33,5 +33,5 @@ goTo.eachMarker(["c0", "c1"], (_, idx) => {
3333

3434
goTo.eachMarker(["a0", "a1"], (_, idx) => {
3535
// Not recommended, because it's an abstract class
36-
verify.completionListContains("Abs", idx == 0 ? "constructor Abs(): Abs" : "class Abs", "", "class");
36+
verify.completionListContains("Abs", idx == 0 ? "constructor Abs(): Abs" : "class Abs", "", idx === 0 ? "constructor" : "class");
3737
});

0 commit comments

Comments
 (0)