private static void showParameterHint(
      final PsiElement element,
      final Editor editor,
      final Object[] descriptors,
      final Project project,
      @Nullable PsiElement highlighted,
      final int elementStart,
      final ParameterInfoHandler handler,
      final boolean requestFocus) {
    if (ParameterInfoController.isAlreadyShown(editor, elementStart)) return;

    if (editor.isDisposed() || !editor.getComponent().isVisible()) return;
    final ParameterInfoComponent component =
        new ParameterInfoComponent(descriptors, editor, handler, requestFocus);
    component.setParameterOwner(element);
    component.setRequestFocus(requestFocus);
    if (highlighted != null) {
      component.setHighlightedParameter(highlighted);
    }

    component.update(); // to have correct preferred size

    final LightweightHint hint = new LightweightHint(component);
    hint.setSelectingHint(true);
    final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
    final ShowParameterInfoHandler.BestLocationPointProvider provider =
        new MyBestLocationPointProvider(editor);
    final Pair<Point, Short> pos =
        provider.getBestPointPosition(hint, element, elementStart, true, HintManager.UNDER);

    PsiDocumentManager.getInstance(project)
        .performLaterWhenAllCommitted(
            () -> {
              if (editor.isDisposed() || DumbService.isDumb(project)) return;

              final Document document = editor.getDocument();
              if (document.getTextLength() < elementStart) return;

              HintHint hintHint =
                  HintManagerImpl.createHintHint(editor, pos.getFirst(), hint, pos.getSecond());
              hintHint.setExplicitClose(true);
              hintHint.setRequestFocus(requestFocus);

              Editor editorToShow =
                  editor instanceof EditorWindow ? ((EditorWindow) editor).getDelegate() : editor;
              // is case of injection we need to calculate position for EditorWindow
              // also we need to show the hint in the main editor because of intention bulb
              hintManager.showEditorHint(
                  hint,
                  editorToShow,
                  pos.getFirst(),
                  HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING,
                  0,
                  false,
                  hintHint);
              new ParameterInfoController(project, editor, elementStart, hint, handler, provider);
            });
  }
  /** @return Point in layered pane coordinate system */
  static Pair<Point, Short> chooseBestHintPosition(
      Project project,
      Editor editor,
      int line,
      int col,
      LightweightHint hint,
      boolean awtTooltip,
      short preferredPosition) {
    HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
    Dimension hintSize = hint.getComponent().getPreferredSize();
    JComponent editorComponent = editor.getComponent();
    JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();

    Point p1;
    Point p2;
    boolean isLookupShown = LookupManager.getInstance(project).getActiveLookup() != null;
    if (isLookupShown) {
      p1 = hintManager.getHintPosition(hint, editor, HintManager.UNDER);
      p2 = hintManager.getHintPosition(hint, editor, HintManager.ABOVE);
    } else {
      LogicalPosition pos = new LogicalPosition(line, col);
      p1 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.UNDER);
      p2 = HintManagerImpl.getHintPosition(hint, editor, pos, HintManager.ABOVE);
    }

    if (!awtTooltip) {
      p1.x = Math.min(p1.x, layeredPane.getWidth() - hintSize.width);
      p1.x = Math.max(p1.x, 0);
      p2.x = Math.min(p2.x, layeredPane.getWidth() - hintSize.width);
      p2.x = Math.max(p2.x, 0);
    }

    boolean p1Ok = p1.y + hintSize.height < layeredPane.getHeight();
    boolean p2Ok = p2.y >= 0;

    if (isLookupShown) {
      if (p1Ok) return new Pair<Point, Short>(p1, HintManager.UNDER);
      if (p2Ok) return new Pair<Point, Short>(p2, HintManager.ABOVE);
    } else {
      if (preferredPosition != HintManager.DEFAULT) {
        if (preferredPosition == HintManager.ABOVE) {
          if (p2Ok) return new Pair<Point, Short>(p2, HintManager.ABOVE);
        } else if (preferredPosition == HintManager.UNDER) {
          if (p1Ok) return new Pair<Point, Short>(p1, HintManager.UNDER);
        }
      }

      if (p1Ok) return new Pair<Point, Short>(p1, HintManager.UNDER);
      if (p2Ok) return new Pair<Point, Short>(p2, HintManager.ABOVE);
    }

    int underSpace = layeredPane.getHeight() - p1.y;
    int aboveSpace = p2.y;
    return aboveSpace > underSpace
        ? new Pair<Point, Short>(new Point(p2.x, 0), HintManager.UNDER)
        : new Pair<Point, Short>(p1, HintManager.ABOVE);
  }
  private void updateComponent() {
    if (!myHint.isVisible()) {
      Disposer.dispose(this);
      return;
    }

    final PsiFile file =
        PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
    CharSequence chars = myEditor.getDocument().getCharsSequence();
    boolean noDelimiter =
        myHandler instanceof ParameterInfoHandlerWithTabActionSupport
            && ((ParameterInfoHandlerWithTabActionSupport) myHandler)
                    .getActualParameterDelimiterType()
                == TokenType.WHITE_SPACE;
    int caretOffset = myEditor.getCaretModel().getOffset();
    final int offset =
        noDelimiter ? caretOffset : CharArrayUtil.shiftBackward(chars, caretOffset - 1, " \t") + 1;

    final UpdateParameterInfoContext context = new MyUpdateParameterInfoContext(offset, file);
    final Object elementForUpdating = myHandler.findElementForUpdatingParameterInfo(context);

    if (elementForUpdating != null) {
      myHandler.updateParameterInfo(elementForUpdating, context);
      if (!myDisposed
          && myHint.isVisible()
          && !myEditor.isDisposed()
          && myEditor.getComponent().getRootPane() != null) {
        myComponent.update();
        IdeTooltip tooltip = myHint.getCurrentIdeTooltip();
        short position =
            tooltip != null ? toShort(tooltip.getPreferredPosition()) : HintManager.UNDER;
        Pair<Point, Short> pos =
            myProvider.getBestPointPosition(
                myHint,
                elementForUpdating instanceof PsiElement ? (PsiElement) elementForUpdating : null,
                caretOffset,
                true,
                position);
        HintManagerImpl.adjustEditorHintPosition(myHint, myEditor, pos.getFirst(), pos.getSecond());
      }
    } else {
      context.removeHint();
    }
  }
    @Override
    @NotNull
    public Pair<Point, Short> getBestPointPosition(
        LightweightHint hint,
        final PsiElement list,
        int offset,
        final boolean awtTooltip,
        short preferredPosition) {
      if (list != null) {
        TextRange range = list.getTextRange();
        if (!range.contains(offset)) {
          offset = range.getStartOffset() + 1;
        }
      }
      if (previousOffset == offset) return Pair.create(previousBestPoint, previousBestPosition);

      final boolean isMultiline =
          list != null && StringUtil.containsAnyChar(list.getText(), "\n\r");
      final LogicalPosition pos = myEditor.offsetToLogicalPosition(offset);
      Pair<Point, Short> position;

      if (!isMultiline) {
        position =
            chooseBestHintPosition(
                myEditor.getProject(),
                myEditor,
                pos.line,
                pos.column,
                hint,
                awtTooltip,
                preferredPosition);
      } else {
        Point p = HintManagerImpl.getHintPosition(hint, myEditor, pos, HintManager.ABOVE);
        position = new Pair<Point, Short>(p, HintManager.ABOVE);
      }
      previousBestPoint = position.getFirst();
      previousBestPosition = position.getSecond();
      previousOffset = offset;
      return position;
    }
  /**
   * @param hideByAnyKey
   * @param x <code>x</code> coordinate in layered pane coordinate system.
   * @param y <code>y</code> coordinate in layered pane coordinate system.
   */
  @Nullable
  public static LightweightHint showEditorFragmentHintAt(
      Editor editor,
      TextRange range,
      int x,
      int y,
      boolean showUpward,
      boolean showFolding,
      boolean hideByAnyKey) {
    if (ApplicationManager.getApplication().isUnitTestMode()) return null;
    Document document = editor.getDocument();

    int startOffset = range.getStartOffset();
    int startLine = document.getLineNumber(startOffset);
    CharSequence text = document.getCharsSequence();
    // There is a possible case that we have a situation like below:
    //    line 1
    //    line 2 <fragment start>
    //    line 3<fragment end>
    // We don't want to include 'line 2' to the target fragment then.
    boolean incrementLine = false;
    for (int offset = startOffset, max = Math.min(range.getEndOffset(), text.length());
        offset < max;
        offset++) {
      char c = text.charAt(offset);
      incrementLine = StringUtil.isWhiteSpace(c);
      if (!incrementLine || c == '\n') {
        break;
      }
    }
    if (incrementLine) {
      startLine++;
    }

    int endLine =
        Math.min(document.getLineNumber(range.getEndOffset()) + 1, document.getLineCount() - 1);

    // if (editor.logicalPositionToXY(new LogicalPosition(startLine, 0)).y >=
    // editor.logicalPositionToXY(new LogicalPosition(endLine, 0)).y) return null;
    if (startLine >= endLine) return null;

    EditorFragmentComponent fragmentComponent =
        createEditorFragmentComponent(editor, startLine, endLine, showFolding, true);

    if (showUpward) {
      y -= fragmentComponent.getPreferredSize().height + 10;
      y = Math.max(0, y);
    }

    final JComponent c = editor.getComponent();
    x = SwingUtilities.convertPoint(c, new Point(-3, 0), UIUtil.getRootPane(c)).x; // IDEA-68016

    Point p = new Point(x, y);
    LightweightHint hint = new MyComponentHint(fragmentComponent);
    HintManagerImpl.getInstanceImpl()
        .showEditorHint(
            hint,
            editor,
            p,
            (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0)
                | HintManager.HIDE_BY_TEXT_CHANGE
                | HintManager.HIDE_BY_MOUSEOVER,
            0,
            false,
            new HintHint(editor, p));
    return hint;
  }