2121import java .util .ArrayList ;
2222import java .util .Arrays ;
2323import java .util .Collection ;
24+ import java .util .LinkedHashSet ;
2425import java .util .List ;
2526import java .util .Map ;
2627import java .util .Set ;
4647import com .intellij .pom .java .LanguageLevel ;
4748import com .intellij .psi .*;
4849import com .intellij .psi .impl .PsiClassImplUtil ;
50+ import com .intellij .psi .impl .PsiSuperMethodImplUtil ;
4951import com .intellij .psi .search .GlobalSearchScope ;
5052import com .intellij .psi .search .PsiShortNamesCache ;
5153import com .intellij .psi .search .searches .ReferencesSearch ;
@@ -86,7 +88,13 @@ static HighlightInfo checkInferredTypeArguments(PsiTypeParameterListOwner listOw
8688 @ Nullable
8789 static HighlightInfo checkInferredTypeArguments (PsiTypeParameter [] typeParameters , PsiElement call , PsiSubstitutor substitutor )
8890 {
89- final Pair <PsiTypeParameter , PsiType > inferredTypeArgument = GenericsUtil .findTypeParameterWithBoundError (typeParameters , substitutor , call , false );
91+ return checkInferredTypeArguments (typeParameters , call , substitutor , false );
92+ }
93+
94+ @ Nullable
95+ static HighlightInfo checkInferredTypeArguments (PsiTypeParameter [] typeParameters , PsiElement call , PsiSubstitutor substitutor , boolean allowUncheckedConversion )
96+ {
97+ final Pair <PsiTypeParameter , PsiType > inferredTypeArgument = GenericsUtil .findTypeParameterWithBoundError (typeParameters , substitutor , call , allowUncheckedConversion );
9098 if (inferredTypeArgument != null )
9199 {
92100 final PsiType extendsType = inferredTypeArgument .second ;
@@ -421,15 +429,9 @@ private static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass,
421429 Set <PsiClass > visited ,
422430 TextRange textRange )
423431 {
424- final PsiClassType [] superTypes = aClass . getSuperTypes ( );
425- for (PsiClassType superType : superTypes )
432+ final List < PsiClassType . ClassResolveResult > superTypes = PsiClassImplUtil . getScopeCorrectedSuperTypes ( aClass , place . getResolveScope () );
433+ for (PsiClassType . ClassResolveResult result : superTypes )
426434 {
427- superType = PsiClassImplUtil .correctType (superType , place .getResolveScope ());
428- if (superType == null )
429- {
430- continue ;
431- }
432- final PsiClassType .ClassResolveResult result = superType .resolveGenerics ();
433435 final PsiClass superClass = result .getElement ();
434436 if (superClass == null || visited .contains (superClass ))
435437 {
@@ -521,55 +523,185 @@ static HighlightInfo checkDefaultMethodOverrideEquivalentToObjectNonPrivate(@Not
521523
522524 static HighlightInfo checkUnrelatedDefaultMethods (@ NotNull PsiClass aClass , @ NotNull Collection <HierarchicalMethodSignature > signaturesWithSupers , @ NotNull PsiIdentifier classIdentifier )
523525 {
524- for (HierarchicalMethodSignature methodSignature : signaturesWithSupers )
526+ final Map <MethodSignature , Set <PsiMethod >> overrideEquivalent = new THashMap <MethodSignature , Set <PsiMethod >>(MethodSignatureUtil .METHOD_PARAMETERS_ERASURE_EQUALITY );
527+ PsiClass [] supers = aClass .getSupers ();
528+ for (int i = 0 ; i < supers .length ; i ++)
525529 {
526- final PsiMethod method = methodSignature .getMethod ();
527- final boolean isAbstract = method .hasModifierProperty (PsiModifier .ABSTRACT );
528- if (method .hasModifierProperty (PsiModifier .DEFAULT ) || isAbstract )
530+ PsiClass superClass = supers [i ];
531+ boolean subType = false ;
532+ for (int j = 0 ; j < supers .length ; j ++)
533+ {
534+ if (j == i )
535+ {
536+ continue ;
537+ }
538+ subType |= supers [j ].isInheritor (supers [i ], true );
539+ }
540+ if (subType )
529541 {
542+ continue ;
543+ }
544+ for (HierarchicalMethodSignature hms : superClass .getVisibleSignatures ())
545+ {
546+ final PsiMethod method = hms .getMethod ();
547+ if (aClass .findMethodsBySignature (method , false ).length > 0 )
548+ {
549+ continue ;
550+ }
530551 final PsiClass containingClass = method .getContainingClass ();
531- List <HierarchicalMethodSignature > superSignatures = methodSignature .getSuperSignatures ();
532- if (!superSignatures .isEmpty ())
552+ if (containingClass == null )
553+ {
554+ continue ;
555+ }
556+ final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil .getClassSubstitutor (containingClass , aClass , PsiSubstitutor .EMPTY );
557+ if (containingClassSubstitutor == null )
558+ {
559+ continue ;
560+ }
561+ final PsiSubstitutor finalSubstitutor = PsiSuperMethodImplUtil .obtainFinalSubstitutor (containingClass , containingClassSubstitutor , hms .getSubstitutor (), false );
562+ final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod .create (method , finalSubstitutor , false );
563+ Set <PsiMethod > methods = overrideEquivalent .get (signature );
564+ if (methods == null )
565+ {
566+ methods = new LinkedHashSet <PsiMethod >();
567+ overrideEquivalent .put (signature , methods );
568+ }
569+ methods .add (method );
570+ }
571+ }
572+
573+ final boolean isInterface = aClass .isInterface ();
574+ for (Set <PsiMethod > overrideEquivalentMethods : overrideEquivalent .values ())
575+ {
576+ if (overrideEquivalentMethods .size () <= 1 )
577+ {
578+ continue ;
579+ }
580+ List <PsiMethod > defaults = null ;
581+ List <PsiMethod > astracts = null ;
582+ boolean hasConcrete = false ;
583+ for (PsiMethod method : overrideEquivalentMethods )
584+ {
585+ final boolean isDefault = method .hasModifierProperty (PsiModifier .DEFAULT );
586+ final boolean isAbstract = method .hasModifierProperty (PsiModifier .ABSTRACT );
587+ if (isDefault )
533588 {
534- for ( HierarchicalMethodSignature signature : superSignatures )
589+ if ( defaults == null )
535590 {
536- final PsiMethod superMethod = signature .getMethod ();
537- final PsiClass superContainingClass = superMethod .getContainingClass ();
538- if (containingClass != null && superContainingClass != null && !InheritanceUtil .isInheritorOrSelf (containingClass , superContainingClass , true ))
539- {
540- final boolean isDefault = superMethod .hasModifierProperty (PsiModifier .DEFAULT );
541- if (!aClass .hasModifierProperty (PsiModifier .ABSTRACT ) && !isDefault && !isAbstract )
542- {
543- final String message = JavaErrorMessages .message (aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract" ,
544- HighlightUtil .formatClass (superContainingClass ), JavaHighlightUtil .formatMethod (superMethod ), HighlightUtil .formatClass (superContainingClass , false ));
545- final HighlightInfo info = HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).range (classIdentifier ).descriptionAndTooltip (message ).create ();
546- QuickFixAction .registerQuickFixAction (info , QUICK_FIX_FACTORY .createImplementMethodsFix (aClass ));
547- return info ;
548- }
591+ defaults = new ArrayList <PsiMethod >(2 );
592+ }
593+ defaults .add (method );
594+ }
595+ if (isAbstract )
596+ {
597+ if (astracts == null )
598+ {
599+ astracts = new ArrayList <PsiMethod >(2 );
600+ }
601+ astracts .add (method );
602+ }
603+ hasConcrete |= !isDefault && !isAbstract ;
604+ }
549605
550- if (isDefault || !isAbstract && superMethod .hasModifierProperty (PsiModifier .ABSTRACT ))
551- {
552- final String message = isDefault && !isAbstract ? " inherits unrelated defaults for " : " inherits abstract and default for " ;
553- final String inheritUnrelatedDefaultsMessage = HighlightUtil .formatClass (aClass ) +
554- message +
555- JavaHighlightUtil .formatMethod (method ) +
556- " from types " +
557- HighlightUtil .formatClass (containingClass ) +
558- " and " +
559- HighlightUtil .formatClass (superContainingClass );
560- final HighlightInfo info = HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).range (classIdentifier ).descriptionAndTooltip (inheritUnrelatedDefaultsMessage )
561- .create ();
562- QuickFixAction .registerQuickFixAction (info , QUICK_FIX_FACTORY .createImplementMethodsFix (aClass ));
563- return info ;
564- }
565- }
606+ if (!hasConcrete && defaults != null )
607+ {
608+ final PsiMethod defaultMethod = defaults .get (0 );
609+ final PsiClass defaultMethodContainingClass = defaultMethod .getContainingClass ();
610+ if (defaultMethodContainingClass == null )
611+ {
612+ continue ;
613+ }
614+ final PsiMethod unrelatedMethod = astracts != null ? astracts .get (0 ) : defaults .get (1 );
615+ final PsiClass unrelatedMethodContainingClass = unrelatedMethod .getContainingClass ();
616+ if (unrelatedMethodContainingClass == null )
617+ {
618+ continue ;
619+ }
620+ if (!aClass .hasModifierProperty (PsiModifier .ABSTRACT ) && astracts != null && unrelatedMethodContainingClass .isInterface ())
621+ {
622+ if (defaultMethodContainingClass .isInheritor (unrelatedMethodContainingClass , true ) && MethodSignatureUtil .isSubsignature (unrelatedMethod .getSignature (PsiSubstitutor .EMPTY ),
623+ defaultMethod .getSignature (PsiSubstitutor .EMPTY )))
624+ {
625+ continue ;
566626 }
627+ final String key = aClass instanceof PsiEnumConstantInitializer ? "enum.constant.should.implement.method" : "class.must.be.abstract" ;
628+ final String message = JavaErrorMessages .message (key , HighlightUtil .formatClass (aClass , false ), JavaHighlightUtil .formatMethod (astracts .get (0 )),
629+ HighlightUtil .formatClass (unrelatedMethodContainingClass , false ));
630+ final HighlightInfo info = HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).range (classIdentifier ).descriptionAndTooltip (message ).create ();
631+ QuickFixAction .registerQuickFixAction (info , QUICK_FIX_FACTORY .createImplementMethodsFix (aClass ));
632+ return info ;
633+ }
634+ if (isInterface || astracts == null || unrelatedMethodContainingClass .isInterface ())
635+ {
636+ if (defaultMethodContainingClass .isInheritor (unrelatedMethodContainingClass , true ) || unrelatedMethodContainingClass .isInheritor (defaultMethodContainingClass , true ))
637+ {
638+ continue ;
639+ }
640+ final String message = astracts != null ? " inherits abstract and default for " : " inherits unrelated defaults for " ;
641+ final HighlightInfo info = HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).range (classIdentifier ).descriptionAndTooltip (HighlightUtil .formatClass (aClass ) +
642+ message +
643+ JavaHighlightUtil .formatMethod (defaultMethod ) +
644+ " from types " +
645+ HighlightUtil .formatClass (defaultMethodContainingClass ) +
646+ " and " +
647+ HighlightUtil .formatClass (unrelatedMethodContainingClass )).create ();
648+ QuickFixAction .registerQuickFixAction (info , QUICK_FIX_FACTORY .createImplementMethodsFix (aClass ));
649+ return info ;
567650 }
568651 }
569652 }
570653 return null ;
571654 }
572655
656+ static HighlightInfo checkUnrelatedConcrete (@ NotNull PsiClass psiClass , @ NotNull PsiIdentifier classIdentifier )
657+ {
658+ final PsiClass superClass = psiClass .getSuperClass ();
659+ if (superClass != null && superClass .hasTypeParameters ())
660+ {
661+ final Collection <HierarchicalMethodSignature > visibleSignatures = superClass .getVisibleSignatures ();
662+ final Map <MethodSignature , PsiMethod > overrideEquivalent = new THashMap <MethodSignature , PsiMethod >(MethodSignatureUtil .METHOD_PARAMETERS_ERASURE_EQUALITY );
663+ for (HierarchicalMethodSignature hms : visibleSignatures )
664+ {
665+ final PsiMethod method = hms .getMethod ();
666+ if (method .hasModifierProperty (PsiModifier .ABSTRACT ) || method .hasModifierProperty (PsiModifier .DEFAULT ))
667+ {
668+ continue ;
669+ }
670+ if (psiClass .findMethodsBySignature (method , false ).length > 0 )
671+ {
672+ continue ;
673+ }
674+ final PsiClass containingClass = method .getContainingClass ();
675+ if (containingClass == null )
676+ {
677+ continue ;
678+ }
679+ final PsiSubstitutor containingClassSubstitutor = TypeConversionUtil .getSuperClassSubstitutor (containingClass , psiClass , PsiSubstitutor .EMPTY );
680+ final PsiSubstitutor finalSubstitutor = PsiSuperMethodImplUtil .obtainFinalSubstitutor (containingClass , containingClassSubstitutor , hms .getSubstitutor (), false );
681+ final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod .create (method , finalSubstitutor , false );
682+ final PsiMethod foundMethod = overrideEquivalent .get (signature );
683+ PsiClass foundMethodContainingClass ;
684+ if (foundMethod != null &&
685+ !foundMethod .hasModifierProperty (PsiModifier .ABSTRACT ) &&
686+ !foundMethod .hasModifierProperty (PsiModifier .DEFAULT ) &&
687+ (foundMethodContainingClass = foundMethod .getContainingClass ()) != null )
688+ {
689+ final String description = "Methods " +
690+ JavaHighlightUtil .formatMethod (foundMethod ) + " from " + HighlightUtil .formatClass (foundMethodContainingClass ) +
691+ " and " +
692+ JavaHighlightUtil .formatMethod (method ) + " from " + HighlightUtil .formatClass (containingClass ) +
693+ " are inherited with the same signature" ;
694+
695+ final HighlightInfo info = HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).range (classIdentifier ).descriptionAndTooltip (description ).create ();
696+ //todo override fix
697+ return info ;
698+ }
699+ overrideEquivalent .put (signature , method );
700+ }
701+ }
702+ return null ;
703+ }
704+
573705 @ Nullable
574706 private static HighlightInfo checkSameErasureNotSubSignatureInner (@ NotNull HierarchicalMethodSignature signature ,
575707 @ NotNull PsiManager manager ,
@@ -1660,29 +1792,15 @@ static HighlightInfo checkInferredIntersections(PsiSubstitutor substitutor, Text
16601792 {
16611793 for (Map .Entry <PsiTypeParameter , PsiType > typeEntry : substitutor .getSubstitutionMap ().entrySet ())
16621794 {
1795+ final String parameterName = typeEntry .getKey ().getName ();
16631796 final PsiType type = typeEntry .getValue ();
16641797 if (type instanceof PsiIntersectionType )
16651798 {
1666- final PsiType [] conjuncts = ((PsiIntersectionType ) type ).getConjuncts ();
1667- for ( int i = 0 ; i < conjuncts . length ; i ++ )
1799+ final String conflictingConjunctsMessage = ((PsiIntersectionType ) type ).getConflictingConjunctsMessage ();
1800+ if ( conflictingConjunctsMessage != null )
16681801 {
1669- PsiClass conjunct = PsiUtil .resolveClassInClassTypeOnly (conjuncts [i ]);
1670- if (conjunct != null && !conjunct .isInterface ())
1671- {
1672- for (int i1 = i + 1 ; i1 < conjuncts .length ; i1 ++)
1673- {
1674- PsiClass oppositeConjunct = PsiUtil .resolveClassInClassTypeOnly (conjuncts [i1 ]);
1675- if (oppositeConjunct != null && !oppositeConjunct .isInterface ())
1676- {
1677- if (!conjunct .isInheritor (oppositeConjunct , true ) && !oppositeConjunct .isInheritor (conjunct , true ))
1678- {
1679- return HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).descriptionAndTooltip ("Type parameter " + typeEntry .getKey ().getName () + " has incompatible upper " +
1680- "bounds: " +
1681- conjunct .getName () + " and " + oppositeConjunct .getName ()).range (ref ).create ();
1682- }
1683- }
1684- }
1685- }
1802+ return HighlightInfo .newHighlightInfo (HighlightInfoType .ERROR ).descriptionAndTooltip ("Type parameter " + parameterName + " has incompatible upper bounds: " +
1803+ conflictingConjunctsMessage ).range (ref ).create ();
16861804 }
16871805 }
16881806 }
@@ -1766,4 +1884,5 @@ public static HighlightInfo checkTypeParameterOverrideEquivalentMethods(PsiClass
17661884 }
17671885 return null ;
17681886 }
1769- }
1887+ }
1888+
0 commit comments