File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -118,6 +118,44 @@ class Module extends TModule {
118118 or
119119 result .( SelfVariableAccess ) .getVariable ( ) .getDeclaringScope ( ) = this .getAnOwnSingletonMethod ( )
120120 }
121+
122+ pragma [ nomagic]
123+ private string getEnclosingModuleName ( ) {
124+ exists ( string qname |
125+ qname = this .getQualifiedName ( ) and
126+ result = qname .regexpReplaceAll ( "::[^:]*$" , "" ) and
127+ qname != result
128+ )
129+ }
130+
131+ pragma [ nomagic]
132+ private string getOwnModuleName ( ) {
133+ result = this .getQualifiedName ( ) .regexpReplaceAll ( "^.*::" , "" )
134+ }
135+
136+ /**
137+ * Gets the enclosing module, as it appears in the qualified name of this module.
138+ *
139+ * For example, the canonical enclosing module of `A::B` is `A`, and `A` itself has no canonical enclosing module.
140+ */
141+ pragma [ nomagic]
142+ Module getCanonicalEnclosingModule ( ) { result .getQualifiedName ( ) = this .getEnclosingModuleName ( ) }
143+
144+ /**
145+ * Gets a module named `name` declared inside this one (not aliased), provided
146+ * that such a module is defined or reopened in the current codebase.
147+ *
148+ * For example, for `A::B` the canonical nested module named `C` would be `A::B::C`.
149+ *
150+ * Note that this is not the same as constant lookup. If `A::B::C` would resolve to a
151+ * module whose qualified name is not `A::B::C`, then it will not be found by
152+ * this predicate.
153+ */
154+ pragma [ nomagic]
155+ Module getCanonicalNestedModule ( string name ) {
156+ result .getCanonicalEnclosingModule ( ) = this and
157+ result .getOwnModuleName ( ) = name
158+ }
121159}
122160
123161/**
Original file line number Diff line number Diff line change @@ -857,6 +857,25 @@ class ModuleNode instanceof Module {
857857 * from ancestors.
858858 */
859859 MethodNode getAnInstanceMethod ( ) { result = this .getInstanceMethod ( _) }
860+
861+ /**
862+ * Gets the enclosing module, as it appears in the qualified name of this module.
863+ *
864+ * For example, the canonical enclosing module of `A::B` is `A`, and `A` itself has no canonical enclosing module.
865+ */
866+ ModuleNode getCanonicalEnclosingModule ( ) { result = super .getCanonicalEnclosingModule ( ) }
867+
868+ /**
869+ * Gets a module named `name` declared inside this one (not aliased), provided
870+ * that such a module is defined or reopened in the current codebase.
871+ *
872+ * For example, for `A::B` the canonical nested module named `C` would be `A::B::C`.
873+ *
874+ * Note that this is not the same as constant lookup. If `A::B::C` would resolve to a
875+ * module whose qualified name is not `A::B::C`, then it will not be found by
876+ * this predicate.
877+ */
878+ ModuleNode getCanonicalNestedModule ( string name ) { result = super .getCanonicalNestedModule ( name ) }
860879}
861880
862881/**
You can’t perform that action at this time.
0 commit comments