// method1 has more general parameter types thn method2 private boolean secondMethodIsPreferable( @NotNull PsiMethod method1, @NotNull PsiSubstitutor substitutor1, @Nullable PsiElement resolveContext1, @NotNull PsiMethod method2, @NotNull PsiSubstitutor substitutor2, @Nullable PsiElement resolveContext2) { if (!method1.getName().equals(method2.getName())) return false; final Boolean custom = GrMethodComparator.checkDominated(method1, substitutor1, method2, substitutor2, this); if (custom != null) return custom; PsiType[] argTypes = myArgumentTypes; if (method1 instanceof GrGdkMethod && method2 instanceof GrGdkMethod) { method1 = ((GrGdkMethod) method1).getStaticMethod(); method2 = ((GrGdkMethod) method2).getStaticMethod(); if (myArgumentTypes != null) { argTypes = PsiType.createArray(argTypes.length + 1); System.arraycopy(myArgumentTypes, 0, argTypes, 1, myArgumentTypes.length); argTypes[0] = myThisType; } } if (myIsConstructor && argTypes != null && argTypes.length == 1) { if (method1.getParameterList().getParametersCount() == 0) return true; if (method2.getParameterList().getParametersCount() == 0) return false; } PsiParameter[] params1 = method1.getParameterList().getParameters(); PsiParameter[] params2 = method2.getParameterList().getParameters(); if (argTypes == null && params1.length != params2.length) return false; if (params1.length < params2.length) { if (params1.length == 0) return false; final PsiType lastType = params1[params1.length - 1].getType(); // varargs applicability return lastType instanceof PsiArrayType; } for (int i = 0; i < params2.length; i++) { final PsiType ptype1 = params1[i].getType(); final PsiType ptype2 = params2[i].getType(); PsiType type1 = substitutor1.substitute(ptype1); PsiType type2 = substitutor2.substitute(ptype2); if (argTypes != null && argTypes.length > i) { PsiType argType = argTypes[i]; if (argType != null) { final boolean converts1 = TypesUtil.isAssignableWithoutConversions( TypeConversionUtil.erasure(type1), argType, myPlace); final boolean converts2 = TypesUtil.isAssignableWithoutConversions( TypeConversionUtil.erasure(type2), argType, myPlace); if (converts1 != converts2) { return converts2; } // see groovy.lang.GroovyCallable if (TypesUtil.resolvesTo(type1, CommonClassNames.JAVA_UTIL_CONCURRENT_CALLABLE) && TypesUtil.resolvesTo(type2, CommonClassNames.JAVA_LANG_RUNNABLE)) { if (InheritanceUtil.isInheritor( argType, GroovyCommonClassNames.GROOVY_LANG_GROOVY_CALLABLE)) return true; } } } if (!typesAgree(TypeConversionUtil.erasure(ptype1), TypeConversionUtil.erasure(ptype2))) return false; if (resolveContext1 != null && resolveContext2 == null) { return !(TypesUtil.resolvesTo(type1, CommonClassNames.JAVA_LANG_OBJECT) && TypesUtil.resolvesTo(type2, CommonClassNames.JAVA_LANG_OBJECT)); } if (resolveContext1 == null && resolveContext2 != null) { return true; } } if (!(method1 instanceof SyntheticElement) && !(method2 instanceof SyntheticElement)) { final PsiType returnType1 = substitutor1.substitute(method1.getReturnType()); final PsiType returnType2 = substitutor2.substitute(method2.getReturnType()); if (!TypesUtil.isAssignableWithoutConversions(returnType1, returnType2, myPlace) && TypesUtil.isAssignableWithoutConversions(returnType2, returnType1, myPlace)) { return false; } } return true; }