// uses hierarchy signature tree if available, traverses class structure by itself otherwise
  public static boolean processDirectSuperMethodsSmart(
      @NotNull PsiMethod method, @NotNull Processor<PsiMethod> superMethodProcessor) {
    // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod);

    PsiClass aClass = method.getContainingClass();
    if (aClass == null) return false;

    if (!canHaveSuperMethod(method, true, false)) return false;

    Map<MethodSignature, HierarchicalMethodSignature> cachedMap =
        SIGNATURES_KEY.getCachedValueOrNull(aClass);
    if (cachedMap != null) {
      HierarchicalMethodSignature signature =
          cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY));
      if (signature != null) {
        List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
        for (HierarchicalMethodSignature superSignature : superSignatures) {
          if (!superMethodProcessor.process(superSignature.getMethod())) return false;
        }
        return true;
      }
    }

    PsiClassType[] directSupers = aClass.getSuperTypes();
    for (PsiClassType directSuper : directSupers) {
      PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics();
      if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) {
        // generics
        break;
      }
      PsiClass directSuperClass = resolveResult.getElement();
      if (directSuperClass == null) continue;
      PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false);
      for (PsiMethod candidate : candidates) {
        if (PsiUtil.canBeOverriden(candidate)) {
          if (!superMethodProcessor.process(candidate)) return false;
        }
      }
      return true;
    }

    List<HierarchicalMethodSignature> superSignatures =
        method.getHierarchicalMethodSignature().getSuperSignatures();
    for (HierarchicalMethodSignature superSignature : superSignatures) {
      if (!superMethodProcessor.process(superSignature.getMethod())) return false;
    }
    return true;
  }
 private static boolean isRunnable(final PsiClass psiClass) {
   if (!(psiClass instanceof GrTypeDefinition)) return false;
   if (psiClass instanceof PsiAnonymousClass) return false;
   if (psiClass.isInterface()) return false;
   final PsiClass runnable =
       JavaPsiFacade.getInstance(psiClass.getProject())
           .findClass("java.lang.Runnable", psiClass.getResolveScope());
   if (runnable == null) return false;
   final PsiMethod runMethod = runnable.getMethods()[0];
   final PsiMethod[] runImplementations = psiClass.findMethodsBySignature(runMethod, false);
   if (runImplementations.length == 1
       && runImplementations[0] instanceof GrMethod
       && ((GrMethod) runImplementations[0]).getBlock() != null) {
     return psiClass.getContainingClass() == null
         || psiClass.hasModifierProperty(PsiModifier.STATIC);
   }
   return false;
 }
  private static boolean addParameterToConstructor(
      final Project project,
      final PsiFile file,
      final Editor editor,
      final PsiMethod constructor,
      final PsiField[] fields)
      throws IncorrectOperationException {
    final PsiParameterList parameterList = constructor.getParameterList();
    final PsiParameter[] parameters = parameterList.getParameters();
    ParameterInfoImpl[] newParamInfos = new ParameterInfoImpl[parameters.length + fields.length];
    final List<PsiVariable> params = new ArrayList<PsiVariable>(Arrays.asList(parameters));
    Collections.addAll(params, fields);
    Collections.sort(params, new FieldParameterComparator(parameterList));

    int i = 0;
    final HashMap<PsiField, String> usedFields = new HashMap<PsiField, String>();
    for (PsiVariable param : params) {
      final PsiType paramType = param.getType();
      if (param instanceof PsiParameter) {
        newParamInfos[i++] =
            new ParameterInfoImpl(
                parameterList.getParameterIndex((PsiParameter) param),
                param.getName(),
                paramType,
                param.getName());
      } else {
        final String uniqueParameterName = getUniqueParameterName(parameters, param, usedFields);
        usedFields.put((PsiField) param, uniqueParameterName);
        newParamInfos[i++] =
            new ParameterInfoImpl(-1, uniqueParameterName, paramType, uniqueParameterName);
      }
    }
    final SmartPointerManager manager = SmartPointerManager.getInstance(project);
    final SmartPsiElementPointer constructorPointer =
        manager.createSmartPsiElementPointer(constructor);

    final PsiMethod fromText =
        JavaPsiFacade.getElementFactory(project)
            .createMethodFromText(createDummyMethod(constructor, newParamInfos), constructor);
    final PsiClass containingClass = constructor.getContainingClass();
    if (containingClass == null) return false;
    final int minUsagesNumber =
        containingClass.findMethodsBySignature(fromText, false).length > 0 ? 0 : 1;
    final List<ParameterInfoImpl> parameterInfos =
        ChangeMethodSignatureFromUsageFix.performChange(
            project, editor, file, constructor, minUsagesNumber, newParamInfos, true, true);

    final ParameterInfoImpl[] resultParams =
        parameterInfos != null
            ? parameterInfos.toArray(new ParameterInfoImpl[parameterInfos.size()])
            : newParamInfos;
    return ApplicationManager.getApplication()
        .runWriteAction(
            new Computable<Boolean>() {
              @Override
              public Boolean compute() {
                return doCreate(
                    project, editor, parameters, constructorPointer, resultParams, usedFields);
              }
            });
  }
  // uses hierarchy signature tree if available, traverses class structure by itself otherwise
  public static boolean isSuperMethodSmart(
      @NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
    // boolean old = PsiSuperMethodUtil.isSuperMethod(method, superMethod);

    if (method == superMethod) return false;
    PsiClass aClass = method.getContainingClass();
    PsiClass superClass = superMethod.getContainingClass();

    if (aClass == null || superClass == null || superClass == aClass) return false;

    if (!canHaveSuperMethod(method, true, false)) return false;

    PsiMethod[] superMethods = null;
    Map<MethodSignature, HierarchicalMethodSignature> cachedMap =
        SIGNATURES_KEY.getCachedValueOrNull(aClass);
    if (cachedMap != null) {
      HierarchicalMethodSignature signature =
          cachedMap.get(method.getSignature(PsiSubstitutor.EMPTY));
      if (signature != null) {
        superMethods =
            MethodSignatureUtil.convertMethodSignaturesToMethods(signature.getSuperSignatures());
      }
    }
    if (superMethods == null) {
      PsiClassType[] directSupers = aClass.getSuperTypes();
      List<PsiMethod> found = null;
      boolean canceled = false;
      for (PsiClassType directSuper : directSupers) {
        PsiClassType.ClassResolveResult resolveResult = directSuper.resolveGenerics();
        if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) {
          // generics
          canceled = true;
          break;
        }
        PsiClass directSuperClass = resolveResult.getElement();
        if (directSuperClass == null) continue;
        PsiMethod[] candidates = directSuperClass.findMethodsBySignature(method, false);
        if (candidates.length != 0) {
          if (found == null) found = new ArrayList<PsiMethod>();
          for (PsiMethod candidate : candidates) {
            if (PsiUtil.canBeOverriden(candidate)) found.add(candidate);
          }
        }
      }
      superMethods =
          canceled
              ? null
              : found == null ? PsiMethod.EMPTY_ARRAY : found.toArray(new PsiMethod[found.size()]);
    }
    if (superMethods == null) {
      superMethods =
          MethodSignatureUtil.convertMethodSignaturesToMethods(
              method.getHierarchicalMethodSignature().getSuperSignatures());
    }

    for (PsiMethod superCandidate : superMethods) {
      if (superMethod.equals(superCandidate) || isSuperMethodSmart(superCandidate, superMethod))
        return true;
    }
    return false;
  }