Swift: refactor the public API wrt captures

This exposes capture- and access-related methods under different names.
This commit is contained in:
Nora Dimitrijević
2023-03-31 16:41:59 +02:00
parent 09502c60d5
commit 96f06f8eca
6 changed files with 110 additions and 6 deletions

View File

@@ -60,7 +60,6 @@ ql/lib/codeql/swift/elements/decl/SubscriptDeclConstructor.qll 3a88617b41f96827c
ql/lib/codeql/swift/elements/decl/TopLevelCodeDeclConstructor.qll 6920a4e7aec45ae2a561cef95b9082b861f81c16c259698541f317481645e194 4bd65820b93a5ec7332dd1bbf59326fc19b77e94c122ad65d41393c84e6ac581
ql/lib/codeql/swift/elements/decl/TypeAliasDecl.qll 984c5802c35e595388f7652cef1a50fb963b32342ab4f9d813b7200a0e6a37ca 630dc9cbf20603855c599a9f86037ba0d889ad3d2c2b6f9ac17508d398bff9e3
ql/lib/codeql/swift/elements/decl/TypeAliasDeclConstructor.qll ba70bb69b3a14283def254cc1859c29963838f624b3f1062a200a8df38f1edd5 96ac51d1b3156d4139e583f7f803e9eb95fe25cc61c12986e1b2972a781f9c8b
ql/lib/codeql/swift/elements/decl/ValueDecl.qll 1b7d8eeb17be4bdbabc156cb0689641ed4f9e697e334d2d14f423ed3d1a419f6 e3056cf6a883da2737cb220a89499a9e3977eb1c56b9e1d2f41a56b71a0c29f9
ql/lib/codeql/swift/elements/expr/AbiSafeConversionExpr.qll 39b856c89b8aff769b75051fd9e319f2d064c602733eaa6fed90d8f626516306 a87738539276438cef63145461adf25309d1938cfac367f53f53d33db9b12844
ql/lib/codeql/swift/elements/expr/AbiSafeConversionExprConstructor.qll 7d70e7c47a9919efcb1ebcbf70e69cab1be30dd006297b75f6d72b25ae75502a e7a741c42401963f0c1da414b3ae779adeba091e9b8f56c9abf2a686e3a04d52
ql/lib/codeql/swift/elements/expr/AbstractClosureExpr.qll 4027b51a171387332f96cb7b78ca87a6906aec76419938157ac24a60cff16519 400790fe643585ad39f40c433eff8934bbe542d140b81341bca3b6dfc5b22861

View File

@@ -1,6 +1,8 @@
private import codeql.swift.generated.AstNode
private import codeql.swift.elements.decl.AbstractFunctionDecl
private import codeql.swift.elements.decl.Decl
private import codeql.swift.elements.expr.AbstractClosureExpr
private import codeql.swift.elements.Callable
private import codeql.swift.generated.ParentChild
private module Cached {
@@ -21,10 +23,59 @@ private module Cached {
AbstractFunctionDecl getEnclosingFunction(AstNode ast) {
result = getEnclosingFunctionStep*(getEnclosingDecl(ast))
}
private Element getEnclosingClosureStep(Element e) {
not e instanceof Callable and
result = getImmediateParent(e)
}
cached
AbstractClosureExpr getEnclosingClosure(AstNode ast) {
result = getEnclosingClosureStep*(getImmediateParent(ast))
}
}
/**
* A node in the abstract syntax tree.
*/
class AstNode extends Generated::AstNode {
/**
* Gets the nearest function definition that contains this AST node, if any.
* This includes functions, methods, (de)initializers, and accessors, but not closures.
*
* For example, in the following code, the AST node for `n + 1` has `foo` as its
* enclosing function (via `getEnclosingFunction`), whereas its enclosing callable is
* the closure `{(n : Int) in n + 1 }` (via `getEnclosingCallable`):
*
* ```swift
* func foo() {
* var f = { (n : Int) in n + 1 }
* }
* ```
*/
final AbstractFunctionDecl getEnclosingFunction() { result = Cached::getEnclosingFunction(this) }
/**
* Gets the nearest declaration that contains this AST node, if any.
*/
final Decl getEnclosingDecl() { result = Cached::getEnclosingDecl(this) }
/**
* Gets the nearest `Callable` that contains this AST node, if any.
* This includes (auto)closures, functions, methods, (de)initializers, and accessors.
*
* For example, in the following code, the AST node for `n + 1` has the closure
* `{(n : Int) in n + 1 }` as its enclosing callable.
*
* ```swift
* func foo() {
* var f = { (n : Int) in n + 1 }
* }
* ```
*/
final Callable getEnclosingCallable() {
if exists(Cached::getEnclosingClosure(this))
then result = Cached::getEnclosingClosure(this)
else result = Cached::getEnclosingFunction(this)
}
}

View File

@@ -1,5 +1,23 @@
private import codeql.swift.generated.decl.CapturedDecl
private import codeql.swift.elements.Callable
private import codeql.swift.elements.expr.DeclRefExpr
/**
* A captured variable or function parameter in the scope of a closure.
*/
class CapturedDecl extends Generated::CapturedDecl {
override string toString() { result = this.getDecl().toString() }
/**
* Gets the closure or function that captures this variable.
*/
Callable getScope() { result.getACapture() = this }
/**
* Get an access to this capture within the scope of its closure.
*/
DeclRefExpr getAnAccess() {
result.getEnclosingCallable() = this.getScope() and
result.getDecl() = this.getDecl()
}
}

View File

@@ -1,4 +1,23 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.decl.ValueDecl
private import codeql.swift.elements.decl.CapturedDecl
private import codeql.swift.elements.expr.DeclRefExpr
class ValueDecl extends Generated::ValueDecl { }
/**
* A declaration that introduces a value with a type.
*/
class ValueDecl extends Generated::ValueDecl {
/**
* Gets a capture of this declaration in the scope of a closure.
*/
CapturedDecl asCapturedDecl() { result.getDecl() = this }
/**
* Holds if this declaration is captured by a closure.
*/
predicate isCaptured() { exists(this.asCapturedDecl()) }
/**
* Gets an expression that references this declaration.
*/
DeclRefExpr getAnAccess() { result.getDecl() = this }
}

View File

@@ -1,13 +1,16 @@
private import codeql.swift.generated.decl.VarDecl
private import codeql.swift.elements.expr.DeclRefExpr
private import codeql.swift.elements.decl.Decl
/**
* A variable declaration.
*/
class VarDecl extends Generated::VarDecl {
override string toString() { result = this.getName() }
DeclRefExpr getAnAccess() { result.getDecl() = this }
}
/**
* A field declaration.
*/
class FieldDecl extends VarDecl {
FieldDecl() { this = any(Decl ctx).getAMember() }
}

View File

@@ -1,9 +1,23 @@
private import codeql.swift.generated.expr.DeclRefExpr
private import codeql.swift.elements.decl.CapturedDecl
/**
* An expression that references or accesses a declaration.
*/
class DeclRefExpr extends Generated::DeclRefExpr {
override string toString() {
if exists(this.getDecl().toString())
then result = this.getDecl().toString()
else result = "(unknown declaration)"
}
/**
* Gets the closure capture referenced by this expression, if any.
*/
CapturedDecl getCapturedDecl() { result.getAnAccess() = this }
/**
* Holds if this expression references a closure capture.
*/
predicate hasCapturedDecl() { exists(this.getCapturedDecl()) }
}