@Override
  public void findTargets(
      TargetKind kind,
      Collection<SModel> scope,
      Consumer<NavigationTarget> consumer,
      Consumer<SModel> processedConsumer) {
    final ID<Integer, List<SNodeDescriptor>> indexName = RootNodeNameIndex.NAME;
    final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();

    for (SModel sm : scope) {
      if (sm instanceof EditableSModel && ((EditableSModel) sm).isChanged()) {
        continue;
      }

      DataSource source = sm.getSource();
      if (!(source instanceof FileDataSource)) {
        continue;
      }

      IFile modelFile = ((FileDataSource) source).getFile();
      String ext = FileUtil.getExtension(modelFile.getName());
      if (ext == null
          || modelFile.isDirectory()
          || !(supportedExtensions.contains(ext.toLowerCase()))) {
        continue;
      }

      VirtualFile vf = VirtualFileUtils.getVirtualFile(modelFile);
      if (vf == null) continue; // e.g. model was deleted

      int fileId = FileBasedIndex.getFileId(vf);
      ConcreteFilesGlobalSearchScope fileScope =
          new ConcreteFilesGlobalSearchScope(Collections.singleton(vf));
      List<List<SNodeDescriptor>> descriptors =
          fileBasedIndex.getValues(indexName, fileId, fileScope);
      if (descriptors.isEmpty()) continue;

      boolean needToLoad = false;
      for (NavigationTarget snd : descriptors.get(0)) {
        PropertyConstraintsDescriptor descriptor =
            ConceptRegistry.getInstance()
                .getConstraintsDescriptor(snd.getConcept().getQualifiedName())
                .getProperty(SNodeUtil.property_INamedConcept_name);
        if (descriptor instanceof BasePropertyConstraintsDescriptor
            && !((BasePropertyConstraintsDescriptor) descriptor).isGetterDefault()) {
          needToLoad = true;
          break;
        }
      }

      if (!needToLoad) {
        for (SNodeDescriptor desc : descriptors.get(0)) {
          consumer.consume(desc);
        }
        processedConsumer.consume(sm);
      }
    }
  }
 @Override
 public void findModelUsages(
     Collection<SModel> scope,
     Set<SModelReference> modelReferences,
     Consumer<SModel> consumer,
     Consumer<SModel> processedConsumer) {
   MultiMap<SModel, SModelReference> candidates =
       findCandidates(scope, modelReferences, processedConsumer, key -> new ModelUse(key));
   for (Entry<SModel, Collection<SModelReference>> candidate : candidates.entrySet()) {
     if (FindUsagesUtil.hasModelUsages(candidate.getKey(), candidate.getValue())) {
       consumer.consume(candidate.getKey());
     }
   }
 }
  private <T> MultiMap<SModel, T> findCandidates(
      Collection<SModel> models,
      Set<T> elems,
      Consumer<SModel> processedModels,
      Function<T, UsageEntry> id) {
    // get all files in scope
    final ManyToManyMap<SModel, VirtualFile> scopeFiles = new ManyToManyMap<SModel, VirtualFile>();
    for (final SModel sm : models) {
      if (sm instanceof EditableSModel && ((EditableSModel) sm).isChanged()) {
        continue;
      }

      DataSource source = sm.getSource();
      // these are data sources this participant knows about
      if (!(source instanceof FileDataSource || source instanceof FilePerRootDataSource)) {
        continue;
      }

      /*
      This is a tmp fix for MPS-24151. See the issue to learn about the correct fix
       */
      if (!(sm instanceof DefaultSModelDescriptor)) {
        continue;
      }

      Collection<IFile> modelFiles = getDataSourceFiles(source);
      for (IFile modelFile : modelFiles) {
        String ext = FileUtil.getExtension(modelFile.getName());
        if (ext == null || modelFile.isDirectory()) {
          continue;
        }

        VirtualFile vf = VirtualFileUtils.getOrCreateVirtualFile(modelFile);
        if (vf == null) {
          LogManager.getLogger(MPSModelsFastFindSupport.class)
              .warn(
                  String.format(
                      "Model %s: virtual file not found for model file. Model file: %s",
                      sm.getName(), modelFile.getPath()));
          continue;
        }
        processedModels.consume(sm);
        scopeFiles.addLink(sm, vf);
      }
    }

    // filter files with usages
    ConcreteFilesGlobalSearchScope allFiles =
        new ConcreteFilesGlobalSearchScope(scopeFiles.getSecond());
    // process indexes
    MultiMap<SModel, T> result = new SetBasedMultiMap<SModel, T>();
    for (T elem : elems) {
      UsageEntry entry = id.apply(elem);

      Collection<VirtualFile> matchingFiles;

      try {
        matchingFiles = MPSModelsIndexer.getContainingFiles(entry, allFiles);
      } catch (ProcessCanceledException ce) {
        matchingFiles = Collections.emptyList();
      }

      // back-transform
      for (VirtualFile file : matchingFiles) {
        for (SModel m : scopeFiles.getBySecond(file)) {
          result.putValue(m, elem);
        }
      }
    }
    return result;
  }