Skip to content

Commit 5e8e735

Browse files
author
Andy
authored
quickInfo: Don't check for type === undefined, check for any (#17815)
* quickInfo: Don't check for `type === undefined`, check for `any` * Fixes: * We still want to do some work even if type is `any` * Second test for `if (type)` is necessary because it might not have been assigned.
1 parent a136f55 commit 5e8e735

File tree

2 files changed

+111
-100
lines changed

2 files changed

+111
-100
lines changed

src/services/symbolDisplay.ts

+101-100
Original file line numberDiff line numberDiff line change
@@ -111,124 +111,123 @@ namespace ts.SymbolDisplay {
111111

112112
let signature: Signature;
113113
type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol.exportSymbol || symbol, location);
114-
if (type) {
115-
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) {
116-
const right = (<PropertyAccessExpression>location.parent).name;
117-
// Either the location is on the right of a property access, or on the left and the right is missing
118-
if (right === location || (right && right.getFullWidth() === 0)) {
119-
location = location.parent;
120-
}
121-
}
122114

123-
// try get the call/construct signature from the type if it matches
124-
let callExpressionLike: CallExpression | NewExpression | JsxOpeningLikeElement;
125-
if (isCallOrNewExpression(location)) {
126-
callExpressionLike = <CallExpression | NewExpression>location;
127-
}
128-
else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
129-
callExpressionLike = <CallExpression | NewExpression>location.parent;
115+
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) {
116+
const right = (<PropertyAccessExpression>location.parent).name;
117+
// Either the location is on the right of a property access, or on the left and the right is missing
118+
if (right === location || (right && right.getFullWidth() === 0)) {
119+
location = location.parent;
130120
}
131-
else if (location.parent && isJsxOpeningLikeElement(location.parent) && isFunctionLike(symbol.valueDeclaration)) {
132-
callExpressionLike = <JsxOpeningLikeElement>location.parent;
121+
}
122+
123+
// try get the call/construct signature from the type if it matches
124+
let callExpressionLike: CallExpression | NewExpression | JsxOpeningLikeElement;
125+
if (isCallOrNewExpression(location)) {
126+
callExpressionLike = <CallExpression | NewExpression>location;
127+
}
128+
else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) {
129+
callExpressionLike = <CallExpression | NewExpression>location.parent;
130+
}
131+
else if (location.parent && isJsxOpeningLikeElement(location.parent) && isFunctionLike(symbol.valueDeclaration)) {
132+
callExpressionLike = <JsxOpeningLikeElement>location.parent;
133+
}
134+
135+
if (callExpressionLike) {
136+
const candidateSignatures: Signature[] = [];
137+
signature = typeChecker.getResolvedSignature(callExpressionLike, candidateSignatures);
138+
if (!signature && candidateSignatures.length) {
139+
// Use the first candidate:
140+
signature = candidateSignatures[0];
133141
}
134142

135-
if (callExpressionLike) {
136-
const candidateSignatures: Signature[] = [];
137-
signature = typeChecker.getResolvedSignature(callExpressionLike, candidateSignatures);
138-
if (!signature && candidateSignatures.length) {
139-
// Use the first candidate:
140-
signature = candidateSignatures[0];
141-
}
143+
const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression || (isCallExpression(callExpressionLike) && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword);
142144

143-
const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression || (isCallExpression(callExpressionLike) && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword);
145+
const allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures();
144146

145-
const allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures();
147+
if (!contains(allSignatures, signature.target) && !contains(allSignatures, signature)) {
148+
// Get the first signature if there is one -- allSignatures may contain
149+
// either the original signature or its target, so check for either
150+
signature = allSignatures.length ? allSignatures[0] : undefined;
151+
}
146152

147-
if (!contains(allSignatures, signature.target) && !contains(allSignatures, signature)) {
148-
// Get the first signature if there is one -- allSignatures may contain
149-
// either the original signature or its target, so check for either
150-
signature = allSignatures.length ? allSignatures[0] : undefined;
153+
if (signature) {
154+
if (useConstructSignatures && (symbolFlags & SymbolFlags.Class)) {
155+
// Constructor
156+
symbolKind = ScriptElementKind.constructorImplementationElement;
157+
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
151158
}
152-
153-
if (signature) {
154-
if (useConstructSignatures && (symbolFlags & SymbolFlags.Class)) {
155-
// Constructor
156-
symbolKind = ScriptElementKind.constructorImplementationElement;
157-
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
159+
else if (symbolFlags & SymbolFlags.Alias) {
160+
symbolKind = ScriptElementKind.alias;
161+
pushTypePart(symbolKind);
162+
displayParts.push(spacePart());
163+
if (useConstructSignatures) {
164+
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
165+
displayParts.push(spacePart());
158166
}
159-
else if (symbolFlags & SymbolFlags.Alias) {
160-
symbolKind = ScriptElementKind.alias;
161-
pushTypePart(symbolKind);
167+
addFullSymbolName(symbol);
168+
}
169+
else {
170+
addPrefixForAnyFunctionOrVar(symbol, symbolKind);
171+
}
172+
173+
switch (symbolKind) {
174+
case ScriptElementKind.jsxAttribute:
175+
case ScriptElementKind.memberVariableElement:
176+
case ScriptElementKind.variableElement:
177+
case ScriptElementKind.constElement:
178+
case ScriptElementKind.letElement:
179+
case ScriptElementKind.parameterElement:
180+
case ScriptElementKind.localVariableElement:
181+
// If it is call or construct signature of lambda's write type name
182+
displayParts.push(punctuationPart(SyntaxKind.ColonToken));
162183
displayParts.push(spacePart());
163184
if (useConstructSignatures) {
164185
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
165186
displayParts.push(spacePart());
166187
}
167-
addFullSymbolName(symbol);
168-
}
169-
else {
170-
addPrefixForAnyFunctionOrVar(symbol, symbolKind);
171-
}
188+
if (!(type.flags & TypeFlags.Object && (<ObjectType>type).objectFlags & ObjectFlags.Anonymous) && type.symbol) {
189+
addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
190+
}
191+
addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature);
192+
break;
172193

173-
switch (symbolKind) {
174-
case ScriptElementKind.jsxAttribute:
175-
case ScriptElementKind.memberVariableElement:
176-
case ScriptElementKind.variableElement:
177-
case ScriptElementKind.constElement:
178-
case ScriptElementKind.letElement:
179-
case ScriptElementKind.parameterElement:
180-
case ScriptElementKind.localVariableElement:
181-
// If it is call or construct signature of lambda's write type name
182-
displayParts.push(punctuationPart(SyntaxKind.ColonToken));
183-
displayParts.push(spacePart());
184-
if (useConstructSignatures) {
185-
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
186-
displayParts.push(spacePart());
187-
}
188-
if (!(type.flags & TypeFlags.Object && (<ObjectType>type).objectFlags & ObjectFlags.Anonymous) && type.symbol) {
189-
addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
190-
}
191-
addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature);
192-
break;
193-
194-
default:
195-
// Just signature
196-
addSignatureDisplayParts(signature, allSignatures);
197-
}
198-
hasAddedSymbolInfo = true;
194+
default:
195+
// Just signature
196+
addSignatureDisplayParts(signature, allSignatures);
199197
}
198+
hasAddedSymbolInfo = true;
200199
}
201-
else if ((isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration
202-
(location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration
203-
// get the signature from the declaration and write it
204-
const functionDeclaration = <FunctionLike>location.parent;
205-
// Use function declaration to write the signatures only if the symbol corresponding to this declaration
206-
const locationIsSymbolDeclaration = find(symbol.declarations, declaration =>
207-
declaration === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent : functionDeclaration));
208-
209-
if (locationIsSymbolDeclaration) {
210-
const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures();
211-
if (!typeChecker.isImplementationOfOverload(functionDeclaration)) {
212-
signature = typeChecker.getSignatureFromDeclaration(functionDeclaration);
213-
}
214-
else {
215-
signature = allSignatures[0];
216-
}
217-
218-
if (functionDeclaration.kind === SyntaxKind.Constructor) {
219-
// show (constructor) Type(...) signature
220-
symbolKind = ScriptElementKind.constructorImplementationElement;
221-
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
222-
}
223-
else {
224-
// (function/method) symbol(..signature)
225-
addPrefixForAnyFunctionOrVar(functionDeclaration.kind === SyntaxKind.CallSignature &&
226-
!(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind);
227-
}
200+
}
201+
else if ((isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration
202+
(location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration
203+
// get the signature from the declaration and write it
204+
const functionDeclaration = <FunctionLike>location.parent;
205+
// Use function declaration to write the signatures only if the symbol corresponding to this declaration
206+
const locationIsSymbolDeclaration = find(symbol.declarations, declaration =>
207+
declaration === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent : functionDeclaration));
208+
209+
if (locationIsSymbolDeclaration) {
210+
const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures();
211+
if (!typeChecker.isImplementationOfOverload(functionDeclaration)) {
212+
signature = typeChecker.getSignatureFromDeclaration(functionDeclaration);
213+
}
214+
else {
215+
signature = allSignatures[0];
216+
}
228217

229-
addSignatureDisplayParts(signature, allSignatures);
230-
hasAddedSymbolInfo = true;
218+
if (functionDeclaration.kind === SyntaxKind.Constructor) {
219+
// show (constructor) Type(...) signature
220+
symbolKind = ScriptElementKind.constructorImplementationElement;
221+
addPrefixForAnyFunctionOrVar(type.symbol, symbolKind);
222+
}
223+
else {
224+
// (function/method) symbol(..signature)
225+
addPrefixForAnyFunctionOrVar(functionDeclaration.kind === SyntaxKind.CallSignature &&
226+
!(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind);
231227
}
228+
229+
addSignatureDisplayParts(signature, allSignatures);
230+
hasAddedSymbolInfo = true;
232231
}
233232
}
234233
}
@@ -417,7 +416,9 @@ namespace ts.SymbolDisplay {
417416
symbolFlags & SymbolFlags.Accessor ||
418417
symbolKind === ScriptElementKind.memberFunctionElement) {
419418
const allSignatures = type.getNonNullableType().getCallSignatures();
420-
addSignatureDisplayParts(allSignatures[0], allSignatures);
419+
if (allSignatures.length) {
420+
addSignatureDisplayParts(allSignatures[0], allSignatures);
421+
}
421422
}
422423
}
423424
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////foo({
4+
//// /**/f: function() {},
5+
//// f() {}
6+
////});
7+
8+
// The symbol indicates that this is a funciton, but the type is `any`.
9+
// Regression test that we don't crash (by trying to get signatures from `any`).
10+
verify.quickInfoAt("", "(method) f");

0 commit comments

Comments
 (0)