private boolean isAmbiguousInherited(PsiClass containingClass1) {
   PsiClass psiClass = PsiTreeUtil.getParentOfType(myPlace, PsiClass.class);
   while (psiClass != null) {
     if (psiClass.isInheritor(containingClass1, false)) {
       return true;
     }
     psiClass = psiClass.getContainingClass();
   }
   return false;
 }
 private boolean isAccessible(PsiClass otherClass) {
   if (otherClass.hasModifierProperty(PsiModifier.PRIVATE)) {
     final PsiClass containingClass = otherClass.getContainingClass();
     PsiClass containingPlaceClass = PsiTreeUtil.getParentOfType(myPlace, PsiClass.class, false);
     while (containingPlaceClass != null) {
       if (containingClass == containingPlaceClass) {
         return true;
       }
       containingPlaceClass = PsiTreeUtil.getParentOfType(containingPlaceClass, PsiClass.class);
     }
     return false;
   }
   return true;
 }
  @Override
  public boolean execute(@NotNull PsiElement element, ResolveState state) {
    if (!(element instanceof PsiClass)) return true;
    final PsiClass aClass = (PsiClass) element;
    final String name = aClass.getName();
    if (!myClassName.equals(name)) {
      return true;
    }
    boolean accessible = myPlace == null || checkAccessibility(aClass);
    if (myCandidates == null) {
      myCandidates = new SmartList<ClassCandidateInfo>();
    } else {
      String fqName = aClass.getQualifiedName();
      if (fqName != null) {
        for (int i = myCandidates.size() - 1; i >= 0; i--) {
          ClassCandidateInfo info = myCandidates.get(i);

          Domination domination =
              dominates(aClass, accessible && isAccessible(aClass), fqName, info);
          if (domination == Domination.DOMINATED_BY) {
            return true;
          } else if (domination == Domination.DOMINATES) {
            myCandidates.remove(i);
          }
        }
      }
    }

    myHasAccessibleCandidate |= accessible;
    myHasInaccessibleCandidate |= !accessible;
    myCandidates.add(
        new ClassCandidateInfo(
            aClass, state.get(PsiSubstitutor.KEY), !accessible, myCurrentFileContext));
    myResult = null;
    if (!accessible) return true;
    if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) {
      final PsiClass containingPlaceClass =
          PsiTreeUtil.getParentOfType(myPlace, PsiClass.class, false);
      if (containingPlaceClass != null
          && !PsiTreeUtil.isAncestor(containingPlaceClass, aClass, true)) {
        return true;
      }
    }
    return myCurrentFileContext instanceof PsiImportStatementBase;
  }
  private boolean checkAccessibility(final PsiClass aClass) {
    // We don't care about accessibility in javadoc
    if (JavaResolveUtil.isInJavaDoc(myPlace)) {
      return true;
    }

    if (PsiImplUtil.isInServerPage(aClass.getContainingFile())) {
      PsiFile file = FileContextUtil.getContextFile(myPlace);
      if (PsiImplUtil.isInServerPage(file)) {
        return true;
      }
    }

    boolean accessible = true;
    if (aClass instanceof PsiTypeParameter) {
      accessible = !myStaticContext;
    }

    PsiManager manager = aClass.getManager();
    if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) {
      PsiElement parent = aClass.getParent();
      while (true) {
        PsiElement parentScope = parent.getParent();
        if (parentScope instanceof PsiJavaFile) break;
        parent = parentScope;
        if (!(parentScope instanceof PsiClass)) break;
      }
      if (parent instanceof PsiDeclarationStatement) {
        parent = parent.getParent();
      }
      accessible = false;
      for (PsiElement placeParent = myPlace;
          placeParent != null;
          placeParent = placeParent.getContext()) {
        if (manager.areElementsEquivalent(placeParent, parent)) accessible = true;
      }
    }
    final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
    if (aClass.hasModifierProperty(PsiModifier.PROTECTED)) {
      accessible = false;
      if (myPlace != null && facade.arePackagesTheSame(aClass, myPlace)) {
        accessible = true;
      } else {
        if (aClass.getContainingClass() != null) {
          accessible =
              myAccessClass == null
                  || myPlace != null
                      && facade.getResolveHelper().isAccessible(aClass, myPlace, myAccessClass);
        }
      }
    }
    if (aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
      if (myPlace == null || !facade.arePackagesTheSame(aClass, myPlace)) {
        accessible = false;
      }
    }
    return accessible;
  }
  private boolean isOnDemand(PsiElement fileContext, PsiClass psiClass) {
    if (isImported(fileContext)) {
      return ((PsiImportStatementBase) fileContext).isOnDemand();
    }

    String fqn = psiClass.getQualifiedName();
    if (fqn == null) return false;

    PsiFile file = myPlace == null ? null : FileContextUtil.getContextFile(myPlace);

    String[] defaultPackages =
        file instanceof PsiJavaFile
            ? ((PsiJavaFile) file).getImplicitlyImportedPackages()
            : DEFAULT_PACKAGES;
    String packageName = StringUtil.getPackageName(fqn);
    for (String defaultPackage : defaultPackages) {
      if (defaultPackage.equals(packageName)) return true;
    }

    // class from my package imported implicitly
    return file instanceof PsiJavaFile && ((PsiJavaFile) file).getPackageName().equals(packageName);
  }
  private Domination dominates(
      PsiClass aClass, boolean accessible, String fqName, ClassCandidateInfo info) {
    final PsiClass otherClass = info.getElement();
    assert otherClass != null;
    String otherQName = otherClass.getQualifiedName();
    if (fqName.equals(otherQName)) {
      return Domination.DOMINATED_BY;
    }

    final PsiClass containingClass1 = aClass.getContainingClass();
    final PsiClass containingClass2 = otherClass.getContainingClass();
    if (myAccessClass != null && !Comparing.equal(containingClass1, containingClass2)) {
      if (myAccessClass.equals(containingClass1)) return Domination.DOMINATES;
      if (myAccessClass.equals(containingClass2)) return Domination.DOMINATED_BY;
    }

    // JLS 8.5:
    // A class may inherit two or more type declarations with the same name, either from two
    // interfaces or from its superclass and an interface.
    // It is a compile-time error to attempt to refer to any ambiguously inherited class or
    // interface by its simple name.
    if (containingClass1 != null
        && containingClass2 != null
        && containingClass2.isInheritor(containingClass1, true)
        && !isImported(myCurrentFileContext)) {
      if (!isAmbiguousInherited(containingClass1)) {
        // shadowing
        return Domination.DOMINATED_BY;
      }
    }

    boolean infoAccessible = info.isAccessible() && isAccessible(otherClass);
    if (infoAccessible && !accessible) {
      return Domination.DOMINATED_BY;
    }
    if (!infoAccessible && accessible) {
      return Domination.DOMINATES;
    }

    // everything wins over class from default package
    boolean isDefault = StringUtil.getPackageName(fqName).length() == 0;
    boolean otherDefault =
        otherQName != null && StringUtil.getPackageName(otherQName).length() == 0;
    if (isDefault && !otherDefault) {
      return Domination.DOMINATED_BY;
    }
    if (!isDefault && otherDefault) {
      return Domination.DOMINATES;
    }

    // single import wins over on-demand
    boolean myOnDemand = isOnDemand(myCurrentFileContext, aClass);
    boolean otherOnDemand = isOnDemand(info.getCurrentFileResolveScope(), otherClass);
    if (myOnDemand && !otherOnDemand) {
      return Domination.DOMINATED_BY;
    }
    if (!myOnDemand && otherOnDemand) {
      return Domination.DOMINATES;
    }

    return Domination.EQUAL;
  }