@Nullable
  public static PsiExpression addTypeArguments(@NotNull PsiExpression expression, @Nullable PsiType toType, boolean withShortening) {
    if (!PsiUtil.isAvailable(JavaFeature.GENERICS, expression)) return null;

    PsiExpression orig = expression;
    expression = PsiUtil.skipParenthesizedExprDown(expression);
    if (expression instanceof PsiMethodCallExpression methodCall) {
      final PsiReferenceParameterList list = methodCall.getMethodExpression().getParameterList();
      if (list == null || list.getTypeArguments().length > 0) return null;
      final JavaResolveResult resolveResult = methodCall.resolveMethodGenerics();
      final PsiElement element = resolveResult.getElement();
      if (element instanceof PsiMethod method) {
        final PsiType returnType = method.getReturnType();
        if (returnType == null) return null;

        final PsiTypeParameter[] typeParameters = method.getTypeParameters();
        if (typeParameters.length > 0) {
          PsiType[] mappings = PsiType.createArray(typeParameters.length);
          PsiResolveHelper helper = JavaPsiFacade.getInstance(expression.getProject()).getResolveHelper();
          LanguageLevel level = PsiUtil.getLanguageLevel(expression);
          for (int i = 0; i < typeParameters.length; i++) {
            PsiTypeParameter typeParameter = typeParameters[i];
            final PsiType substitution;
            if (toType == null) {
              substitution = resolveResult.getSubstitutor().substitute(typeParameter);
              if (!PsiTypesUtil.isDenotableType(substitution, expression)) return null;
            }
            else {
              substitution = helper.getSubstitutionForTypeParameter(typeParameter, returnType, toType, false, level);
            }
            if (substitution == null || PsiTypes.nullType().equals(substitution)) return null;
            mappings[i] = GenericsUtil.eliminateWildcards(substitution, false);
          }

          final PsiElementFactory factory = JavaPsiFacade.getElementFactory(expression.getProject());
          PsiMethodCallExpression copy = (PsiMethodCallExpression)expression.copy();
          final PsiReferenceExpression methodExpression = copy.getMethodExpression();
          final PsiReferenceParameterList parameterList = methodExpression.getParameterList();
          LOG.assertTrue(parameterList != null);
          for (PsiType mapping : mappings) {
            parameterList.add(factory.createTypeElement(mapping));
          }
          if (methodExpression.getQualifierExpression() == null) {
            final PsiExpression qualifierExpression;
            final PsiClass containingClass = method.getContainingClass();
            if (containingClass == null) return null; // not actual method but some copy in DummyHolder, ignore
            if (method.hasModifierProperty(PsiModifier.STATIC)) {
              qualifierExpression = factory.createReferenceExpression(containingClass);
            }
            else {
              qualifierExpression = RefactoringChangeUtil.createThisExpression(method.getManager(), null);
            }
            methodExpression.setQualifierExpression(qualifierExpression);
          }

          PsiExpression result = withShortening
                                 ? (PsiExpression)JavaCodeStyleManager.getInstance(copy.getProject()).shortenClassReferences(copy)
                                 : copy;

          if (orig != expression) {
            PsiExpression parenthesized = (PsiExpression)orig.copy();
            Objects.requireNonNull(PsiUtil.skipParenthesizedExprDown(parenthesized)).replace(result);
            return parenthesized;
          }
          return result;
        }
      }
    }
    return null;
  }
@Nullable
  public static PsiExpression addTypeArguments(@NotNull PsiExpression expression, @Nullable PsiType toType, boolean withShortening)