private static HashSet<PsiMethod> collectDefaultConstructorsToPropagate(PsiMethod method) { final HashSet<PsiMethod> methodsToPropagate = new HashSet<PsiMethod>(); for (PsiClass inheritor : ClassInheritorsSearch.search(method.getContainingClass())) { methodsToPropagate.add(inheritor.getConstructors()[0]); } return methodsToPropagate; }
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) { final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>(); checkExistingMethods(conflicts, true); checkExistingMethods(conflicts, false); final Collection<PsiClass> classes = ClassInheritorsSearch.search(myClass).findAll(); for (FieldDescriptor fieldDescriptor : myFieldDescriptors) { final Set<PsiMethod> setters = new HashSet<PsiMethod>(); final Set<PsiMethod> getters = new HashSet<PsiMethod>(); for (PsiClass aClass : classes) { final PsiMethod getterOverrider = myDescriptor.isToEncapsulateGet() ? aClass.findMethodBySignature(fieldDescriptor.getGetterPrototype(), false) : null; if (getterOverrider != null) { getters.add(getterOverrider); } final PsiMethod setterOverrider = myDescriptor.isToEncapsulateSet() ? aClass.findMethodBySignature(fieldDescriptor.getSetterPrototype(), false) : null; if (setterOverrider != null) { setters.add(setterOverrider); } } if (!getters.isEmpty() || !setters.isEmpty()) { final PsiField field = fieldDescriptor.getField(); for (PsiReference reference : ReferencesSearch.search(field)) { final PsiElement place = reference.getElement(); if (place instanceof PsiReferenceExpression) { final PsiExpression qualifierExpression = ((PsiReferenceExpression) place).getQualifierExpression(); final PsiClass ancestor; if (qualifierExpression == null) { ancestor = PsiTreeUtil.getParentOfType(place, PsiClass.class, false); } else { ancestor = PsiUtil.resolveClassInType(qualifierExpression.getType()); } final boolean isGetter = !PsiUtil.isAccessedForWriting((PsiExpression) place); for (PsiMethod overridden : isGetter ? getters : setters) { if (InheritanceUtil.isInheritorOrSelf(myClass, ancestor, true)) { conflicts.putValue( overridden, "There is already a " + RefactoringUIUtil.getDescription(overridden, true) + " which would hide generated " + (isGetter ? "getter" : "setter") + " for " + place.getText()); break; } } } } } } return showConflicts(conflicts, refUsages.get()); }
@NotNull @Override public List<LightRef> getHierarchyRestrictedToLibraryScope( @NotNull LightRef baseRef, @NotNull PsiElement basePsi, @NotNull ByteArrayEnumerator names, @NotNull GlobalSearchScope libraryScope) { final PsiClass baseClass = ObjectUtils.notNull( basePsi instanceof PsiClass ? (PsiClass) basePsi : ReadAction.compute(() -> (PsiMember) basePsi).getContainingClass()); final List<LightRef> overridden = new ArrayList<>(); Processor<PsiClass> processor = c -> { if (c.hasModifierProperty(PsiModifier.PRIVATE)) return true; String qName = ReadAction.compute(() -> c.getQualifiedName()); if (qName == null) return true; overridden.add(baseRef.override(id(qName, names))); return true; }; ClassInheritorsSearch.search( baseClass, LibraryScopeCache.getInstance(baseClass.getProject()).getLibrariesOnlyScope(), true) .forEach(processor); return overridden; }
public InheritorRenamer(PsiClass aClass, String newClassName) { for (final PsiClass inheritor : ClassInheritorsSearch.search(aClass).findAll()) { if (inheritor.getName() != null) { myElements.add(inheritor); } } suggestAllNames(aClass.getName(), newClassName); }
public boolean execute( @NotNull final AllOverridingMethodsSearch.SearchParameters p, @NotNull final Processor<Pair<PsiMethod, PsiMethod>> consumer) { final PsiClass psiClass = p.getPsiClass(); PsiMethod[] methodsArray = psiClass.getMethods(); final List<PsiMethod> methods = new ArrayList<PsiMethod>(methodsArray.length); for (PsiMethod method : methodsArray) { if (PsiUtil.canBeOverriden(method)) methods.add(method); } final SearchScope scope = p.getScope(); Processor<PsiClass> inheritorsProcessor = new Processor<PsiClass>() { public boolean process(PsiClass inheritor) { // could be null if not java inheritor, TODO only JavaClassInheritors are needed PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(psiClass, inheritor, PsiSubstitutor.EMPTY); if (substitutor == null) return true; for (PsiMethod method : methods) { if (method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && !JavaPsiFacade.getInstance(inheritor.getProject()) .arePackagesTheSame(psiClass, inheritor)) continue; MethodSignature signature = method.getSignature(substitutor); PsiMethod inInheritor = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false); if (inInheritor == null || inInheritor.hasModifierProperty(PsiModifier.STATIC)) { if (psiClass.isInterface() && !inheritor.isInterface()) { // check for sibling implementation final PsiClass superClass = inheritor.getSuperClass(); if (superClass != null && !superClass.isInheritor(psiClass, true)) { inInheritor = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived( inheritor, superClass, signature, true); if (inInheritor != null && !inInheritor.hasModifierProperty(PsiModifier.STATIC)) { if (!consumer.process(new Pair<PsiMethod, PsiMethod>(method, inInheritor))) return false; } } } continue; } if (!consumer.process(new Pair<PsiMethod, PsiMethod>(method, inInheritor))) return false; } return true; } }; return ClassInheritorsSearch.search(psiClass, scope, true).forEach(inheritorsProcessor); }
private static void addInheritorUsages( PsiClass aClass, final GlobalSearchScope searchScope, final List<UsageInfo> usages) { for (PsiClass inheritor : ClassInheritorsSearch.search(aClass, searchScope, false).findAll()) { if (!inheritor.isInterface()) { usages.add(new InheritorUsageInfo(inheritor)); } else { addInheritorUsages(inheritor, searchScope, usages); } } }
private void doJUnit3test() throws IOException { myFixture.configureByFile(getFileName()); List<String> directives = InTextDirectivesUtils.findListWithPrefix( "// CLASS: ", FileUtil.loadFile(new File(getPathToFile()))); assertFalse("Specify CLASS directive in test file", directives.isEmpty()); String superClassName = directives.get(0); PsiClass psiClass = getPsiClass(superClassName); checkResult(ClassInheritorsSearch.search(psiClass, getProjectScope(), false)); }
private static void addInheritors( final PsiClass aClass, final Processor<UsageInfo> results, final JavaClassFindUsagesOptions options) { ClassInheritorsSearch.search(aClass, options.searchScope, options.isCheckDeepInheritance) .forEach( new PsiElementProcessorAdapter<PsiClass>( new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass element) { addResult(results, element, options); return true; } })); }
private static void addImplementingClasses( PsiClass anInterface, final Processor<UsageInfo> results, final JavaClassFindUsagesOptions options) { ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance) .forEach( new PsiElementProcessorAdapter<PsiClass>( new PsiElementProcessor<PsiClass>() { @Override public boolean execute(@NotNull PsiClass inheritor) { if (!inheritor.isInterface()) { addResult(results, inheritor, options); } return true; } })); }
public static boolean processImplementations( final PsiClass psiClass, final Processor<PsiElement> processor, SearchScope scope) { final boolean showInterfaces = Registry.is("ide.goto.implementation.show.interfaces"); if (!ClassInheritorsSearch.search(psiClass, scope, true) .forEach( new PsiElementProcessorAdapter<>( element -> { if (!showInterfaces && element.isInterface()) { return true; } return processor.process(element); }))) { return false; } return FunctionalExpressionSearch.search(psiClass, scope) .forEach((Processor<PsiFunctionalExpression>) processor::process); }
private static List<LanguageDefinition> collectLanguageDefinitions(final ConvertContext context) { final Project project = context.getProject(); final Collection<PsiClass> allLanguages = CachedValuesManager.getManager(project) .getCachedValue( project, () -> { final PsiClass languageClass = JavaPsiFacade.getInstance(project) .findClass(Language.class.getName(), GlobalSearchScope.allScope(project)); if (languageClass == null) { return Result.create( Collections.emptyList(), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); } final GlobalSearchScope projectProductionScope = GlobalSearchScopesCore.projectProductionScope(project); GlobalSearchScope allScope = projectProductionScope.union(ProjectScope.getLibrariesScope(project)); final Collection<PsiClass> allInheritors = ClassInheritorsSearch.search(languageClass, allScope, true).findAll(); return Result.create( allInheritors, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT); }); if (allLanguages.isEmpty()) { return Collections.emptyList(); } final List<LanguageDefinition> libraryDefinitions = collectLibraryLanguages(context, allLanguages); final GlobalSearchScope projectProductionScope = GlobalSearchScopesCore.projectProductionScope(project); final Collection<PsiClass> projectLanguages = ContainerUtil.filter( allLanguages, aClass -> PsiSearchScopeUtil.isInScope(projectProductionScope, aClass)); final List<LanguageDefinition> projectDefinitions = collectProjectLanguages(projectLanguages, libraryDefinitions); final List<LanguageDefinition> all = ContainerUtil.newArrayList(libraryDefinitions); all.addAll(projectDefinitions); return all; }
@NotNull public static Map<PsiMethod, SiblingInfo> getSiblingInheritanceInfos( @NotNull final Collection<PsiMethod> methods) { MultiMap<PsiClass, PsiMethod> byClass = MultiMap.create(); for (PsiMethod method : methods) { PsiClass containingClass = method.getContainingClass(); if (canHaveSiblingSuper(method, containingClass)) { byClass.putValue(containingClass, method); } } Map<PsiMethod, SiblingInfo> result = new HashMap<>(); for (PsiClass psiClass : byClass.keySet()) { SiblingInheritorSearcher searcher = new SiblingInheritorSearcher(byClass.get(psiClass), psiClass); ClassInheritorsSearch.search(psiClass, psiClass.getUseScope(), true, true, false) .forEach(searcher); result.putAll(searcher.getResult()); } return result; }
private void addExprTypesByDerivedClasses(LinkedHashSet<PsiType> set, PsiExpression expr) { PsiType type = expr.getType(); if (!(type instanceof PsiClassType)) return; PsiClass refClass = PsiUtil.resolveClassInType(type); if (refClass == null) return; PsiManager manager = PsiManager.getInstance(myProject); PsiElementProcessor.CollectElementsWithLimit<PsiClass> processor = new PsiElementProcessor.CollectElementsWithLimit<>(5); ClassInheritorsSearch.search(refClass).forEach(new PsiElementProcessorAdapter<>(processor)); if (processor.isOverflow()) return; for (PsiClass derivedClass : processor.getCollection()) { if (derivedClass instanceof PsiAnonymousClass) continue; PsiType derivedType = JavaPsiFacade.getInstance(manager.getProject()) .getElementFactory() .createType(derivedClass); set.add(derivedType); } }
@Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { int offset = editor.getCaretModel().getOffset(); final PsiMethod method = findMethod(file, offset); if (method == null || !method.isValid()) return false; setText(getIntentionName(method)); if (!method.getManager().isInProject(method)) return false; PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return false; final boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); if (isAbstract || !method.hasModifierProperty(PsiModifier.PRIVATE) && !method.hasModifierProperty(PsiModifier.STATIC)) { if (!isAbstract && !isOnIdentifier(file, offset)) return false; MyElementProcessor processor = new MyElementProcessor(method); if (containingClass.isEnum()) { for (PsiField field : containingClass.getFields()) { if (field instanceof PsiEnumConstant) { final PsiEnumConstantInitializer initializingClass = ((PsiEnumConstant) field).getInitializingClass(); if (initializingClass == null) { processor.myHasMissingImplementations = true; } else { if (!processor.execute(initializingClass)) { break; } } } } } ClassInheritorsSearch.search(containingClass, false) .forEach(new PsiElementProcessorAdapter<PsiClass>(processor)); return isAvailable(processor); } return false; }
private void processMethodsDuplicates() { ProgressManager.getInstance() .runProcessWithProgressSynchronously( () -> ApplicationManager.getApplication() .runReadAction( () -> { if (!myTargetSuperClass.isValid()) return; final Query<PsiClass> search = ClassInheritorsSearch.search(myTargetSuperClass); final Set<VirtualFile> hierarchyFiles = new HashSet<>(); for (PsiClass aClass : search) { final PsiFile containingFile = aClass.getContainingFile(); if (containingFile != null) { final VirtualFile virtualFile = containingFile.getVirtualFile(); if (virtualFile != null) { hierarchyFiles.add(virtualFile); } } } final Set<PsiMember> methodsToSearchDuplicates = new HashSet<>(); for (PsiMember psiMember : myMembersAfterMove) { if (psiMember instanceof PsiMethod && psiMember.isValid() && ((PsiMethod) psiMember).getBody() != null) { methodsToSearchDuplicates.add(psiMember); } } MethodDuplicatesHandler.invokeOnScope( myProject, methodsToSearchDuplicates, new AnalysisScope(myProject, hierarchyFiles), true); }), MethodDuplicatesHandler.REFACTORING_NAME, true, myProject); }
@NotNull private Object[] getSubclassVariants( @NotNull PsiPackage context, @NotNull String[] extendClasses) { HashSet<Object> lookups = new HashSet<Object>(); GlobalSearchScope packageScope = PackageScope.packageScope(context, true); GlobalSearchScope scope = myJavaClassReferenceSet.getProvider().getScope(); if (scope != null) { packageScope = packageScope.intersectWith(scope); } final GlobalSearchScope allScope = ProjectScope.getAllScope(context.getProject()); final boolean instantiatable = JavaClassReferenceProvider.INSTANTIATABLE.getBooleanValue(getOptions()); final boolean notInterface = JavaClassReferenceProvider.NOT_INTERFACE.getBooleanValue(getOptions()); final boolean notEnum = JavaClassReferenceProvider.NOT_ENUM.getBooleanValue(getOptions()); final boolean concrete = JavaClassReferenceProvider.CONCRETE.getBooleanValue(getOptions()); final ClassKind classKind = getClassKind(); for (String extendClassName : extendClasses) { final PsiClass extendClass = JavaPsiFacade.getInstance(context.getProject()).findClass(extendClassName, allScope); if (extendClass != null) { // add itself if (packageScope.contains(extendClass.getContainingFile().getVirtualFile())) { if (isClassAccepted( extendClass, classKind, instantiatable, concrete, notInterface, notEnum)) { ContainerUtil.addIfNotNull(createSubclassLookupValue(context, extendClass), lookups); } } for (final PsiClass clazz : ClassInheritorsSearch.search(extendClass, packageScope, true)) { if (isClassAccepted(clazz, classKind, instantiatable, concrete, notInterface, notEnum)) { ContainerUtil.addIfNotNull(createSubclassLookupValue(context, clazz), lookups); } } } } return lookups.toArray(); }
@Override public void visitClass(@NotNull PsiClass aClass) { // no call to super, so that it doesn't drill down to inner classes if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { return; } if (!UtilityClassUtil.isUtilityClass(aClass)) { return; } if (ignoreClassesWithOnlyMain && hasOnlyMain(aClass)) { return; } if (hasPrivateConstructor(aClass)) { return; } final SearchScope scope = GlobalSearchScope.projectScope(aClass.getProject()); final Query<PsiClass> query = ClassInheritorsSearch.search(aClass, scope, true, true); final PsiClass subclass = query.findFirst(); if (subclass != null) { return; } registerClassError(aClass, aClass); }
private static void findSubmemberHidesFieldCollisions( final PsiField field, final String newName, final List<UsageInfo> result) { if (field.getContainingClass() == null) return; if (field.hasModifierProperty(PsiModifier.PRIVATE)) return; final PsiClass containingClass = field.getContainingClass(); Collection<PsiClass> inheritors = ClassInheritorsSearch.search(containingClass).findAll(); for (PsiClass inheritor : inheritors) { PsiField conflictingField = inheritor.findFieldByName(newName, false); if (conflictingField != null) { result.add(new SubmemberHidesMemberUsageInfo(conflictingField, field)); } else { // local class final PsiMember member = PsiTreeUtil.getParentOfType(inheritor, PsiMember.class); if (member != null) { final ArrayList<PsiVariable> variables = new ArrayList<>(); ControlFlowUtil.collectOuterLocals(variables, inheritor, inheritor, member); for (PsiVariable variable : variables) { if (newName.equals(variable.getName())) { result.add(new FieldHidesLocalUsageInfo(variable, field)); } } } } } }
public void testEnumWithInitializedConstants() throws Exception { setupLoadingFilter(); final GlobalSearchScope moduleScope = GlobalSearchScope.moduleScope(myModule); PsiClass enumClass = myJavaFacade.findClass("enums.OurEnumWithInitializedConstants", moduleScope); assertNotNull(enumClass); assertTrue(enumClass.isEnum()); PsiField[] fields = enumClass.getFields(); assertEquals(3, fields.length); assertTrue(fields[0] instanceof PsiEnumConstant); assertTrue(fields[1] instanceof PsiEnumConstant); assertTrue(fields[2] instanceof PsiEnumConstant); PsiAnonymousClass initializingClass0 = ((PsiEnumConstant) fields[0]).getInitializingClass(); PsiClass baseClass0 = initializingClass0.getBaseClassType().resolve(); assertTrue(baseClass0 == enumClass); PsiAnonymousClass initializingClass1 = ((PsiEnumConstant) fields[1]).getInitializingClass(); PsiClass baseClass1 = initializingClass1.getBaseClassType().resolve(); assertTrue(baseClass1 == enumClass); PsiAnonymousClass initializingClass2 = ((PsiEnumConstant) fields[1]).getInitializingClass(); PsiClass baseClass2 = initializingClass2.getBaseClassType().resolve(); assertTrue(baseClass2 == enumClass); assertTrue(initializingClass0.isInheritor(enumClass, false)); assertTrue(initializingClass1.isInheritor(enumClass, false)); assertTrue(initializingClass2.isInheritor(enumClass, false)); final PsiClass[] enumInheritors = ClassInheritorsSearch.search(enumClass, moduleScope, false).toArray(PsiClass.EMPTY_ARRAY); assertEquals(3, enumInheritors.length); assertTrue(Arrays.asList(enumInheritors).contains(initializingClass0)); assertTrue(Arrays.asList(enumInheritors).contains(initializingClass1)); assertTrue(Arrays.asList(enumInheritors).contains(initializingClass2)); PsiMethod[] methods1 = initializingClass2.getMethods(); assertEquals(1, methods1.length); assertEquals("foo", methods1[0].getName()); final PsiClass baseInterfaceClass = myJavaFacade.findClass( "enums.OurBaseInterface", GlobalSearchScope.moduleWithLibrariesScope(myModule)); assertNotNull(baseInterfaceClass); final PsiClass[] inheritors = ClassInheritorsSearch.search(baseInterfaceClass, moduleScope, false) .toArray(PsiClass.EMPTY_ARRAY); assertEquals(1, inheritors.length); assertTrue(inheritors[0] instanceof PsiAnonymousClass); teardownLoadingFilter(); assertTrue(inheritors[0].getParent().getParent() instanceof PsiExpressionList); assertTrue(inheritors[0].getParent().getParent().getParent() == fields[2]); final PsiExpression[] expressions2 = ((PsiEnumConstant) fields[2]).getArgumentList().getExpressions(); assertEquals(1, expressions2.length); assertTrue(expressions2[0] instanceof PsiNewExpression); final PsiAnonymousClass anonymousClass2 = ((PsiNewExpression) expressions2[0]).getAnonymousClass(); assertTrue(anonymousClass2 != null); assertTrue(anonymousClass2.isInheritor(baseInterfaceClass, false)); }
public static void processSubTypes( PsiType psiType, final PsiElement context, boolean getRawSubtypes, @NotNull final PrefixMatcher matcher, Consumer<PsiType> consumer) { int arrayDim = psiType.getArrayDimensions(); psiType = psiType.getDeepComponentType(); if (!(psiType instanceof PsiClassType)) return; final Condition<String> shortNameCondition = new Condition<String>() { @Override public boolean value(String s) { return matcher.prefixMatches(s); } }; final PsiClassType baseType = (PsiClassType) psiType; final PsiClassType.ClassResolveResult baseResult = ApplicationManager.getApplication() .runReadAction( new Computable<PsiClassType.ClassResolveResult>() { @Override public PsiClassType.ClassResolveResult compute() { return JavaCompletionUtil.originalize(baseType).resolveGenerics(); } }); final PsiClass baseClass = baseResult.getElement(); final PsiSubstitutor baseSubstitutor = baseResult.getSubstitutor(); if (baseClass == null) return; final GlobalSearchScope scope = ApplicationManager.getApplication() .runReadAction( new Computable<GlobalSearchScope>() { @Override public GlobalSearchScope compute() { return context.getResolveScope(); } }); final Processor<PsiClass> inheritorsProcessor = createInheritorsProcessor( context, baseType, arrayDim, getRawSubtypes, consumer, baseClass, baseSubstitutor); if (matcher.getPrefix().length() > 2) { AllClassesGetter.processJavaClasses( matcher, context.getProject(), scope, new Processor<PsiClass>() { @Override public boolean process(PsiClass psiClass) { if (psiClass.isInheritor(baseClass, true)) { return inheritorsProcessor.process(psiClass); } return true; } }); } else { final Query<PsiClass> baseQuery = ClassInheritorsSearch.search( new ClassInheritorsSearch.SearchParameters( baseClass, scope, true, false, false, shortNameCondition)); final Query<PsiClass> query = new FilteredQuery<PsiClass>( baseQuery, new Condition<PsiClass>() { @Override public boolean value(final PsiClass psiClass) { return !(psiClass instanceof PsiTypeParameter); } }); query.forEach(inheritorsProcessor); } }
private static void checkSuperclassMembers( PsiClass superClass, MemberInfoBase<? extends PsiMember>[] infos, MultiMap<PsiElement, String> conflictsList) { for (MemberInfoBase<? extends PsiMember> info : infos) { PsiMember member = info.getMember(); boolean isConflict = false; if (member instanceof PsiField) { String name = member.getName(); isConflict = superClass.findFieldByName(name, false) != null; } else if (member instanceof PsiMethod) { PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor( superClass, member.getContainingClass(), PsiSubstitutor.EMPTY); MethodSignature signature = ((PsiMethod) member).getSignature(superSubstitutor); final PsiMethod superClassMethod = MethodSignatureUtil.findMethodBySignature(superClass, signature, false); isConflict = superClassMethod != null; } if (isConflict) { String message = RefactoringBundle.message( "0.already.contains.a.1", RefactoringUIUtil.getDescription(superClass, false), RefactoringUIUtil.getDescription(member, false)); message = CommonRefactoringUtil.capitalize(message); conflictsList.putValue(superClass, message); } if (member instanceof PsiMethod) { final PsiMethod method = (PsiMethod) member; final PsiModifierList modifierList = method.getModifierList(); if (!modifierList.hasModifierProperty(PsiModifier.PRIVATE)) { for (PsiClass subClass : ClassInheritorsSearch.search(superClass)) { if (method.getContainingClass() != subClass) { MethodSignature signature = ((PsiMethod) member) .getSignature( TypeConversionUtil.getSuperClassSubstitutor( superClass, subClass, PsiSubstitutor.EMPTY)); final PsiMethod wouldBeOverriden = MethodSignatureUtil.findMethodBySignature(subClass, signature, false); if (wouldBeOverriden != null && VisibilityUtil.compare( VisibilityUtil.getVisibilityModifier(wouldBeOverriden.getModifierList()), VisibilityUtil.getVisibilityModifier(modifierList)) > 0) { conflictsList.putValue( wouldBeOverriden, CommonRefactoringUtil.capitalize( RefactoringUIUtil.getDescription(method, true) + " in super class would clash with local method from " + RefactoringUIUtil.getDescription(subClass, true))); } } } } } } }
// returns super method, sub class public static Pair<PsiMethod, PsiClass> getSiblingInheritedViaSubClass( @NotNull final PsiMethod method, @NotNull Map<PsiClass, PsiClass> subClassCache) { if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return null; if (method.hasModifierProperty(PsiModifier.STATIC)) return null; final PsiClass containingClass = method.getContainingClass(); boolean hasSubClass = containingClass != null && !containingClass.isInterface() && subClassCache.get(containingClass) != null; if (!hasSubClass) { return null; } final Collection<PsiAnchor> checkedInterfaces = new THashSet<PsiAnchor>(); final Ref<Pair<PsiMethod, PsiClass>> result = Ref.create(); ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false) .forEach( new Processor<PsiClass>() { @Override public boolean process(PsiClass inheritor) { for (PsiClassType interfaceType : inheritor.getImplementsListTypes()) { PsiClassType.ClassResolveResult resolved = interfaceType.resolveGenerics(); PsiClass anInterface = resolved.getElement(); if (anInterface == null || !checkedInterfaces.add(PsiAnchor.create(anInterface))) continue; for (PsiMethod superMethod : anInterface.findMethodsByName(method.getName(), true)) { PsiClass superInterface = superMethod.getContainingClass(); if (superInterface == null) { continue; } if (containingClass.isInheritor(superInterface, true)) { // if containingClass implements the superInterface then it's not a sibling // inheritance but a pretty boring the usual one continue; } // calculate substitutor of containingClass --> inheritor PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor( containingClass, inheritor, PsiSubstitutor.EMPTY); // calculate substitutor of inheritor --> superInterface substitutor = TypeConversionUtil.getSuperClassSubstitutor( superInterface, inheritor, substitutor); final MethodSignature superSignature = superMethod.getSignature(substitutor); final MethodSignature derivedSignature = method.getSignature(PsiSubstitutor.EMPTY); boolean isOverridden = MethodSignatureUtil.isSubsignature(superSignature, derivedSignature); if (!isOverridden) { continue; } result.set(Pair.create(superMethod, inheritor)); return false; } } return true; } }); return result.get(); }