public static boolean isClassEquivalentTo(@NotNull PsiClass aClass, PsiElement another) {
    if (aClass == another) return true;
    if (!(another instanceof PsiClass)) return false;
    if (!another.isValid()) return false;
    boolean isImplicitClass = aClass instanceof PsiImplicitClass;
    boolean anotherImplicitClass = another instanceof PsiImplicitClass;
    if (isImplicitClass != anotherImplicitClass) return false;
    if (!isImplicitClass) {
      String name1 = aClass.getName();
      if (name1 == null) return false;
      String name2 = ((PsiClass)another).getName();
      if (name2 == null) return false;
      if (name1.hashCode() != name2.hashCode()) return false;
      if (!name1.equals(name2)) return false;
    }
    String qName1 = aClass.getQualifiedName();
    String qName2 = ((PsiClass)another).getQualifiedName();
    if (qName1 == null || qName2 == null) {
      if (!Strings.areSameInstance(qName1, qName2)) return false;

      if (aClass instanceof PsiTypeParameter && another instanceof PsiTypeParameter) {
        PsiTypeParameter p1 = (PsiTypeParameter)aClass;
        PsiTypeParameter p2 = (PsiTypeParameter)another;

        if (p1.getIndex() != p2.getIndex()) {
          return false;
        }
        if (TypeConversionUtil.areSameFreshVariables(p1, p2)) {
          return true;
        }

        return !Boolean.FALSE.equals(RecursionManager.doPreventingRecursion(Pair.create(p1, p2), true, () ->
          aClass.getManager().areElementsEquivalent(p1.getOwner(), p2.getOwner())));
      }
      else {
        return false;
      }
    }
    if (!qName1.equals(qName2)) {
      return false;
    }

    if (aClass.getOriginalElement().equals(another.getOriginalElement())) {
      return true;
    }

    PsiFile file1 = getOriginalFile(aClass);
    PsiFile file2 = getOriginalFile((PsiClass)another);

    //see com.intellij.openapi.vcs.changes.PsiChangeTracker
    //see com.intellij.psi.impl.PsiFileFactoryImpl#createFileFromText(CharSequence,PsiFile)
    PsiFile original1 = file1.getUserData(PsiFileFactory.ORIGINAL_FILE);
    PsiFile original2 = file2.getUserData(PsiFileFactory.ORIGINAL_FILE);
    if (original1 == original2 && original1 != null || original1 == file2 || original2 == file1 || file1 == file2) {
      return true;
    }

    FileIndexFacade fileIndex = FileIndexFacade.getInstance(file1.getProject());
    FileIndexFacade fileIndex2 = FileIndexFacade.getInstance(file2.getProject());
    VirtualFile vfile1 = file1.getViewProvider().getVirtualFile();
    VirtualFile vfile2 = file2.getViewProvider().getVirtualFile();
    boolean lib1 = fileIndex.isInLibraryClasses(vfile1);
    boolean lib2 = fileIndex2.isInLibraryClasses(vfile2);

    //if copy from another project, fileIndex of correct project should be requested
    return (fileIndex.isInSource(vfile1) || lib1) && (fileIndex2.isInSource(vfile2) || lib2);
  }
public static boolean isClassEquivalentTo(@NotNull PsiClass aClass, PsiElement another)