package jetbrains.mps.ide.ui.finders;
/*Generated by MPS */
import jetbrains.mps.ide.findusages.findalgorithm.finders.BaseFinder;
import jetbrains.mps.ide.findusages.findalgorithm.finders.IFinder;
import java.util.Set;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.ide.findusages.model.SearchResults;
import jetbrains.mps.ide.findusages.model.SearchQuery;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.module.SModuleReference;
import java.util.Collection;
import jetbrains.mps.util.IterableUtil;
import java.util.HashSet;
import org.jetbrains.mps.openapi.util.SubProgressKind;
import jetbrains.mps.project.Solution;
import jetbrains.mps.smodel.Language;
import jetbrains.mps.project.DevKit;
import jetbrains.mps.smodel.Generator;
import jetbrains.mps.ide.findusages.model.SearchResult;
import org.jetbrains.mps.openapi.module.SDependency;
import org.jetbrains.mps.openapi.module.SDependencyScope;
import jetbrains.mps.smodel.SModelStereotype;
import java.util.LinkedHashSet;
import org.jetbrains.mps.openapi.model.SModelReference;
import jetbrains.mps.smodel.SModelOperations;
import jetbrains.mps.smodel.SModelInternal;
/**
* In fact, ModuleDependencyFinder, looks up given module as a dependency in other modules and their models.
*/
public class ModuleUsagesFinder extends BaseFinder implements IFinder {
/*package*/ static final String USED_BY = "used by";
private static final String DEPENDENT_MODULES = "dependent modules";
private static final String RUNTIME_MODULES = "runtime modules";
private static final String EXTENDING_LANGUAGES = "extending languages";
private static final String EXTENDING_GENERATORS = "extending generators";
/**
* valid during find() only
*/
private Set<SModel> myModels2Visit;
public ModuleUsagesFinder() {
}
@Override
public String getDescription() {
return "Module Usages";
}
@Override
public SearchResults find(SearchQuery query, ProgressMonitor monitor) {
SearchResults searchResults = new SearchResults();
Object value = query.getObjectHolder().getObject();
SModule searchedModule = null;
SModuleReference searchedModuleRef = null;
if (value instanceof SModule) {
searchedModule = ((SModule) value);
searchedModuleRef = searchedModule.getModuleReference();
} else if (value instanceof SModuleReference) {
searchedModuleRef = (SModuleReference) value;
searchedModule = query.getScope().resolve(searchedModuleRef);
}
if (searchedModuleRef == null) {
return searchResults;
}
searchResults.getSearchedNodes().add(searchedModuleRef);
Collection<SModule> modules = IterableUtil.asCollection(query.getScope().getModules());
myModels2Visit = new HashSet<SModel>(IterableUtil.asCollection(query.getScope().getModels()));
monitor.start("", 2);
ProgressMonitor subTask = monitor.subTask(1, SubProgressKind.REPLACING);
subTask.start("Looking up uses in modules", modules.size());
for (SModule module : modules) {
if (monitor.isCanceled()) {
return searchResults;
}
if (module instanceof Solution) {
collectUsagesInSolution(searchedModuleRef, (Solution) module, searchResults);
} else if (module instanceof Language) {
collectUsagesInLanguage(searchedModuleRef, (Language) module, searchResults);
} else if (module instanceof DevKit) {
collectUsagesInDevKit(searchedModuleRef, (DevKit) module, searchResults);
} else if (module instanceof Generator) {
collectUsagesInGenerator(searchedModuleRef, (Generator) module, searchResults);
}
subTask.advance(1);
}
subTask = monitor.subTask(1, SubProgressKind.REPLACING);
if (searchedModule != null) {
final DevKit searchedDevkit;
int steps = myModels2Visit.size();
if (searchedModule instanceof DevKit) {
searchedDevkit = (DevKit) searchedModule;
steps *= 2;
} else {
searchedDevkit = null;
}
subTask.start("Looking up uses in models", steps);
ModuleUsagesFinder.ModuleUseInModel f = new ModuleUsagesFinder.ModuleUseInModel(searchedModule, searchResults);
for (SModel model : myModels2Visit) {
f.collect(model);
subTask.advance(1);
}
if (searchedDevkit != null) {
ModuleUsagesFinder.DevKitUseInModel f2 = new ModuleUsagesFinder.DevKitUseInModel(searchedDevkit, searchResults);
for (SModel model : myModels2Visit) {
f2.collect(model);
subTask.advance(1);
}
}
}
monitor.done();
myModels2Visit = null;
return searchResults;
}
/*package*/ void collectUsagesInSolution(SModuleReference searchModuleRef, Solution solution, SearchResults searchResults) {
if (getDeclaredDependenciesTargets(solution).contains(searchModuleRef)) {
searchResults.add(new SearchResult<Solution>(solution, DEPENDENT_MODULES));
collectUsagesInModels(solution);
}
}
/*package*/ void collectUsagesInLanguage(SModuleReference searchModuleRef, Language language, SearchResults searchResults) {
boolean used = false;
if (language.getExtendedLanguageRefs().contains(searchModuleRef)) {
used = true;
searchResults.add(new SearchResult<Language>(language, EXTENDING_LANGUAGES));
}
if (getDeclaredDependenciesTargets(language).contains(searchModuleRef)) {
used = true;
searchResults.add(new SearchResult<Language>(language, DEPENDENT_MODULES));
}
if (language.getRuntimeModulesReferences().contains(searchModuleRef)) {
used = true;
searchResults.add(new SearchResult<Language>(language, RUNTIME_MODULES));
}
if (used) {
collectUsagesInModels(language);
}
}
/*package*/ void collectUsagesInGenerator(SModuleReference searchModuleRef, Generator generator, SearchResults searchResults) {
boolean depExtends = false;
boolean depDesign = false;
boolean depRegular = false;
for (SDependency dep : findDependencies(generator, searchModuleRef)) {
if (dep.getScope() == SDependencyScope.EXTENDS) {
depExtends = true;
} else if (dep.getScope() == SDependencyScope.DESIGN) {
depDesign = true;
} else {
depRegular = true;
}
}
if (depExtends) {
searchResults.add(new SearchResult<Generator>(generator, EXTENDING_GENERATORS));
}
if (depDesign) {
searchResults.add(new SearchResult<Generator>(generator, DEPENDENT_MODULES));
}
if (depRegular) {
searchResults.add(new SearchResult<Generator>(generator, DEPENDENT_MODULES));
}
if (depExtends || depRegular || depDesign) {
collectUsagesInModels(generator);
}
}
/*package*/ void collectUsagesInDevKit(SModuleReference searchModuleRef, DevKit devKit, SearchResults searchResults) {
if (getDeclaredDependenciesTargets(devKit).contains(searchModuleRef)) {
searchResults.add(new SearchResult<DevKit>(devKit, DEPENDENT_MODULES));
}
}
/*package*/ static Set<SModuleReference> getDeclaredDependenciesTargets(SModule module) {
Set<SModuleReference> result = new HashSet<SModuleReference>();
for (SDependency dep : module.getDeclaredDependencies()) {
result.add(dep.getTargetModule());
}
return result;
}
private void collectUsagesInModels(SModule owner) {
for (SModel model : owner.getModels()) {
if (!((SModelStereotype.isUserModel(model)))) {
continue;
}
myModels2Visit.add(model);
}
}
private static Set<SDependency> findDependencies(SModule from, SModuleReference to) {
// FIXME nice candidate to move into SModule (along with findDependencies(SDependencyKind)
LinkedHashSet<SDependency> rv = new LinkedHashSet<SDependency>();
for (SDependency dep : from.getDeclaredDependencies()) {
if (dep.getTargetModule().equals(to)) {
rv.add(dep);
}
}
return rv;
}
/**
* Models have imports, pointing to other models with SModelReference.
* We need to find out whether these model references point to any model of a given module.
* One approach is to get SModuleReference from SModelReference, another is to know all module's models
* and match against their references. Former approach doesn't work as few model reference are capable of
* telling their module reference.
*/
private static class ModuleUseInModel {
private final SearchResults mySearchResults;
private final Set<SModelReference> myModelsToFind;
public ModuleUseInModel(SModule toFind, SearchResults toPopulate) {
myModelsToFind = new HashSet<SModelReference>();
for (SModel m : toFind.getModels()) {
myModelsToFind.add(m.getReference());
}
mySearchResults = toPopulate;
}
public void collect(SModel model) {
for (SModelReference i : SModelOperations.getImportedModelUIDs(model)) {
if (myModelsToFind.contains(i)) {
mySearchResults.add(new SearchResult<SModel>(model, ModuleUsagesFinder.USED_BY));
break;
}
}
}
}
private static class DevKitUseInModel {
private final SearchResults mySearchResults;
private final SModuleReference myDevKitToFind;
public DevKitUseInModel(DevKit toFind, SearchResults toPopulate) {
myDevKitToFind = toFind.getModuleReference();
mySearchResults = toPopulate;
}
public void collect(SModel model) {
if (model instanceof SModelInternal) {
if (((SModelInternal) model).importedDevkits().contains(myDevKitToFind)) {
mySearchResults.add(new SearchResult<SModel>(model, USED_BY));
}
}
}
}
}