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); } } } }