@Override
    public void renderValue(@NotNull XValueTextRenderer renderer, @Nullable XValueNodeImpl node) {
      boolean compact = node != null;
      if (myError != null) {
        if (myValue.endsWith(myError)) {
          renderer.renderValue(myValue.substring(0, myValue.length() - myError.length()));
        }
        renderer.renderError(myError);
      } else {
        if (compact && node.getValueContainer() instanceof JavaValue) {
          final JavaValue container = (JavaValue) node.getValueContainer();

          if (container.getDescriptor().isArray()) {
            final ArrayReference value = (ArrayReference) container.getDescriptor().getValue();
            final ArrayType type = (ArrayType) container.getDescriptor().getType();
            if (type != null) {
              final String typeName = type.componentTypeName();
              if (TypeConversionUtil.isPrimitive(typeName)
                  || CommonClassNames.JAVA_LANG_STRING.equals(typeName)) {
                int size = value.length();
                int max =
                    Math.min(size, CommonClassNames.JAVA_LANG_STRING.equals(typeName) ? 5 : 10);
                // TODO [eu]: this is a quick fix for IDEA-136606, need to move this away from
                // EDT!!!
                final List<Value> values = value.getValues(0, max);
                int i = 0;
                final List<String> vals = new ArrayList<String>(max);
                while (i < values.size()) {
                  vals.add(StringUtil.first(values.get(i).toString(), 15, true));
                  i++;
                }
                String more = "";
                if (vals.size() < size) {
                  more = ", + " + (size - vals.size()) + " more";
                }

                renderer.renderValue("{" + StringUtil.join(vals, ", ") + more + "}");
                return;
              }
            }
          }
        }

        String value = myValue;
        if (myValueDescriptor.isString()) {
          renderer.renderStringValue(myValue, "\"\\", XValueNode.MAX_VALUE_LENGTH);
          return;
        } else if (myValueDescriptor.getLastRenderer() instanceof ToStringRenderer
            || myValueDescriptor.getLastRenderer() instanceof ToStringBasedRenderer) {
          value = StringUtil.wrapWithDoubleQuote(truncateToMaxLength(myValue));
        } else if (myValueDescriptor.getLastRenderer() instanceof CompoundReferenceRenderer) {
          value = truncateToMaxLength(myValue);
        }
        renderer.renderValue(value);
      }
    }
 @Override
 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
   super.visitMethodCallExpression(expression);
   final PsiReferenceExpression methodExpression = expression.getMethodExpression();
   @NonNls final String name = methodExpression.getReferenceName();
   if (HardcodedMethodConstants.TO_STRING.equals(name)) {
     final PsiExpressionList argumentList = expression.getArgumentList();
     final PsiExpression[] arguments = argumentList.getExpressions();
     if (arguments.length != 0) {
       return;
     }
     final PsiExpression qualifier = methodExpression.getQualifierExpression();
     checkExpression(qualifier);
   } else if ("append".equals(name)) {
     final PsiExpression qualifier = methodExpression.getQualifierExpression();
     if (!TypeUtils.expressionHasTypeOrSubtype(
         qualifier, CommonClassNames.JAVA_LANG_ABSTRACT_STRING_BUILDER)) {
       return;
     }
     final PsiExpressionList argumentList = expression.getArgumentList();
     final PsiExpression[] arguments = argumentList.getExpressions();
     if (arguments.length != 1) {
       return;
     }
     final PsiExpression argument = arguments[0];
     checkExpression(argument);
   } else if ("valueOf".equals(name)) {
     final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
     if (!(qualifierExpression instanceof PsiReferenceExpression)) {
       return;
     }
     final PsiReferenceExpression referenceExpression =
         (PsiReferenceExpression) qualifierExpression;
     final String canonicalText = referenceExpression.getCanonicalText();
     if (!CommonClassNames.JAVA_LANG_STRING.equals(canonicalText)) {
       return;
     }
     final PsiExpressionList argumentList = expression.getArgumentList();
     final PsiExpression[] arguments = argumentList.getExpressions();
     if (arguments.length != 1) {
       return;
     }
     final PsiExpression argument = arguments[0];
     checkExpression(argument);
   }
 }
  @Nullable
  public static PsiType getLeastUpperBound(
      @NotNull PsiType type1, @NotNull PsiType type2, PsiManager manager) {
    if (type1 instanceof GrTupleType && type2 instanceof GrTupleType) {
      GrTupleType tuple1 = (GrTupleType) type1;
      GrTupleType tuple2 = (GrTupleType) type2;
      PsiType[] components1 = tuple1.getComponentTypes();
      PsiType[] components2 = tuple2.getComponentTypes();

      if (components1.length == 0) return genNewListBy(type2, manager);
      if (components2.length == 0) return genNewListBy(type1, manager);

      PsiType[] components3 = new PsiType[Math.min(components1.length, components2.length)];
      for (int i = 0; i < components3.length; i++) {
        PsiType c1 = components1[i];
        PsiType c2 = components2[i];
        if (c1 == null || c2 == null) {
          components3[i] = null;
        } else {
          components3[i] = getLeastUpperBound(c1, c2, manager);
        }
      }
      return new GrTupleType(
          components3,
          JavaPsiFacade.getInstance(manager.getProject()),
          tuple1.getScope().intersectWith(tuple2.getResolveScope()));
    } else if (checkEmptyListAndList(type1, type2)) {
      return genNewListBy(type2, manager);
    } else if (checkEmptyListAndList(type2, type1)) {
      return genNewListBy(type1, manager);
    } else if (type1 instanceof GrMapType && type2 instanceof GrMapType) {
      return GrMapType.merge(((GrMapType) type1), ((GrMapType) type2));
    } else if (checkEmptyMapAndMap(type1, type2)) {
      return genNewMapBy(type2, manager);
    } else if (checkEmptyMapAndMap(type2, type1)) {
      return genNewMapBy(type1, manager);
    } else if (type1 instanceof GrClosureType && type2 instanceof GrClosureType) {
      GrClosureType clType1 = (GrClosureType) type1;
      GrClosureType clType2 = (GrClosureType) type2;
      GrSignature signature1 = clType1.getSignature();
      GrSignature signature2 = clType2.getSignature();

      if (signature1 instanceof GrClosureSignature && signature2 instanceof GrClosureSignature) {
        if (((GrClosureSignature) signature1).getParameterCount()
            == ((GrClosureSignature) signature2).getParameterCount()) {
          final GrClosureSignature signature =
              GrClosureSignatureImpl.getLeastUpperBound(
                  ((GrClosureSignature) signature1), ((GrClosureSignature) signature2), manager);
          if (signature != null) {
            GlobalSearchScope scope =
                clType1.getResolveScope().intersectWith(clType2.getResolveScope());
            final LanguageLevel languageLevel =
                ComparatorUtil.max(clType1.getLanguageLevel(), clType2.getLanguageLevel());
            return GrClosureType.create(
                signature,
                scope,
                JavaPsiFacade.getInstance(manager.getProject()),
                languageLevel,
                true);
          }
        }
      }
    } else if (GroovyCommonClassNames.GROOVY_LANG_GSTRING.equals(type1.getCanonicalText())
        && CommonClassNames.JAVA_LANG_STRING.equals(type2.getInternalCanonicalText())) {
      return type2;
    } else if (GroovyCommonClassNames.GROOVY_LANG_GSTRING.equals(type2.getCanonicalText())
        && CommonClassNames.JAVA_LANG_STRING.equals(type1.getInternalCanonicalText())) {
      return type1;
    }
    final PsiType result = getLeastUpperBoundForNumericType(type1, type2);
    if (result != null) return result;
    return GenericsUtil.getLeastUpperBound(type1, type2, manager);
  }