Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
23 changes: 21 additions & 2 deletions swift/ql/lib/codeql/swift/elements/decl/Decl.qll
Original file line number Diff line number Diff line change
@@ -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.Decl
private import codeql.swift.elements.decl.DeclWithMembers
private import codeql.swift.elements.decl.NominalTypeDecl
private import codeql.swift.elements.decl.ExtensionDecl

class Decl extends Generated::Decl { }
class Decl extends Generated::Decl {
/**
* Gets the class, struct, enum, protocol, or extension that declared
* this `Decl` as a member.
*/
cached

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is there a rule of thumb for when I should cache a predicate?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's always a bit difficult to judge when (and how) something should be cached. Generally, if a predicate is (1) expensive to compute, and (2) used in multiple queries, then it should most likely be cached. In this case, I don't think that the predicate should be cached as I don't think getDeclaringDecl is expensive to compute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The simplest rule of thumb is: if in doubt, don't mark predicates cached when you write them (or use pragma[only_bind_into] and other hints). The optimizer doesn't usually need these tags to do a good job, and you can make things worse by using them. In the case of cached, I believe it prevents the optimizer from using the context in which the predicate is called to reduce its size, which can sometimes cost more than any gains.

The time to use these tools IMO is when you've identified a measurable performance problem and you're trying to fix it. I guess the other situation is when you're implementing or copying a familiar pattern where cached has worked out well before.

DeclWithMembers getDeclaringDecl() { result.getAMember() = this }

/**
* Gets the class, struct, enum, or protocol that declared
* (or was extended with) this `Decl` as a member.
*/
NominalTypeDecl getDeclaringTypeDecl() {
result.getAMember() = this
or
result = any(ExtensionDecl e | e.getAMember() = this).getExtendedTypeDecl()
}
}
26 changes: 26 additions & 0 deletions swift/ql/lib/codeql/swift/elements/decl/DeclWithMembers.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
private import codeql.swift.elements.decl.IterableDeclContext
private import codeql.swift.elements.decl.VarDecl
private import codeql.swift.elements.decl.SubscriptDecl
private import codeql.swift.elements.decl.Decl

class DeclWithMembers extends Decl, IterableDeclContext {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm still of the opinion that there's not really a need to have a class like this as part of the public AST. Rather, I'd much rather see the importing of the IterableDeclContext class disappear from swift.qll, and its use purely as an implementation detail in order to get getImmediateMember/getMember predicates on the classes that currently extend IterableDeclContext.

I think we should delay this change until we've settled on a decision here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

And I'm not very happy with the name DeclWithMembers. I think we're talking about a declaration of a kind that can have members, not one that necessarily does. Consider:

struct MyStruct {}

/**
* Gets the `index`th member (0-based) of this nominal type or extension `Decl`,
* including `AccessorDecl`s of immediate members.
*/
override Decl getImmediateMember(int index) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure, but maybe this logic should be part of the extractor or codegen.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We generally prefer to put logic in QL when we have the choice, and there are no good reasons for putting in the extractor.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

... I'd like to tell you why we prefer that. I think it has to do with QL being easier to see and easier to change.

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
)
}
}
34 changes: 3 additions & 31 deletions swift/ql/lib/codeql/swift/elements/decl/MethodDecl.qll
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
private import swift

private Decl getAMember(IterableDeclContext ctx) {
ctx.getAMember() = result
or
exists(VarDecl var |
ctx.getAMember() = var and
var.getAnAccessorDecl() = result
)
}
private import codeql.swift.elements.decl.DeclWithMembers

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(DeclWithMembers decl).getAMember() }

/**
* Holds if this function is called `funcName` and its a member of a
Expand All @@ -29,17 +11,7 @@ class MethodDecl extends AbstractFunctionDecl {
cached
predicate hasQualifiedName(string typeName, string funcName) {
this.getName() = funcName and
(
exists(NominalTypeDecl c |
c.getFullName() = typeName and
c.getAMember() = this
)
or
exists(ExtensionDecl e |
e.getExtendedTypeDecl().getFullName() = typeName and
e.getAMember() = this
)
)
this.getDeclaringTypeDecl().getFullName() = typeName

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I do like this, having getDeclaringDecl and getDeclaringTypeDecl both widely available and clearly defined is a big plus.

}

/**
Expand Down
4 changes: 2 additions & 2 deletions swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
private import codeql.swift.generated.decl.VarDecl
private import codeql.swift.elements.expr.DeclRefExpr
private import codeql.swift.elements.decl.IterableDeclContext
private import codeql.swift.elements.decl.DeclWithMembers

class VarDecl extends Generated::VarDecl {
override string toString() { result = this.getName() }
Expand All @@ -9,5 +9,5 @@ class VarDecl extends Generated::VarDecl {
}

class FieldDecl extends VarDecl {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Maybe this should be PropertyDecl, to keep it consistent with the language's preferred name.

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

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

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

query predicate methodDecl(
DeclWithMembers decl, MethodDecl member, string memberClass, string memberQName
) {
isInTestModule(member) and
memberClass = member.getPrimaryQlClasses() and
decl.getAMember() = member and
exists(string memberModule, string memberType, string memberName |
member.hasQualifiedName(memberModule, memberType, memberName) and
memberQName = memberModule + "." + memberType + "." + memberName
)
}
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 }
}
}