private static boolean methodCallExpressionsAreEquivalent(
     @NotNull GrMethodCall methodExp1, @NotNull GrMethodCall methodExp2) {
   final GrExpression methodExpression1 = methodExp1.getInvokedExpression();
   final GrExpression methodExpression2 = methodExp2.getInvokedExpression();
   if (!expressionsAreEquivalent(methodExpression1, methodExpression2)) {
     return false;
   }
   final GrArgumentList argumentList1 = methodExp1.getArgumentList();
   if (argumentList1 == null) {
     return false;
   }
   final GrArgumentList argumentList2 = methodExp2.getArgumentList();
   if (argumentList2 == null) {
     return false;
   }
   final GrExpression[] args1 = argumentList1.getExpressionArguments();
   final GrExpression[] args2 = argumentList2.getExpressionArguments();
   if (!expressionListsAreEquivalent(args1, args2)) {
     return false;
   }
   final GrNamedArgument[] namedArgs1 = argumentList1.getNamedArguments();
   final GrNamedArgument[] namedArgs2 = argumentList2.getNamedArguments();
   if (!namedArgumentListsAreEquivalent(namedArgs1, namedArgs2)) {
     return false;
   }
   final GrClosableBlock[] closures1 = methodExp1.getClosureArguments();
   final GrClosableBlock[] closures2 = methodExp2.getClosureArguments();
   return expressionListsAreEquivalent(closures1, closures2);
 }
  private static boolean applicationStatementsAreEquivalent(
      GrApplicationStatement statement1, GrApplicationStatement statement2) {
    final GrExpression funExpression1 = statement1.getInvokedExpression();
    final GrExpression funExpression2 = statement2.getInvokedExpression();
    if (!expressionsAreEquivalent(funExpression1, funExpression2)) {
      return false;
    }

    final GrArgumentList argumentList1 = statement1.getArgumentList();
    if (argumentList1 == null) {
      return false;
    }
    final GrArgumentList argumentList2 = statement2.getArgumentList();
    if (argumentList2 == null) {
      return false;
    }
    final GrExpression[] args1 = argumentList1.getExpressionArguments();
    final GrExpression[] args2 = argumentList2.getExpressionArguments();
    if (!expressionListsAreEquivalent(args1, args2)) {
      return false;
    }
    final GrNamedArgument[] namedArgs1 = argumentList1.getNamedArguments();
    final GrNamedArgument[] namedArgs2 = argumentList2.getNamedArguments();
    if (!namedArgumentListsAreEquivalent(namedArgs1, namedArgs2)) {
      return false;
    }
    return true;
  }
 public void visitArgumentList(GrArgumentList list) {
   List<TypeConstraint> constraints = new ArrayList<TypeConstraint>();
   for (GroovyResolveResult variant : ResolveUtil.getCallVariants(list)) {
     final Map<GrExpression, Pair<PsiParameter, PsiType>> map =
         GrClosureSignatureUtil.mapArgumentsToParameters(
             variant,
             list,
             true,
             true,
             list.getNamedArguments(),
             list.getExpressionArguments(),
             GrClosableBlock.EMPTY_ARRAY);
     addConstraintsFromMap(constraints, map);
   }
   if (!constraints.isEmpty()) {
     myResult = constraints.toArray(new TypeConstraint[constraints.size()]);
   }
 }
    public void visitMethodCallExpression(GrMethodCallExpression methodCall) {
      final GrExpression invokedExpression = methodCall.getInvokedExpression();
      if (myExpression.equals(invokedExpression)) {
        myResult =
            new TypeConstraint[] {
              SubtypeConstraint.create(GroovyCommonClassNames.GROOVY_LANG_CLOSURE, methodCall)
            };
        return;
      }

      final GrClosableBlock[] closureArgs = methodCall.getClosureArguments();
      //noinspection SuspiciousMethodCalls
      final int closureIndex = Arrays.asList(closureArgs).indexOf(myExpression);
      if (closureIndex >= 0) {
        List<TypeConstraint> constraints = new ArrayList<TypeConstraint>();
        for (GroovyResolveResult variant : ResolveUtil.getCallVariants(myExpression)) {
          final GrArgumentList argumentList = methodCall.getArgumentList();
          final GrNamedArgument[] namedArgs =
              argumentList == null ? GrNamedArgument.EMPTY_ARRAY : argumentList.getNamedArguments();
          final GrExpression[] expressionArgs =
              argumentList == null
                  ? GrExpression.EMPTY_ARRAY
                  : argumentList.getExpressionArguments();
          try {
            final Map<GrExpression, Pair<PsiParameter, PsiType>> map =
                GrClosureSignatureUtil.mapArgumentsToParameters(
                    variant, methodCall, true, true, namedArgs, expressionArgs, closureArgs);
            addConstraintsFromMap(constraints, map);
          } catch (RuntimeException e) {
            LOG.error(
                "call: " + methodCall.getText() + "\nsymbol: " + variant.getElement().getText(), e);
          }
        }
        if (!constraints.isEmpty()) {
          myResult = constraints.toArray(new TypeConstraint[constraints.size()]);
        }
      }
    }
        @Override
        public PsiType fun(GrIndexPropertyImpl index) {
          GrExpression selected = index.getInvokedExpression();
          PsiType thisType = selected.getType();

          if (thisType == null) return null;

          GrArgumentList argList = index.getArgumentList();

          PsiType[] argTypes = PsiUtil.getArgumentTypes(argList);
          if (argTypes == null) return null;

          final PsiManager manager = index.getManager();
          final GlobalSearchScope resolveScope = index.getResolveScope();

          if (argTypes.length == 0) {
            PsiType arrType = null;
            if (selected instanceof GrBuiltinTypeClassExpression) {
              arrType = ((GrBuiltinTypeClassExpression) selected).getPrimitiveType();
            }

            if (selected instanceof GrReferenceExpression) {
              final PsiElement resolved = ((GrReferenceExpression) selected).resolve();
              if (resolved instanceof PsiClass) {
                String qname = ((PsiClass) resolved).getQualifiedName();
                if (qname != null) {
                  arrType = TypesUtil.createTypeByFQClassName(qname, index);
                }
              }
            }

            if (arrType != null) {
              final PsiArrayType param = arrType.createArrayType();
              return TypesUtil.createJavaLangClassType(param, index.getProject(), resolveScope);
            }
          }

          if (PsiImplUtil.isSimpleArrayAccess(
              thisType, argTypes, manager, resolveScope, PsiUtil.isLValue(index))) {
            return TypesUtil.boxPrimitiveType(
                ((PsiArrayType) thisType).getComponentType(), manager, resolveScope);
          }

          final GroovyResolveResult[] candidates = index.multiResolve(false);

          PsiType[] args =
              PsiUtil.getArgumentTypes(
                  argList.getNamedArguments(),
                  argList.getExpressionArguments(),
                  GrClosableBlock.EMPTY_ARRAY,
                  true,
                  null,
                  false);
          final GroovyResolveResult candidate = PsiImplUtil.extractUniqueResult(candidates);
          final PsiElement element = candidate.getElement();
          if (element instanceof PsiNamedElement) {
            final String name = ((PsiNamedElement) element).getName();
            if ("putAt".equals(name) && args != null) {
              args =
                  ArrayUtil.append(
                      args, TypeInferenceHelper.getInitializerFor(index), PsiType.class);
            }
          }
          PsiType overloadedOperatorType =
              ResolveUtil.extractReturnTypeFromCandidate(candidate, index, args);

          PsiType componentType = extractMapValueType(thisType, args, manager, resolveScope);

          if (overloadedOperatorType != null
              && (componentType == null
                  || !TypesUtil.isAssignable(
                      overloadedOperatorType, componentType, manager, resolveScope))) {
            return TypesUtil.boxPrimitiveType(overloadedOperatorType, manager, resolveScope);
          }
          return componentType;
        }
 @NotNull
 @Override
 public GrNamedArgument[] getNamedArguments() {
   GrArgumentList list = getArgumentList();
   return list.getNamedArguments();
 }
  private GroovyResolveResult[] resolveImpl(
      boolean incompleteCode, @Nullable GrExpression upToArgument) {
    GrExpression invoked = getInvokedExpression();
    PsiType thisType = invoked.getType();

    if (thisType == null) return GroovyResolveResult.EMPTY_ARRAY;

    GrArgumentList argList = getArgumentList();

    PsiType[] argTypes =
        PsiUtil.getArgumentTypes(
            argList.getNamedArguments(),
            argList.getExpressionArguments(),
            GrClosableBlock.EMPTY_ARRAY,
            true,
            upToArgument,
            false);
    if (argTypes == null) return GroovyResolveResult.EMPTY_ARRAY;

    final PsiManager manager = getManager();
    final GlobalSearchScope resolveScope = getResolveScope();

    if (argTypes.length == 0) {
      PsiType arrType = null;
      if (invoked instanceof GrBuiltinTypeClassExpression) {
        arrType = ((GrBuiltinTypeClassExpression) invoked).getPrimitiveType();
      }

      if (invoked instanceof GrReferenceExpression) {
        final PsiElement resolved = ((GrReferenceExpression) invoked).resolve();
        if (resolved instanceof PsiClass) {
          String qname = ((PsiClass) resolved).getQualifiedName();
          if (qname != null) {
            arrType = TypesUtil.createTypeByFQClassName(qname, this);
          }
        }
      }

      if (arrType != null) {
        return GroovyResolveResult.EMPTY_ARRAY;
      }
    }

    GroovyResolveResult[] candidates;
    final String name;
    if (PsiUtil.isLValue(this)) {
      name = "putAt";
      if (!incompleteCode) {
        argTypes =
            ArrayUtil.append(argTypes, TypeInferenceHelper.getInitializerFor(this), PsiType.class);
      }
    } else {
      name = "getAt";
    }

    if (PsiImplUtil.isSimpleArrayAccess(
        thisType, argTypes, manager, resolveScope, PsiUtil.isLValue(this))) {
      return GroovyResolveResult.EMPTY_ARRAY;
    }

    candidates =
        ResolveUtil.getMethodCandidates(
            thisType, name, this, true, incompleteCode, false, argTypes);

    // hack for remove DefaultGroovyMethods.getAt(Object, ...)
    if (candidates.length == 2) {
      for (int i = 0; i < candidates.length; i++) {
        GroovyResolveResult candidate = candidates[i];
        final PsiElement element = candidate.getElement();
        if (element instanceof GrGdkMethod) {
          final PsiMethod staticMethod = ((GrGdkMethod) element).getStaticMethod();
          final PsiParameter param = staticMethod.getParameterList().getParameters()[0];
          if (param.getType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
            return new GroovyResolveResult[] {candidates[1 - i]};
          }
        }
      }
    }

    if (candidates.length != 1) {
      final GrTupleType tupleType =
          new GrTupleType(argTypes, JavaPsiFacade.getInstance(getProject()), resolveScope);
      candidates = ResolveUtil.getMethodCandidates(thisType, name, this, tupleType);
    }
    return candidates;
  }