@Override
  public SearchResults find(SearchQuery query, @NotNull ProgressMonitor monitor) {
    SearchResults<SNode> searchResults = new SearchResults<SNode>();
    Object value = query.getObjectHolder().getObject();
    SModule module = null;
    if (value instanceof SModule) {
      module = ((SModule) value);
    } else if (value instanceof SModuleReference) {
      module = query.getScope().resolve(((SModuleReference) value));
    }
    if (!(module instanceof Language)) {
      return searchResults;
    }
    Language language = (Language) module;
    SModel structureModel = language.getStructureModelDescriptor();
    if (structureModel == null) {
      return searchResults;
    }
    if (!(structureModel.getRootNodes().iterator().hasNext())) {
      return searchResults;
    }
    List<SNode> roots = new LinkedList<SNode>();
    for (SNode root : structureModel.getRootNodes()) {
      roots.add(root);
    }
    searchResults.getSearchedNodes().addAll(roots);

    monitor.start("", IterableUtil.asCollection(structureModel.getRootNodes()).size() + 1);
    try {
      SearchResults<SModel> modelResults =
          FindUtils.getSearchResults(
              monitor.subTask(1),
              new SearchQuery(
                  structureModel.getReference(), GlobalScopeMinusTransient.getInstance()),
              new ModelImportsUsagesFinder());
      List<SModel> models = new ArrayList<SModel>();
      for (SearchResult<SModel> sModelSearchResult : modelResults.getSearchResults()) {
        models.add(sModelSearchResult.getObject());
      }
      SearchScope scope = new ModelsScope(models.toArray(new SModel[models.size()]));
      SearchResults<SNode> results = new SearchResults();
      for (SNode node : roots) {
        if (monitor.isCanceled()) {
          break;
        }
        results.addAll(
            FindUtils.getSearchResults(
                monitor.subTask(1),
                node,
                scope,
                "jetbrains.mps.lang.structure.findUsages.NodeUsages_Finder"));
        results.removeDuplicates();
      }
      searchResults.getSearchResults().addAll(results.getSearchResults());
      return searchResults;
    } finally {
      monitor.done();
    }
  }
  public SearchResults find(SearchQuery query, ProgressMonitor monitor) {
    SearchResults<SNode> searchResults = new SearchResults<SNode>();
    IHolder holder = query.getObjectHolder();
    assert holder instanceof ModuleHolder;
    IModule module = ((ModuleHolder) holder).getObject();
    assert module instanceof Language;
    Language language = (Language) module;
    SModelDescriptor structureModel = language.getStructureModelDescriptor();
    if (structureModel == null) {
      return searchResults;
    }
    SModel sModel = structureModel.getSModel();
    if (sModel == null) {
      return searchResults;
    }
    if (sModel.rootsCount() == 0) {
      return searchResults;
    }
    List<SNode> roots = new LinkedList<SNode>();
    for (SNode root : sModel.roots()) {
      roots.add(root);
    }
    searchResults.getSearchedNodes().addAll(roots);

    monitor.start("", sModel.rootsCount() + 1);
    try {
      SearchResults<SModel> modelResults =
          FindUtils.getSearchResults(
              monitor.subTask(1),
              new SearchQuery(sModel, GlobalScopeMinusTransient.getInstance()),
              new ModelUsagesFinder());
      List<SModelDescriptor> models = new ArrayList<SModelDescriptor>();
      for (SearchResult<SModel> sModelSearchResult : modelResults.getSearchResults()) {
        models.add(sModelSearchResult.getObject().getModelDescriptor());
      }
      IScope scope = new ModelsOnlyScope(models.toArray(new SModelDescriptor[models.size()]));
      SearchResults results = new SearchResults();
      for (SNode node : roots) {
        if (monitor != null && monitor.isCanceled()) {
          break;
        }
        results.addAll(
            FindUtils.getSearchResults(
                monitor.subTask(1),
                node,
                scope,
                "jetbrains.mps.lang.structure.findUsages.NodeUsages_Finder"));
        results.removeDuplicates();
      }
      searchResults.getSearchResults().addAll(results.getSearchResults());
      return searchResults;
    } finally {
      monitor.done();
    }
  }