public Set<SNode> findDescendants(SNode node, Set<SNode> descendantsKnownInModel) {
    if (!myFindUsagesSupported) return new HashSet<SNode>();
    boolean changed = false;
    if (myModelDescriptor instanceof EditableSModelDescriptor) {
      changed = ((EditableSModelDescriptor) myModelDescriptor).isChanged();
    }
    boolean atLeastRootsLoaded =
        myModelDescriptor.getLoadingState().compareTo(ModelLoadingState.ROOTS_LOADED) >= 0;
    if (atLeastRootsLoaded && !changed && !descendantsKnownInModel.isEmpty())
      return descendantsKnownInModel;
    if (myNeedSearchForStrings
        && !myModelRootManager.containsString(myModelDescriptor, node.getId()))
      return descendantsKnownInModel;

    SModel model = myModelDescriptor.getSModel();
    Set<SNode> result = new HashSet<SNode>();
    if (model != null) {
      for (SNode root : model.roots()) {
        addDescendants(root, node, result);
      }
    }
    descendantsKnownInModel.clear();
    descendantsKnownInModel.addAll(result);
    return descendantsKnownInModel;
  }
 public ModelFindOperations(SModelDescriptor modelDescriptor) {
   myModelDescriptor = modelDescriptor;
   myModelRootManager = myModelDescriptor.getModelRootManager();
   myFindUsagesSupported = myModelRootManager.isFindUsagesSupported();
   myNeedSearchForStrings = myModelDescriptor.getLoadingState() != ModelLoadingState.FULLY_LOADED;
   if (!myNeedSearchForStrings && myModelDescriptor instanceof EditableSModelDescriptor) {
     myNeedSearchForStrings = !((EditableSModelDescriptor) myModelDescriptor).isChanged();
   }
 }
  public boolean hasImportedModel(SModelDescriptor modelDescriptor) {
    if (!myFindUsagesSupported) return false;
    if (myNeedSearchForStrings
        && !myModelRootManager.containsString(myModelDescriptor, modelDescriptor.toString()))
      return false;

    SModel model = myModelDescriptor.getSModel();
    if (model == null) return false;

    return SModelOperations.getImportElement(model, modelDescriptor.getSModelReference()) != null;
  }
  public boolean hasLanguage(Language language) {
    if (!myFindUsagesSupported) return false;

    if (myNeedSearchForStrings
        && !myModelRootManager.containsString(myModelDescriptor, language.getModuleFqName()))
      return false;

    SModel model = myModelDescriptor.getSModel();
    if (model == null) return false;

    return SModelOperations.hasLanguage(model, language.getModuleReference());
  }
  public Set<SReference> findUsages(Set<SNode> nodes) {
    if (!myFindUsagesSupported) return Collections.emptySet();

    if (myNeedSearchForStrings) {
      Set<String> strings = new HashSet<String>();
      for (SNode node : nodes) {
        strings.add(quoteSpecialXMLCharacters(node.getId()));
      }
      if (!myModelRootManager.containsSomeString(myModelDescriptor, strings))
        return Collections.emptySet();
    }

    SModel model = myModelDescriptor.getSModel();
    if (model == null) return Collections.emptySet();

    Set<SReference> result = new HashSet<SReference>();
    for (SNode root : model.roots()) {
      addUsages(root, nodes, result);
    }
    return result;
  }
  public boolean hasUsages(Set<SModelReference> models) {
    if (!myFindUsagesSupported) return false;

    if (myNeedSearchForStrings) {
      Set<String> strings = new HashSet<String>();
      for (SModelReference model : models) {
        strings.add(quoteSpecialXMLCharacters(model.toString()));
      }
      if (!myModelRootManager.containsSomeString(myModelDescriptor, strings)) return false;
    }

    SModel model = myModelDescriptor.getSModel();
    if (model == null) return false;

    for (SModelDescriptor modelDescriptor :
        SModelOperations.allImportedModels(model, GlobalScope.getInstance())) {
      if (models.contains(modelDescriptor.getSModelReference())) {
        return true;
      }
    }
    return false;
  }