44overlay [ local?]
55module ;
66
7+ private import unified as U
78private import AstPlugin
89private import codeql.files.FileSystem
910private import codeql.unified.internal.NameBinding as NameBinding
@@ -37,7 +38,11 @@ module Unified {
3738 )
3839 }
3940
40- /** Gets the nearest enclosing class declaration, if any. */
41+ /**
42+ * Gets the nearest syntactically enclosing class declaration, if any.
43+ *
44+ * For the semantically enclosing class, use `getParentClass()` instead.
45+ */
4146 ClassLikeDeclaration getEnclosingClass ( ) {
4247 exists ( AstNode parent | parent = this .getParent ( ) |
4348 result = parent
@@ -47,6 +52,33 @@ module Unified {
4752 )
4853 }
4954
55+ /**
56+ * Gets the class that this node belongs to, if any.
57+ *
58+ * Unlike `getEnclosingClass`, this takes extensions into account:
59+ *
60+ * ```swift
61+ * class A {
62+ * let x : Int // belongs to class A
63+ * }
64+ *
65+ * extension A {
66+ * func foo() {} // also belongs to the class A
67+ * }
68+ * ```
69+ */
70+ ClassLikeDeclaration getParentClass ( ) {
71+ exists ( ClassLikeDeclaration encl | encl = this .getEnclosingClass ( ) |
72+ not exists ( encl .getExtensionTarget ( ) ) and
73+ result = encl
74+ or
75+ exists ( NameBinding:: NamespaceNode ns |
76+ ns .isStaticMemberNamespace ( result ) and
77+ ns .getAnExtension ( ) .isStaticMemberNamespace ( encl )
78+ )
79+ )
80+ }
81+
5082 private AstNode overrideEnclosingCallableParent ( ) {
5183 exists ( FunctionExpr func |
5284 // Capture declarations are evaluated as part of the outer context, and
@@ -205,17 +237,36 @@ module Unified {
205237 /**
206238 * Gets the name of this member qualified by the short names of each immediately-enclosing class.
207239 */
208- string getQualifiedName ( ) {
209- exists ( ClassLikeDeclaration cls |
210- this = cls .getAMember ( ) and
211- result = cls .getQualifiedName ( ) + "." + this .getNameOrFallback ( )
212- )
240+ string getQualifiedName ( ) { result = QualifiedName< getParentClass / 1 > :: getQualifiedName ( this ) }
241+ }
242+
243+ private signature ClassLikeDeclaration getDeclaringClassSig ( Member m ) ;
244+
245+ private module QualifiedName< getDeclaringClassSig / 1 getDeclaringClass> {
246+ string getQualifiedName ( Member m ) {
247+ not m instanceof U:: EnumCaseConstructor and
248+ result = getQualifiedName ( getDeclaringClass ( m ) ) + "." + m .getNameOrFallback ( )
249+ or
250+ not exists ( getDeclaringClass ( m ) ) and
251+ result = m .getNameOrFallback ( )
213252 or
214- not this = any ( ClassLikeDeclaration cls ) .getAMember ( ) and
215- result = this .getNameOrFallback ( )
253+ result = getQualifiedName ( m .( U:: EnumCaseConstructor ) .getEnumCaseClass ( ) )
216254 }
217255 }
218256
257+ private ClassLikeDeclaration getParentClass ( Member m ) {
258+ result .getAMemberIncludingExtensions ( ) = m
259+ }
260+
261+ private ClassLikeDeclaration getEnclosingClass ( Member m ) { result .getAMember ( ) = m }
262+
263+ /**
264+ * Similar to `Member.getQualifiedName`, but avoids a dependency on name binding, making
265+ * it suitable for use in `toString` predicates.
266+ */
267+ private predicate getQualifiedNameForToString =
268+ QualifiedName< getEnclosingClass / 1 > :: getQualifiedName / 1 ;
269+
219270 class ClassLikeDeclaration extends G:: ClassLikeDeclaration {
220271 /** Gets the name of this declaration. */
221272 string getName ( ) { result = this .getNameNode ( ) .getValue ( ) }
@@ -226,8 +277,24 @@ module Unified {
226277 NameBinding:: getStaticBindingTargetFromRef ( this .getABaseType ( ) .getType ( ) )
227278 }
228279
280+ /**
281+ * Gets a member of this class, including members from extensions.
282+ */
283+ Member getAMemberIncludingExtensions ( ) {
284+ result = this .getAMember ( ) and
285+ not exists ( this .getExtensionTarget ( ) )
286+ or
287+ exists ( ClassLikeDeclaration ext , NameBinding:: NamespaceNode ns |
288+ ns .isStaticMemberNamespace ( this ) and
289+ ns .getAnExtension ( ) .isStaticMemberNamespace ( ext ) and
290+ result = ext .getAMember ( )
291+ )
292+ }
293+
229294 override string toString ( ) {
230- result = concat ( getClassLikeDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
295+ result =
296+ concat ( getClassLikeDeclarationKeyword ( this ) + " " ) +
297+ concat ( getQualifiedNameForToString ( this ) )
231298 }
232299 }
233300
@@ -237,7 +304,8 @@ module Unified {
237304
238305 override string toString ( ) {
239306 result =
240- concat ( getConstructorDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
307+ concat ( getConstructorDeclarationKeyword ( this ) + " " ) +
308+ concat ( getQualifiedNameForToString ( this ) )
241309 }
242310 }
243311
@@ -251,7 +319,9 @@ module Unified {
251319 string getName ( ) { result = this .getNameNode ( ) .getValue ( ) }
252320
253321 override string toString ( ) {
254- result = concat ( getFunctionDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
322+ result =
323+ concat ( getFunctionDeclarationKeyword ( this ) + " " ) +
324+ concat ( getQualifiedNameForToString ( this ) )
255325 }
256326 }
257327
@@ -263,7 +333,9 @@ module Unified {
263333 string getName ( ) { result = this .getNameNode ( ) .getValue ( ) }
264334
265335 override string toString ( ) {
266- result = concat ( getVariableDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
336+ result =
337+ concat ( getVariableDeclarationKeyword ( this ) + " " ) +
338+ concat ( getQualifiedNameForToString ( this ) )
267339 }
268340 }
269341
0 commit comments