goToTypeDefinition: Go to function return type (#25952)

* goToTypeDefinition: Go to function return type

* Add more tests

* If a function returns 'void' or some other type with no definition, just return the function definition.
This commit is contained in:
Andy
2018-08-07 12:54:19 -07:00
committed by GitHub
parent eaf0d59d35
commit 794f3a5e76
8 changed files with 105 additions and 37 deletions

View File

@@ -1674,7 +1674,7 @@ Actual: ${stringify(fullActual)}`);
for (const { name, text } of outputFiles) {
const fromTestFile = this.getFileContent(name);
if (fromTestFile !== text) {
this.raiseError("Emit output is not as expected: " + showTextDiff(fromTestFile, text));
this.raiseError(`Emit output for ${name} is not as expected: ${showTextDiff(fromTestFile, text)}`);
}
}
}

View File

@@ -136,9 +136,30 @@ namespace ts.GoToDefinition {
}
const symbol = typeChecker.getSymbolAtLocation(node);
const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, node);
return type && flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
t.symbol && getDefinitionFromSymbol(typeChecker, t.symbol, node));
if (!symbol) return undefined;
const typeAtLocation = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
const returnType = tryGetReturnTypeOfFunction(symbol, typeAtLocation, typeChecker);
const fromReturnType = returnType && definitionFromType(returnType, typeChecker, node);
// If a function returns 'void' or some other type with no definition, just return the function definition.
return fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node);
}
function definitionFromType(type: Type, checker: TypeChecker, node: Node): DefinitionInfo[] {
return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
t.symbol && getDefinitionFromSymbol(checker, t.symbol, node));
}
function tryGetReturnTypeOfFunction(symbol: Symbol, type: Type, checker: TypeChecker): Type | undefined {
// If the type is just a function's inferred type,
// go-to-type should go to the return type instead, since go-to-definition takes you to the function anyway.
if (type.symbol === symbol ||
// At `const f = () => {}`, the symbol is `f` and the type symbol is at `() => {}`
symbol.valueDeclaration && type.symbol && isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer === type.symbol.valueDeclaration as Node) {
const sigs = type.getCallSignatures();
if (sigs.length === 1) return checker.getReturnTypeOfSignature(first(sigs));
}
return undefined;
}
export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan | undefined {