package jetbrains.mps.ide.actions;
/*Generated by MPS */
import jetbrains.mps.workbench.action.BaseAction;
import javax.swing.Icon;
import com.intellij.openapi.actionSystem.AnActionEvent;
import java.util.Map;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import jetbrains.mps.project.MPSProject;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import org.jetbrains.mps.openapi.model.SNodeReference;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.progress.ProgressMonitorAdapter;
import jetbrains.mps.smodel.ModelAccessHelper;
import jetbrains.mps.util.Computable;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.smodel.ModelDependencyScanner;
import jetbrains.mps.util.NameUtil;
import org.jetbrains.mps.openapi.model.SModel;
import java.util.HashSet;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.util.DepthFirstConceptIterator;
import jetbrains.mps.ide.findusages.model.SearchResult;
import jetbrains.mps.ide.findusages.view.FindUtils;
import jetbrains.mps.progress.EmptyProgressMonitor;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.ide.findusages.model.scopes.GlobalScope;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.internal.collections.runtime.ISelector;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import jetbrains.mps.internal.collections.runtime.IWhereFilter;
import jetbrains.mps.smodel.behaviour.BHReflection;
import jetbrains.mps.core.aspects.behaviour.SMethodTrimmedId;
import com.intellij.openapi.progress.ProgressManager;
import jetbrains.mps.ide.findusages.model.IResultProvider;
import jetbrains.mps.ide.findusages.findalgorithm.finders.BaseFinder;
import jetbrains.mps.ide.findusages.model.SearchResults;
import jetbrains.mps.ide.findusages.model.SearchQuery;
import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.ide.findusages.view.UsageToolOptions;
import jetbrains.mps.ide.findusages.view.UsagesViewTool;
public class FindUnusedAndDeprecatedConcepts_Action extends BaseAction {
private static final Icon ICON = null;
public FindUnusedAndDeprecatedConcepts_Action() {
super("Find unused and deprecated concepts", "", ICON);
this.setIsAlwaysVisible(false);
this.setExecuteOutsideCommand(true);
}
@Override
public boolean isDumbAware() {
return true;
}
@Override
protected boolean collectActionData(AnActionEvent event, final Map<String, Object> _params) {
if (!(super.collectActionData(event, _params))) {
return false;
}
{
Project p = event.getData(CommonDataKeys.PROJECT);
MapSequence.fromMap(_params).put("ideaProject", p);
if (p == null) {
return false;
}
}
{
MPSProject p = event.getData(MPSCommonDataKeys.MPS_PROJECT);
MapSequence.fromMap(_params).put("mpsProject", p);
if (p == null) {
return false;
}
}
return true;
}
@Override
public void doExecute(@NotNull final AnActionEvent event, final Map<String, Object> _params) {
final List<SNodeReference> conceptsToShow = ListSequence.fromList(new ArrayList<SNodeReference>());
Task.Modal modal = new Task.Modal(((Project) MapSequence.fromMap(_params).get("ideaProject")), event.getPresentation().getText(), true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
final ProgressMonitor monitor = new ProgressMonitorAdapter(indicator);
List<SNodeReference> concepts = new ModelAccessHelper(((MPSProject) MapSequence.fromMap(_params).get("mpsProject")).getModelAccess()).runReadAction(new Computable<List<SNodeReference>>() {
public List<SNodeReference> compute() {
Iterable<? extends SModule> modules = ((MPSProject) MapSequence.fromMap(_params).get("mpsProject")).getModulesWithGenerators();
int totalWork = Sequence.fromIterable(modules).count() * 2;
// iterate all modules: 1/2, + 1/8 + 1/4 + 1/8
monitor.start("Find unused and deprecated concepts", totalWork);
ModelDependencyScanner scanner = new ModelDependencyScanner().usedConcepts(true).usedLanguages(false).crossModelReferences(false);
for (SModule module : modules) {
monitor.step(String.format("Look up concepts in use: %s...", NameUtil.compactNamespace(module.getModuleName())));
for (SModel m : module.getModels()) {
if (monitor.isCanceled()) {
return null;
}
scanner.walk(m);
}
monitor.advance(1);
}
monitor.step("Complete concept hierarchy...");
final HashSet<String> conceptsInUse = new HashSet<String>();
for (SConcept inUse : scanner.getConcepts()) {
// could use concept<>.super-concepts/all<+> here, but resort to code that has been there for a while
for (SAbstractConcept c : new DepthFirstConceptIterator(inUse)) {
conceptsInUse.add(c.getQualifiedName());
}
if (monitor.isCanceled()) {
return null;
}
}
monitor.advance(totalWork / 8);
monitor.step("Look up concept declarations...");
Iterable<SearchResult<Object>> searchResults = FindUtils.getSearchResults(new EmptyProgressMonitor(), SNodeOperations.getNode("r:00000000-0000-4000-0000-011c89590292(jetbrains.mps.lang.structure.structure)", "1071489090640"), new GlobalScope(), "jetbrains.mps.lang.structure.findUsages.ConceptInstances_Finder").getSearchResults();
if (monitor.isCanceled()) {
return null;
}
monitor.advance(totalWork / 4);
monitor.step("Filter unused and deprecated...");
// FIXME why it's not a dedicated IFinder that takes AbstractConceptDeclaration instances as search query and nodes/models as scope?
Iterable<SNode> allConcepts = SNodeOperations.ofConcept(Sequence.fromIterable(searchResults).select(new ISelector<SearchResult<Object>, Object>() {
public Object select(SearchResult<Object> it) {
return it.getObject();
}
}).ofType(SNode.class), MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, "jetbrains.mps.lang.structure.structure.AbstractConceptDeclaration"));
List<SNodeReference> rv = Sequence.fromIterable(allConcepts).where(new IWhereFilter<SNode>() {
public boolean accept(SNode concept) {
return ((boolean) (Boolean) BHReflection.invoke(concept, SMethodTrimmedId.create("isDeprecated", null, "hOwoPtR"))) || !(conceptsInUse.contains(NameUtil.nodeFQName(concept)));
}
}).select(new ISelector<SNode, SNodeReference>() {
public SNodeReference select(SNode it) {
return SNodeOperations.getPointer(it);
}
}).toListSequence();
monitor.done();
return rv;
}
});
ListSequence.fromList(conceptsToShow).addSequence(ListSequence.fromList(concepts));
}
};
ProgressManager.getInstance().run(modal);
FindUnusedAndDeprecatedConcepts_Action.this.showUsagesViewForNodes(conceptsToShow, _params);
}
/*package*/ void showUsagesViewForNodes(final List<SNodeReference> nodes, final Map<String, Object> _params) {
IResultProvider provider = FindUtils.makeProvider(new BaseFinder() {
@Override
public SearchResults find(SearchQuery query, ProgressMonitor progress) {
final SRepository repo = ((MPSProject) MapSequence.fromMap(_params).get("mpsProject")).getRepository();
SearchResults<SNode> results = new SearchResults<SNode>();
for (SNode node : ListSequence.fromList(nodes).select(new ISelector<SNodeReference, SNode>() {
public SNode select(SNodeReference it) {
return it.resolve(repo);
}
}).where(new IWhereFilter<SNode>() {
public boolean accept(SNode it) {
return it != null;
}
})) {
results.getSearchResults().add(new SearchResult<SNode>(node, "Uncategorized"));
}
return results;
}
@Override
public String getDescription() {
return "Specific Nodes";
}
});
UsageToolOptions opt = new UsageToolOptions().allowRunAgain(false).navigateIfSingle(false).forceNewTab(false).notFoundMessage("Nothing");
UsagesViewTool.showUsages(((Project) MapSequence.fromMap(_params).get("ideaProject")), provider, new SearchQuery(jetbrains.mps.project.GlobalScope.getInstance()), opt);
}
}