@Override @Nullable public PsiType getNominalType() { final GroovyResolveResult resolveResult = advancedResolve(); PsiElement resolved = resolveResult.getElement(); for (GrReferenceTypeEnhancer enhancer : GrReferenceTypeEnhancer.EP_NAME.getExtensions()) { PsiType type = enhancer.getReferenceType(this, resolved); if (type != null) { return type; } } IElementType dotType = getDotTokenType(); if (dotType == GroovyTokenTypes.mMEMBER_POINTER) { return GrClosureType.create(multiResolve(false), this); } if (isDefinitelyKeyOfMap()) { final PsiType type = getTypeFromMapAccess(this); if (type != null) { return type; } } PsiType result = getNominalTypeInner(resolved); if (result == null) return null; result = TypesUtil.substituteAndNormalizeType( result, resolveResult.getSubstitutor(), resolveResult.getSpreadState(), this); return result; }
@Nullable private static PsiType getTypeFromClassRef(@NotNull GrReferenceExpressionImpl ref) { if ("class".equals(ref.getReferenceName())) { return TypesUtil.createJavaLangClassType( PsiImplUtil.getQualifierType(ref), ref.getProject(), ref.getResolveScope()); } return null; }
@Nullable private static PsiType getTypeFromSpreadOperator(@NotNull GrReferenceExpressionImpl ref) { if (ref.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) { return TypesUtil.createType(CommonClassNames.JAVA_UTIL_LIST, ref); } return null; }
private static PsiType doFun(GrReferenceExpression refExpr) { if (ResolveUtil.isClassReference(refExpr)) { GrExpression qualifier = refExpr.getQualifier(); LOG.assertTrue(qualifier != null); return TypesUtil.createJavaLangClassType( qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope()); } if (PsiUtil.isCompileStatic(refExpr)) { final GroovyResolveResult resolveResult = refExpr.advancedResolve(); final PsiElement resolvedF = resolveResult.getElement(); final PsiType type; if (resolvedF instanceof GrField) { type = ((GrField) resolvedF).getType(); } else if (resolvedF instanceof GrAccessorMethod) { type = ((GrAccessorMethod) resolvedF).getProperty().getType(); } else { type = null; } if (type != null) { return resolveResult.getSubstitutor().substitute(type); } } final PsiElement resolved = refExpr.resolve(); final PsiType nominal = refExpr.getNominalType(); Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr); if (reassigned != null && reassigned.booleanValue()) { return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true); } final PsiType inferred = getInferredTypes(refExpr, resolved); if (inferred == null) { if (nominal == null) { // inside nested closure we could still try to infer from variable initializer. Not sound, // but makes sense if (resolved instanceof GrVariable) { LOG.assertTrue(resolved.isValid()); return ((GrVariable) resolved).getTypeGroovy(); } } return nominal; } if (nominal == null) return inferred; if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) { if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) { return nominal; } } return inferred; }
private boolean isDefinitelyKeyOfMap() { final GrExpression qualifier = ResolveUtil.getSelfOrWithQualifier(this); if (qualifier == null) return false; if (qualifier instanceof GrReferenceExpression) { // key in 'java.util.Map.key' is not access to map, it is access to // static property of field final PsiElement resolved = ((GrReferenceExpression) qualifier).resolve(); if (resolved instanceof PsiClass) return false; } final PsiType type = qualifier.getType(); if (type == null) return false; if (!InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_UTIL_MAP)) return false; final String qname = TypesUtil.getQualifiedName(type); return !GroovyCommonClassNames.GROOVY_UTIL_CONFIG_OBJECT.equals(qname); }
@Nullable private PsiType getNominalTypeInner(@Nullable PsiElement resolved) { if (resolved == null && !"class".equals(getReferenceName())) { resolved = resolve(); } if (resolved instanceof PsiClass) { final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); if (PsiUtil.isInstanceThisRef(this)) { final PsiClassType categoryType = GdkMethodUtil.getCategoryType((PsiClass) resolved); if (categoryType != null) { return categoryType; } else { return factory.createType((PsiClass) resolved); } } else if (PsiUtil.isSuperReference(this)) { PsiClass contextClass = PsiUtil.getContextClass(this); if (GrTraitUtil.isTrait(contextClass)) { PsiClassType[] extendsTypes = contextClass.getExtendsListTypes(); PsiClassType[] implementsTypes = contextClass.getImplementsListTypes(); PsiClassType[] superTypes = ArrayUtil.mergeArrays(implementsTypes, extendsTypes, PsiClassType.ARRAY_FACTORY); return PsiIntersectionType.createIntersection(ArrayUtil.reverseArray(superTypes)); } return factory.createType((PsiClass) resolved); } if (getParent() instanceof GrReferenceExpression) { return factory.createType((PsiClass) resolved); } else { return TypesUtil.createJavaLangClassType( factory.createType((PsiClass) resolved), getProject(), getResolveScope()); } } if (resolved instanceof GrVariable) { return ((GrVariable) resolved).getDeclaredType(); } if (resolved instanceof PsiVariable) { return ((PsiVariable) resolved).getType(); } if (resolved instanceof PsiMethod) { PsiMethod method = (PsiMethod) resolved; if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) { return method.getParameterList().getParameters()[0].getType(); } // 'class' property with explicit generic PsiClass containingClass = method.getContainingClass(); if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && "getClass".equals(method.getName())) { return TypesUtil.createJavaLangClassType( PsiImplUtil.getQualifierType(this), getProject(), getResolveScope()); } return PsiUtil.getSmartReturnType(method); } if (resolved == null) { final PsiType fromClassRef = getTypeFromClassRef(this); if (fromClassRef != null) { return fromClassRef; } final PsiType fromMapAccess = getTypeFromMapAccess(this); if (fromMapAccess != null) { return fromMapAccess; } final PsiType fromSpreadOperator = getTypeFromSpreadOperator(this); if (fromSpreadOperator != null) { return fromSpreadOperator; } } return null; }