package jetbrains.mps.ide.modelchecker.actions;
/*Generated by MPS */
import jetbrains.mps.ide.modelchecker.platform.actions.SpecificChecker;
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 jetbrains.mps.lang.smodel.generator.smodelAdapter.SModuleOperations;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.internal.collections.runtime.IWhereFilter;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.ide.modelchecker.platform.actions.ModelChecker;
import jetbrains.mps.smodel.behaviour.BHReflection;
import jetbrains.mps.core.aspects.behaviour.SMethodTrimmedId;
import org.jetbrains.mps.openapi.model.SReference;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.AttributeOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.IAttributeDescriptor;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SInterfaceConcept;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SConceptOperations;
import jetbrains.mps.smodel.runtime.ConceptDescriptor;
import jetbrains.mps.smodel.adapter.structure.concept.SAbstractConceptAdapter;
import jetbrains.mps.smodel.runtime.StaticScope;
public class ReferenceableConceptsChecker extends SpecificChecker {
public ReferenceableConceptsChecker() {
}
@Override
public List<SearchResult<ModelCheckerIssue>> checkModel(final SModel model, final ProgressMonitor monitor) {
final List<SearchResult<ModelCheckerIssue>> results = ListSequence.fromList(new ArrayList<SearchResult<ModelCheckerIssue>>());
if (model == null || model == null || model.getModule() == null) {
return results;
}
if (monitor.isCanceled()) {
return results;
}
monitor.start("illegal references", 1);
if (SModuleOperations.isAspect(model, "structure")) {
for (SNode concept : ListSequence.fromList(SModelOperations.roots(model, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, "jetbrains.mps.lang.structure.structure.AbstractConceptDeclaration")))) {
for (SNode ref : ListSequence.fromList(SLinkOperations.getChildren(concept, MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, 0xf979c3ba6bL, "linkDeclaration"))).where(new IWhereFilter<SNode>() {
public boolean accept(SNode it) {
return SPropertyOperations.hasValue(it, MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979bd086aL, 0xf980556927L, "metaClass"), "reference", "reference");
}
})) {
SNode target = SLinkOperations.getTarget(ref, MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979bd086aL, 0xf98055fef0L, "target"));
if (SNodeOperations.isInstanceOf(target, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration"))) {
SNode decl = SNodeOperations.cast(target, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration"));
if (SPropertyOperations.hasValue(decl, MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, 0x4b014033eedc8a48L, "staticScope"), "none", null)) {
SpecificChecker.addIssue(results, ref, "Reference to a non-referenceable concept found: " + SPropertyOperations.getString(target, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name")), ModelChecker.SEVERITY_ERROR, "reference to a non-referenceable concept", null);
}
}
}
if (SNodeOperations.isInstanceOf(concept, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration")) && SPropertyOperations.hasValue(SNodeOperations.cast(concept, MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration")), MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, 0x4b014033eedc8a48L, "staticScope"), "none", null)) {
if (((boolean) (Boolean) BHReflection.invoke(concept, SMethodTrimmedId.create("isSubconceptOf", MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, "jetbrains.mps.lang.structure.structure.AbstractConceptDeclaration"), "73yVtVlWOga"), SNodeOperations.getNode("r:00000000-0000-4000-0000-011c89590288(jetbrains.mps.lang.core.structure)", "1169194658468")))) {
SpecificChecker.addIssue(results, concept, "INamedConcept inheritors are usually referenceable", ModelChecker.SEVERITY_WARNING, "non-referenceable named concept", null);
}
}
}
}
for (SNode node : ListSequence.fromList(SModelOperations.nodes(model, null))) {
if (monitor.isCanceled()) {
break;
}
// Check for unresolved references
for (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 target = jetbrains.mps.util.SNodeOperations.getTargetNodeSilently(ref);
if (target == null) {
SpecificChecker.addIssue(results, node, "Unresolved reference: " + SLinkOperations.getResolveInfo(ref), ModelChecker.SEVERITY_ERROR, "unresolved reference", null);
continue;
}
checkNode(results, target, node, false, target);
SNode curr = target;
while (!(SNodeOperations.isAttribute(curr))) {
curr = SNodeOperations.getParent(curr);
if (curr == null) {
break;
}
checkNode(results, curr, node, true, target);
}
}
}
return results;
}
private void checkNode(List<SearchResult<ModelCheckerIssue>> results, SNode node, SNode refNode, boolean isAncestor, SNode anchor) {
SAbstractConcept cncpt = SNodeOperations.getConcept(node);
if (!((cncpt.isValid()))) {
SpecificChecker.addIssue(results, node, "No concept found for " + node.toString(), ModelChecker.SEVERITY_ERROR, "no concept", null);
return;
}
if (cncpt instanceof SInterfaceConcept) {
SpecificChecker.addIssue(results, node, "Interface instance found! " + node.toString(), ModelChecker.SEVERITY_ERROR, "interface instance", null);
return;
}
if (cncpt.isAbstract()) {
SpecificChecker.addIssue(results, node, "Abstract concept instance found! " + node.toString(), ModelChecker.SEVERITY_ERROR, "abstract concept instance", null);
return;
}
if (isAncestor) {
if (SConceptOperations.isSubConceptOf(SNodeOperations.asSConcept(cncpt), MetaAdapterFactory.getInterfaceConcept(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x2ea65c0b397bd5beL, "jetbrains.mps.lang.core.structure.ScopeFacade")) && !(ListSequence.fromList(SNodeOperations.getNodeAncestors(refNode, null, true)).contains(node))) {
SpecificChecker.addIssue(results, anchor, "Reference from outside to a node under ScopeFacade: facade=" + cncpt.getName(), ModelChecker.SEVERITY_ERROR, "reference to a non-referenceable node", null);
}
} else {
ConceptDescriptor cd = ((SAbstractConceptAdapter) cncpt).getConceptDescriptor();
if (cd.getStaticScope() == StaticScope.NONE) {
SpecificChecker.addIssue(results, anchor, "Reference to a non-referenceable node found: " + cncpt.getName(), ModelChecker.SEVERITY_ERROR, "reference to a non-referenceable node", null);
} else if (cd.getStaticScope() == StaticScope.NONE && !((SNodeOperations.getContainingRoot(node) == SNodeOperations.getContainingRoot(refNode)))) {
SpecificChecker.addIssue(results, anchor, "Cross-root reference to a locally referenceable node found: " + cncpt.getName(), ModelChecker.SEVERITY_ERROR, "reference to a locally referenceable node", null);
}
}
}
}