@Nullable public String extractDeprecationMessage() { PyStatementList statementList = getStatementList(); if (statementList == null) { return null; } return extractDeprecationMessage(Arrays.asList(statementList.getStatements())); }
@Nullable private Ref<? extends PyType> getYieldStatementType(@NotNull final TypeEvalContext context) { Ref<PyType> elementType = null; final PyBuiltinCache cache = PyBuiltinCache.getInstance(this); final PyStatementList statements = getStatementList(); final Set<PyType> types = new LinkedHashSet<>(); statements.accept( new PyRecursiveElementVisitor() { @Override public void visitPyYieldExpression(PyYieldExpression node) { final PyExpression expr = node.getExpression(); final PyType type = expr != null ? context.getType(expr) : null; if (node.isDelegating() && type instanceof PyCollectionType) { final PyCollectionType collectionType = (PyCollectionType) type; // TODO: Select the parameter types that matches T in Iterable[T] final List<PyType> elementTypes = collectionType.getElementTypes(context); types.add(elementTypes.isEmpty() ? null : elementTypes.get(0)); } else { types.add(type); } } @Override public void visitPyFunction(PyFunction node) { // Ignore nested functions } }); final int n = types.size(); if (n == 1) { elementType = Ref.create(types.iterator().next()); } else if (n > 0) { elementType = Ref.create(PyUnionType.union(types)); } if (elementType != null) { final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR); if (generator != null) { final List<PyType> parameters = Arrays.asList(elementType.get(), null, getReturnStatementType(context)); return Ref.create(new PyCollectionTypeImpl(generator, false, parameters)); } } if (!types.isEmpty()) { return Ref.create(null); } return null; }
@NotNull @Override protected List<PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) { return Lists.<PyElement>newArrayList(filterNameless(Arrays.asList(pyClass.getMethods()))); }
@Override public boolean hasConflict(@NotNull final PyFunction member, @NotNull final PyClass aClass) { return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods())); }
@NotNull public static ParseResult parsePep484FunctionTypeComment( @NotNull PsiElement anchor, @NotNull String text) { final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create(); final Function<Pair<ParseResult, List<ParseResult>>, ParseResult> toParamTypeList = pair -> { if (pair != null) { final ParseResult first = pair.getFirst(); final List<ParseResult> second = pair.getSecond(); final List<PyType> itemTypes = new ArrayList<>(); ParseResult result = first; itemTypes.add(result.getType()); for (ParseResult r : second) { result = result.merge(r); itemTypes.add(r.getType()); } return result.withType(ParameterListType.fromParameterTypes(itemTypes)); } return EMPTY_RESULT.withType(new ParameterListType(Collections.emptyList())); }; final FunctionalParser<ParseResult, PyElementType> ellipsis = op("...").map(token -> EMPTY_RESULT.withType(EllipsisType.INSTANCE)).named("ellipsis"); final FunctionalParser<ParseResult, PyElementType> classType = token(IDENTIFIER) .then(many(op(".").skipThen(token(IDENTIFIER)))) .map(new MakeSimpleType(anchor)) .cached() .named("class-type"); final FunctionalParser<ParseResult, PyElementType> typeParamList = op("[") .skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr))))) .thenSkip(op("]")) .map(toParamTypeList) .named("type-param-list"); final FunctionalParser<ParseResult, PyElementType> typeParam = typeExpr.or(typeParamList).or(ellipsis).named("type-param"); final FunctionalParser<ParseResult, PyElementType> genericType = classType .thenSkip(op("[")) .then(typeParam) .then(many(op(",").skipThen(typeParam))) .thenSkip(op("]")) .map( value -> { final Pair<ParseResult, ParseResult> firstPair = value.getFirst(); final ParseResult first = firstPair.getFirst(); final ParseResult second = firstPair.getSecond(); final List<ParseResult> third = value.getSecond(); final List<PyType> typesInBrackets = new ArrayList<>(); typesInBrackets.add(second.getType()); ParseResult result = first; result = result.merge(second); for (ParseResult r : third) { typesInBrackets.add(r.getType()); result = result.merge(r); } final List<PyType> elementTypes = third.isEmpty() ? Collections.singletonList(second.getType()) : typesInBrackets; final PsiElement resolved = first.getElement(); if (resolved != null) { final PyType typingType = PyTypingTypeProvider.getType(resolved, elementTypes); if (typingType != null) { return result.withType(typingType); } } return EMPTY_RESULT; }) .named("generic-type"); typeExpr.define(genericType.or(classType)).named("type-expr"); final FunctionalParser<ParseResult, PyElementType> paramType = maybe(op("*")) .then(maybe(op("*"))) .then(typeExpr) .map( pair -> { final ParseResult paramResult = pair.getSecond(); final PyType type = paramResult.getType(); int starCount = 0; if (pair.getFirst().getFirst() != null) { starCount++; } if (pair.getFirst().getSecond() != null) { starCount++; } if (starCount == 0) { return paramResult; } else if (starCount == 1) { final PyClassType tupleType = PyTupleType.createHomogeneous(anchor, type); if (tupleType != null) { return paramResult.withType(tupleType); } return EMPTY_RESULT; } else if (starCount == 2) { final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor); final PyClassType dictType = builtinCache.getDictType(); if (dictType != null) { final PyClass pyClass = dictType.getPyClass(); return paramResult.withType( new PyCollectionTypeImpl( pyClass, false, Arrays.asList(builtinCache.getStrType(), type))); } return EMPTY_RESULT; } return EMPTY_RESULT; }) .named("param-type"); final FunctionalParser<ParseResult, PyElementType> paramTypes = paramType.then(many(op(",").skipThen(paramType))).map(toParamTypeList).named("param-types"); final FunctionalParser<ParseResult, PyElementType> funcType = op("(") .skipThen(maybe(paramTypes.or(ellipsis))) .thenSkip(op(")")) .thenSkip(op("->")) .then(typeExpr) .map( value -> { final ParseResult paramsResult = value.getFirst(); final ParseResult returnResult = value.getSecond(); final List<PyCallableParameter> parameters; ParseResult result = returnResult; if (paramsResult != null) { result = result.merge(paramsResult); final ParameterListType paramTypesList = as(paramsResult.getType(), ParameterListType.class); if (paramTypesList != null) { parameters = paramTypesList.getCallableParameters(); } // ellipsis else { parameters = null; } } else { parameters = Collections.emptyList(); result = returnResult; } return result.withType( new PyCallableTypeImpl(parameters, returnResult.getType())); }) .named("func-type"); final FunctionalParser<ParseResult, PyElementType> typeFile = funcType.endOfInput().named("function-type-comment"); try { return typeFile.parse(tokenize(text)); } catch (ParserException e) { return EMPTY_RESULT; } }
/** @param anchor should never be null or null will be returned */ @NotNull public static ParseResult parse(@Nullable final PsiElement anchor, @NotNull String type) { PyPsiUtils.assertValid(anchor); if (anchor == null) { return EMPTY_RESULT; } final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create(); final FunctionalParser<ParseResult, PyElementType> classType = token(IDENTIFIER) .then(many(op(".").skipThen(token(IDENTIFIER)))) .map(new MakeSimpleType(anchor)) .cached() .named("class-type"); final FunctionalParser<ParseResult, PyElementType> tupleType = op("(") .skipThen(typeExpr) .then(many(op(",").skipThen(typeExpr))) .thenSkip(op(")")) .map( value -> { ParseResult result = value.getFirst(); final List<ParseResult> rest = value.getSecond(); if (rest.isEmpty()) { return result; } final List<PyType> types = new ArrayList<>(); types.add(result.getType()); for (ParseResult r : rest) { result = result.merge(r); types.add(r.getType()); } return result.withType(PyTupleType.create(anchor, types)); }) .named("tuple-type"); final FunctionalParser<ParseResult, PyElementType> typeParameter = token(PARAMETER) .then(maybe(op("<=").skipThen(typeExpr))) .map( value -> { final Token<PyElementType> token = value.getFirst(); final String name = token.getText().toString(); final TextRange range = token.getRange(); final ParseResult boundResult = value.getSecond(); if (boundResult != null) { final PyGenericType type1 = new PyGenericType(name, boundResult.getType()); final ParseResult result = new ParseResult(null, type1, range); return result.merge(boundResult).withType(type1); } return new ParseResult(null, new PyGenericType(name, null), range); }) .named("type-parameter"); final FunctionalParser<ParseResult, PyElementType> simpleExpr = classType.or(tupleType).or(typeParameter).named("simple-expr"); final FunctionalParser<ParseResult, PyElementType> paramExpr = classType .thenSkip(op("[")) .then(typeExpr) .then(many(op(",").skipThen(typeExpr))) .thenSkip(op("]")) .map( value -> { final Pair<ParseResult, ParseResult> firstPair = value.getFirst(); final ParseResult first = firstPair.getFirst(); final ParseResult second = firstPair.getSecond(); final List<ParseResult> third = value.getSecond(); final PyType firstType = first.getType(); final List<PyType> typesInBrackets = new ArrayList<>(); typesInBrackets.add(second.getType()); ParseResult result = first; result = result.merge(second); for (ParseResult r : third) { typesInBrackets.add(r.getType()); result = result.merge(r); } final List<PyType> elementTypes = third.isEmpty() ? Collections.singletonList(second.getType()) : typesInBrackets; final PsiElement resolved = first.getElement(); if (resolved != null) { final PyType typingType = PyTypingTypeProvider.getType(resolved, elementTypes); if (typingType != null) { return result.withType(typingType); } } if (firstType instanceof PyClassType) { final PyType type1 = new PyCollectionTypeImpl( ((PyClassType) firstType).getPyClass(), false, elementTypes); return result.withType(type1); } return EMPTY_RESULT; }) .or( classType .thenSkip(op("of")) .then(simpleExpr) .map( value -> { final ParseResult firstResult = value.getFirst(); final ParseResult secondResult = value.getSecond(); final ParseResult result = firstResult.merge(secondResult); final PyType firstType = firstResult.getType(); final PyType secondType = secondResult.getType(); if (firstType != null) { if (firstType instanceof PyClassType && secondType != null) { return result.withType( new PyCollectionTypeImpl( ((PyClassType) firstType).getPyClass(), false, Collections.singletonList(secondType))); } return result.withType(firstType); } return EMPTY_RESULT; })) .or( classType .thenSkip(op("from")) .then(simpleExpr) .thenSkip(op("to")) .then(simpleExpr) .map( value -> { final Pair<ParseResult, ParseResult> firstPair = value.getFirst(); final ParseResult first = firstPair.getFirst(); final ParseResult second = firstPair.getSecond(); final ParseResult third = value.getSecond(); final PyType firstType = first.getType(); if (firstType instanceof PyClassType) { final List<PyType> elementTypes = Arrays.asList(second.getType(), third.getType()); final PyCollectionTypeImpl type1 = new PyCollectionTypeImpl( ((PyClassType) firstType).getPyClass(), false, elementTypes); return first.merge(second).merge(third).withType(type1); } return EMPTY_RESULT; })) .named("param-expr"); final FunctionalParser<ParseResult, PyElementType> callableExpr = op("(") .skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr))))) .thenSkip(op(")")) .thenSkip(op("->")) .then(typeExpr) .map( value -> { final List<PyCallableParameter> parameters = new ArrayList<>(); final ParseResult returnResult = value.getSecond(); ParseResult result; final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst(); if (firstPair != null) { final ParseResult first = firstPair.getFirst(); final List<ParseResult> second = firstPair.getSecond(); result = first; parameters.add(new PyCallableParameterImpl(null, first.getType())); for (ParseResult r : second) { result = result.merge(r); parameters.add(new PyCallableParameterImpl(null, r.getType())); } result = result.merge(returnResult); } else { result = returnResult; } return result.withType( new PyCallableTypeImpl(parameters, returnResult.getType())); }) .named("callable-expr"); final FunctionalParser<ParseResult, PyElementType> singleExpr = paramExpr.or(callableExpr).or(simpleExpr).named("single-expr"); final FunctionalParser<ParseResult, PyElementType> unionExpr = singleExpr .then(many(op("or").or(op("|")).skipThen(singleExpr))) .map( value -> { final ParseResult first = value.getFirst(); final List<ParseResult> rest = value.getSecond(); if (rest.isEmpty()) { return first; } final List<PyType> types = new ArrayList<>(); types.add(first.getType()); ParseResult result = first; for (ParseResult r : rest) { types.add(r.getType()); result = result.merge(r); } return result.withType(PyUnionType.union(types)); }) .named("union-expr"); typeExpr.define(unionExpr).named("type-expr"); final FunctionalParser<ParseResult, PyElementType> typeFile = typeExpr.endOfInput().named("type-file"); try { return typeFile.parse(tokenize(type)); } catch (ParserException e) { return EMPTY_RESULT; } }