@Nullable public static PyType getType(@NotNull PsiElement resolved, @NotNull List<PyType> elementTypes) { final String qualifiedName = getQualifiedName(resolved); final List<Integer> paramListTypePositions = new ArrayList<>(); final List<Integer> ellipsisTypePositions = new ArrayList<>(); for (int i = 0; i < elementTypes.size(); i++) { final PyType type = elementTypes.get(i); if (type instanceof PyTypeParser.ParameterListType) { paramListTypePositions.add(i); } else if (type instanceof PyTypeParser.EllipsisType) { ellipsisTypePositions.add(i); } } if (!paramListTypePositions.isEmpty()) { if (!("typing.Callable".equals(qualifiedName) && paramListTypePositions.equals(list(0)))) { return null; } } if (!ellipsisTypePositions.isEmpty()) { if (!("typing.Callable".equals(qualifiedName) && ellipsisTypePositions.equals(list(0)) || "typing.Tuple".equals(qualifiedName) && ellipsisTypePositions.equals(list(1)) && elementTypes.size() == 2)) { return null; } } if ("typing.Union".equals(qualifiedName)) { return PyUnionType.union(elementTypes); } if ("typing.Optional".equals(qualifiedName) && elementTypes.size() == 1) { return PyUnionType.union(elementTypes.get(0), PyNoneType.INSTANCE); } if ("typing.Callable".equals(qualifiedName) && elementTypes.size() == 2) { final PyTypeParser.ParameterListType paramList = as(elementTypes.get(0), PyTypeParser.ParameterListType.class); if (paramList != null) { return new PyCallableTypeImpl(paramList.getCallableParameters(), elementTypes.get(1)); } if (elementTypes.get(0) instanceof PyTypeParser.EllipsisType) { return new PyCallableTypeImpl(null, elementTypes.get(1)); } } if ("typing.Tuple".equals(qualifiedName)) { if (elementTypes.size() > 1 && elementTypes.get(1) instanceof PyTypeParser.EllipsisType) { return PyTupleType.createHomogeneous(resolved, elementTypes.get(0)); } return PyTupleType.create(resolved, elementTypes); } final PyType builtinCollection = getBuiltinCollection(resolved); if (builtinCollection instanceof PyClassType) { final PyClassType classType = (PyClassType) builtinCollection; return new PyCollectionTypeImpl(classType.getPyClass(), false, elementTypes); } return null; }
@Nullable private static PyType getParameterizedType( @NotNull PsiElement element, @NotNull Context context) { if (element instanceof PySubscriptionExpression) { final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression) element; final PyExpression operand = subscriptionExpr.getOperand(); final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); final PyType operandType = getType(operand, context); if (operandType instanceof PyClassType) { final PyClass cls = ((PyClassType) operandType).getPyClass(); final List<PyType> indexTypes = getIndexTypes(subscriptionExpr, context); if (PyNames.TUPLE.equals(cls.getQualifiedName())) { if (indexExpr instanceof PyTupleExpression) { final PyExpression[] elements = ((PyTupleExpression) indexExpr).getElements(); if (elements.length == 2 && isEllipsis(elements[1])) { return PyTupleType.createHomogeneous(element, indexTypes.get(0)); } } return PyTupleType.create(element, indexTypes); } else if (indexExpr != null) { return new PyCollectionTypeImpl(cls, false, indexTypes); } } } return null; }
private static PyType getTypeByControlFlow( @NotNull String name, @NotNull TypeEvalContext context, @NotNull PyExpression anchor, @NotNull ScopeOwner scopeOwner) { PyAugAssignmentStatement augAssignment = PsiTreeUtil.getParentOfType(anchor, PyAugAssignmentStatement.class); try { final PyElement element = augAssignment != null ? augAssignment : anchor; final List<ReadWriteInstruction> defs = PyDefUseUtil.getLatestDefs(scopeOwner, name, element, true); if (!defs.isEmpty()) { PyType type = defs.get(0).getType(context, anchor); for (int i = 1; i < defs.size(); i++) { type = PyUnionType.union(type, defs.get(i).getType(context, anchor)); } return type; } } catch (PyDefUseUtil.InstructionNotFoundException ignored) { } return null; }
@Nullable private String extractReturnType() { final String ARROW = "->"; final StructuredDocString structuredDocString = getStructuredDocString(); if (structuredDocString != null) { return structuredDocString.getReturnType(); } final String docString = getDocStringValue(); if (docString != null && docString.contains(ARROW)) { final List<String> lines = StringUtil.split(docString, "\n"); while (lines.size() > 0 && lines.get(0).trim().length() == 0) { lines.remove(0); } if (lines.size() > 1 && lines.get(1).trim().length() == 0) { String firstLine = lines.get(0); int pos = firstLine.lastIndexOf(ARROW); if (pos >= 0) { return firstLine.substring(pos + 2).trim(); } } } return null; }
@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; }
protected static PsiElement findAnchor(List<PsiElement> occurrences) { PsiElement anchor = occurrences.get(0); next: do { final PyStatement statement = PsiTreeUtil.getParentOfType(anchor, PyStatement.class); if (statement != null) { final PsiElement parent = statement.getParent(); for (PsiElement element : occurrences) { if (!PsiTreeUtil.isAncestor(parent, element, true)) { anchor = statement; continue next; } } } return statement; } while (true); }
private boolean smartIntroduce(final IntroduceOperation operation) { final Editor editor = operation.getEditor(); final PsiFile file = operation.getFile(); int offset = editor.getCaretModel().getOffset(); PsiElement elementAtCaret = file.findElementAt(offset); if (!checkIntroduceContext(file, editor, elementAtCaret)) return true; final List<PyExpression> expressions = new ArrayList<PyExpression>(); while (elementAtCaret != null) { if (elementAtCaret instanceof PyStatement || elementAtCaret instanceof PyFile) { break; } if (elementAtCaret instanceof PyExpression && isValidIntroduceVariant(elementAtCaret)) { expressions.add((PyExpression) elementAtCaret); } elementAtCaret = elementAtCaret.getParent(); } if (expressions.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { operation.setElement(expressions.get(0)); performActionOnElement(operation); return true; } else if (expressions.size() > 1) { IntroduceTargetChooser.showChooser( editor, expressions, new Pass<PyExpression>() { @Override public void pass(PyExpression pyExpression) { operation.setElement(pyExpression); performActionOnElement(operation); } }, new Function<PyExpression, String>() { public String fun(PyExpression pyExpression) { return pyExpression.getText(); } }); return true; } return false; }
@Nullable private Modifier getWrappersFromStub() { final StubElement parentStub = getStub().getParentStub(); final List childrenStubs = parentStub.getChildrenStubs(); int index = childrenStubs.indexOf(getStub()); if (index >= 0 && index < childrenStubs.size() - 1) { StubElement nextStub = (StubElement) childrenStubs.get(index + 1); if (nextStub instanceof PyTargetExpressionStub) { final PyTargetExpressionStub targetExpressionStub = (PyTargetExpressionStub) nextStub; if (targetExpressionStub.getInitializerType() == PyTargetExpressionStub.InitializerType.CallExpression) { final QualifiedName qualifiedName = targetExpressionStub.getInitializer(); if (QualifiedName.fromComponents(PyNames.CLASSMETHOD).equals(qualifiedName)) { return CLASSMETHOD; } if (QualifiedName.fromComponents(PyNames.STATICMETHOD).equals(qualifiedName)) { return STATICMETHOD; } } } } return null; }
@Nullable @Override public ParseResult fun(@NotNull Pair<Token<PyElementType>, List<Token<PyElementType>>> value) { final Token<PyElementType> first = value.getFirst(); final List<Token<PyElementType>> rest = value.getSecond(); final TextRange firstRange = first.getRange(); final boolean unqualified = rest.isEmpty(); if (unqualified) { final ParseResult result = parseBuiltinType(first); if (result != null) { return result; } } final PsiFile file = myAnchor.getContainingFile(); final List<Token<PyElementType>> tokens = new ArrayList<>(); tokens.add(first); tokens.addAll(rest); if (file instanceof PyFile) { final PyFile pyFile = (PyFile) file; final TypeEvalContext context = TypeEvalContext.codeInsightFallback(file.getProject()); final Map<TextRange, PyType> types = new HashMap<>(); final Map<PyType, TextRange> fullRanges = new HashMap<>(); final Map<PyType, PyImportElement> imports = new HashMap<>(); PyType type = resolveQualifierType(tokens, pyFile, context, types, fullRanges, imports); PsiElement resolved = type != null ? getElement(type) : null; if (type != null) { final PyResolveContext resolveContext = PyResolveContext.defaultContext().withTypeEvalContext(context); final PyExpression expression = myAnchor instanceof PyExpression ? (PyExpression) myAnchor : null; for (Token<PyElementType> token : tokens) { final PyType qualifierType = type; type = null; final List<? extends RatedResolveResult> results = qualifierType.resolveMember( token.getText().toString(), expression, AccessDirection.READ, resolveContext); if (results != null && !results.isEmpty()) { resolved = results.get(0).getElement(); if (resolved instanceof PyTypedElement) { type = context.getType((PyTypedElement) resolved); if (type != null && !allowResolveToType(type)) { type = null; break; } if (type instanceof PyClassLikeType) { type = ((PyClassLikeType) type).toInstance(); } } } if (type == null) { break; } types.put(token.getRange(), type); fullRanges.put( type, TextRange.create(firstRange.getStartOffset(), token.getRange().getEndOffset())); } if (type != null) { return new ParseResult(resolved, type, types, fullRanges, imports); } } } return EMPTY_RESULT; }