package com.intellij.psi.impl.search;

import com.intellij.psi.*;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import org.jetbrains.annotations.NotNull;

/**
 * @author max
 */
public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, OverridingMethodsSearch.SearchParameters> {
  public boolean execute(@NotNull final OverridingMethodsSearch.SearchParameters p, @NotNull final Processor<PsiMethod> consumer) {
    final PsiMethod method = p.getMethod();
    final SearchScope scope = p.getScope();

    final PsiClass parentClass = method.getContainingClass();

    Processor<PsiClass> inheritorsProcessor = new Processor<PsiClass>() {
      public boolean process(PsiClass inheritor) {
        PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(parentClass, inheritor, PsiSubstitutor.EMPTY);
        MethodSignature signature = method.getSignature(substitutor);
        PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false);
        if (found == null || !isAcceptable(found, method)) {
          if (parentClass.isInterface() && !inheritor.isInterface()) {  //check for sibling implementation
            final PsiClass superClass = inheritor.getSuperClass();
            if (superClass != null && !superClass.isInheritor(parentClass, true)) {
              found = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(inheritor, superClass, signature, true);
              if (found != null && isAcceptable(found, method)) {
                return consumer.process(found) && p.isCheckDeep();
              }
            }
          }
          return true;
        }
        return consumer.process(found) && p.isCheckDeep();
      }
    };

    return ClassInheritorsSearch.search(parentClass, scope, true).forEach(inheritorsProcessor);
  }

  private static boolean isAcceptable(final PsiMethod found, final PsiMethod method) {
    return !found.hasModifierProperty(PsiModifier.STATIC) &&
           (!method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ||
            JavaPsiFacade.getInstance(found.getProject())
              .arePackagesTheSame(method.getContainingClass(), found.getContainingClass()));
  }
}

@@ -32,16 +32,121 @@
 earch;%0A%0A
+import com.intellij.openapi.application.ApplicationManager;%0Aimport com.intellij.openapi.util.Computable;%0A
 import c
@@ -598,16 +598,59 @@
 NotNull;
+%0Aimport org.jetbrains.annotations.Nullable;
 %0A%0A/**%0A *
@@ -1068,24 +1068,55 @@
 ingClass();%0A
+    assert parentClass != null;
 %0A    Process
@@ -1207,16 +1207,22 @@
 process(
+final 
 PsiClass
@@ -1235,24 +1235,606 @@
 itor) %7B%0A    
+    PsiMethod found = ApplicationManager.getApplication().runReadAction(new Computable%3CPsiMethod%3E() %7B%0A          @Nullable%0A          public PsiMethod compute() %7B%0A            return findOverridingMethod(inheritor, parentClass, method);%0A          %7D%0A        %7D);%0A        return found == null %7C%7C consumer.process(found) && p.isCheckDeep();%0A      %7D%0A    %7D;%0A%0A    return ClassInheritorsSearch.search(parentClass, scope, true).forEach(inheritorsProcessor);%0A  %7D%0A%0A  @Nullable%0A  private static PsiMethod findOverridingMethod(PsiClass inheritor, @NotNull PsiClass parentClass, PsiMethod method) %7B%0A
     PsiSubst
@@ -1949,20 +1949,16 @@
 Y);%0A    
- 
-   
 MethodSi
@@ -2011,20 +2011,16 @@
 tutor);%0A
-    
     PsiM
@@ -2106,28 +2106,24 @@
 re, false);%0A
-    
     if (foun
@@ -2128,20 +2128,19 @@
 und 
-=
+!
 = null 
-%7C%7C !
+&& 
 isAc
@@ -2168,24 +2168,45 @@
 d)) %7B%0A      
+return found;%0A    %7D%0A%0A
     if (pare
@@ -2294,22 +2294,16 @@
 ntation%0A
-      
       fi
@@ -2351,30 +2351,24 @@
 perClass();%0A
-      
       if (su
@@ -2445,18 +2445,24 @@
     
-      foun
+PsiMethod derive
 d = 
@@ -2577,22 +2577,18 @@
     
-      if (foun
+if (derive
 d !=
@@ -2601,36 +2601,38 @@
 && isAcceptable(
-foun
+derive
 d, method)) %7B%0A  
@@ -2643,113 +2643,48 @@
     
-      
 return 
-consumer.process(found) && p.isCheckDeep();%0A              %7D%0A            %7D%0A   
+derived;%0A        %7D%0A      %7D%0A
     
-   
 %7D%0A
-      
     
@@ -2694,193 +2694,12 @@
 urn 
-true;%0A        %7D%0A        return consumer.process(found) && p.isCheckDeep();%0A      %7D%0A    %7D;%0A%0A    return ClassInheritorsSearch.search(parentClass, scope, true).forEach(inheritorsProcessor)
+null
 ;%0A  

read action during overriding methods search (EA-26607)