package jetbrains.mps.ide.modelchecker.platform.actions; /*Generated by MPS */ import java.util.List; import jetbrains.mps.ide.findusages.model.SearchResult; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.util.ProgressMonitor; import jetbrains.mps.smodel.SModelStereotype; import java.util.Collections; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.lang.smodel.generator.smodelAdapter.AttributeOperations; import jetbrains.mps.lang.smodel.generator.smodelAdapter.IAttributeDescriptor; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import org.jetbrains.mps.util.DescendantsTreeIterator; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations; import org.jetbrains.mps.openapi.model.SReference; public class GeneratorTemplatesChecker extends SpecificChecker { private List<SearchResult<ModelCheckerIssue>> myResults; public GeneratorTemplatesChecker() { } @Override public List<SearchResult<ModelCheckerIssue>> checkModel(SModel model, ProgressMonitor progressMonitor) { if (!(SModelStereotype.isGeneratorModel(model))) { return Collections.emptyList(); } myResults = ListSequence.fromList(new ArrayList<SearchResult<ModelCheckerIssue>>()); if (progressMonitor.isCanceled()) { return myResults; } progressMonitor.start("cross-templates references", ListSequence.fromList(SModelOperations.roots(model, null)).count()); for (SNode root : ListSequence.fromList(SModelOperations.roots(model, null))) { if (AttributeOperations.getAttribute(root, new IAttributeDescriptor.NodeAttribute(MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x11017244494L, "jetbrains.mps.lang.generator.structure.RootTemplateAnnotation"))) != null) { scanTemplateNode(root, progressMonitor); } if (progressMonitor.isCanceled()) { return myResults; } progressMonitor.advance(1); } progressMonitor.done(); return myResults; } private void scanTemplateNode(SNode root, ProgressMonitor progressMonitor) { DescendantsTreeIterator it = new DescendantsTreeIterator(root); while (it.hasNext()) { if (progressMonitor.isCanceled()) { return; } SNode node = it.next(); if (SNodeOperations.isInstanceOf(node, MetaAdapterFactory.getInterfaceConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x11dc0f7933bL, "jetbrains.mps.lang.generator.structure.AbstractMacro"))) { if (SNodeOperations.isInstanceOf(node, MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x1047c1472deL, "jetbrains.mps.lang.generator.structure.IfMacro")) && SNodeOperations.isInstanceOf(SLinkOperations.getTarget(SNodeOperations.cast(node, MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x1047c1472deL, "jetbrains.mps.lang.generator.structure.IfMacro")), MetaAdapterFactory.getContainmentLink(0xb401a68083254110L, 0x8fd384331ff25befL, 0x1047c1472deL, 0x1163aea5803L, "alternativeConsequence")), MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x112103dd1e8L, "jetbrains.mps.lang.generator.structure.InlineTemplate_RuleConsequence"))) { // afaik IF/ELSE consequence is the only place we need to treat in a distinct way scanTemplateNode(SLinkOperations.getTarget(SNodeOperations.cast(SLinkOperations.getTarget(SNodeOperations.cast(node, MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x1047c1472deL, "jetbrains.mps.lang.generator.structure.IfMacro")), MetaAdapterFactory.getContainmentLink(0xb401a68083254110L, 0x8fd384331ff25befL, 0x1047c1472deL, 0x1163aea5803L, "alternativeConsequence")), MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x112103dd1e8L, "jetbrains.mps.lang.generator.structure.InlineTemplate_RuleConsequence")), MetaAdapterFactory.getContainmentLink(0xb401a68083254110L, 0x8fd384331ff25befL, 0x112103dd1e8L, 0x112103ebf76L, "templateNode")), progressMonitor); } it.skipChildren(); continue; } if (SNodeOperations.isInstanceOf(node, MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x11017244494L, "jetbrains.mps.lang.generator.structure.RootTemplateAnnotation")) || SNodeOperations.isInstanceOf(node, MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0xff1b29b76cL, "jetbrains.mps.lang.generator.structure.TemplateFragment"))) { // it's unlikely to see TF under root template (impossible?) but does it hurt to have it excluded here? it.skipChildren(); continue; } checkReferences(node); } } private void checkReferences(SNode node) { for (SReference ref : ListSequence.fromList(SNodeOperations.getReferences(node))) { // there's macro to adjust the reference, don't care 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) { continue; } // if reference points to a generator model... if (!(SModelStereotype.isGeneratorModel(SNodeOperations.getModel(target)))) { continue; } SNode root = SNodeOperations.getContainingRoot(target); // and it's a root template in the generator model... if (AttributeOperations.getAttribute(root, new IAttributeDescriptor.NodeAttribute(MetaAdapterFactory.getConcept(0xb401a68083254110L, 0x8fd384331ff25befL, 0x11017244494L, "jetbrains.mps.lang.generator.structure.RootTemplateAnnotation"))) == null) { continue; } if (root == SNodeOperations.getContainingRoot(node)) { continue; } SpecificChecker.addIssue(myResults, node, String.format("Reference across root templates in role '%s', use mapping label or reference macro", ref.getLink().getName()), ModelChecker.SEVERITY_WARNING, "Cross-template reference", null); } } }