11private import codeql.swift.generated.AstNode
22private import codeql.swift.elements.decl.AbstractFunctionDecl
33private import codeql.swift.elements.decl.Decl
4+ private import codeql.swift.elements.expr.AbstractClosureExpr
5+ private import codeql.swift.elements.Callable
46private import codeql.swift.generated.ParentChild
57
68private module Cached {
@@ -21,10 +23,59 @@ private module Cached {
2123 AbstractFunctionDecl getEnclosingFunction ( AstNode ast ) {
2224 result = getEnclosingFunctionStep * ( getEnclosingDecl ( ast ) )
2325 }
26+
27+ private Element getEnclosingClosureStep ( Element e ) {
28+ not e instanceof Callable and
29+ result = getImmediateParent ( e )
30+ }
31+
32+ cached
33+ AbstractClosureExpr getEnclosingClosure ( AstNode ast ) {
34+ result = getEnclosingClosureStep * ( getImmediateParent ( ast ) )
35+ }
2436}
2537
38+ /**
39+ * A node in the abstract syntax tree.
40+ */
2641class AstNode extends Generated:: AstNode {
42+ /**
43+ * Gets the nearest function definition that contains this AST node, if any.
44+ * This includes functions, methods, (de)initializers, and accessors, but not closures.
45+ *
46+ * For example, in the following code, the AST node for `n + 1` has `foo` as its
47+ * enclosing function (via `getEnclosingFunction`), whereas its enclosing callable is
48+ * the closure `{(n : Int) in n + 1 }` (via `getEnclosingCallable`):
49+ *
50+ * ```swift
51+ * func foo() {
52+ * var f = { (n : Int) in n + 1 }
53+ * }
54+ * ```
55+ */
2756 final AbstractFunctionDecl getEnclosingFunction ( ) { result = Cached:: getEnclosingFunction ( this ) }
2857
58+ /**
59+ * Gets the nearest declaration that contains this AST node, if any.
60+ */
2961 final Decl getEnclosingDecl ( ) { result = Cached:: getEnclosingDecl ( this ) }
62+
63+ /**
64+ * Gets the nearest `Callable` that contains this AST node, if any.
65+ * This includes (auto)closures, functions, methods, (de)initializers, and accessors.
66+ *
67+ * For example, in the following code, the AST node for `n + 1` has the closure
68+ * `{(n : Int) in n + 1 }` as its enclosing callable.
69+ *
70+ * ```swift
71+ * func foo() {
72+ * var f = { (n : Int) in n + 1 }
73+ * }
74+ * ```
75+ */
76+ final Callable getEnclosingCallable ( ) {
77+ if exists ( Cached:: getEnclosingClosure ( this ) )
78+ then result = Cached:: getEnclosingClosure ( this )
79+ else result = Cached:: getEnclosingFunction ( this )
80+ }
3081}
0 commit comments