@Nullable public static PsiClass getSuperClass(@NotNull PsiClass psiClass) { PsiManager manager = psiClass.getManager(); GlobalSearchScope resolveScope = psiClass.getResolveScope(); final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); if (psiClass.isInterface()) { return facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope); } if (psiClass.isEnum()) { return facade.findClass(CommonClassNames.JAVA_LANG_ENUM, resolveScope); } if (psiClass instanceof PsiAnonymousClass) { PsiClassType baseClassReference = ((PsiAnonymousClass) psiClass).getBaseClassType(); PsiClass baseClass = baseClassReference.resolve(); if (baseClass == null || baseClass.isInterface()) return facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope); return baseClass; } if (CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) return null; final PsiClassType[] referenceElements = psiClass.getExtendsListTypes(); if (referenceElements.length == 0) return facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope); PsiClass psiResoved = referenceElements[0].resolve(); return psiResoved == null ? facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, resolveScope) : psiResoved; }
@NotNull public static PsiElement[] findSuperElements(@NotNull PsiElement element) { if (element instanceof PsiClass) { PsiClass aClass = (PsiClass) element; List<PsiClass> allSupers = new ArrayList<>(Arrays.asList(aClass.getSupers())); for (Iterator<PsiClass> iterator = allSupers.iterator(); iterator.hasNext(); ) { PsiClass superClass = iterator.next(); if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) iterator.remove(); } return allSupers.toArray(new PsiClass[allSupers.size()]); } if (element instanceof PsiMethod) { PsiMethod method = (PsiMethod) element; if (method.isConstructor()) { PsiMethod constructorInSuper = PsiSuperMethodUtil.findConstructorInSuper(method); if (constructorInSuper != null) { return new PsiMethod[] {constructorInSuper}; } } else { PsiMethod[] superMethods = method.findSuperMethods(false); if (superMethods.length == 0) { PsiMethod superMethod = getSiblingInheritedViaSubClass(method); if (superMethod != null) { superMethods = new PsiMethod[] {superMethod}; } } return superMethods; } } return PsiElement.EMPTY_ARRAY; }
private static boolean canHaveSiblingSuper(PsiMethod method, PsiClass containingClass) { return containingClass != null && PsiUtil.canBeOverriden(method) && !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.NATIVE) && method.hasModifierProperty(PsiModifier.PUBLIC) && !containingClass.isInterface() && !CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()); }
private static boolean canHaveSuperMethod( PsiMethod method, boolean checkAccess, boolean allowStaticMethod) { if (method.isConstructor()) return false; if (!allowStaticMethod && method.hasModifierProperty(PsiModifier.STATIC)) return false; if (checkAccess && method.hasModifierProperty(PsiModifier.PRIVATE)) return false; PsiClass parentClass = method.getContainingClass(); return parentClass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(parentClass.getQualifiedName()); }
private static boolean overridesPublicObjectMethod(PsiMethod psiMethod) { boolean overrideObject = false; for (PsiMethod superMethod : psiMethod.findDeepestSuperMethods()) { final PsiClass containingClass = superMethod.getContainingClass(); if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())) { if (superMethod.hasModifierProperty(PsiModifier.PUBLIC)) { overrideObject = true; break; } } } return overrideObject; }
private static boolean isSuperMethod( PsiClass aClass, HierarchicalMethodSignature hierarchicalMethodSignature, HierarchicalMethodSignature superSignatureHierarchical) { PsiMethod superMethod = superSignatureHierarchical.getMethod(); PsiClass superClass = superMethod.getContainingClass(); PsiClass containingClass = hierarchicalMethodSignature.getMethod().getContainingClass(); if (!superMethod.isConstructor()) { if (!aClass.equals(superClass)) { if (PsiUtil.isAccessible(aClass.getProject(), superMethod, aClass, aClass)) { if (MethodSignatureUtil.isSubsignature( superSignatureHierarchical, hierarchicalMethodSignature)) { if (superClass != null) { if (superClass.isInterface() || CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) { if (superMethod.hasModifierProperty(PsiModifier.DEFAULT) || hierarchicalMethodSignature .getMethod() .hasModifierProperty(PsiModifier.DEFAULT)) { return !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true); } return true; } if (containingClass != null) { if (containingClass.isInterface()) { return false; } if (!aClass.isInterface() && !InheritanceUtil.isInheritorOrSelf(superClass, containingClass, true)) { return true; } } } } } } } return false; }
@NotNull public static PsiClassType[] getSuperTypes(@NotNull PsiClass psiClass) { if (psiClass instanceof PsiAnonymousClass) { PsiClassType baseClassType = ((PsiAnonymousClass) psiClass).getBaseClassType(); PsiClass baseClass = baseClassType.resolve(); if (baseClass == null || !baseClass.isInterface()) { return new PsiClassType[] {baseClassType}; } else { PsiClassType objectType = PsiType.getJavaLangObject(psiClass.getManager(), psiClass.getResolveScope()); return new PsiClassType[] {objectType, baseClassType}; } } PsiClassType[] extendsTypes = psiClass.getExtendsListTypes(); PsiClassType[] implementsTypes = psiClass.getImplementsListTypes(); boolean hasExtends = extendsTypes.length != 0; int extendsListLength = extendsTypes.length + (hasExtends ? 0 : 1); PsiClassType[] result = new PsiClassType[extendsListLength + implementsTypes.length]; System.arraycopy(extendsTypes, 0, result, 0, extendsTypes.length); if (!hasExtends) { if (CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) { return PsiClassType.EMPTY_ARRAY; } PsiManager manager = psiClass.getManager(); PsiClassType objectType = PsiType.getJavaLangObject(manager, psiClass.getResolveScope()); result[0] = objectType; } System.arraycopy(implementsTypes, 0, result, extendsListLength, implementsTypes.length); for (int i = 0; i < result.length; i++) { PsiClassType type = result[i]; result[i] = (PsiClassType) PsiUtil.captureToplevelWildcards(type, psiClass); } return result; }
protected void checkSameSignatures(@NotNull List<CandidateInfo> conflicts) { // candidates should go in order of class hierarchy traversal // in order for this to work Map<MethodSignature, CandidateInfo> signatures = new THashMap<MethodSignature, CandidateInfo>(conflicts.size()); Set<PsiMethod> superMethods = new HashSet<PsiMethod>(); for (CandidateInfo conflict : conflicts) { final PsiMethod method = ((MethodCandidateInfo) conflict).getElement(); for (HierarchicalMethodSignature methodSignature : method.getHierarchicalMethodSignature().getSuperSignatures()) { final PsiMethod superMethod = methodSignature.getMethod(); final PsiClass aClass = superMethod.getContainingClass(); if (aClass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) { superMethods.add(superMethod); } } } nextConflict: for (int i = 0; i < conflicts.size(); i++) { ProgressManager.checkCanceled(); CandidateInfo info = conflicts.get(i); PsiMethod method = (PsiMethod) info.getElement(); if (!method.hasModifierProperty(PsiModifier.STATIC) && superMethods.contains(method)) { conflicts.remove(i); i--; continue; } PsiClass class1 = method.getContainingClass(); PsiSubstitutor infoSubstitutor = ((MethodCandidateInfo) info).getSubstitutor(false); MethodSignature signature = method.getSignature(infoSubstitutor); CandidateInfo existing = signatures.get(signature); if (existing == null) { signatures.put(signature, info); continue; } PsiMethod existingMethod = (PsiMethod) existing.getElement(); PsiClass existingClass = existingMethod.getContainingClass(); if (class1 != null && existingClass != null) { // prefer interface methods to methods from Object if (class1.isInterface() && CommonClassNames.JAVA_LANG_OBJECT.equals(existingClass.getQualifiedName())) { signatures.put(signature, info); continue; } else if (existingClass.isInterface() && CommonClassNames.JAVA_LANG_OBJECT.equals(class1.getQualifiedName())) { conflicts.remove(info); i--; continue; } } if (method == existingMethod) { PsiElement scope1 = info.getCurrentFileResolveScope(); PsiElement scope2 = existing.getCurrentFileResolveScope(); if (scope1 instanceof PsiClass && scope2 instanceof PsiClass && PsiTreeUtil.isAncestor(scope1, scope2, true) && !existing .isAccessible()) { // prefer methods from outer class to inaccessible base class // methods signatures.put(signature, info); continue; } } // filter out methods with incorrect inferred bounds (for unrelated methods only) boolean existingTypeParamAgree = areTypeParametersAgree(existing); boolean infoTypeParamAgree = areTypeParametersAgree(info); if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) { conflicts.remove(i); i--; continue; } if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) { signatures.put(signature, info); int index = conflicts.indexOf(existing); conflicts.remove(index); i--; continue; } if (InheritanceUtil.isInheritorOrSelf(class1, existingClass, true) || InheritanceUtil.isInheritorOrSelf(existingClass, class1, true)) { PsiParameter[] parameters = method.getParameterList().getParameters(); final PsiParameter[] existingParameters = existingMethod.getParameterList().getParameters(); for (int i1 = 0, parametersLength = parameters.length; i1 < parametersLength; i1++) { if (parameters[i1].getType() instanceof PsiArrayType && !(existingParameters[i1].getType() instanceof PsiArrayType)) { // prefer more specific type signatures.put(signature, info); continue nextConflict; } } PsiType returnType1 = method.getReturnType(); PsiType returnType2 = existingMethod.getReturnType(); if (returnType1 != null && returnType2 != null) { returnType1 = infoSubstitutor.substitute(returnType1); returnType2 = ((MethodCandidateInfo) existing).getSubstitutor(false).substitute(returnType2); if (!returnType1.equals(returnType2) && returnType1.isAssignableFrom(returnType2)) { conflicts.remove(i); i--; continue; } } // prefer derived class signatures.put(signature, info); } else { final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class); if (methodCallExpression != null) { final PsiReferenceExpression expression = methodCallExpression.getMethodExpression(); final PsiExpression qualifierExpression = expression.getQualifierExpression(); PsiClass currentClass; if (qualifierExpression != null) { currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType()); } else { currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class); } if (currentClass != null && existingClass != null && class1 != null) { final PsiSubstitutor eSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor( existingClass, currentClass, PsiSubstitutor.EMPTY, null); final PsiSubstitutor cSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor( class1, currentClass, PsiSubstitutor.EMPTY, null); if (eSubstitutor != null && cSubstitutor != null && MethodSignatureUtil.areSignaturesEqual( existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) { final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType()); final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType()); if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) { if (TypeConversionUtil.isAssignable(returnType, returnType1, false)) { if (class1.isInterface() && !existingClass.isInterface()) continue; conflicts.remove(existing); } else { if (!TypeConversionUtil.isAssignable(returnType1, returnType, false)) continue; conflicts.remove(i); } i--; break; } } } } } } }