package jetbrains.mps.ide.modelchecker.actions;
/*Generated by MPS */
import jetbrains.mps.ide.modelchecker.platform.actions.SpecificChecker;
import jetbrains.mps.project.Project;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import jetbrains.mps.util.PathManager;
import java.util.List;
import jetbrains.mps.ide.findusages.model.SearchResult;
import jetbrains.mps.ide.modelchecker.platform.actions.ModelCheckerIssue;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations;
import org.jetbrains.mps.openapi.model.SReference;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.AttributeOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.IAttributeDescriptor;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.ide.modelchecker.platform.actions.ModelChecker;
import jetbrains.mps.ide.modelchecker.platform.actions.IModelCheckerFix;
import jetbrains.mps.resolve.ResolverComponent;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.persistence.DataSource;
import jetbrains.mps.vfs.IFile;
import jetbrains.mps.extapi.persistence.FileDataSource;
import jetbrains.mps.smodel.Language;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModuleOperations;
import jetbrains.mps.project.Solution;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations;
public class AspectDependenciesChecker extends SpecificChecker {
private static int CORE = 1;
private static int EDITOR = 2;
private static int WORKBENCH = 3;
private static int OTHER = 4;
private final Project myProject;
private final SModule coreModule;
private final SModule editorModule;
private final String languagesUtilPath;
public AspectDependenciesChecker(@NotNull Project mpsProject) {
myProject = mpsProject;
this.coreModule = PersistenceFacade.getInstance().createModuleReference("6ed54515-acc8-4d1e-a16c-9fd6cfe951ea(MPS.Core)").resolve(mpsProject.getRepository());
this.editorModule = PersistenceFacade.getInstance().createModuleReference("1ed103c3-3aa6-49b7-9c21-6765ee11f224(MPS.Editor)").resolve(mpsProject.getRepository());
this.languagesUtilPath = PathManager.getHomePath() + "/languages/util/";
}
@Override
public List<SearchResult<ModelCheckerIssue>> checkModel(SModel model, ProgressMonitor monitor) {
List<SearchResult<ModelCheckerIssue>> results = ListSequence.fromList(new ArrayList<SearchResult<ModelCheckerIssue>>());
monitor.start("wrong aspect dependencies", 1);
int modelKind = getModelKind(model, null);
if (modelKind == OTHER) {
monitor.done();
return results;
}
for (SNode node : ListSequence.fromList(SModelOperations.nodes(model, null))) {
if (monitor.isCanceled()) {
break;
}
// Check for unresolved references
for (final SReference ref : ListSequence.fromList(SNodeOperations.getReferences(node))) {
if ((AttributeOperations.getAttribute(node, new IAttributeDescriptor.LinkAttribute(MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0xfd7f44d616L, "jetbrains.mps.lang.generator.structure.ReferenceMacro"), ref.getLink())) != null)) {
continue;
}
SNode targetNode = jetbrains.mps.util.SNodeOperations.getTargetNodeSilently(ref);
if (targetNode == null) {
SpecificChecker.addIssue(results, node, "Unresolved reference: " + SLinkOperations.getResolveInfo(ref), ModelChecker.SEVERITY_ERROR, "unresolved reference", new IModelCheckerFix() {
public boolean doFix() {
return ResolverComponent.getInstance().resolve(ref, myProject.getRepository());
}
});
continue;
}
SModel targetModel = SNodeOperations.getModel(targetNode);
int targetKind = getModelKind(targetModel, ref);
if (targetKind > modelKind) {
SpecificChecker.addIssue(results, node, "Wrong reference: " + SLinkOperations.getResolveInfo(ref) + ", reference from " + kindToString(modelKind) + " to " + kindToString(targetKind), ModelChecker.SEVERITY_ERROR, "wrong aspect dependency (" + kindToString(modelKind) + ")", null);
}
}
}
monitor.done();
return results;
}
public int getModelKind(SModel model, @Nullable SReference reference) {
DataSource source = (model != null ? model.getSource() : null);
IFile modelFile = (source instanceof FileDataSource ? ((FileDataSource) source).getFile() : null);
if (modelFile != null) {
String filePath = modelFile.getPath().replace('\\', '/');
if (filePath.startsWith(languagesUtilPath)) {
return OTHER;
}
}
SModule module = model.getModule();
if (module instanceof Language) {
if (SModuleOperations.isAspect(model, "actions")) {
return EDITOR;
} else if (SModuleOperations.isAspect(model, "behavior")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "constraints")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "dataFlow")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "editor")) {
return EDITOR;
} else if (SModuleOperations.isAspect(model, "findUsages")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "intentions")) {
return EDITOR;
} else if (SModuleOperations.isAspect(model, "plugin")) {
return WORKBENCH;
} else if (SModuleOperations.isAspect(model, "refactorings")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "scripts")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "structure")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "migration")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "test")) {
return EDITOR;
} else if (SModuleOperations.isAspect(model, "textGen")) {
return CORE;
} else if (SModuleOperations.isAspect(model, "typesystem")) {
return CORE;
} else {
return CORE;
}
} else if (module instanceof Solution) {
String moduleFqName = module.getModuleName();
if (moduleFqName.equals("JDK")) {
return CORE;
}
if (moduleFqName.equals("MPS.Core")) {
return CORE;
}
if (moduleFqName.equals("MPS.Editor")) {
return EDITOR;
}
if (moduleFqName.equals("MPS.Workbench")) {
return WORKBENCH;
}
if (moduleFqName.equals("MPS.Classpath")) {
SNode refTargetRoot = reference.getTargetNode().getContainingRoot();
if (SNodeOperations.isInstanceOf(refTargetRoot, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier"))) {
String cName = SPropertyOperations.getString(SNodeOperations.cast(refTargetRoot, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier")), MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name"));
String modelName = model.getModelName();
if (findInModule(coreModule, modelName, cName)) {
return CORE;
}
if (findInModule(editorModule, modelName, cName)) {
return EDITOR;
}
return WORKBENCH;
}
return OTHER;
}
Solution sol = (Solution) module;
switch (sol.getKind()) {
case NONE:
return OTHER;
case PLUGIN_CORE:
return CORE;
case PLUGIN_EDITOR:
return EDITOR;
case PLUGIN_OTHER:
return WORKBENCH;
default:
}
}
return OTHER;
}
public static boolean findInModule(SModule module, String modelName, String rootName) {
for (SModel d : module.getModels()) {
if (d.getModelName().equals(modelName)) {
for (SNode _n : d.getRootNodes()) {
SNode n = (SNode) _n;
if (SNodeOperations.isInstanceOf(n, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier")) && SPropertyOperations.getString(SNodeOperations.cast(n, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier")), MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name")).equals(rootName)) {
return true;
}
}
}
}
return false;
}
public static String kindToString(int kind) {
switch (kind) {
case 1:
return "core";
case 2:
return "editor";
case 3:
return "workbench";
default:
}
return "unknown";
}
}