package jetbrains.mps.baseLanguage.textGen; /*Generated by MPS */ import jetbrains.mps.make.java.RootDependencies; import org.jetbrains.mps.openapi.model.SNode; import java.util.HashSet; import jetbrains.mps.util.JavaNameUtil; import jetbrains.mps.util.InternUtil; import jetbrains.mps.baseLanguage.behavior.Classifier__BehaviorDescriptor; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.lang.core.behavior.INamedConcept__BehaviorDescriptor; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.util.NameUtil; import java.util.ArrayList; import java.util.Collections; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations; /** * Common context for any Classifier TextUnit (top-level), manages imports for shorter names and tracks dependencies * to facilitate further creation of bl dependencies file */ public class ClassifierUnitContext implements RootDependencies.Source { private final SNode myClassifierNode; private final ImportsContext myImports; private final HashSet<String> myDepends; private final HashSet<String> myExtends; public ClassifierUnitContext(SNode topClassifierNode) { // FIXME don't really need to keep a node, just don't want to refactor NameUtil.nodeFQName uses right now myClassifierNode = topClassifierNode; myImports = new ImportsContext(topClassifierNode); myDepends = new HashSet<String>(); myExtends = new HashSet<String>(); } public ImportEntry getClassifierRefText(String packageName, String fqName, SNode contextNode) { addDependency(packageName, fqName); // FIXME there's likely no reason to pass package name and fqName (except, perhaps, for nested classes) // Could we instead pass node<Classifier> here directly? Indeed, although it's a major refactoring of crapy // BaseLanguageTextGen, where we go back and forth from node<Classifier> to strings return myImports.getClassifierRefText(packageName, fqName, contextNode); } private void addDependency(String packageName, String fqName) { // using only root classifiers as dependencies String nestedName = JavaNameUtil.nestedClassName(packageName, fqName); int dotIndex = nestedName.indexOf('.'); String dependencyFqName; if (dotIndex == -1) { dependencyFqName = fqName; } else { dependencyFqName = packageName + '.' + nestedName.substring(0, dotIndex); } // set<string> dependencies = getUserObjects(TextGen.DEPENDENCY); myDepends.add(InternUtil.intern(dependencyFqName)); } public void registerDependenciesOf(SNode cls) { boolean topClassifier = !((boolean) Classifier__BehaviorDescriptor.isInner_idsWroEc0xXl.invoke(cls)); if (SNodeOperations.isInstanceOf(cls, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101edd46144L, "jetbrains.mps.baseLanguage.structure.Interface"))) { registerExtendsRelation(SLinkOperations.getChildren(SNodeOperations.cast(cls, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101edd46144L, "jetbrains.mps.baseLanguage.structure.Interface")), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101edd46144L, 0x101eddadad7L, "extendedInterface")), topClassifier); } else if (SNodeOperations.isInstanceOf(cls, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c108ca66L, "jetbrains.mps.baseLanguage.structure.ClassConcept"))) { registerExtendsRelation(SLinkOperations.getChildren(SNodeOperations.cast(cls, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c108ca66L, "jetbrains.mps.baseLanguage.structure.ClassConcept")), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c108ca66L, 0xff2ac0b419L, "implementedInterface")), topClassifier); registerExtendsRelation(Sequence.<SNode>singleton(SLinkOperations.getTarget(SNodeOperations.cast(cls, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c108ca66L, "jetbrains.mps.baseLanguage.structure.ClassConcept")), MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xf8c108ca66L, 0x10f6353296dL, "superclass"))), topClassifier); } } /** * * @param classifiers collection to report * @param isTopClassifier true indicates we generate a top-level class, false for inner class indicates we shall record relaxed dependency */ private void registerExtendsRelation(Iterable<SNode> classifiers, boolean isTopClassifier) { // if an inner class extends/implements outer classifier, we shall not record this dependency as 'extends' of a // top-level unit (see sample in MPS-17604). Perhaps, we shall not record this dependency at all? // set<string> dependencies = getUserObjects(isTopClassifier ? TextGen.EXTENDS : TextGen.DEPENDENCY); HashSet<String> deps = (isTopClassifier ? myExtends : myDepends); for (SNode c : SLinkOperations.collect(classifiers, MetaAdapterFactory.getReferenceLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101de48bf9eL, 0x101de490babL, "classifier"))) { deps.add(getTopmostClassifierName(c)); } } private String getTopmostClassifierName(SNode c) { // Classifier could be inner, for our purposes it's sufficent to record dependency from the top-most classifier // We use these to build module dependency graph for compilation, nested classes are irrelevant as // (a) they are in the same module anyway // (b) reverse map of class to module is built for top classifiers only, we won't find anything there for nested class // (see j.m.make.Dependencies) return INamedConcept__BehaviorDescriptor.getFqName_idhEwIO9y.invoke(ListSequence.fromList(SNodeOperations.getNodeAncestors(c, MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier"), true)).last()); // I don't need list of ancestors, but c.ancestor<root,concept> looks at the root node only (which is not right, IMO) // Why not Java-specific naming utility here, e.g. JavaNameUtil? Because getFqName does the same better (respects nested classifiers) and without any statics. } @Override public RootDependencies getDependencies() { // 1. nodeFQName comes from legacy TextGen String nodeFQName = NameUtil.nodeFQName(myClassifierNode); // 2. FIXME fileName construction is a hack. I can't access actual TU.getFileName() here. // Once I refactor ModelDependencies not to keep file name in RootDependencies object, I'd use 3-arg cons and drop the hack. // 3. Filtering and sorting of dependencies originate from TextGen legacy, left as is for now myDepends.removeAll(myExtends); myDepends.remove(nodeFQName); myDepends.remove(null); myExtends.remove(nodeFQName); // registerExtendsRelation(singleton(classifier.extends)) yields null for classes without superclass\n myExtends.remove(null); ArrayList<String> dep = new ArrayList<String>(myDepends); ArrayList<String> ext = new ArrayList<String>(myExtends); Collections.sort(dep); Collections.sort(ext); return new RootDependencies(nodeFQName, SPropertyOperations.getString(myClassifierNode, MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name")) + ".java", dep, ext); } }