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,30 @@ 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+ result .getNameNode ( ) = NameBinding:: getStaticBindingTargetFromRef ( encl .getExtensionTarget ( ) )
76+ )
77+ }
78+
5079 private AstNode overrideEnclosingCallableParent ( ) {
5180 exists ( FunctionExpr func |
5281 // Capture declarations are evaluated as part of the outer context, and
@@ -205,17 +234,36 @@ module Unified {
205234 /**
206235 * Gets the name of this member qualified by the short names of each immediately-enclosing class.
207236 */
208- string getQualifiedName ( ) {
209- exists ( ClassLikeDeclaration cls |
210- this = cls .getAMember ( ) and
211- result = cls .getQualifiedName ( ) + "." + this .getNameOrFallback ( )
212- )
237+ string getQualifiedName ( ) { result = QualifiedName< getParentClass / 1 > :: getQualifiedName ( this ) }
238+ }
239+
240+ private signature ClassLikeDeclaration getDeclaringClassSig ( Member m ) ;
241+
242+ private module QualifiedName< getDeclaringClassSig / 1 getDeclaringClass> {
243+ string getQualifiedName ( Member m ) {
244+ not m instanceof U:: EnumCaseConstructor and
245+ result = getQualifiedName ( getDeclaringClass ( m ) ) + "." + m .getNameOrFallback ( )
246+ or
247+ not exists ( getDeclaringClass ( m ) ) and
248+ result = m .getNameOrFallback ( )
213249 or
214- not this = any ( ClassLikeDeclaration cls ) .getAMember ( ) and
215- result = this .getNameOrFallback ( )
250+ result = getQualifiedName ( m .( U:: EnumCaseConstructor ) .getEnumCaseClass ( ) )
216251 }
217252 }
218253
254+ private ClassLikeDeclaration getParentClass ( Member m ) {
255+ result .getAMemberIncludingExtensions ( ) = m
256+ }
257+
258+ private ClassLikeDeclaration getEnclosingClass ( Member m ) { result .getAMember ( ) = m }
259+
260+ /**
261+ * Similar to `Member.getQualifiedName`, but avoids a dependency on name binding, making
262+ * it suitable for use in `toString` predicates.
263+ */
264+ private predicate getQualifiedNameForToString =
265+ QualifiedName< getEnclosingClass / 1 > :: getQualifiedName / 1 ;
266+
219267 class ClassLikeDeclaration extends G:: ClassLikeDeclaration {
220268 /** Gets the name of this declaration. */
221269 string getName ( ) { result = this .getNameNode ( ) .getValue ( ) }
@@ -226,8 +274,22 @@ module Unified {
226274 NameBinding:: getStaticBindingTargetFromRef ( this .getABaseType ( ) .getType ( ) )
227275 }
228276
277+ /**
278+ * Gets a member of this class, including members from extensions.
279+ */
280+ Member getAMemberIncludingExtensions ( ) {
281+ result = this .getAMember ( )
282+ or
283+ exists ( ClassLikeDeclaration ext |
284+ this .getNameNode ( ) = NameBinding:: getStaticBindingTargetFromRef ( ext .getExtensionTarget ( ) ) and
285+ result = ext .getAMember ( )
286+ )
287+ }
288+
229289 override string toString ( ) {
230- result = concat ( getClassLikeDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
290+ result =
291+ concat ( getClassLikeDeclarationKeyword ( this ) + " " ) +
292+ concat ( getQualifiedNameForToString ( this ) )
231293 }
232294 }
233295
@@ -237,7 +299,8 @@ module Unified {
237299
238300 override string toString ( ) {
239301 result =
240- concat ( getConstructorDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
302+ concat ( getConstructorDeclarationKeyword ( this ) + " " ) +
303+ concat ( getQualifiedNameForToString ( this ) )
241304 }
242305 }
243306
@@ -251,7 +314,9 @@ module Unified {
251314 string getName ( ) { result = this .getNameNode ( ) .getValue ( ) }
252315
253316 override string toString ( ) {
254- result = concat ( getFunctionDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
317+ result =
318+ concat ( getFunctionDeclarationKeyword ( this ) + " " ) +
319+ concat ( getQualifiedNameForToString ( this ) )
255320 }
256321 }
257322
@@ -263,7 +328,9 @@ module Unified {
263328 string getName ( ) { result = this .getNameNode ( ) .getValue ( ) }
264329
265330 override string toString ( ) {
266- result = concat ( getVariableDeclarationKeyword ( this ) + " " ) + concat ( this .getQualifiedName ( ) )
331+ result =
332+ concat ( getVariableDeclarationKeyword ( this ) + " " ) +
333+ concat ( getQualifiedNameForToString ( this ) )
267334 }
268335 }
269336
0 commit comments