+ # FIXME used to bypass RTA limitation on type resolution
+ type MENTITY: SELF
+
+ # Collect modifier keywords like `redef`, `private` etc
+ fun collect_modifiers: Array[String] do return new Array[String]
+
+ # Collect `self` linearization anchored on `mainmodule`
+ fun collect_linearization(mainmodule: MModule): nullable Array[MEntity] do
+ return null
+ end
+
+ # Collect `self` ancestors (direct and indirect)
+ #
+ # The concept of ancestor is abstract at this stage.
+ fun collect_ancestors(mainmodule: MModule, filter: nullable ModelFilter): Set[MENTITY] do
+ var done = new HashSet[MENTITY]
+ var todo = new Array[MENTITY]
+
+ todo.add_all collect_parents(mainmodule, filter)
+ while todo.not_empty do
+ var mentity = todo.pop
+ if mentity == self or done.has(mentity) then continue
+ done.add mentity
+ todo.add_all mentity.collect_parents(mainmodule, filter)
+ end
+ return done
+ end
+
+ # Collect `self` parents (direct ancestors)
+ #
+ # The concept of parent is abstract at this stage.
+ fun collect_parents(mainmodule: MModule, filter: nullable ModelFilter): Set[MENTITY] is abstract
+
+ # Collect `self` children (direct descendants)
+ #
+ # The concept of child is abstract at this stage.
+ fun collect_children(mainmodule: MModule, filter: nullable ModelFilter): Set[MENTITY] is abstract
+
+ # Collect `self` descendants (direct and direct)
+ #
+ # The concept of descendant is abstract at this stage.
+ fun collect_descendants(mainmodule: MModule, filter: nullable ModelFilter): Set[MENTITY] do
+ var done = new HashSet[MENTITY]
+ var todo = new Array[MENTITY]
+
+ todo.add_all collect_children(mainmodule, filter)
+ while todo.not_empty do
+ var mentity = todo.pop
+ if mentity == self or done.has(mentity) then continue
+ done.add mentity
+ todo.add_all mentity.collect_children(mainmodule, filter)
+ end
+ return done
+ end
+
+ # Build a poset representing `self` in it's own hierarchy
+ #
+ # The notion of hierarchy depends on the type of MEntity.
+ #
+ # Here a recap:
+ # * `MPackage`: package dependencies
+ # * `MGroup`: group dependencies
+ # * `MModule`: modules imports
+ # * `MClass`: class inheritance (all classdefs flattened)
+ # * `MClassDef`: classdef inheritance
+ # * `MProperty`: property definitions graph (all propdefs flattened)
+ # * `MPropDef`: property definitions graph
+ fun hierarchy_poset(mainmodule: MModule, filter: nullable ModelFilter): POSet[MENTITY] do
+ var poset = new POSet[MENTITY]
+ var parents_done = new HashSet[MENTITY]
+ var parents = new Array[MENTITY]
+ parents.add self
+ while parents.not_empty do
+ var mentity = parents.pop
+ if parents_done.has(mentity) then continue
+ parents_done.add mentity
+ poset.add_node mentity
+ for parent in mentity.collect_parents(mainmodule, filter) do
+ poset.add_edge(mentity, parent)
+ parents.add parent
+ end
+ end
+ var children_done = new HashSet[MEntity]
+ var children = new Array[MEntity]
+ children.add self
+ while children.not_empty do
+ var mentity = children.pop
+ if children_done.has(mentity) then continue
+ children_done.add mentity
+ for child in mentity.collect_children(mainmodule, filter) do
+ poset.add_edge(child, mentity)
+ children.add child
+ end
+ end
+ return poset
+ end
+end
+
+redef class Model
+
+ # Collect all MPackages in `self`
+ fun collect_mpackages(filter: nullable ModelFilter): HashSet[MPackage] do
+ var res = new HashSet[MPackage]
+ for mpackage in mpackages do
+ if filter == null or filter.accept_mentity(mpackage) then res.add(mpackage)
+ end
+ return res
+ end
+
+ # Collect all MGroups in `self`
+ fun collect_mgroups(filter: nullable ModelFilter): HashSet[MGroup] do
+ var res = new HashSet[MGroup]
+ for mpackage in collect_mpackages(filter) do
+ res.add_all mpackage.collect_all_mgroups(filter)
+ end
+ return res
+ end
+
+ # Collect all MModules in `self`
+ fun collect_mmodules(filter: nullable ModelFilter): HashSet[MModule] do
+ var res = new HashSet[MModule]
+ for mpackage in collect_mpackages(filter) do
+ res.add_all mpackage.collect_all_mmodules(filter)
+ end
+ return res
+ end
+
+ # Collect all MClasses in `self`
+ fun collect_mclasses(filter: nullable ModelFilter): HashSet[MClass] do
+ var res = new HashSet[MClass]
+ for mclass in mclasses do
+ if filter == null or filter.accept_mentity(mclass) then res.add mclass
+ end
+ return res
+ end
+
+ # Collect all MClasses introduced in `self`
+ fun collect_intro_mclasses(filter: nullable ModelFilter): HashSet[MClass] do
+ var res = new HashSet[MClass]
+ for mpackage in collect_mpackages(filter) do
+ res.add_all mpackage.collect_intro_mclasses(filter)
+ end
+ return res
+ end
+
+ # Collect all MClassDefs in `self`
+ fun collect_mclassdefs(filter: nullable ModelFilter): HashSet[MClassDef] do
+ var res = new HashSet[MClassDef]
+ for mclass in collect_mclasses(filter) do
+ res.add_all mclass.collect_mclassdefs(filter)
+ end
+ return res
+ end
+
+ # Collect all MProperties introduced in `self`
+ fun collect_intro_mproperties(filter: nullable ModelFilter): HashSet[MProperty] do
+ var res = new HashSet[MProperty]
+ for mpackage in collect_mpackages(filter) do
+ res.add_all mpackage.collect_intro_mproperties(filter)
+ end
+ return res
+ end
+
+ # Collect all MProperties in `self`
+ fun collect_mproperties(filter: nullable ModelFilter): HashSet[MProperty] do
+ var res = new HashSet[MProperty]
+ for mproperty in mproperties do
+ if filter == null or filter.accept_mentity(mproperty) then res.add mproperty
+ end
+ return res
+ end
+
+ # Collect all MPropDefs in `self`
+ fun collect_mpropdefs(filter: nullable ModelFilter): HashSet[MPropDef] do
+ var res = new HashSet[MPropDef]
+ for mproperty in collect_mproperties(filter) do
+ for mpropdef in mproperty.mpropdefs do
+ if filter == null or filter.accept_mentity(mpropdef) then res.add mpropdef
+ end
+ end
+ return res
+ end
+
+ # Collect all MEntities in `self`
+ fun collect_mentities(filter: nullable ModelFilter): HashSet[MEntity] do
+ var res = new HashSet[MEntity]
+ res.add_all collect_mpackages(filter)
+ res.add_all collect_mgroups(filter)
+ res.add_all collect_mmodules(filter)
+ res.add_all collect_mclasses(filter)
+ res.add_all collect_mclassdefs(filter)
+ res.add_all collect_mproperties(filter)
+ res.add_all collect_mpropdefs(filter)
+ return res
+ end
+
+ # Searches the MEntity that matches `full_name`.
+ fun mentity_by_full_name(full_name: String, filter: nullable ModelFilter): nullable MEntity do
+ for mentity in collect_mentities(filter) do
+ if filter != null and not filter.accept_mentity(mentity) then continue
+ if mentity.full_name == full_name then return mentity
+ end
+ return null
+ end
+
+ # Searches the MEntities that matches `full_name`.
+ fun mentities_by_name(name: String, filter: nullable ModelFilter): Array[MEntity] do
+ var res = new Array[MEntity]
+ for mentity in collect_mentities(filter) do
+ if filter != null and not filter.accept_mentity(mentity) then continue
+ if mentity.name == name then res.add mentity
+ end
+ return res