@Nullable
  private PyType getTypeFromUsages(@NotNull TypeEvalContext context) {
    final Set<String> usedAttributes = new LinkedHashSet<>();

    final ScopeOwner owner = ScopeUtil.getScopeOwner(this);
    final String name = getName();

    final Ref<Boolean> parameterWasReassigned = Ref.create(false);
    final Ref<Boolean> noneComparison = Ref.create(false);

    if (owner != null && name != null) {
      owner.accept(new PyRecursiveElementVisitor() {
        @Override
        public void visitPyElement(@NotNull PyElement node) {
          if (parameterWasReassigned.get()) return;

          if (node instanceof ScopeOwner && node != owner) {
            return;
          }
          if (node instanceof PyQualifiedExpression expr) {
            final PyExpression qualifier = expr.getQualifier();
            if (qualifier != null) {
              final String attributeName = expr.getReferencedName();
              final PyExpression referencedExpr = node instanceof PyBinaryExpression && PyNames.isRightOperatorName(attributeName) ?
                                                  ((PyBinaryExpression)node).getRightExpression() : qualifier;
              if (attributeName != null && isReferenceToParameter(referencedExpr)) {
                usedAttributes.add(attributeName);
              }
            }
            else if (isReferenceToParameter(expr)) {
              StreamEx.of(getParametersByCallArgument(expr, context))
                      .nonNull()
                      .map(parameter -> parameter.getType(context))
                      .select(PyStructuralType.class)
                      .forEach(type -> usedAttributes.addAll(type.getAttributeNames()));
            }
          }
          super.visitPyElement(node);
        }

        @Override
        public void visitPyIfStatement(@NotNull PyIfStatement node) {
          if (parameterWasReassigned.get()) return;

          final PyExpression ifCondition = node.getIfPart().getCondition();
          if (ifCondition != null) {
            ifCondition.accept(this);
          }
          for (PyIfPart part : node.getElifParts()) {
            final PyExpression elseIfCondition = part.getCondition();
            if (elseIfCondition != null) {
              elseIfCondition.accept(this);
            }
          }
        }

        @Override
        public void visitPyCallExpression(@NotNull PyCallExpression node) {
          if (parameterWasReassigned.get()) return;

          Optional
            .ofNullable(node.getCallee())
            .filter(callee -> "len".equals(callee.getName()) && isReferenceToParameter(node.getArgument(0, PyReferenceExpression.class)))
            .map(PyExpression::getReference)
            .map(PsiReference::resolve)
            .filter(element -> PyBuiltinCache.getInstance(element).isBuiltin(element))
            .ifPresent(callable -> usedAttributes.add(PyNames.LEN));

          super.visitPyCallExpression(node);
        }

        @Override
        public void visitPyForStatement(@NotNull PyForStatement node) {
          if (parameterWasReassigned.get()) return;

          if (isReferenceToParameter(node.getForPart().getSource())) {
            usedAttributes.add(PyNames.ITER);
          }

          super.visitPyForStatement(node);
        }

        @Override
        public void visitPyTargetExpression(@NotNull PyTargetExpression node) {
          if (parameterWasReassigned.get()) return;

          if (isReferenceToParameter(node)) {
            parameterWasReassigned.set(true);
          }
          else {
            super.visitPyTargetExpression(node);
          }
        }

        @Override
        public void visitPyBinaryExpression(@NotNull PyBinaryExpression node) {
          super.visitPyBinaryExpression(node);

          if (noneComparison.get() || !node.isOperator(PyNames.IS) && !node.isOperator("isnot")) return;

          final PyExpression lhs = node.getLeftExpression();
          final PyExpression rhs = node.getRightExpression();

          if (isReferenceToParameter(lhs) ^ isReferenceToParameter(rhs) &&
              (lhs != null && context.getType(lhs) instanceof PyNoneType) ^ (rhs != null && context.getType(rhs) instanceof PyNoneType)) {
            noneComparison.set(true);
          }
        }

        @Contract("null -> false")
        private boolean isReferenceToParameter(@Nullable PsiElement element) {
          if (element == null) return false;
          final PsiReference reference = element.getReference();
          return reference != null && reference.isReferenceTo(PyNamedParameterImpl.this);
        }
      });
    }

    if (!usedAttributes.isEmpty()) {
      final PyStructuralType structuralType = new PyStructuralType(usedAttributes, true);
      return noneComparison.get() ? PyUnionType.union(structuralType, PyNoneType.INSTANCE) : structuralType;
    }

    return null;
  }
@Nullable
  private PyType getTypeFromUsages(@NotNull TypeEvalContext context)