/**
   * Adds type and description representation from function docstring
   *
   * @param parameter parameter of a function
   * @return true if type from docstring was added
   */
  private boolean addTypeAndDescriptionFromDocstring(@NotNull final PyNamedParameter parameter) {
    final PyFunction function = PsiTreeUtil.getParentOfType(parameter, PyFunction.class);
    if (function != null) {
      final String docString = PyPsiUtils.strValue(function.getDocStringExpression());
      final Pair<String, String> typeAndDescr = getTypeAndDescription(docString, parameter);

      final String type = typeAndDescr.first;
      final String description = typeAndDescr.second;

      if (type != null) {
        final PyType pyType = PyTypeParser.getTypeByName(parameter, type);
        if (pyType instanceof PyClassType) {
          myBody
              .addItem(": ")
              .addWith(
                  new LinkWrapper(PythonDocumentationProvider.LINK_TYPE_PARAM),
                  $(pyType.getName()));
        } else {
          myBody.addItem(": ").addItem(type);
        }
      }

      if (description != null) {
        myEpilog.addItem(BR).addItem(description);
      }

      return type != null;
    }

    return false;
  }
 public PyFunctionStub createStub(@NotNull final PyFunction psi, final StubElement parentStub) {
   PyFunctionImpl function = (PyFunctionImpl) psi;
   String message = function.extractDeprecationMessage();
   final PyStringLiteralExpression docStringExpression = function.getDocStringExpression();
   return new PyFunctionStubImpl(
       psi.getName(),
       PyPsiUtils.strValue(docStringExpression),
       message == null ? null : StringRef.fromString(message),
       parentStub,
       getStubElementType());
 }
 @NotNull
 public static List<RatedResolveResult> multiResolveImportElement(
     PyImportElement importElement, @NotNull final QualifiedName qName) {
   if (ApplicationManager.getApplication().isUnitTestMode()) {
     PyPsiUtils.assertValid(importElement);
   }
   final PyStatement importStatement = importElement.getContainingImportStatement();
   if (importStatement instanceof PyFromImportStatement) {
     return resolveNameInFromImport((PyFromImportStatement) importStatement, qName);
   } else {
     return resolveNameInImportStatement(importElement, qName);
   }
 }
  /** @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;
    }
  }