protected Collection<String> generateSuggestedNames(PyExpression expression) { Collection<String> candidates = new LinkedHashSet<String>() { @Override public boolean add(String s) { if (PyNames.isReserved(s)) { return false; } return super.add(s); } }; String text = expression.getText(); final Pair<PsiElement, TextRange> selection = expression.getUserData(PyReplaceExpressionUtil.SELECTION_BREAKS_AST_NODE); if (selection != null) { text = selection.getSecond().substring(text); } if (expression instanceof PyCallExpression) { final PyExpression callee = ((PyCallExpression) expression).getCallee(); if (callee != null) { text = callee.getText(); } } if (text != null) { candidates.addAll(NameSuggesterUtil.generateNames(text)); } final TypeEvalContext context = TypeEvalContext.userInitiated(expression.getContainingFile()); PyType type = context.getType(expression); if (type != null && type != PyNoneType.INSTANCE) { String typeName = type.getName(); if (typeName != null) { if (type.isBuiltin()) { typeName = typeName.substring(0, 1); } candidates.addAll(NameSuggesterUtil.generateNamesByType(typeName)); } } final PyKeywordArgument kwArg = PsiTreeUtil.getParentOfType(expression, PyKeywordArgument.class); if (kwArg != null && kwArg.getValueExpression() == expression) { candidates.add(kwArg.getKeyword()); } final PyArgumentList argList = PsiTreeUtil.getParentOfType(expression, PyArgumentList.class); if (argList != null) { final CallArgumentsMapping result = argList.analyzeCall(PyResolveContext.noImplicits()); if (result.getMarkedCallee() != null) { final PyNamedParameter namedParameter = result.getPlainMappedParams().get(expression); if (namedParameter != null) { candidates.add(namedParameter.getName()); } } } return candidates; }
private static void highlightMissingArguments( PyArgumentList node, ProblemsHolder holder, CallArgumentsMapping result) { ASTNode our_node = node.getNode(); if (our_node != null) { ASTNode close_paren = our_node.findChildByType(PyTokenTypes.RPAR); if (close_paren != null) { for (PyNamedParameter param : result.getUnmappedParams()) { holder.registerProblem( close_paren.getPsi(), PyBundle.message("INSP.parameter.$0.unfilled", param.getName())); } } } }
@Nullable public Ref<PyType> getParameterType( @NotNull PyNamedParameter param, @NotNull PyFunction func, @NotNull TypeEvalContext context) { final PyAnnotation annotation = param.getAnnotation(); if (annotation != null) { // XXX: Requires switching from stub to AST final PyExpression value = annotation.getValue(); if (value != null) { final PyType type = getType(value, new Context(context)); if (type != null) { final PyType optionalType = getOptionalTypeFromDefaultNone(param, type, context); return Ref.create(optionalType != null ? optionalType : type); } } } final String paramComment = param.getTypeCommentAnnotation(); if (paramComment != null) { return Ref.create(getStringBasedType(paramComment, param, new Context(context))); } final String comment = func.getTypeCommentAnnotation(); if (comment != null) { final PyTypeParser.ParseResult result = PyTypeParser.parsePep484FunctionTypeComment(param, comment); final PyCallableType functionType = as(result.getType(), PyCallableType.class); if (functionType != null) { final List<PyCallableParameter> paramTypes = functionType.getParameters(context); // Function annotation of kind (...) -> Type if (paramTypes == null) { return Ref.create(); } final PyParameter[] funcParams = func.getParameterList().getParameters(); final int startOffset = omitFirstParamInTypeComment(func) ? 1 : 0; for (int paramIndex = 0; paramIndex < funcParams.length; paramIndex++) { if (funcParams[paramIndex] == param) { final int typeIndex = paramIndex - startOffset; if (typeIndex >= 0 && typeIndex < paramTypes.size()) { return Ref.create(paramTypes.get(typeIndex).getType(context)); } break; } } } } return null; }
@Nullable private static PyType getOptionalTypeFromDefaultNone( @NotNull PyNamedParameter param, @NotNull PyType type, @NotNull TypeEvalContext context) { final PyExpression defaultValue = param.getDefaultValue(); if (defaultValue != null) { final PyType defaultType = context.getType(defaultValue); if (defaultType instanceof PyNoneType) { return PyUnionType.union(type, defaultType); } } return null; }
private static Pair<String, String> getTypeAndDescription( @Nullable final String docString, @NotNull final PyNamedParameter followed) { StructuredDocString structuredDocString = DocStringUtil.parse(docString); String type = null; String desc = null; if (structuredDocString != null) { final String name = followed.getName(); type = structuredDocString.getParamType(name); desc = structuredDocString.getParamDescription(name); } return Pair.create(type, desc); }
@Override public void visitPyDecoratorList(final PyDecoratorList node) { PyDecorator[] decorators = node.getDecorators(); for (PyDecorator deco : decorators) { if (deco.hasArgumentList()) continue; final PyCallExpression.PyMarkedCallee markedCallee = deco.resolveCallee(resolveWithoutImplicits()); if (markedCallee != null && !markedCallee.isImplicitlyResolved()) { final Callable callable = markedCallee.getCallable(); int firstParamOffset = markedCallee.getImplicitOffset(); final List<PyParameter> params = PyUtil.getParameters(callable, myTypeEvalContext); final PyNamedParameter allegedFirstParam = params.size() < firstParamOffset ? null : params.get(firstParamOffset - 1).getAsNamed(); if (allegedFirstParam == null || allegedFirstParam.isKeywordContainer()) { // no parameters left to pass function implicitly, or wrong param type registerProblem( deco, PyBundle.message( "INSP.func.$0.lacks.first.arg", callable.getName())); // TODO: better names for anon lambdas } else { // possible unfilled params for (int i = firstParamOffset; i < params.size(); i += 1) { final PyParameter parameter = params.get(i); if (parameter instanceof PySingleStarParameter) continue; final PyNamedParameter par = parameter.getAsNamed(); // param tuples, non-starred or non-default won't do if (par == null || (!par.isKeywordContainer() && !par.isPositionalContainer() && !par.hasDefaultValue())) { String parameterName = par != null ? par.getName() : "(...)"; registerProblem( deco, PyBundle.message("INSP.parameter.$0.unfilled", parameterName)); } } } } // else: this case is handled by arglist visitor } }