Added hover, definition, reference, and rename support for named arguments.

This commit is contained in:
Eric Traut 2019-11-25 21:20:51 -08:00
parent f7ba301b75
commit 3de18fb8cf
2 changed files with 50 additions and 1 deletions

View File

@ -3429,6 +3429,10 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
const expectedType = specializeType(argParam.paramType, typeVarMap, makeConcrete);
const exprType = getTypeOfExpression(argParam.argument.valueExpression, expectedType);
argType = exprType.type;
if (argParam.argument && argParam.argument.name && !isSpeculativeMode) {
writeTypeCache(argParam.argument.name, argType);
}
} else {
argType = getTypeForArgument(argParam.argument);
}
@ -7647,6 +7651,22 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
return AnalyzerNodeInfo.getFileInfo(node)!;
}
function getDeclarationFromFunctionNamedParameter(type: FunctionType, paramName: string): Declaration | undefined {
if (type.category === TypeCategory.Function && type.details.declaration) {
const functionDecl = type.details.declaration;
if (functionDecl.type === DeclarationType.Method || functionDecl.type === DeclarationType.Function) {
const functionNode = functionDecl.node;
const functionScope = AnalyzerNodeInfo.getScope(functionNode)!;
const paramSymbol = functionScope.lookUpSymbol(paramName)!;
if (paramSymbol) {
return paramSymbol.getDeclarations().find(decl => decl.type === DeclarationType.Parameter);
}
}
}
return undefined;
}
function getDeclarationsForNameNode(node: NameNode): Declaration[] | undefined {
const declarations: Declaration[] = [];
const nameValue = node.value;
@ -7724,6 +7744,32 @@ export function createTypeEvaluator(importLookup: ImportLookup): TypeEvaluator {
declarations.push(aliasDeclaration);
}
}
} else if (node.parent && node.parent.nodeType === ParseNodeType.Argument && node === node.parent.name) {
// The target node is the name in a named argument. We need to determine whether
// the corresponding named parameter can be determined from the context.
const argNode = node.parent;
const paramName = node.value;
if (argNode.parent && argNode.parent.nodeType === ParseNodeType.Call) {
const baseType = getType(argNode.parent.leftExpression, undefined, EvaluatorFlags.DoNotSpecialize);
if (baseType.category === TypeCategory.Function && baseType.details.declaration) {
const paramDecl = getDeclarationFromFunctionNamedParameter(baseType, paramName);
if (paramDecl) {
declarations.push(paramDecl);
}
} else if (baseType.category === TypeCategory.Class) {
const initMethodType = getTypeFromObjectMember(argNode.parent.leftExpression,
ObjectType.create(baseType), '__init__', { method: 'get' },
new DiagnosticAddendum(),
MemberAccessFlags.SkipForMethodLookup | MemberAccessFlags.SkipObjectBaseClass);
if (initMethodType && initMethodType.category === TypeCategory.Function) {
const paramDecl = getDeclarationFromFunctionNamedParameter(initMethodType, paramName);
if (paramDecl) {
declarations.push(paramDecl);
}
}
}
}
} else {
const scope = ScopeUtils.getScopeForNode(node);
if (scope) {

View File

@ -132,7 +132,10 @@ export class ReferencesProvider {
const symbolDeclType = resolvedDeclarations[0].type;
// Parameters are local to a scope, so they don't require a global search.
const requiresGlobalSearch = symbolDeclType !== DeclarationType.Parameter;
// If it's a named argument referring to a parameter, we still need to perform
// the global search.
const requiresGlobalSearch = symbolDeclType !== DeclarationType.Parameter ||
(node.parent !== undefined && node.parent.nodeType === ParseNodeType.Argument);
const results: ReferencesResult = {
requiresGlobalSearch,