@Nullable
  public static GrExpression getRuntimeQualifier(GrReferenceExpression refExpr) {
    GrExpression qualifier = refExpr.getQualifierExpression();
    if (qualifier != null) return qualifier;

    for (GrClosableBlock closure = PsiTreeUtil.getParentOfType(refExpr, GrClosableBlock.class);
        closure != null;
        closure = PsiTreeUtil.getParentOfType(closure, GrClosableBlock.class)) {

      PsiElement parent = closure.getParent();
      if (parent instanceof GrArgumentList) parent = parent.getParent();
      if (!(parent instanceof GrMethodCall)) continue;

      GrExpression funExpr = ((GrMethodCall) parent).getInvokedExpression();
      if (!(funExpr instanceof GrReferenceExpression)) return funExpr;

      final PsiElement resolved = ((GrReferenceExpression) funExpr).resolve();
      if (!(resolved instanceof PsiMethod)) return funExpr;

      if (resolved instanceof GrGdkMethod
          && isFromDGM((GrGdkMethod) resolved)
          && !GdkMethodUtil.isWithName(((GrGdkMethod) resolved).getStaticMethod().getName())) {
        continue;
      }

      qualifier = ((GrReferenceExpression) funExpr).getQualifierExpression();
      if (qualifier != null) return qualifier;
    }

    return null;
  }
  @Nullable
  public static PsiType inferExpectedTypeForDiamond(GrExpression diamondNew) {
    PsiElement skipped = PsiUtil.skipParentheses(diamondNew, true);
    assert skipped != null;
    PsiElement pparent = skipped.getParent();
    if (pparent instanceof GrAssignmentExpression
        && PsiTreeUtil.isAncestor(
            ((GrAssignmentExpression) pparent).getRValue(), diamondNew, false)) {
      GrExpression lValue = ((GrAssignmentExpression) pparent).getLValue();
      if (PsiUtil.mightBeLValue(lValue)) {
        return lValue.getNominalType();
      }
    } else if (pparent instanceof GrVariable
        && ((GrVariable) pparent).getInitializerGroovy() == diamondNew) {
      return ((GrVariable) pparent).getDeclaredType();
    } else if (pparent instanceof GrListOrMap) {
      PsiElement ppparent = PsiUtil.skipParentheses(pparent.getParent(), true);

      if (ppparent instanceof GrAssignmentExpression
          && PsiTreeUtil.isAncestor(
              ((GrAssignmentExpression) ppparent).getRValue(), pparent, false)) {

        PsiElement lValue =
            PsiUtil.skipParentheses(((GrAssignmentExpression) ppparent).getLValue(), false);
        if (lValue instanceof GrTupleExpression) {
          GrExpression[] initializers = ((GrListOrMap) pparent).getInitializers();
          int index = ArrayUtil.find(initializers, diamondNew);
          GrExpression[] expressions = ((GrTupleExpression) lValue).getExpressions();
          if (index < expressions.length) {
            return expressions[index].getNominalType();
          }
        }
      }
    }

    return null;
  }
    @Override
    public void visitAnnotationArrayInitializer(GrAnnotationArrayInitializer arrayInitializer) {
      final GrAnnotationNameValuePair nameValuePair =
          PsiTreeUtil.getParentOfType(
              arrayInitializer,
              GrAnnotationNameValuePair.class,
              true,
              GrDefaultAnnotationValue.class);
      if (nameValuePair != null) {

        final PsiClass annot = ResolveUtil.resolveAnnotation(arrayInitializer);
        if (annot == null) return;

        final String name = nameValuePair.getName();
        if (name == null) return;

        final PsiMethod[] attrs = annot.findMethodsByName(name, false);
        if (attrs.length > 0) {
          PsiType type = attrs[0].getReturnType();
          while (type instanceof PsiArrayType) type = ((PsiArrayType) type).getComponentType();
          if (type != null && isAcceptableAnnotationValueType(type)) {
            myResult = createSimpleSubTypeResult(type);
          }
        }
      } else {
        final GrAnnotationMethod method =
            PsiTreeUtil.getParentOfType(arrayInitializer, GrAnnotationMethod.class);
        assert method != null;

        PsiType type = method.getReturnType();

        int count = 1;
        PsiElement parent = arrayInitializer.getParent();
        while (parent instanceof GrAnnotationArrayInitializer) {
          count++;
          parent = parent.getParent();
        }

        while (type instanceof PsiArrayType && count > 0) {
          type = ((PsiArrayType) type).getComponentType();
          count--;
        }
        if (type != null && isAcceptableAnnotationValueType(type)) {
          myResult = createSimpleSubTypeResult(type);
        }
      }
    }
 private static boolean isFirstChild(PsiElement element) {
   return PsiUtil.skipWhitespacesAndComments(element.getParent().getFirstChild(), true) == element;
 }
  @Nullable
  public static GrExpression replaceExpression(
      GrExpression oldExpr, GrExpression newExpr, boolean removeUnnecessaryParentheses) {
    PsiElement oldParent = oldExpr.getParent();
    if (oldParent == null) throw new PsiInvalidElementAccessException(oldExpr);

    if (!(oldExpr instanceof GrApplicationStatement)) {
      newExpr = ApplicationStatementUtil.convertToMethodCallExpression(newExpr);
    }

    // Remove unnecessary parentheses
    if (removeUnnecessaryParentheses
        && oldParent instanceof GrParenthesizedExpression
        && !(oldParent.getParent() instanceof GrArgumentLabel)) {
      return ((GrExpression) oldParent)
          .replaceWithExpression(newExpr, removeUnnecessaryParentheses);
    }

    // regexes cannot be after identifier , try to replace it with simple string
    if (getRegexAtTheBeginning(newExpr) != null && isAfterIdentifier(oldExpr)) {
      final PsiElement copy = newExpr.copy();
      final GrLiteral regex = getRegexAtTheBeginning(copy);
      LOG.assertTrue(regex != null);
      final GrLiteral stringLiteral = GrStringUtil.createStringFromRegex(regex);
      if (regex == copy) {
        return oldExpr.replaceWithExpression(stringLiteral, removeUnnecessaryParentheses);
      } else {
        regex.replace(stringLiteral);
        return oldExpr.replaceWithExpression((GrExpression) copy, removeUnnecessaryParentheses);
      }
    }

    GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject());
    if (oldParent instanceof GrStringInjection) {
      if (newExpr instanceof GrString
          || newExpr instanceof GrLiteral && ((GrLiteral) newExpr).getValue() instanceof String) {
        return GrStringUtil.replaceStringInjectionByLiteral(
            (GrStringInjection) oldParent, (GrLiteral) newExpr);
      } else {
        newExpr = factory.createExpressionFromText("{" + newExpr.getText() + "}");
        oldParent.getNode().replaceChild(oldExpr.getNode(), newExpr.getNode());
        return newExpr;
      }
    }

    if (PsiTreeUtil.getParentOfType(oldExpr, GrStringInjection.class, false, GrCodeBlock.class)
        != null) {
      final PsiElement replaced = oldExpr.replace(newExpr);
      final GrStringInjection stringInjection =
          PsiTreeUtil.getParentOfType(replaced, GrStringInjection.class);
      GrStringUtil.wrapInjection(stringInjection);
      assert stringInjection != null;
      return stringInjection.getClosableBlock();
    }

    // check priorities
    if (oldParent instanceof GrExpression && !(oldParent instanceof GrParenthesizedExpression)) {
      GrExpression addedParenth =
          addParenthesesIfNeeded(newExpr, oldExpr, (GrExpression) oldParent);
      if (newExpr != addedParenth) {
        return oldExpr.replaceWithExpression(addedParenth, removeUnnecessaryParentheses);
      }
    }

    // if replace closure argument with expression
    // we should add the expression in arg list
    if (oldExpr instanceof GrClosableBlock
        && !(newExpr instanceof GrClosableBlock)
        && oldParent instanceof GrMethodCallExpression
        && ArrayUtil.contains(
            oldExpr, ((GrMethodCallExpression) oldParent).getClosureArguments())) {
      return ((GrMethodCallExpression) oldParent)
          .replaceClosureArgument((GrClosableBlock) oldExpr, newExpr);
    }

    newExpr = (GrExpression) oldExpr.replace(newExpr);

    // if newExpr is the first grand child of command argument list we should replace command arg
    // list with parenthesised arg list.
    // In other case the code will be broken. So we try to find wrapping command arg list counting
    // levels. After arg list replace we go inside it
    // to find target parenthesised expression.
    if (newExpr instanceof GrParenthesizedExpression && isFirstChild(newExpr)) {
      int parentCount = 0;

      PsiElement element = oldParent;
      while (element != null && !(element instanceof GrCommandArgumentList)) {
        if (element instanceof GrCodeBlock || element instanceof GrParenthesizedExpression) break;
        if (element instanceof PsiFile) break;

        final PsiElement parent = element.getParent();
        if (parent == null) break;
        if (!isFirstChild(element)) break;

        element = parent;
        parentCount++;
      }

      if (element instanceof GrCommandArgumentList) {
        final GrCommandArgumentList commandArgList = (GrCommandArgumentList) element;

        final PsiElement parent = commandArgList.getParent();
        LOG.assertTrue(parent instanceof GrApplicationStatement);

        final GrMethodCall methodCall =
            factory.createMethodCallByAppCall((GrApplicationStatement) parent);
        final GrMethodCall newCall = (GrMethodCall) parent.replace(methodCall);

        PsiElement result = newCall.getArgumentList().getAllArguments()[0];

        for (int i = 0; i < parentCount; i++) {
          result = PsiUtil.skipWhitespacesAndComments(result.getFirstChild(), true);
        }

        LOG.assertTrue(result instanceof GrParenthesizedExpression);
        return (GrExpression) result;
      }
    }
    return newExpr;
  }