package jetbrains.mps.workbench.findusages;
/*Generated by MPS */
import com.intellij.openapi.components.ApplicationComponent;
import org.jetbrains.mps.openapi.persistence.FindUsagesParticipant;
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import jetbrains.mps.persistence.PersistenceRegistry;
import jetbrains.mps.ide.MPSCoreComponents;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import org.jetbrains.mps.openapi.model.SModel;
import java.util.Set;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.util.Consumer;
import org.jetbrains.mps.openapi.model.SReference;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import java.util.HashSet;
import jetbrains.mps.internal.collections.runtime.IWhereFilter;
import jetbrains.mps.smodel.SNodeId;
import jetbrains.mps.util.containers.MultiMap;
import java.util.function.Function;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import java.util.Map;
import jetbrains.mps.findUsages.NodeUsageFinder;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SLanguage;
import jetbrains.mps.findUsages.FindUsagesUtil;
import org.jetbrains.mps.openapi.model.SModelReference;
import jetbrains.mps.smodel.SModelStereotype;
import org.jetbrains.annotations.Nullable;
import jetbrains.mps.util.containers.SetBasedMultiMap;
import jetbrains.mps.persistence.java.library.JavaClassStubModelDescriptor;
import jetbrains.mps.util.containers.ManyToManyMap;
import com.intellij.openapi.vfs.VirtualFile;
import jetbrains.mps.extapi.persistence.FolderSetDataSource;
import gnu.trove.THashSet;
import jetbrains.mps.vfs.IFile;
import java.util.ArrayList;
import jetbrains.mps.ide.vfs.VirtualFileUtils;
import org.apache.log4j.Level;
import java.util.Arrays;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.psi.impl.cache.impl.id.IdIndex;
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry;
import com.intellij.openapi.progress.ProcessCanceledException;
import java.util.Collections;
public class StubModelsFastFindSupport implements ApplicationComponent, FindUsagesParticipant {
private static final Logger LOG = LogManager.getLogger(StubModelsFastFindSupport.class);
private final PersistenceRegistry myRegistry;
public StubModelsFastFindSupport(MPSCoreComponents mpsCore) {
myRegistry = mpsCore.getPlatform().findComponent(PersistenceRegistry.class);
}
@Override
public void initComponent() {
myRegistry.addFindUsagesParticipant(this);
}
@Override
public void disposeComponent() {
myRegistry.removeFindUsagesParticipant(this);
}
@NotNull
@Override
public String getComponentName() {
return StubModelsFastFindSupport.class.getSimpleName();
}
@Override
public void findUsages(Collection<SModel> models, Set<SNode> nodes, Consumer<SReference> consumer, Consumer<SModel> processedConsumer) {
nodes = SetSequence.fromSetWithValues(new HashSet<SNode>(), SetSequence.fromSet(nodes).where(new IWhereFilter<SNode>() {
public boolean accept(SNode it) {
return it.getNodeId() instanceof SNodeId.Foreign;
}
}));
MultiMap<SModel, SNode> candidates = findCandidates(models, nodes, processedConsumer, new Function<SNode, String>() {
public String apply(SNode key) {
return key.getNodeId().toString();
}
});
for (SNode node : SetSequence.fromSet(nodes)) {
SNode snode = ((SNode) node);
if (!(SNodeOperations.isInstanceOf(snode, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x1024639ed74L, "jetbrains.mps.baseLanguage.structure.TypeVariableDeclaration")))) {
continue;
}
candidates.putValue(SNodeOperations.getModel(snode), node);
}
for (Map.Entry<SModel, Collection<SNode>> e : candidates.entrySet()) {
new NodeUsageFinder(e.getValue(), consumer).collectUsages(e.getKey());
}
}
@Override
public void findInstances(Collection<SModel> models, Set<SAbstractConcept> concepts, Consumer<SNode> consumer, Consumer<SModel> processedConsumer) {
final SLanguage bl = MetaAdapterFactory.getLanguage(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, "jetbrains.mps.baseLanguage");
concepts = SetSequence.fromSetWithValues(new HashSet<SAbstractConcept>(), SetSequence.fromSet(concepts).where(new IWhereFilter<SAbstractConcept>() {
public boolean accept(SAbstractConcept it) {
return bl.equals(it.getLanguage());
}
}));
MultiMap<SModel, SAbstractConcept> candidates = findCandidates(models, concepts, processedConsumer, null);
for (Map.Entry<SModel, Collection<SAbstractConcept>> e : candidates.entrySet()) {
FindUsagesUtil.collectInstances(e.getKey(), e.getValue(), consumer);
}
}
@Override
public void findModelUsages(Collection<SModel> scope, Set<SModelReference> modelReferences, Consumer<SModel> consumer, Consumer<SModel> processedConsumer) {
modelReferences = SetSequence.fromSetWithValues(new HashSet<SModelReference>(), SetSequence.fromSet(modelReferences).where(new IWhereFilter<SModelReference>() {
public boolean accept(SModelReference it) {
return SModelStereotype.JAVA_STUB.equals(it.getName().getStereotype());
}
}));
MultiMap<SModel, SModelReference> candidates = findCandidates(scope, modelReferences, processedConsumer, new Function<SModelReference, String>() {
public String apply(SModelReference key) {
return key.getModelName();
}
});
for (Map.Entry<SModel, Collection<SModelReference>> e : candidates.entrySet()) {
if (FindUsagesUtil.hasModelUsages(e.getKey(), e.getValue())) {
consumer.consume(e.getKey());
}
}
}
private <T> MultiMap<SModel, T> findCandidates(Collection<SModel> models, Set<T> elems, Consumer<SModel> processedConsumer, @Nullable Function<T, String> id) {
MultiMap<SModel, T> result = new SetBasedMultiMap<SModel, T>();
if (elems.isEmpty()) {
for (SModel sm : models) {
if (sm instanceof JavaClassStubModelDescriptor) {
processedConsumer.consume(sm);
}
}
return result;
}
// get all files in scope
final ManyToManyMap<SModel, VirtualFile> scopeFiles = new ManyToManyMap<SModel, VirtualFile>();
Set<FolderSetDataSource> sources = new THashSet<FolderSetDataSource>();
for (final SModel sm : models) {
if (!(sm instanceof JavaClassStubModelDescriptor)) {
continue;
}
FolderSetDataSource source = ((JavaClassStubModelDescriptor) sm).getSource();
if (!(sources.add(source))) {
continue;
}
Collection<IFile> files = source.getAffectedFiles();
ArrayList<VirtualFile> vFiles = new ArrayList();
for (IFile path : files) {
final VirtualFile vf = VirtualFileUtils.getOrCreateVirtualFile(path);
if (vf == null) {
if (LOG.isEnabledFor(Level.WARN)) {
LOG.warn("File " + path + ", which belows to model source of model " + sm.getReference().toString() + ", was not found in VFS. Assuming no usages in this file.");
}
continue;
}
if (vf.isDirectory()) {
vFiles.addAll(Arrays.asList(vf.getChildren()));
} else {
vFiles.add(vf);
}
}
for (VirtualFile vf : vFiles) {
// do not enter any directories but one at the top level. Java package (corresponds to model) is just a list of files under single folder,
// nested folder corresponds to another package
if (vf.isDirectory()) {
continue;
}
scopeFiles.addLink(sm, vf);
}
if (!(vFiles.isEmpty())) {
// for stub models not backed by IDEA's VF, we shall not tell we've processed them.
// Let another find participant (e.g. the slowest default that walks model) to look up usages.
processedConsumer.consume(sm);
}
}
for (T elem : elems) {
String nodeId = (id == null ? elem.toString() : id.apply(elem));
// filter files with usages
ConcreteFilesGlobalSearchScope allFiles = new ConcreteFilesGlobalSearchScope(scopeFiles.getSecond());
Collection<VirtualFile> matchingFiles;
try {
matchingFiles = FileBasedIndex.getInstance().getContainingFiles(IdIndex.NAME, new IdIndexEntry(nodeId, true), 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;
}
}