Skip to content

Swift: Simplify the API for Decl members #11046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions swift/ql/lib/codeql/swift/elements/decl/IterableDeclContext.qll
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.decl.IterableDeclContext
private import codeql.swift.elements.decl.Decl
private import codeql.swift.elements.decl.VarDecl
private import codeql.swift.elements.decl.SubscriptDecl

class IterableDeclContext extends Generated::IterableDeclContext { }
class IterableDeclContext extends Generated::IterableDeclContext {
/**
* Gets the `index`th member of this iterable declaration context (0-based),
* including `AccessorDecl`s of immediate members.
*/
override Decl getImmediateMember(int index) {
result =
rank[1 + index](Decl member, Decl immMember, int immIndex, int accIndex |
immMember = super.getImmediateMember(immIndex) and
(
member = immMember and accIndex = -1
or
member = immMember.(VarDecl).getImmediateAccessorDecl(accIndex)
or
member = immMember.(SubscriptDecl).getImmediateAccessorDecl(accIndex)
)
|
member order by immIndex, accIndex
)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sold on this change, as I do think accessors are logically and visually under a VarDecl or SubscriptDecl (and by visually I mean they are declared in subblocks of variable/subscript declarations). I would rather keep them that way.

Even if we do go with this, this requires taking them out of the children of VarDecl/SubscriptDecl, as the ast/no_double_parents.ql test failure shows.

21 changes: 1 addition & 20 deletions swift/ql/lib/codeql/swift/elements/decl/MethodDecl.qll
Original file line number Diff line number Diff line change
@@ -1,26 +1,7 @@
private import swift

private Decl getAMember(IterableDeclContext ctx) {
ctx.getAMember() = result
or
exists(VarDecl var |
ctx.getAMember() = var and
var.getAnAccessorDecl() = result
)
}

class MethodDecl extends AbstractFunctionDecl {
MethodDecl() {
this = getAMember(any(ClassDecl c))
or
this = getAMember(any(StructDecl c))
or
this = getAMember(any(ExtensionDecl c))
or
this = getAMember(any(EnumDecl c))
or
this = getAMember(any(ProtocolDecl c))
}
MethodDecl() { this = any(IterableDeclContext decl).getAMember() }

/**
* Holds if this function is called `funcName` and its a member of a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
declHasMemberAtIndex
| Class1 | 0 | iterabledeclcontext.swift:13:2:13:10 | init() | ConstructorDecl |
| Class1 | 1 | iterabledeclcontext.swift:14:2:14:10 | deinit() | DestructorDecl |
| Class1 | 2 | iterabledeclcontext.swift:16:2:16:27 | var ... = ... | PatternBindingDecl |
| Class1 | 3 | iterabledeclcontext.swift:16:6:16:6 | constantField | ConcreteVarDecl |
| Class1 | 4 | iterabledeclcontext.swift:16:6:16:6 | get | AccessorDecl |
| Class1 | 5 | iterabledeclcontext.swift:17:2:17:27 | var ... = ... | PatternBindingDecl |
| Class1 | 6 | iterabledeclcontext.swift:17:6:17:6 | mutableField | ConcreteVarDecl |
| Class1 | 7 | iterabledeclcontext.swift:17:6:17:6 | get | AccessorDecl |
| Class1 | 8 | iterabledeclcontext.swift:17:6:17:6 | set | AccessorDecl |
| Class1 | 9 | iterabledeclcontext.swift:17:6:17:6 | (unnamed function decl) | AccessorDecl |
| Class1 | 10 | iterabledeclcontext.swift:18:2:18:40 | var ... = ... | PatternBindingDecl |
| Class1 | 11 | iterabledeclcontext.swift:18:13:18:13 | staticConstantField | ConcreteVarDecl |
| Class1 | 12 | iterabledeclcontext.swift:18:13:18:13 | get | AccessorDecl |
| Class1 | 13 | iterabledeclcontext.swift:19:2:19:40 | var ... = ... | PatternBindingDecl |
| Class1 | 14 | iterabledeclcontext.swift:19:13:19:13 | staticMutableField | ConcreteVarDecl |
| Class1 | 15 | iterabledeclcontext.swift:19:13:19:13 | get | AccessorDecl |
| Class1 | 16 | iterabledeclcontext.swift:19:13:19:13 | set | AccessorDecl |
| Class1 | 17 | iterabledeclcontext.swift:19:13:19:13 | (unnamed function decl) | AccessorDecl |
| Class1 | 18 | iterabledeclcontext.swift:21:2:23:2 | var ... = ... | PatternBindingDecl |
| Class1 | 19 | iterabledeclcontext.swift:21:12:21:12 | gettableClassField | ConcreteVarDecl |
| Class1 | 20 | iterabledeclcontext.swift:21:36:23:2 | get | AccessorDecl |
| Class1 | 21 | iterabledeclcontext.swift:24:2:27:2 | var ... = ... | PatternBindingDecl |
| Class1 | 22 | iterabledeclcontext.swift:24:6:24:6 | observableField | ConcreteVarDecl |
| Class1 | 23 | iterabledeclcontext.swift:25:3:25:36 | willSet | AccessorDecl |
| Class1 | 24 | iterabledeclcontext.swift:26:3:26:34 | didSet | AccessorDecl |
| Class1 | 25 | iterabledeclcontext.swift:24:6:24:6 | get | AccessorDecl |
| Class1 | 26 | iterabledeclcontext.swift:24:6:24:6 | set | AccessorDecl |
| Class1 | 27 | iterabledeclcontext.swift:24:6:24:6 | (unnamed function decl) | AccessorDecl |
| Class1 | 28 | iterabledeclcontext.swift:29:2:36:2 | subscript ... | SubscriptDecl |
| Class1 | 29 | iterabledeclcontext.swift:30:3:32:3 | get | AccessorDecl |
| Class1 | 30 | iterabledeclcontext.swift:33:3:35:3 | set | AccessorDecl |
| Class1 | 31 | iterabledeclcontext.swift:29:2:29:2 | (unnamed function decl) | AccessorDecl |
| Class1 | 32 | iterabledeclcontext.swift:38:2:38:25 | instanceMethod() | ConcreteFuncDecl |
| Class1 | 33 | iterabledeclcontext.swift:39:2:39:30 | staticMethod() | ConcreteFuncDecl |
| Class1 | 34 | iterabledeclcontext.swift:40:2:40:28 | classMethod() | ConcreteFuncDecl |
| Class1 | 35 | iterabledeclcontext.swift:44:2:44:25 | Associated | TypeAliasDecl |
| Class1 | 36 | iterabledeclcontext.swift:48:2:50:2 | NestedClass | ClassDecl |
| Class1 | 37 | iterabledeclcontext.swift:51:2:53:2 | NestedStruct | StructDecl |
| Class1 | 38 | iterabledeclcontext.swift:54:2:58:2 | NestedEnum | EnumDecl |
| NestedClass | 0 | iterabledeclcontext.swift:49:3:49:25 | foo() | ConcreteFuncDecl |
| NestedClass | 1 | file://:0:0:0:0 | Associated | TypeAliasDecl |
| NestedClass | 2 | iterabledeclcontext.swift:48:8:48:8 | deinit() | DestructorDecl |
| NestedClass | 3 | iterabledeclcontext.swift:48:8:48:8 | init() | ConstructorDecl |
| NestedEnum | 0 | iterabledeclcontext.swift:55:3:55:8 | case ... | EnumCaseDecl |
| NestedEnum | 1 | iterabledeclcontext.swift:55:8:55:8 | case1 | EnumElementDecl |
| NestedEnum | 2 | iterabledeclcontext.swift:56:3:56:8 | case ... | EnumCaseDecl |
| NestedEnum | 3 | iterabledeclcontext.swift:56:8:56:8 | case2 | EnumElementDecl |
| NestedEnum | 4 | iterabledeclcontext.swift:57:3:57:25 | foo() | ConcreteFuncDecl |
| NestedEnum | 5 | file://:0:0:0:0 | __derived_enum_equals(_:_:) | ConcreteFuncDecl |
| NestedEnum | 6 | file://:0:0:0:0 | var ... = ... | PatternBindingDecl |
| NestedEnum | 7 | file://:0:0:0:0 | hash(into:) | ConcreteFuncDecl |
| NestedEnum | 8 | file://:0:0:0:0 | Associated | TypeAliasDecl |
| NestedEnum | 9 | file://:0:0:0:0 | hashValue | ConcreteVarDecl |
| NestedEnum | 10 | file://:0:0:0:0 | get | AccessorDecl |
| NestedStruct | 0 | iterabledeclcontext.swift:52:3:52:25 | foo() | ConcreteFuncDecl |
| NestedStruct | 1 | file://:0:0:0:0 | Associated | TypeAliasDecl |
| NestedStruct | 2 | iterabledeclcontext.swift:51:9:51:9 | init() | ConstructorDecl |
| Protocol1 | 0 | iterabledeclcontext.swift:5:2:5:30 | Associated | AssociatedTypeDecl |
| Protocol1 | 1 | iterabledeclcontext.swift:6:2:6:16 | foo() | ConcreteFuncDecl |
| extension | 0 | iterabledeclcontext.swift:9:2:9:45 | foo() | ConcreteFuncDecl |
methodDecl
| Class1 | iterabledeclcontext.swift:13:2:13:10 | init() | ConstructorDecl |
| Class1 | iterabledeclcontext.swift:14:2:14:10 | deinit() | DestructorDecl |
| Class1 | iterabledeclcontext.swift:16:6:16:6 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:17:6:17:6 | (unnamed function decl) | AccessorDecl |
| Class1 | iterabledeclcontext.swift:17:6:17:6 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:17:6:17:6 | set | AccessorDecl |
| Class1 | iterabledeclcontext.swift:18:13:18:13 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:19:13:19:13 | (unnamed function decl) | AccessorDecl |
| Class1 | iterabledeclcontext.swift:19:13:19:13 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:19:13:19:13 | set | AccessorDecl |
| Class1 | iterabledeclcontext.swift:21:36:23:2 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:24:6:24:6 | (unnamed function decl) | AccessorDecl |
| Class1 | iterabledeclcontext.swift:24:6:24:6 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:24:6:24:6 | set | AccessorDecl |
| Class1 | iterabledeclcontext.swift:25:3:25:36 | willSet | AccessorDecl |
| Class1 | iterabledeclcontext.swift:26:3:26:34 | didSet | AccessorDecl |
| Class1 | iterabledeclcontext.swift:29:2:29:2 | (unnamed function decl) | AccessorDecl |
| Class1 | iterabledeclcontext.swift:30:3:32:3 | get | AccessorDecl |
| Class1 | iterabledeclcontext.swift:33:3:35:3 | set | AccessorDecl |
| Class1 | iterabledeclcontext.swift:38:2:38:25 | instanceMethod() | ConcreteFuncDecl |
| Class1 | iterabledeclcontext.swift:39:2:39:30 | staticMethod() | ConcreteFuncDecl |
| Class1 | iterabledeclcontext.swift:40:2:40:28 | classMethod() | ConcreteFuncDecl |
| NestedClass | iterabledeclcontext.swift:48:8:48:8 | deinit() | DestructorDecl |
| NestedClass | iterabledeclcontext.swift:48:8:48:8 | init() | ConstructorDecl |
| NestedClass | iterabledeclcontext.swift:49:3:49:25 | foo() | ConcreteFuncDecl |
| NestedEnum | file://:0:0:0:0 | __derived_enum_equals(_:_:) | ConcreteFuncDecl |
| NestedEnum | file://:0:0:0:0 | get | AccessorDecl |
| NestedEnum | file://:0:0:0:0 | hash(into:) | ConcreteFuncDecl |
| NestedEnum | iterabledeclcontext.swift:57:3:57:25 | foo() | ConcreteFuncDecl |
| NestedStruct | iterabledeclcontext.swift:51:9:51:9 | init() | ConstructorDecl |
| NestedStruct | iterabledeclcontext.swift:52:3:52:25 | foo() | ConcreteFuncDecl |
| Protocol1 | iterabledeclcontext.swift:6:2:6:16 | foo() | ConcreteFuncDecl |
| extension | iterabledeclcontext.swift:9:2:9:45 | foo() | ConcreteFuncDecl |
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import swift

predicate isInTestModule(Decl decl) { decl.getModule().getName() = "iterabledeclcontext" }

query predicate declHasMemberAtIndex(
IterableDeclContext decl, int index, Decl member, string memberClass
) {
isInTestModule(decl) and
member = decl.getMember(index) and
memberClass = member.getPrimaryQlClasses()
}

query predicate methodDecl(IterableDeclContext d, MethodDecl m, string mClass) {
isInTestModule(m) and
mClass = m.getPrimaryQlClasses() and
d.getAMember() = m
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

func freeFunction() {}

protocol Protocol1 {
associatedtype Associated = Int
func foo() -> Int
}
extension Protocol1 {
func foo() -> Int { return 1 /* default */ }
}

class Class1: Protocol1 {
init() {}
deinit {}

let constantField: Int = 42
var mutableField: Int? = nil
static let staticConstantField: Int = 42
static var staticMutableField: Int? = nil

class var gettableClassField: Int {
return 42 /* get-Accessor */
}
var observableField: Int = 1 {
willSet { /* willSet-Accessor */ }
didSet { /* didSet-Accessor */ }
}

subscript(_ index: Int) -> Int {
get {
return mutableField ?? 0 /* get-Accessor */
}
set(value) {
mutableField = index + value /* set-Accessor */
}
}

func instanceMethod() {}
static func staticMethod() {}
class func classMethod() {}

// Type members:

typealias Associated = Int

// Nominal types:

class NestedClass: Protocol1 {
func foo() -> Int { 2 }
}
struct NestedStruct: Protocol1 {
func foo() -> Int { 3 }
}
enum NestedEnum: Protocol1 {
case case1
case case2
func foo() -> Int { 4 }
}
}