diff --git a/unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll b/unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll index 9db28d702497..e29f1c780720 100644 --- a/unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll +++ b/unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll @@ -480,6 +480,8 @@ module Public { } } +final class PotentialLocalNameAccess = PotentialLocalNameAccessImpl; + /** * A name node that is possibly a reference to a local name, but could also refer to a member * visible through imports or inheritance. @@ -493,17 +495,27 @@ module Public { * } * ``` */ -class PotentialLocalNameAccess extends IdentifierExpr { +abstract private class PotentialLocalNameAccessImpl extends AstNode { /** Gets the representative for the local name being accessed. */ LocalName getLocalName() { result = this.(LocalNameBindingOutput::LocalAccess).getLocal() } /** Gets the name being accessed. */ - string getName() { result = this.getValue() } + abstract string getName(); /** Holds if this is one of the binding sites for a name, such as the `x` in `let x = 123`. */ predicate isBindingSite() { this instanceof NameBinding } } +private class IdentifierPotentialLocalNameAccess extends PotentialLocalNameAccessImpl, + IdentifierExpr +{ + override string getName() { result = this.getValue() } +} + +private class SuperPotentialLocalNameAccess extends PotentialLocalNameAccessImpl, SuperExpr { + override string getName() { result = any(NameBindingPlugin p).getSuperLocalName() } +} + /** Gets the implicitly-declared variable through which the given callable refers to its receiver. */ LocalVariable getImplicitReceiverVariable(Callable callable) { exists(string name | diff --git a/unified/ql/lib/codeql/unified/internal/NameBindingPlugin.qll b/unified/ql/lib/codeql/unified/internal/NameBindingPlugin.qll index 067b60eea683..be95f7889585 100644 --- a/unified/ql/lib/codeql/unified/internal/NameBindingPlugin.qll +++ b/unified/ql/lib/codeql/unified/internal/NameBindingPlugin.qll @@ -68,6 +68,12 @@ class NameBindingPlugin extends Unit { /** Gets the name of the implicit receiver parameter in `callable`, if it has one. */ string getImplicitReceiverParameterName(Callable callable) { none() } + /** + * Gets the name to be used when resolving `super` expressions, for example + * `this` or `self`. + */ + string getSuperLocalName() { none() } + /** * Gets the name through which static members of the enclosing class `cls` can be * accessed, for example `Self` in Swift. diff --git a/unified/ql/lib/codeql/unified/internal/NameBindingPluginSwift.qll b/unified/ql/lib/codeql/unified/internal/NameBindingPluginSwift.qll index 846bb2ba8c67..f91232f21323 100644 --- a/unified/ql/lib/codeql/unified/internal/NameBindingPluginSwift.qll +++ b/unified/ql/lib/codeql/unified/internal/NameBindingPluginSwift.qll @@ -107,6 +107,8 @@ class NameBindingPluginSwift extends NameBindingPlugin { result = "self" } + override string getSuperLocalName() { result = "self" } + bindingset[cls] override string getStaticSelfName(ClassLikeDeclaration cls) { exists(cls) and result = "Self" } } diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/Content.qll b/unified/ql/lib/codeql/unified/internal/dataflow/Content.qll index ecb69457783d..8fe4d30cc5e4 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/Content.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/Content.qll @@ -1,5 +1,7 @@ private import unified private import AllDataFlow +private import codeql.unified.internal.typeinference.TypeInference as T +private import codeql.unified.internal.typeinference.TypeInferencePlugin as TP /** * Holds if a MaD access path token of form `name[arg]` exists. @@ -8,8 +10,20 @@ predicate isAccessPathTokenPresent(string name, string arg) { arg = any(FlowSummaryOutput::Private::AccessPathToken tok).getAnArgument(name) } +private class ResolvedField extends VariableDeclaration { + ResolvedField() { this = T::resolveFieldAccess(_) } + + string getName() { + result = super.getName() and + not this = any(TP::TupleType tt).getField(_) + or + this = any(TP::TupleType tt).getField(result) + } +} + private newtype TContent = TArrayElement() or + TFieldContent(ResolvedField field) or TNamedMember(string name) { name = any(Identifier id).getValue() or @@ -24,6 +38,8 @@ private newtype TContent = TCapturedVariable(CaptureSsaInput::CapturedVariable v) class Content extends TContent { + ResolvedField asField() { this = TFieldContent(result) } + string asNamedMember() { this = TNamedMember(result) } predicate isArrayElement() { this = TArrayElement() } @@ -31,6 +47,8 @@ class Content extends TContent { string toString() { result = this.asNamedMember() or + result = this.asField().getName() + or this.isArrayElement() and result = "ArrayElement" or result = this.asCapturedVariable().toString() @@ -38,9 +56,17 @@ class Content extends TContent { LocalVariable asCapturedVariable() { this = TCapturedVariable(result) } - Location getLocation() { result = this.asCapturedVariable().getLocation() } + Location getLocation() { + result = this.asCapturedVariable().getLocation() + or + result = this.asField().getLocation() + } } +private class TContentApprox = TArrayElement or TNamedMember or TCapturedVariable; + +class ContentApprox extends Content, TContentApprox { } + private newtype TContentSet = TSingleton(Content content) class ContentSet extends TContentSet { @@ -52,10 +78,35 @@ class ContentSet extends TContentSet { Content getAStoreContent() { result = this.asSingleton() } - Content getAReadContent() { result = this.asSingleton() } + Content getAReadContent() { + result = this.asSingleton() + or + result.asNamedMember() = this.asSingleton().asField().getName() + or + result.asField().getName() = this.asSingleton().asNamedMember() + } } module ContentSet { + /** + * Gets the resolved field content for `access`, falling back to name-based content when resolution + * is missing. + */ + ContentSet member(Expr access) { + result.asSingleton().asField() = T::resolveFieldAccess(access) + or + not exists(T::resolveFieldAccess(access)) and + not exists(T::resolveAccessorAccess(access)) and + exists(string name | + name = + [ + access.(MemberAccessExpr).getMemberName(), + access.(UnqualifiedMemberAccess).getMemberName() + ] and + result = namedMember(name) + ) + } + ContentSet namedMember(string name) { result.asSingleton().asNamedMember() = name } ContentSet arrayElement() { result.asSingleton().isArrayElement() } diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll index d804e790b7a7..2f355d790823 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll @@ -92,11 +92,11 @@ predicate step(BuilderNode node1, Step step, BuilderNode node2) { or exists(UnqualifiedMemberAccess access | access.isInstanceAccess() | node1.isLocalVariableRead(access, access.getImplicitQualifierVariable()) and - step.readName(access.getMemberName()) and + step.read(ContentSet::member(access)) and node2.isResultValue(access) or (node1.isIncomingValue(access) or node1.isPostUpdate(access)) and - step.storeName(access.getMemberName()) and + step.store(ContentSet::member(access)) and node2.isLocalVariablePostUpdate(access, access.getImplicitQualifierVariable()) or // Pass the receiver along to the getter/setter invoked by this expression @@ -129,11 +129,11 @@ predicate step(BuilderNode node1, Step step, BuilderNode node2) { or exists(MemberAccessExpr expr | node1.isResultValue(expr.getBase()) and - step.readName(expr.getMemberName()) and + step.read(ContentSet::member(expr)) and node2.isResultValue(expr) or (node1.isIncomingValue(expr) or node1.isPostUpdate(expr)) and - step.storeName(expr.getMemberName()) and + step.store(ContentSet::member(expr)) and node2.isPostUpdate(expr.getBase()) or // Pass the receiver along to the getter/setter invoked by this expression diff --git a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowInstantiation.qll b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowInstantiation.qll index 1c18b907c57c..8bce64150db6 100644 --- a/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowInstantiation.qll +++ b/unified/ql/lib/codeql/unified/internal/dataflow/DataFlowInstantiation.qll @@ -15,9 +15,13 @@ module DataFlowInput implements InputSig { class ContentSet = D::ContentSet; - class ContentApprox = Content; // TODO + class ContentApprox = D::ContentApprox; - ContentApprox getContentApprox(Content c) { result = c } // TODO + ContentApprox getContentApprox(Content c) { + result = c + or + result.asNamedMember() = c.asField().getName() + } // // Parameter, argument, return, and out nodes and their positions/kinds diff --git a/unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll b/unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll index 2dd7596e29cc..34b6c34dc47f 100644 --- a/unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll +++ b/unified/ql/lib/codeql/unified/internal/typeinference/TypeInference.qll @@ -219,7 +219,11 @@ module Input3 implements InputSig3 { } class Variable extends LocalNameBindingOutput::Local { - Expr getAnAccess() { result = super.getAnAccess() } + Expr getAnAccess() { + result = super.getAnAccess() and + // for type inference, we want super expressions to have the type of the base class + not result instanceof SuperExpr + } } final class VariableDeclaration = VariableDeclarationImpl; diff --git a/unified/ql/test/library-tests/dataflow/fields.swift b/unified/ql/test/library-tests/dataflow/fields.swift new file mode 100644 index 000000000000..4742a04a033c --- /dev/null +++ b/unified/ql/test/library-tests/dataflow/fields.swift @@ -0,0 +1,89 @@ +func source(_ s: String) -> String { return s } + +@discardableResult +func sink(_ s: Any) -> String { return "" } + +class FieldBox { + var field: String = "" +} + +class OtherFieldBox { + var field: String = "" +} + +class InheritedFieldBox: FieldBox {} + +func resolvedFields() { + let box = FieldBox() + box.field = source("fields.resolved") + sink(box.field) // $ hasValueFlow=fields.resolved + sink((box as! OtherFieldBox).field) // no flow +} + +func inheritedFields() { + let box = InheritedFieldBox() + box.field = source("fields.inherited") + sink((box as! FieldBox).field) // $ hasValueFlow=fields.inherited +} + +func unresolvedFieldRead() { + let box = FieldBox() + box.field = source("fields.unresolved-read") + sink((box as! UnknownFieldBox).field) // $ hasValueFlow=fields.unresolved-read +} + +func unresolvedFieldStore() { + let box = FieldBox() + (box as! UnknownFieldBox).field = source("fields.unresolved-store") + sink(box.field) // $ hasValueFlow=fields.unresolved-store +} + +func summarizedFieldRead() { + let box = FieldBox() + box.field = source("fields.summary") + sink(TestType.readField(box)) // $ hasValueFlow=fields.summary +} + +class BaseBox { + var field: String = "" +} + +class OverridingBox: BaseBox { + override var field: String { + get { super.field } + set { super.field = newValue } + } +} + +func overriddenFieldRead() { + let base: BaseBox = OverridingBox() + base.field = source("fields.override-read") + let sub = base as! OverridingBox + sink(sub.field) // $ hasValueFlow=fields.override-read +} + +protocol FieldProtocol { + var field: String { get set } +} + +class ProtocolBox: FieldProtocol { + var field: String = "" +} + +func protocolFieldRead() { + let box = ProtocolBox() + box.field = source("fields.protocol") + sink(box.field) // $ hasValueFlow=fields.protocol + let p = box as FieldProtocol + sink(p.field) // $ MISSING: hasValueFlow=fields.protocol -- missing dispatch from `FieldProtocol.get_field` to `ProtocolBox.field` +} + +func protocolFieldWrite() { + let box = ProtocolBox() + var p = box as FieldProtocol + p.field = source("fields.protocol") + sink(p.field) // $ MISSING: hasValueFlow=fields.protocol -- missing dispatch from `FieldProtocol.{get,set}_field` to `ProtocolBox.field` + sink(box.field) // $ MISSING: hasValueFlow=fields.protocol (aliasing) + let box2 = p as! OtherFieldBox + sink(box2.field) // no flow +} diff --git a/unified/ql/test/library-tests/dataflow/test.expected b/unified/ql/test/library-tests/dataflow/test.expected index 40fb146a8fde..f801d3968e1e 100644 --- a/unified/ql/test/library-tests/dataflow/test.expected +++ b/unified/ql/test/library-tests/dataflow/test.expected @@ -32,6 +32,7 @@ edges | accessors_instance.swift:119:13:119:17 | field | accessors_instance.swift:125:18:125:22 | field | provenance | | | accessors_instance.swift:119:21:119:35 | source(...) | accessors_instance.swift:119:13:119:17 | field | provenance | | | accessors_instance.swift:134:24:134:31 | newValue [0] | accessors_instance.swift:134:24:134:33 | ... .0 | provenance | | +| accessors_instance.swift:134:24:134:31 | newValue [0] | accessors_instance.swift:134:24:134:33 | ... .0 | provenance | | | accessors_instance.swift:143:5:143:7 | [post] ... .p [0] | accessors_instance.swift:134:24:134:31 | newValue [0] | provenance | | | accessors_instance.swift:143:5:143:9 | ... .0 | accessors_instance.swift:143:5:143:7 | [post] ... .p [0] | provenance | | | accessors_instance.swift:143:13:143:27 | source(...) | accessors_instance.swift:143:5:143:9 | ... .0 | provenance | | @@ -243,6 +244,40 @@ edges | enums.swift:82:12:82:12 | e [foo.0] | enums.swift:83:10:83:23 | ... .foo(...) [foo.0] | provenance | | | enums.swift:83:10:83:23 | ... .foo(...) [foo.0] | enums.swift:83:22:83:22 | x | provenance | | | enums.swift:83:22:83:22 | x | enums.swift:84:14:84:14 | x | provenance | | +| fields.swift:18:5:18:7 | [post] box [field] | fields.swift:19:10:19:12 | box [field] | provenance | | +| fields.swift:18:5:18:13 | ... .field | fields.swift:18:5:18:7 | [post] box [field] | provenance | | +| fields.swift:18:17:18:41 | source(...) | fields.swift:18:5:18:13 | ... .field | provenance | | +| fields.swift:19:10:19:12 | box [field] | fields.swift:19:10:19:18 | ... .field | provenance | | +| fields.swift:25:5:25:7 | [post] box [field] | fields.swift:26:11:26:13 | box [field] | provenance | | +| fields.swift:25:5:25:13 | ... .field | fields.swift:25:5:25:7 | [post] box [field] | provenance | | +| fields.swift:25:17:25:42 | source(...) | fields.swift:25:5:25:13 | ... .field | provenance | | +| fields.swift:26:11:26:13 | box [field] | fields.swift:26:11:26:26 | TypeCastExpr [field] | provenance | | +| fields.swift:26:11:26:26 | TypeCastExpr [field] | fields.swift:26:10:26:33 | ... .field | provenance | | +| fields.swift:31:5:31:7 | [post] box [field] | fields.swift:32:11:32:13 | box [field] | provenance | | +| fields.swift:31:5:31:13 | ... .field | fields.swift:31:5:31:7 | [post] box [field] | provenance | | +| fields.swift:31:17:31:48 | source(...) | fields.swift:31:5:31:13 | ... .field | provenance | | +| fields.swift:32:11:32:13 | box [field] | fields.swift:32:11:32:33 | TypeCastExpr [field] | provenance | | +| fields.swift:32:11:32:33 | TypeCastExpr [field] | fields.swift:32:10:32:40 | ... .field | provenance | | +| fields.swift:37:5:37:35 | ... .field | fields.swift:37:6:37:28 | [post] TypeCastExpr [field] | provenance | | +| fields.swift:37:6:37:28 | [post] TypeCastExpr [field] | fields.swift:38:10:38:12 | box [field] | provenance | | +| fields.swift:37:39:37:71 | source(...) | fields.swift:37:5:37:35 | ... .field | provenance | | +| fields.swift:38:10:38:12 | box [field] | fields.swift:38:10:38:18 | ... .field | provenance | | +| fields.swift:43:5:43:7 | [post] box [field] | fields.swift:44:29:44:31 | box [field] | provenance | | +| fields.swift:43:5:43:13 | ... .field | fields.swift:43:5:43:7 | [post] box [field] | provenance | | +| fields.swift:43:17:43:40 | source(...) | fields.swift:43:5:43:13 | ... .field | provenance | | +| fields.swift:44:29:44:31 | box [field] | fields.swift:44:10:44:32 | ... .readField(...) | provenance | | +| fields.swift:53:15:53:19 | super [field] | fields.swift:53:15:53:25 | ... .field | provenance | | +| fields.swift:60:5:60:8 | [post] base [field] | fields.swift:61:15:61:18 | base [field] | provenance | | +| fields.swift:60:5:60:14 | ... .field | fields.swift:60:5:60:8 | [post] base [field] | provenance | | +| fields.swift:60:18:60:47 | source(...) | fields.swift:60:5:60:14 | ... .field | provenance | | +| fields.swift:61:9:61:11 | sub [field] | fields.swift:62:10:62:12 | sub [field] | provenance | | +| fields.swift:61:15:61:18 | base [field] | fields.swift:61:9:61:11 | sub [field] | provenance | | +| fields.swift:62:10:62:12 | sub [field] | fields.swift:53:15:53:19 | super [field] | provenance | | +| fields.swift:62:10:62:12 | sub [field] | fields.swift:62:10:62:18 | ... .field | provenance | | +| fields.swift:75:5:75:7 | [post] box [field] | fields.swift:76:10:76:12 | box [field] | provenance | | +| fields.swift:75:5:75:13 | ... .field | fields.swift:75:5:75:7 | [post] box [field] | provenance | | +| fields.swift:75:17:75:41 | source(...) | fields.swift:75:5:75:13 | ... .field | provenance | | +| fields.swift:76:10:76:12 | box [field] | fields.swift:76:10:76:18 | ... .field | provenance | | | flow-summaries.swift:2:9:2:9 | x | flow-summaries.swift:3:35:3:35 | x | provenance | | | flow-summaries.swift:2:13:2:26 | source(...) | flow-summaries.swift:2:9:2:9 | x | provenance | | | flow-summaries.swift:3:9:3:9 | y | flow-summaries.swift:4:10:4:10 | y | provenance | | @@ -568,6 +603,7 @@ nodes | accessors_instance.swift:119:21:119:35 | source(...) | semmle.label | source(...) | | accessors_instance.swift:125:18:125:22 | field | semmle.label | field | | accessors_instance.swift:134:24:134:31 | newValue [0] | semmle.label | newValue [0] | +| accessors_instance.swift:134:24:134:31 | newValue [0] | semmle.label | newValue [0] | | accessors_instance.swift:134:24:134:33 | ... .0 | semmle.label | ... .0 | | accessors_instance.swift:143:5:143:7 | [post] ... .p [0] | semmle.label | [post] ... .p [0] | | accessors_instance.swift:143:5:143:9 | ... .0 | semmle.label | ... .0 | @@ -832,6 +868,47 @@ nodes | enums.swift:83:10:83:23 | ... .foo(...) [foo.0] | semmle.label | ... .foo(...) [foo.0] | | enums.swift:83:22:83:22 | x | semmle.label | x | | enums.swift:84:14:84:14 | x | semmle.label | x | +| fields.swift:18:5:18:7 | [post] box [field] | semmle.label | [post] box [field] | +| fields.swift:18:5:18:13 | ... .field | semmle.label | ... .field | +| fields.swift:18:17:18:41 | source(...) | semmle.label | source(...) | +| fields.swift:19:10:19:12 | box [field] | semmle.label | box [field] | +| fields.swift:19:10:19:18 | ... .field | semmle.label | ... .field | +| fields.swift:25:5:25:7 | [post] box [field] | semmle.label | [post] box [field] | +| fields.swift:25:5:25:13 | ... .field | semmle.label | ... .field | +| fields.swift:25:17:25:42 | source(...) | semmle.label | source(...) | +| fields.swift:26:10:26:33 | ... .field | semmle.label | ... .field | +| fields.swift:26:11:26:13 | box [field] | semmle.label | box [field] | +| fields.swift:26:11:26:26 | TypeCastExpr [field] | semmle.label | TypeCastExpr [field] | +| fields.swift:31:5:31:7 | [post] box [field] | semmle.label | [post] box [field] | +| fields.swift:31:5:31:13 | ... .field | semmle.label | ... .field | +| fields.swift:31:17:31:48 | source(...) | semmle.label | source(...) | +| fields.swift:32:10:32:40 | ... .field | semmle.label | ... .field | +| fields.swift:32:11:32:13 | box [field] | semmle.label | box [field] | +| fields.swift:32:11:32:33 | TypeCastExpr [field] | semmle.label | TypeCastExpr [field] | +| fields.swift:37:5:37:35 | ... .field | semmle.label | ... .field | +| fields.swift:37:6:37:28 | [post] TypeCastExpr [field] | semmle.label | [post] TypeCastExpr [field] | +| fields.swift:37:39:37:71 | source(...) | semmle.label | source(...) | +| fields.swift:38:10:38:12 | box [field] | semmle.label | box [field] | +| fields.swift:38:10:38:18 | ... .field | semmle.label | ... .field | +| fields.swift:43:5:43:7 | [post] box [field] | semmle.label | [post] box [field] | +| fields.swift:43:5:43:13 | ... .field | semmle.label | ... .field | +| fields.swift:43:17:43:40 | source(...) | semmle.label | source(...) | +| fields.swift:44:10:44:32 | ... .readField(...) | semmle.label | ... .readField(...) | +| fields.swift:44:29:44:31 | box [field] | semmle.label | box [field] | +| fields.swift:53:15:53:19 | super [field] | semmle.label | super [field] | +| fields.swift:53:15:53:25 | ... .field | semmle.label | ... .field | +| fields.swift:60:5:60:8 | [post] base [field] | semmle.label | [post] base [field] | +| fields.swift:60:5:60:14 | ... .field | semmle.label | ... .field | +| fields.swift:60:18:60:47 | source(...) | semmle.label | source(...) | +| fields.swift:61:9:61:11 | sub [field] | semmle.label | sub [field] | +| fields.swift:61:15:61:18 | base [field] | semmle.label | base [field] | +| fields.swift:62:10:62:12 | sub [field] | semmle.label | sub [field] | +| fields.swift:62:10:62:18 | ... .field | semmle.label | ... .field | +| fields.swift:75:5:75:7 | [post] box [field] | semmle.label | [post] box [field] | +| fields.swift:75:5:75:13 | ... .field | semmle.label | ... .field | +| fields.swift:75:17:75:41 | source(...) | semmle.label | source(...) | +| fields.swift:76:10:76:12 | box [field] | semmle.label | box [field] | +| fields.swift:76:10:76:18 | ... .field | semmle.label | ... .field | | flow-summaries.swift:2:9:2:9 | x | semmle.label | x | | flow-summaries.swift:2:13:2:26 | source(...) | semmle.label | source(...) | | flow-summaries.swift:3:9:3:9 | y | semmle.label | y | @@ -1192,6 +1269,7 @@ subpaths | capture.swift:49:13:49:13 | x | capture.swift:45:22:45:24 | arg | capture.swift:46:9:46:9 | y | capture.swift:50:10:50:10 | y | | capture.swift:60:13:60:13 | x | capture.swift:56:22:56:24 | arg | capture.swift:57:9:57:9 | [post] y [0] | capture.swift:61:10:61:10 | y [0] | | capture.swift:93:9:93:9 | x | capture.swift:99:16:99:16 | x | capture.swift:99:16:99:16 | x | capture.swift:94:13:94:19 | local(...) | +| fields.swift:62:10:62:12 | sub [field] | fields.swift:53:15:53:19 | super [field] | fields.swift:53:15:53:25 | ... .field | fields.swift:62:10:62:18 | ... .field | | flow-summaries.swift:54:35:54:48 | source(...) | flow-summaries.swift:54:53:54:53 | y | flow-summaries.swift:54:65:54:65 | y | flow-summaries.swift:54:10:54:67 | ... .throughCallback(...) | | flow-summaries.swift:55:35:55:48 | source(...) | flow-summaries.swift:55:53:55:53 | y | flow-summaries.swift:55:65:55:71 | ... + ... | flow-summaries.swift:55:10:55:73 | ... .throughCallback(...) | | test.swift:196:30:196:44 | source(...) | test.swift:189:22:189:22 | s | test.swift:189:58:189:58 | s | test.swift:196:16:196:45 | asyncIdentity(...) | @@ -1288,6 +1366,13 @@ testFailures | enums.swift:65:10:65:14 | opt_x | enums.swift:63:31:63:44 | source(...) | enums.swift:65:10:65:14 | opt_x | $@ | enums.swift:63:31:63:44 | source(...) | source(...) | | enums.swift:76:14:76:14 | x | enums.swift:73:34:73:47 | source(...) | enums.swift:76:14:76:14 | x | $@ | enums.swift:73:34:73:47 | source(...) | source(...) | | enums.swift:84:14:84:14 | x | enums.swift:73:34:73:47 | source(...) | enums.swift:84:14:84:14 | x | $@ | enums.swift:73:34:73:47 | source(...) | source(...) | +| fields.swift:19:10:19:18 | ... .field | fields.swift:18:17:18:41 | source(...) | fields.swift:19:10:19:18 | ... .field | $@ | fields.swift:18:17:18:41 | source(...) | source(...) | +| fields.swift:26:10:26:33 | ... .field | fields.swift:25:17:25:42 | source(...) | fields.swift:26:10:26:33 | ... .field | $@ | fields.swift:25:17:25:42 | source(...) | source(...) | +| fields.swift:32:10:32:40 | ... .field | fields.swift:31:17:31:48 | source(...) | fields.swift:32:10:32:40 | ... .field | $@ | fields.swift:31:17:31:48 | source(...) | source(...) | +| fields.swift:38:10:38:18 | ... .field | fields.swift:37:39:37:71 | source(...) | fields.swift:38:10:38:18 | ... .field | $@ | fields.swift:37:39:37:71 | source(...) | source(...) | +| fields.swift:44:10:44:32 | ... .readField(...) | fields.swift:43:17:43:40 | source(...) | fields.swift:44:10:44:32 | ... .readField(...) | $@ | fields.swift:43:17:43:40 | source(...) | source(...) | +| fields.swift:62:10:62:18 | ... .field | fields.swift:60:18:60:47 | source(...) | fields.swift:62:10:62:18 | ... .field | $@ | fields.swift:60:18:60:47 | source(...) | source(...) | +| fields.swift:76:10:76:18 | ... .field | fields.swift:75:17:75:41 | source(...) | fields.swift:76:10:76:18 | ... .field | $@ | fields.swift:75:17:75:41 | source(...) | source(...) | | flow-summaries.swift:4:10:4:10 | y | flow-summaries.swift:2:13:2:26 | source(...) | flow-summaries.swift:4:10:4:10 | y | $@ | flow-summaries.swift:2:13:2:26 | source(...) | source(...) | | flow-summaries.swift:11:14:11:14 | y | flow-summaries.swift:8:13:8:26 | source(...) | flow-summaries.swift:11:14:11:14 | y | $@ | flow-summaries.swift:8:13:8:26 | source(...) | source(...) | | flow-summaries.swift:18:10:18:10 | y | flow-summaries.swift:16:18:16:31 | source(...) | flow-summaries.swift:18:10:18:10 | y | $@ | flow-summaries.swift:16:18:16:31 | source(...) | source(...) | diff --git a/unified/ql/test/library-tests/dataflow/test.ext.yml b/unified/ql/test/library-tests/dataflow/test.ext.yml index 352ac28dad95..bd9f79dc0e63 100644 --- a/unified/ql/test/library-tests/dataflow/test.ext.yml +++ b/unified/ql/test/library-tests/dataflow/test.ext.yml @@ -18,3 +18,4 @@ extensions: - ["", "TestType", true, "swap(_:_:)", "", "", "Argument[1]", "Argument[0]", "value", "manual"] - ["", "TestType", true, "getField()", "", "", "Argument[self].Member[field]", "ReturnValue", "value", "manual"] - ["", "TestType", true, "setField(_:)", "", "", "Argument[0]", "Argument[self].Member[field]", "value", "manual"] + - ["", "TestType", true, "readField(_:)", "", "", "Argument[0].Member[field]", "ReturnValue", "value", "manual"] diff --git a/unified/ql/test/library-tests/local-name-binding/self_access.swift b/unified/ql/test/library-tests/local-name-binding/self_access.swift index da1132f41913..e3050195e4ce 100644 --- a/unified/ql/test/library-tests/local-name-binding/self_access.swift +++ b/unified/ql/test/library-tests/local-name-binding/self_access.swift @@ -38,3 +38,9 @@ class C { } } } + +class Sub: C { // $ access=C + func t6() { // implicit-self=t6.self + super.t1() // $ access=t6.self (we treat `super` as an alias for `self`) + } +}