From 4dca9aa9582272b7137a563a986f94a5b213a0a0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 6 Mar 2026 15:33:11 +0100 Subject: [PATCH 01/72] Rust: Small refactor in `TypeMention.qll` --- .../internal/typeinference/AssociatedType.qll | 4 +- .../internal/typeinference/TypeMention.qll | 43 +++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll index 656fd8e7ec8..8469c6da092 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/AssociatedType.qll @@ -39,8 +39,8 @@ predicate pathTypeAsTraitAssoc( /** * Holds if `assoc` is accessed on `tp` in `path`. * - * That is, this is the case when `path` is of the form `::AssocType` or `tp::AssocType`; and `AssocType` resolves to `assoc`. + * That is, this is the case when `path` is of the form `::AssocType` + * or `tp::AssocType`; and `AssocType` resolves to `assoc`. */ predicate tpAssociatedType(TypeParam tp, AssocType assoc, Path path) { resolvePath(path.getQualifier()) = tp and diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll index 631add42d04..dcb3fc0b0f4 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll @@ -699,9 +699,13 @@ class PreTypeMention = PreTypeMention::TypeMention; /** * Holds if `path` accesses an associated type `alias` from `trait` on a * concrete type given by `tm`. + * + * `implOrTmTrait` is either the mention that resolves to `trait` when `path` + * is of the form `::AssocType`, or the enclosing `impl` block + * when `path` is of the form `Self::AssocType`. */ private predicate pathConcreteTypeAssocType( - Path path, PreTypeMention tm, TraitItemNode trait, PreTypeMention tmTrait, TypeAlias alias + Path path, PreTypeMention tm, TraitItemNode trait, AstNode implOrTmTrait, TypeAlias alias ) { exists(Path qualifier | qualifier = path.getQualifier() and @@ -710,19 +714,19 @@ private predicate pathConcreteTypeAssocType( // path of the form `::AssocType` // ^^^ tm ^^^^^^^^^ name exists(string name | - pathTypeAsTraitAssoc(path, tm, tmTrait, trait, name) and + pathTypeAsTraitAssoc(path, tm, implOrTmTrait, trait, name) and getTraitAssocType(trait, name) = alias ) or // path of the form `Self::AssocType` within an `impl` block // tm ^^^^ ^^^^^^^^^ name - exists(ImplItemNode impl | - alias = resolvePath(path) and - qualifier = impl.getASelfPath() and - tm = impl.(Impl).getSelfTy() and - trait.getAnAssocItem() = alias and - tmTrait = impl.getTraitPath() - ) + implOrTmTrait = + any(ImplItemNode impl | + alias = resolvePath(path) and + qualifier = impl.getASelfPath() and + tm = impl.(Impl).getSelfTy() and + trait.getAnAssocItem() = alias + ) ) } @@ -741,21 +745,26 @@ private module PathSatisfiesConstraint = */ private Type getPathConcreteAssocTypeAt(Path path, TypePath typePath) { exists( - PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, PreTypeMention tmTrait, + PreTypeMention tm, ImplItemNode impl, TraitItemNode trait, TraitType t, AstNode implOrTmTrait, TypeAlias alias, TypePath path0 | - pathConcreteTypeAssocType(path, tm, trait, tmTrait, alias) and + pathConcreteTypeAssocType(path, tm, trait, implOrTmTrait, alias) and t = TTrait(trait) and PathSatisfiesConstraint::satisfiesConstraintTypeThrough(tm, impl, t, path0, result) and path0.isCons(TAssociatedTypeTypeParameter(trait, alias), typePath) | - tmTrait.getTypeAt(TypePath::nil()) != t + implOrTmTrait instanceof Impl or - not exists(TypePath path1, Type t1 | - t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and - not t1 instanceof TypeParameter and - t1 != tmTrait.getTypeAt(path1) - ) + // When `path` is of the form `::AssocType` we need to check + // that `impl` is not more specific than the mentioned trait + implOrTmTrait = + any(PreTypeMention tmTrait | + not exists(TypePath path1, Type t1 | + t1 = impl.getTraitPath().(PreTypeMention).getTypeAt(path1) and + not t1 instanceof TypeParameter and + t1 != tmTrait.getTypeAt(path1) + ) + ) ) } From c5360ba46cb9b096f9b89011a65105ff8d59da91 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 9 Mar 2026 12:58:08 +0000 Subject: [PATCH 02/72] Python: Fix bad join in method call order computation This join had badness 1127 on the project FiacreT/M-moire, producing ~31 million tuples in order to end up with only ~27k tuples later in the pipeline. With the fix, we reduce this by roughly the full 31 million (the new materialised helper predicate accounting for roughly 130k tuples on its own). Co-authored-by: Mathias Vorreiter Pedersen --- .../Classes/CallsToInitDel/MethodCallOrder.qll | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll b/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll index 635953168d7..232c29e7dee 100644 --- a/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll +++ b/python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll @@ -152,11 +152,7 @@ predicate missingCallToSuperclassMethod(Class base, Function shouldCall, string */ predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCall, string name) { missingCallToSuperclassMethod(base, shouldCall, name) and - not exists(Class superBase | - // Alert only on the highest base class that has the issue - superBase = getADirectSuperclass+(base) and - missingCallToSuperclassMethod(superBase, shouldCall, name) - ) and + not superclassAlsoMissesCall(base, shouldCall, name) and not exists(Function subShouldCall | // Mention in the alert only the lowest method we're missing the call to subShouldCall.getScope() = getADirectSubclass+(shouldCall.getScope()) and @@ -164,6 +160,15 @@ predicate missingCallToSuperclassMethodRestricted(Class base, Function shouldCal ) } +/** + * Holds if a strict superclass of `base` is also missing a call to `shouldCall` named `name`, + * indicating that `base` is not the highest class in the hierarchy with this issue. + */ +pragma[nomagic] +private predicate superclassAlsoMissesCall(Class base, Function shouldCall, string name) { + missingCallToSuperclassMethod(getADirectSuperclass+(base), shouldCall, name) +} + /** * If `base` contains a `super()` call, gets a method in the inheritance hierarchy of `name` in the MRO of `base` * that does not contain a `super()` call, but would call `shouldCall` if it did, which does not otherwise get called From 25a20f74f0a9d811d8adaa0037e3ada62f94c3c5 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Wed, 11 Mar 2026 11:54:18 +0000 Subject: [PATCH 03/72] Revert "Bump rules_android from 0.6.4 to 0.7.1" This reverts commit c7349740f089e97b61d985f3add7a60db4dcc2b9. It was making the build fail --- .../registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel b/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel index 162e914f894..ec37914a8f7 100644 --- a/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel +++ b/misc/bazel/registry/modules/rules_kotlin/2.2.2-codeql.1/MODULE.bazel @@ -8,7 +8,7 @@ module( bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "rules_java", version = "8.9.0") -bazel_dep(name = "rules_android", version = "0.7.1") +bazel_dep(name = "rules_android", version = "0.6.4") bazel_dep(name = "bazel_features", version = "1.25.0") bazel_dep(name = "protobuf", version = "29.0", repo_name = "com_google_protobuf") bazel_dep(name = "rules_proto", version = "6.0.2", repo_name = "rules_proto") From 1253553aeccd237d09d2c7d0f3a8aaf968ec114a Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 25 Feb 2026 09:09:51 +0100 Subject: [PATCH 04/72] JS: Add browser source kinds --- .../frameworks/data/ModelsAsData.qll | 12 +++++++ .../security/dataflow/RemoteFlowSources.qll | 36 ++++++++++++------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll index e4adff2a9ac..391f2ea1b33 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll @@ -35,6 +35,18 @@ private class RemoteFlowSourceFromMaD extends RemoteFlowSource { override string getSourceType() { result = "Remote flow" } } +private class ClientSideRemoteFlowSourceFromMaD extends ClientSideRemoteFlowSource { + private ClientSideRemoteFlowKind kind; + + ClientSideRemoteFlowSourceFromMaD() { ModelOutput::sourceNode(this, kind) } + + override ClientSideRemoteFlowKind getKind() { result = kind } + + override string getSourceType() { + result = "Source node (" + this.getThreatModel() + ") [from data-extension]" + } +} + /** * A threat-model flow source originating from a data extension. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll index 9f4975e605a..5b1424fb86e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll @@ -43,35 +43,47 @@ import Cached /** * A type of remote flow source that is specific to the browser environment. + * + * The underlying string also corresponds to a source kind. */ class ClientSideRemoteFlowKind extends string { ClientSideRemoteFlowKind() { - this = ["query", "fragment", "path", "url", "name", "message-event"] + this = + [ + "browser", "browser-url-query", "browser-url-fragment", "browser-url-path", "browser-url", + "browser-window-name", "browser-message-event" + ] } /** - * Holds if this is the `query` kind, describing sources derived from the query parameters of the browser URL, + * Holds if this is the `browser` kind, indicating a remote source in a browser context, that does not fit into one + * of the more specific kinds. + */ + predicate isGenericBrowserSourceKind() { this = "browser" } + + /** + * Holds if this is the `browser-url-query` kind, describing sources derived from the query parameters of the browser URL, * such as `location.search`. */ - predicate isQuery() { this = "query" } + predicate isQuery() { this = "browser-url-query" } /** - * Holds if this is the `frgament` kind, describing sources derived from the fragment part of the browser URL, + * Holds if this is the `browser-url-fragment` kind, describing sources derived from the fragment part of the browser URL, * such as `location.hash`. */ - predicate isFragment() { this = "fragment" } + predicate isFragment() { this = "browser-url-fragment" } /** - * Holds if this is the `path` kind, describing sources derived from the pathname of the browser URL, + * Holds if this is the `browser-url-path` kind, describing sources derived from the pathname of the browser URL, * such as `location.pathname`. */ - predicate isPath() { this = "path" } + predicate isPath() { this = "browser-url-path" } /** - * Holds if this is the `url` kind, describing sources derived from the browser URL, + * Holds if this is the `browser-url` kind, describing sources derived from the browser URL, * where the untrusted part of the URL is prefixed by trusted data, such as the scheme and hostname. */ - predicate isUrl() { this = "url" } + predicate isUrl() { this = "browser-url" } /** Holds if this is the `query` or `fragment` kind. */ predicate isQueryOrFragment() { this.isQuery() or this.isFragment() } @@ -83,13 +95,13 @@ class ClientSideRemoteFlowKind extends string { predicate isPathOrUrl() { this.isPath() or this.isUrl() } /** Holds if this is the `name` kind, describing sources derived from the window name, such as `window.name`. */ - predicate isWindowName() { this = "name" } + predicate isWindowName() { this = "browser-window-name" } /** - * Holds if this is the `message-event` kind, describing sources derived from cross-window message passing, + * Holds if this is the `browser-message-event` kind, describing sources derived from cross-window message passing, * such as `event` in `window.onmessage = event => {...}`. */ - predicate isMessageEvent() { this = "message-event" } + predicate isMessageEvent() { this = "browser-message-event" } } /** From 4a001f960f161d3f9e001af6a4dcdc84b26b46ee Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 25 Feb 2026 09:41:38 +0100 Subject: [PATCH 05/72] JS: Add tests in request forgery queries --- .../Security/CWE-918/ClientSideRequestForgery.expected | 6 ++++++ .../Security/CWE-918/ClientSideRequestForgery.ext.yml | 7 +++++++ .../query-tests/Security/CWE-918/RequestForgery.expected | 6 ++++++ .../query-tests/Security/CWE-918/RequestForgery.ext.yml | 7 +++++++ .../ql/test/query-tests/Security/CWE-918/clientSide.js | 3 +++ .../ql/test/query-tests/Security/CWE-918/serverSide.js | 3 +++ 6 files changed, 32 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml create mode 100644 javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml diff --git a/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected index 1d6b8781db7..aed2cabe358 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.expected @@ -3,6 +3,7 @@ | clientSide.js:14:5:14:64 | request ... search) | clientSide.js:14:42:14:63 | window. ... .search | clientSide.js:14:13:14:63 | 'https: ... .search | The $@ of this request depends on a $@. | clientSide.js:14:13:14:63 | 'https: ... .search | URL | clientSide.js:14:42:14:63 | window. ... .search | user-provided value | | clientSide.js:17:5:17:58 | request ... '/id') | clientSide.js:16:22:16:41 | window.location.hash | clientSide.js:17:13:17:57 | 'https: ... + '/id' | The $@ of this request depends on a $@. | clientSide.js:17:13:17:57 | 'https: ... + '/id' | URL | clientSide.js:16:22:16:41 | window.location.hash | user-provided value | | clientSide.js:21:5:21:54 | request ... '/id') | clientSide.js:20:18:20:28 | window.name | clientSide.js:21:13:21:53 | 'https: ... + '/id' | The $@ of this request depends on a $@. | clientSide.js:21:13:21:53 | 'https: ... + '/id' | URL | clientSide.js:20:18:20:28 | window.name | user-provided value | +| clientSide.js:27:5:27:19 | request(custom) | clientSide.js:26:20:26:56 | require ... ource() | clientSide.js:27:13:27:18 | custom | The $@ of this request depends on a $@. | clientSide.js:27:13:27:18 | custom | URL | clientSide.js:26:20:26:56 | require ... ource() | user-provided value | edges | clientSide.js:11:11:11:15 | query | clientSide.js:12:42:12:46 | query | provenance | | | clientSide.js:11:19:11:40 | window. ... .search | clientSide.js:11:19:11:53 | window. ... ring(1) | provenance | | @@ -16,6 +17,8 @@ edges | clientSide.js:20:11:20:14 | name | clientSide.js:21:42:21:45 | name | provenance | | | clientSide.js:20:18:20:28 | window.name | clientSide.js:20:11:20:14 | name | provenance | | | clientSide.js:21:42:21:45 | name | clientSide.js:21:13:21:53 | 'https: ... + '/id' | provenance | | +| clientSide.js:26:11:26:16 | custom | clientSide.js:27:13:27:18 | custom | provenance | | +| clientSide.js:26:20:26:56 | require ... ource() | clientSide.js:26:11:26:16 | custom | provenance | | nodes | clientSide.js:11:11:11:15 | query | semmle.label | query | | clientSide.js:11:19:11:40 | window. ... .search | semmle.label | window. ... .search | @@ -33,4 +36,7 @@ nodes | clientSide.js:20:18:20:28 | window.name | semmle.label | window.name | | clientSide.js:21:13:21:53 | 'https: ... + '/id' | semmle.label | 'https: ... + '/id' | | clientSide.js:21:42:21:45 | name | semmle.label | name | +| clientSide.js:26:11:26:16 | custom | semmle.label | custom | +| clientSide.js:26:20:26:56 | require ... ource() | semmle.label | require ... ource() | +| clientSide.js:27:13:27:18 | custom | semmle.label | custom | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml new file mode 100644 index 00000000000..950186d58df --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-918/ClientSideRequestForgery.ext.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + - ['testlib', 'Member[getBrowserSource].ReturnValue', 'browser-url-query'] + - ['testlib', 'Member[getServerSource].ReturnValue', 'remote'] diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected index 1818e116d82..79383f58521 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.expected @@ -39,6 +39,7 @@ | serverSide.js:143:5:143:26 | axios.g ... t.href) | serverSide.js:139:19:139:31 | req.query.url | serverSide.js:143:15:143:25 | target.href | The $@ of this request depends on a $@. | serverSide.js:143:15:143:25 | target.href | URL | serverSide.js:139:19:139:31 | req.query.url | user-provided value | | serverSide.js:145:5:145:25 | axios.g ... dedUrl) | serverSide.js:139:19:139:31 | req.query.url | serverSide.js:145:15:145:24 | encodedUrl | The $@ of this request depends on a $@. | serverSide.js:145:15:145:24 | encodedUrl | URL | serverSide.js:139:19:139:31 | req.query.url | user-provided value | | serverSide.js:147:5:147:25 | axios.g ... pedUrl) | serverSide.js:139:19:139:31 | req.query.url | serverSide.js:147:15:147:24 | escapedUrl | The $@ of this request depends on a $@. | serverSide.js:147:15:147:24 | escapedUrl | URL | serverSide.js:139:19:139:31 | req.query.url | user-provided value | +| serverSide.js:151:1:151:15 | request(custom) | serverSide.js:150:16:150:51 | require ... ource() | serverSide.js:151:9:151:14 | custom | The $@ of this request depends on a $@. | serverSide.js:151:9:151:14 | custom | URL | serverSide.js:150:16:150:51 | require ... ource() | user-provided value | edges | Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | Request/app/api/proxy/route2.serverSide.ts:4:11:4:13 | url | provenance | | | Request/app/api/proxy/route2.serverSide.ts:4:11:4:13 | url | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | provenance | | @@ -144,6 +145,8 @@ edges | serverSide.js:146:11:146:20 | escapedUrl | serverSide.js:147:15:147:24 | escapedUrl | provenance | | | serverSide.js:146:24:146:36 | escape(input) | serverSide.js:146:11:146:20 | escapedUrl | provenance | | | serverSide.js:146:31:146:35 | input | serverSide.js:146:24:146:36 | escape(input) | provenance | | +| serverSide.js:150:7:150:12 | custom | serverSide.js:151:9:151:14 | custom | provenance | | +| serverSide.js:150:16:150:51 | require ... ource() | serverSide.js:150:7:150:12 | custom | provenance | | nodes | Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | semmle.label | { url } | | Request/app/api/proxy/route2.serverSide.ts:4:11:4:13 | url | semmle.label | url | @@ -271,4 +274,7 @@ nodes | serverSide.js:146:24:146:36 | escape(input) | semmle.label | escape(input) | | serverSide.js:146:31:146:35 | input | semmle.label | input | | serverSide.js:147:15:147:24 | escapedUrl | semmle.label | escapedUrl | +| serverSide.js:150:7:150:12 | custom | semmle.label | custom | +| serverSide.js:150:16:150:51 | require ... ource() | semmle.label | require ... ource() | +| serverSide.js:151:9:151:14 | custom | semmle.label | custom | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml new file mode 100644 index 00000000000..950186d58df --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-918/RequestForgery.ext.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + - ['testlib', 'Member[getBrowserSource].ReturnValue', 'browser-url-query'] + - ['testlib', 'Member[getServerSource].ReturnValue', 'remote'] diff --git a/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js b/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js index aa4174cd9ab..1651fb01f44 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js @@ -22,4 +22,7 @@ export function MyComponent() { request('https://example.com/api?q=' + name); request(window.location.href + '?q=123'); + + const custom = require('testlib').getBrowserSource(); // $ Source[js/client-side-request-forgery] + request(custom) // $ Alert[js/client-side-request-forgery]; } diff --git a/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js b/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js index 38f2bb72ac3..7cf16ccb1ed 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js @@ -146,3 +146,6 @@ var server2 = http.createServer(function (req, res) { const escapedUrl = escape(input); axios.get(escapedUrl); // $ Alert[js/request-forgery] }); + +const custom = require('testlib').getServerSource(); // $ Source[js/request-forgery] +request(custom) // $ Alert[js/request-forgery]; From 72142b51f7ff5218d3ea9642883d43ef8c89d3d5 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Fri, 6 Mar 2026 14:09:47 +0100 Subject: [PATCH 06/72] C/C++ overlay: switch to updated discard strategy --- .../lib/semmle/code/cpp/internal/Overlay.qll | 129 +++++------------- 1 file changed, 37 insertions(+), 92 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll index 3dea144bbf6..a7fd8477dbe 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll @@ -6,117 +6,62 @@ private import OverlayXml /** * Holds always for the overlay variant and never for the base variant. - * This local predicate is used to define local predicates that behave - * differently for the base and overlay variant. */ overlay[local] predicate isOverlay() { databaseMetadata("isOverlay", "true") } -overlay[local] -private string getLocationFilePath(@location_default loc) { - exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result)) -} - /** - * Gets the file path for an element with a single location. + * Holds if the TRAP file or tag `t` is reachable from some source file + * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. */ overlay[local] -private string getSingleLocationFilePath(@element e) { - exists(@location_default loc | - var_decls(e, _, _, _, loc) - or - fun_decls(e, _, _, _, loc) - or - type_decls(e, _, loc) - or - namespace_decls(e, _, loc, _) - or - macroinvocations(e, _, loc, _) - or - preprocdirects(e, _, loc) - or - diagnostics(e, _, _, _, _, loc) - or - usings(e, _, loc, _) - or - static_asserts(e, _, _, loc, _) - or - derivations(e, _, _, _, loc) - or - frienddecls(e, _, _, loc) - or - comments(e, _, loc) - or - exprs(e, _, loc) - or - stmts(e, _, loc) - or - initialisers(e, _, _, loc) - or - attributes(e, _, _, _, loc) - or - attribute_args(e, _, _, _, loc) - or - namequalifiers(e, _, _, loc) - or - enumconstants(e, _, _, _, _, loc) - or - type_mentions(e, _, loc, _) - or - lambda_capture(e, _, _, _, _, _, loc) - or - concept_templates(e, _, loc) - | - result = getLocationFilePath(loc) +private predicate locallyReachableTrapOrTag(boolean isOverlayVariant, string sourceFile, @trap_or_tag t) { + exists(@source_file sf, @trap trap | + (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and + source_file_uses_trap(sf, trap) and + source_file_name(sf, sourceFile) and + (t = trap or trap_uses_tag(trap, t)) ) } /** - * Gets the file path for an element with potentially multiple locations. + * Holds if element `e` is in TRAP file or tag `t` + * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. */ overlay[local] -private string getMultiLocationFilePath(@element e) { - exists(@location_default loc | - var_decls(_, e, _, _, loc) - or - fun_decls(_, e, _, _, loc) - or - type_decls(_, e, loc) - or - namespace_decls(_, e, loc, _) - | - result = getLocationFilePath(loc) - ) -} - -/** - * A local helper predicate that holds in the base variant and never in the - * overlay variant. - */ -overlay[local] -private predicate isBase() { not isOverlay() } - -/** - * Holds if `path` was extracted in the overlay database. - */ -overlay[local] -private predicate overlayHasFile(string path) { - isOverlay() and - files(_, path) and - path != "" +private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) { + (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and + in_trap_or_tag(e, t) } /** * Discards an element from the base variant if: - * - It has a single location in a file extracted in the overlay, or - * - All of its locations are in files extracted in the overlay. + * - We have knowledge about what TRAP file or tag it is in (in the base). + * - It is not in any overlay TRAP file or tag that is reachable from an overlay source file. + * - For every base TRAP file or tag that contains it and is reachable from a base source file, + * either the source file has changed or the overlay has redefined the TRAP file or tag. */ overlay[discard_entity] private predicate discardElement(@element e) { - isBase() and - ( - overlayHasFile(getSingleLocationFilePath(e)) - or - forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path)) + // If we don't have any knowledge about what TRAP file something + // is in, then we don't want to discard it, so we only consider + // entities that are known to be in a base TRAP file or tag. + locallyInTrapOrTag(false, e, _) and + // Anything that is reachable from an overlay source file should + // not be discarded. + not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) | + locallyReachableTrapOrTag(true, _, t) + ) and + // Finally, we have to make sure that base shouldn't retain it. + // If it is reachable from a base source file, then that is + // sufficient unless either the base source file has changed (in + // particular, been deleted) or the overlay has redefined the TRAP + // file or tag it is in. + forall(@trap_or_tag t, string sourceFile | + locallyInTrapOrTag(false, e, t) and + locallyReachableTrapOrTag(false, sourceFile, t) + | + overlayChangedFiles(sourceFile) or + locallyReachableTrapOrTag(true, _, t) ) } From ef6c1a996800af8826d58443b8a97ff87e7a2e1d Mon Sep 17 00:00:00 2001 From: idrissrio Date: Fri, 6 Mar 2026 17:12:22 +0100 Subject: [PATCH 07/72] C/C++ overlay: fix failing `header_dependency` test --- cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll index a7fd8477dbe..189dd25918c 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll @@ -15,7 +15,9 @@ predicate isOverlay() { databaseMetadata("isOverlay", "true") } * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. */ overlay[local] -private predicate locallyReachableTrapOrTag(boolean isOverlayVariant, string sourceFile, @trap_or_tag t) { +private predicate locallyReachableTrapOrTag( + boolean isOverlayVariant, string sourceFile, @trap_or_tag t +) { exists(@source_file sf, @trap trap | (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and source_file_uses_trap(sf, trap) and @@ -55,13 +57,15 @@ private predicate discardElement(@element e) { // Finally, we have to make sure that base shouldn't retain it. // If it is reachable from a base source file, then that is // sufficient unless either the base source file has changed (in - // particular, been deleted) or the overlay has redefined the TRAP - // file or tag it is in. + // particular, been deleted), or the overlay has redefined the TRAP + // file or tag it is in, or the overlay runner has re-extracted the same + // source file (e.g. because a header it includes has changed). forall(@trap_or_tag t, string sourceFile | locallyInTrapOrTag(false, e, t) and locallyReachableTrapOrTag(false, sourceFile, t) | overlayChangedFiles(sourceFile) or - locallyReachableTrapOrTag(true, _, t) + locallyReachableTrapOrTag(true, _, t) or + locallyReachableTrapOrTag(true, sourceFile, _) ) } From a92d97744f44e760bdeb55f7bd19fc5488f0c865 Mon Sep 17 00:00:00 2001 From: idrissrio Date: Mon, 9 Mar 2026 16:25:29 +0100 Subject: [PATCH 08/72] C/C++ overlay: address review comment --- cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll index 189dd25918c..7ceb592330a 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll @@ -11,7 +11,7 @@ overlay[local] predicate isOverlay() { databaseMetadata("isOverlay", "true") } /** - * Holds if the TRAP file or tag `t` is reachable from some source file + * Holds if the TRAP file or tag `t` is reachable from source file `sourceFile` * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. */ overlay[local] From 48a03e2a0429b3e0d1fa7b4dc909b8535d1ad928 Mon Sep 17 00:00:00 2001 From: Idriss Riouak Date: Tue, 10 Mar 2026 08:53:33 +0100 Subject: [PATCH 09/72] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll index 7ceb592330a..e93bf578921 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/Overlay.qll @@ -41,7 +41,8 @@ private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap * - We have knowledge about what TRAP file or tag it is in (in the base). * - It is not in any overlay TRAP file or tag that is reachable from an overlay source file. * - For every base TRAP file or tag that contains it and is reachable from a base source file, - * either the source file has changed or the overlay has redefined the TRAP file or tag. + * either the source file has changed, or the overlay has redefined the TRAP file or tag, + * or the overlay runner has re-extracted the same source file. */ overlay[discard_entity] private predicate discardElement(@element e) { @@ -54,7 +55,7 @@ private predicate discardElement(@element e) { not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) | locallyReachableTrapOrTag(true, _, t) ) and - // Finally, we have to make sure that base shouldn't retain it. + // Finally, we have to make sure the base variant does not retain it. // If it is reachable from a base source file, then that is // sufficient unless either the base source file has changed (in // particular, been deleted), or the overlay has redefined the TRAP From 6fb10555ff1cd6ee901e57ab65dd1f29bf78d028 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Mar 2026 09:27:03 -0500 Subject: [PATCH 10/72] Correct comment about AES crypto algorithm strength --- go/ql/src/Security/CWE-327/examples/Crypto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/src/Security/CWE-327/examples/Crypto.go b/go/ql/src/Security/CWE-327/examples/Crypto.go index b3f71f0772b..ec34c0c6cf5 100644 --- a/go/ql/src/Security/CWE-327/examples/Crypto.go +++ b/go/ql/src/Security/CWE-327/examples/Crypto.go @@ -13,7 +13,7 @@ func EncryptMessageWeak(key []byte, message []byte) (dst []byte) { } func EncryptMessageStrong(key []byte, message []byte) (dst []byte) { - // GOOD, AES is a weak crypto algorithm + // GOOD, AES is a strong crypto algorithm block, _ := aes.NewCipher(key) block.Encrypt(dst, message) return From 5db30c994794d3a157373a074b78e5222a5c1d4f Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 11 Mar 2026 15:40:07 +0100 Subject: [PATCH 11/72] JS: Add change note --- .../ql/lib/change-notes/2026-03-11-browser-source-kinds.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md diff --git a/javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md b/javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md new file mode 100644 index 00000000000..71d06f3d1b6 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-03-11-browser-source-kinds.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for browser-specific source kinds (`browser`, `browser-url-query`, `browser-url-fragment`, `browser-url-path`, `browser-url`, `browser-window-name`, `browser-message-event`) that can be used in data extensions to model sources in browser environments. From da7da80b2b1ec88e0b14e0313ed88e133c3d28fb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:42:05 +0000 Subject: [PATCH 12/72] C++: Add pseudo-buildless test cases (some missing declarations). --- .../Arithmetic/IntMultToLong/Buildless.c | 28 +++++++++++++++++++ .../IntMultToLong/IntMultToLong.expected | 5 ++++ 2 files changed, 33 insertions(+) create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c new file mode 100644 index 00000000000..8f14110a3b9 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c @@ -0,0 +1,28 @@ +// semmle-extractor-options: --expect_errors + +void test_float_double1(float f, double d) { + float r1 = f * f; // GOOD + float r2 = f * d; // GOOD + double r3 = f * f; // BAD + double r4 = f * d; // GOOD + + float f1 = fabsf(f * f); // GOOD [FALSE POSITIVE] + float f2 = fabsf(f * d); // GOOD + double f3 = fabs(f * f); // BAD + double f4 = fabs(f * d); // GOOD +} + +double fabs(double f); +float fabsf(float f); + +void test_float_double2(float f, double d) { + float r1 = f * f; // GOOD + float r2 = f * d; // GOOD + double r3 = f * f; // BAD + double r4 = f * d; // GOOD + + float f1 = fabsf(f * f); // GOOD + float f2 = fabsf(f * d); // GOOD + double f3 = fabs(f * f); // BAD + double f4 = fabs(f * d); // GOOD +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected index 2806aaa809f..1a2427beb20 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected @@ -1,3 +1,8 @@ +| Buildless.c:6:17:6:21 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | +| Buildless.c:9:22:9:26 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | +| Buildless.c:11:22:11:26 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | +| Buildless.c:21:17:21:21 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | +| Buildless.c:26:22:26:26 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | | IntMultToLong.c:4:10:4:14 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. | | IntMultToLong.c:7:16:7:20 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. | | IntMultToLong.c:18:19:18:23 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | From 00d8a100515db3cf39cc8531bf5964e81b98fc64 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:42:30 +0000 Subject: [PATCH 13/72] C++: Add Function.hasAmbiguousReturnType. --- cpp/ql/lib/semmle/code/cpp/Function.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/Function.qll b/cpp/ql/lib/semmle/code/cpp/Function.qll index 10b156e3fb6..b5ea5b3cbc7 100644 --- a/cpp/ql/lib/semmle/code/cpp/Function.qll +++ b/cpp/ql/lib/semmle/code/cpp/Function.qll @@ -524,6 +524,14 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0)) ) } + + /** + * Holds if this function has ambiguous return type (this occurs sometimes in + * Build Mode None). + */ + predicate hasAmbiguousReturnType() { + count(this.getType()) != 1 + } } pragma[noinline] From 6552c849f0d05d706b1cff7fe5ff21ff0d345f1e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:42:28 +0000 Subject: [PATCH 14/72] C++: Fix BMN issue in cpp/integer-multiplication-cast-to-long. --- cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql | 4 +++- .../Likely Bugs/Arithmetic/IntMultToLong/Buildless.c | 6 +++--- .../Arithmetic/IntMultToLong/IntMultToLong.expected | 3 --- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql index a54ac9020c8..6747d177c80 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql +++ b/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql @@ -218,7 +218,9 @@ where // only report if we cannot prove that the result of the // multiplication will be less (resp. greater) than the // maximum (resp. minimum) number we can compute. - overflows(me, t1) + overflows(me, t1) and + // exclude cases where the expression type may not have been extracted accurately + not me.getParent().(Call).getTarget().hasAmbiguousReturnType() select me, "Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '" + me.getFullyConverted().getType().toString() + "'." diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c index 8f14110a3b9..3d01a28fae0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/Buildless.c @@ -6,9 +6,9 @@ void test_float_double1(float f, double d) { double r3 = f * f; // BAD double r4 = f * d; // GOOD - float f1 = fabsf(f * f); // GOOD [FALSE POSITIVE] + float f1 = fabsf(f * f); // GOOD float f2 = fabsf(f * d); // GOOD - double f3 = fabs(f * f); // BAD + double f3 = fabs(f * f); // BAD [NOT DETECTED] double f4 = fabs(f * d); // GOOD } @@ -23,6 +23,6 @@ void test_float_double2(float f, double d) { float f1 = fabsf(f * f); // GOOD float f2 = fabsf(f * d); // GOOD - double f3 = fabs(f * f); // BAD + double f3 = fabs(f * f); // BAD [NOT DETECTED] double f4 = fabs(f * d); // GOOD } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected index 1a2427beb20..05b2b7e1ea3 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Arithmetic/IntMultToLong/IntMultToLong.expected @@ -1,8 +1,5 @@ | Buildless.c:6:17:6:21 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | -| Buildless.c:9:22:9:26 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | -| Buildless.c:11:22:11:26 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | | Buildless.c:21:17:21:21 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | -| Buildless.c:26:22:26:26 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | | IntMultToLong.c:4:10:4:14 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. | | IntMultToLong.c:7:16:7:20 | ... * ... | Multiplication result may overflow 'int' before it is converted to 'long long'. | | IntMultToLong.c:18:19:18:23 | ... * ... | Multiplication result may overflow 'float' before it is converted to 'double'. | From 4a39055322bff79e0f2e4d3c3e283c6291440e19 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:52:34 +0000 Subject: [PATCH 15/72] C++: Change note. --- .../2026-03-11-integer-multiplication-cast-to-long.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md diff --git a/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md b/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md new file mode 100644 index 00000000000..a0efd8a8785 --- /dev/null +++ b/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed an issue with the "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query causing false positive results in Build Mode Node databases. From b9b3b3a0b52e97b837db12f047206d3939c8fb78 Mon Sep 17 00:00:00 2001 From: Mario Campos Date: Wed, 11 Mar 2026 22:37:20 -0500 Subject: [PATCH 16/72] Empty commit for missed Green Check From ca7017f3d721eb5ede1eeedad89296592e188a7b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 18 Feb 2026 08:30:40 +0100 Subject: [PATCH 17/72] Rust: Add more type inference tests --- .../type-inference/overloading.rs | 49 +++ .../type-inference/regressions.rs | 32 ++ .../type-inference/type-inference.expected | 354 ++++++++++++++++++ 3 files changed, 435 insertions(+) diff --git a/rust/ql/test/library-tests/type-inference/overloading.rs b/rust/ql/test/library-tests/type-inference/overloading.rs index 0bf6598c1d1..9d5e0f39cf7 100644 --- a/rust/ql/test/library-tests/type-inference/overloading.rs +++ b/rust/ql/test/library-tests/type-inference/overloading.rs @@ -400,3 +400,52 @@ mod from_default { x } } + +mod inherent_before_trait { + struct S(T); + + trait Trait { + fn foo(&self); + fn bar(&self); + } + + impl S { + // S::foo + fn foo(x: &Self) {} + + // S::bar + fn bar(&self) {} + } + + impl Trait for S { + // _as_Trait>::foo + fn foo(&self) { + S::foo(self); // $ MISSING: target=S::foo + S::::foo(self); // $ MISSING: target=S::foo + self.foo() // $ target=_as_Trait>::foo + } + + // _as_Trait>::bar + fn bar(&self) { + S::bar(self); // $ target=S::bar + S::::bar(self); // $ target=S::bar + self.bar() // $ target=S::bar + } + } + + impl Trait for S { + // _as_Trait>::foo + fn foo(&self) { + // `S::foo(self);` is not valid + S::::foo(self); // $ MISSING: target=_as_Trait>::foo + self.foo() // $ target=_as_Trait>::foo + } + + // _as_Trait>::bar + fn bar(&self) { + // `S::bar(self);` is not valid + S::::bar(self); // $ target=_as_Trait>::bar + self.bar() // $ target=_as_Trait>::bar + } + } +} diff --git a/rust/ql/test/library-tests/type-inference/regressions.rs b/rust/ql/test/library-tests/type-inference/regressions.rs index 9365588c64a..37c61b2b7e7 100644 --- a/rust/ql/test/library-tests/type-inference/regressions.rs +++ b/rust/ql/test/library-tests/type-inference/regressions.rs @@ -74,3 +74,35 @@ mod regression2 { let x = s1 - &s2; // $ target=S1SubRefS2 type=x:S2 } } + +mod regression3 { + trait SomeTrait {} + + trait MyFrom { + fn my_from(value: T) -> Self; + } + + impl MyFrom for T { + fn my_from(s: T) -> Self { + s + } + } + + impl MyFrom for Option { + fn my_from(val: T) -> Option { + Some(val) + } + } + + pub struct S(Ts); + + pub fn f(x: T2) -> T2 + where + T2: SomeTrait + MyFrom>, + Option: MyFrom, + { + let y = MyFrom::my_from(x); // $ target=my_from + let z = MyFrom::my_from(y); // $ target=my_from + z + } +} diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index d3ec61e9603..c9b948939ac 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -4012,6 +4012,70 @@ inferCertainType | overloading.rs:397:10:397:10 | b | | {EXTERNAL LOCATION} | bool | | overloading.rs:397:25:401:5 | { ... } | | overloading.rs:372:5:372:14 | S1 | | overloading.rs:398:20:398:20 | b | | {EXTERNAL LOCATION} | bool | +| overloading.rs:408:16:408:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:408:16:408:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:409:16:409:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:409:16:409:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:414:16:414:16 | x | | {EXTERNAL LOCATION} | & | +| overloading.rs:414:16:414:16 | x | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:414:16:414:16 | x | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:414:26:414:27 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:417:16:417:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:417:16:417:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:417:16:417:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:417:23:417:24 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:422:16:422:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:422:16:422:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:422:16:422:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:422:23:426:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:13:423:24 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:20:423:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:423:20:423:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:423:20:423:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:424:13:424:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:424:27:424:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:424:27:424:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:424:27:424:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:425:13:425:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:425:13:425:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:425:13:425:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:429:16:429:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:429:16:429:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:429:16:429:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:429:23:433:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:13:430:24 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:20:430:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:430:20:430:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:430:20:430:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:431:13:431:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:431:27:431:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:431:27:431:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:431:27:431:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:432:13:432:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:432:13:432:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:432:13:432:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:438:16:438:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:438:16:438:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:438:16:438:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:438:23:442:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:13:440:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:27:440:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:440:27:440:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:440:27:440:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:441:13:441:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:441:13:441:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:441:13:441:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:445:16:445:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:445:16:445:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:445:16:445:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:445:23:449:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:13:447:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:27:447:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:447:27:447:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:447:27:447:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:448:13:448:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:448:13:448:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:448:13:448:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:13:26:133:1 | { ... } | T | {EXTERNAL LOCATION} | () | | pattern_matching.rs:15:5:18:5 | if ... {...} | | {EXTERNAL LOCATION} | () | @@ -4960,6 +5024,17 @@ inferCertainType | regressions.rs:67:29:67:33 | other | TRef | regressions.rs:41:5:42:14 | S2 | | regressions.rs:71:14:75:5 | { ... } | | {EXTERNAL LOCATION} | () | | regressions.rs:74:22:74:24 | &s2 | | {EXTERNAL LOCATION} | & | +| regressions.rs:82:20:82:24 | value | | regressions.rs:81:18:81:18 | T | +| regressions.rs:86:20:86:20 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:86:34:88:9 | { ... } | | regressions.rs:85:10:85:10 | T | +| regressions.rs:87:13:87:13 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:92:20:92:22 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:92:41:94:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:92:41:94:9 | { ... } | T | regressions.rs:91:10:91:10 | T | +| regressions.rs:93:18:93:20 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:99:22:99:22 | x | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:103:5:107:5 | { ... } | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:33:104:33 | x | | regressions.rs:99:18:99:19 | T2 | inferType | associated_types.rs:5:15:5:18 | SelfParam | | associated_types.rs:1:1:2:21 | Wrapper | | associated_types.rs:5:15:5:18 | SelfParam | A | associated_types.rs:4:6:4:6 | A | @@ -12675,6 +12750,74 @@ inferType | overloading.rs:399:17:399:29 | ...::from(...) | | overloading.rs:372:5:372:14 | S1 | | overloading.rs:399:28:399:28 | s | | overloading.rs:364:5:365:13 | S | | overloading.rs:400:9:400:9 | x | | overloading.rs:372:5:372:14 | S1 | +| overloading.rs:408:16:408:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:408:16:408:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:409:16:409:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:409:16:409:20 | SelfParam | TRef | overloading.rs:407:5:410:5 | Self [trait Trait] | +| overloading.rs:414:16:414:16 | x | | {EXTERNAL LOCATION} | & | +| overloading.rs:414:16:414:16 | x | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:414:16:414:16 | x | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:414:26:414:27 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:417:16:417:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:417:16:417:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:417:16:417:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:417:23:417:24 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:422:16:422:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:422:16:422:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:422:16:422:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:422:23:426:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:13:423:24 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:423:20:423:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:423:20:423:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:423:20:423:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:424:13:424:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:424:27:424:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:424:27:424:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:424:27:424:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:425:13:425:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:425:13:425:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:425:13:425:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:425:13:425:22 | self.foo() | | {EXTERNAL LOCATION} | () | +| overloading.rs:429:16:429:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:429:16:429:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:429:16:429:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:429:23:433:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:13:430:24 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:430:20:430:23 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:430:20:430:23 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:430:20:430:23 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:431:13:431:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:431:27:431:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:431:27:431:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:431:27:431:30 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:432:13:432:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:432:13:432:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:432:13:432:16 | self | TRef.T | {EXTERNAL LOCATION} | i32 | +| overloading.rs:432:13:432:22 | self.bar() | | {EXTERNAL LOCATION} | () | +| overloading.rs:438:16:438:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:438:16:438:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:438:16:438:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:438:23:442:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:13:440:31 | ...::foo(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:440:27:440:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:440:27:440:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:440:27:440:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:441:13:441:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:441:13:441:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:441:13:441:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:441:13:441:22 | self.foo() | | {EXTERNAL LOCATION} | () | +| overloading.rs:445:16:445:20 | SelfParam | | {EXTERNAL LOCATION} | & | +| overloading.rs:445:16:445:20 | SelfParam | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:445:16:445:20 | SelfParam | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:445:23:449:9 | { ... } | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:13:447:31 | ...::bar(...) | | {EXTERNAL LOCATION} | () | +| overloading.rs:447:27:447:30 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:447:27:447:30 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:447:27:447:30 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:448:13:448:16 | self | | {EXTERNAL LOCATION} | & | +| overloading.rs:448:13:448:16 | self | TRef | overloading.rs:405:5:405:19 | S | +| overloading.rs:448:13:448:16 | self | TRef.T | {EXTERNAL LOCATION} | i64 | +| overloading.rs:448:13:448:22 | self.bar() | | {EXTERNAL LOCATION} | () | | pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option | | pattern_matching.rs:13:26:133:1 | { ... } | T | {EXTERNAL LOCATION} | () | | pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option | @@ -14818,4 +14961,215 @@ inferType | regressions.rs:74:22:74:24 | &s2 | | {EXTERNAL LOCATION} | & | | regressions.rs:74:22:74:24 | &s2 | TRef | regressions.rs:41:5:42:14 | S2 | | regressions.rs:74:23:74:24 | s2 | | regressions.rs:41:5:42:14 | S2 | +| regressions.rs:82:20:82:24 | value | | regressions.rs:81:18:81:18 | T | +| regressions.rs:86:20:86:20 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:86:34:88:9 | { ... } | | regressions.rs:85:10:85:10 | T | +| regressions.rs:87:13:87:13 | s | | regressions.rs:85:10:85:10 | T | +| regressions.rs:92:20:92:22 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:92:41:94:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:92:41:94:9 | { ... } | T | regressions.rs:91:10:91:10 | T | +| regressions.rs:93:13:93:21 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:93:13:93:21 | Some(...) | T | regressions.rs:91:10:91:10 | T | +| regressions.rs:93:18:93:20 | val | | regressions.rs:91:10:91:10 | T | +| regressions.rs:99:22:99:22 | x | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:103:5:107:5 | { ... } | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:104:33:104:33 | x | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | +| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | testFailures From 84d1828a9c47280ce9f6ea0de180a050cbf76ae5 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 12 Mar 2026 09:35:36 +0100 Subject: [PATCH 18/72] JavaScript extractor: recognise bun and tsx in shebang lines Update the shebang regexp (renamed NODE_INVOCATION -> JS_INVOCATION) to also match 'bun' and 'tsx' so that scripts using these runtimes are correctly identified as JavaScript files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/com/semmle/js/extractor/FileExtractor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index 9cf5c3b295c..70d6677855d 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -28,13 +28,13 @@ import com.semmle.util.trap.TrapWriter.Label; */ public class FileExtractor { /** - * Pattern to use on the shebang line of a script to identify whether it is a Node.js script. + * Pattern to use on the shebang line of a script to identify whether it is a JavaScript script. * - *

There are many different ways of invoking the Node.js interpreter (directly, through {@code + *

There are many different ways of invoking a JavaScript interpreter (directly, through {@code * env}, with or without flags, with or without modified environment, etc.), so we simply look for - * the word {@code "node"} or {@code "nodejs"}. + * the word {@code "node"}, {@code "nodejs"}, {@code "bun"}, or {@code "tsx"}. */ - private static final Pattern NODE_INVOCATION = Pattern.compile("\\bnode(js)?\\b"); + private static final Pattern JS_INVOCATION = Pattern.compile("\\b(node(js)?|bun|tsx)\\b"); /** A pattern that matches strings starting with `{ "...":`, suggesting JSON data. */ public static final Pattern JSON_OBJECT_START = @@ -157,7 +157,7 @@ public class FileExtractor { // do a cheap check first if (firstLine != null && firstLine.startsWith("#!")) { // now do the slightly more expensive one - return NODE_INVOCATION.matcher(firstLine).find(); + return JS_INVOCATION.matcher(firstLine).find(); } } catch (IOException e) { Exceptions.ignore(e, "We simply skip this file."); @@ -302,7 +302,7 @@ public class FileExtractor { int lengthOfText = endOfLine - startOfText; String text = new String(bytes, startOfText, lengthOfText, StandardCharsets.UTF_8); // Check if the shebang is a recognized JavaScript intepreter. - return !NODE_INVOCATION.matcher(text).find(); + return !JS_INVOCATION.matcher(text).find(); } @Override From b8c44be59947db13145c573382d62d5c59ab3e22 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 12 Mar 2026 09:46:35 +0100 Subject: [PATCH 19/72] Add QL test for bun/tsx shebang recognition in TypeScript files Add test files with #!/usr/bin/env bun, #!/usr/bin/env tsx, and #!/usr/bin/env node shebangs. The query lists extracted .ts files, verifying that all three shebangs are recognized and the files are not skipped by the extractor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../test/library-tests/TypeScript/Shebangs/Shebangs.expected | 4 ++++ .../ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql | 4 ++++ .../ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts | 2 ++ .../ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts | 2 ++ .../ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts | 2 ++ .../ql/test/library-tests/TypeScript/Shebangs/tsconfig.json | 3 +++ 6 files changed, 17 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected new file mode 100644 index 00000000000..3f4d018029a --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.expected @@ -0,0 +1,4 @@ +| shebang_bun.ts | +| shebang_node.ts | +| shebang_tsx.ts | +| tsconfig.json | diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql new file mode 100644 index 00000000000..1b3590b82d0 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/Shebangs.ql @@ -0,0 +1,4 @@ +import javascript + +from File f +select f.getRelativePath() diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts new file mode 100644 index 00000000000..417e04ff16a --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_bun.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env bun +const x: number = 1; diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts new file mode 100644 index 00000000000..10b11969aa5 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_node.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +const x: number = 1; diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts new file mode 100644 index 00000000000..31331240ced --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/shebang_tsx.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env tsx +const x: number = 1; diff --git a/javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json new file mode 100644 index 00000000000..82194fc7ab0 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Shebangs/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["."] +} From 1b6f3a43ef4f75187d9a050679b458b95c426a66 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 23 Feb 2026 10:41:43 +0100 Subject: [PATCH 20/72] Rust: Unify type inference logic for associated functions --- .../rust/elements/internal/ImplImpl.qll | 6 + .../elements/internal/InvocationExprImpl.qll | 2 +- .../typeinference/BlanketImplementation.qll | 23 +- .../internal/typeinference/FunctionType.qll | 239 +- .../internal/typeinference/TypeInference.qll | 2216 ++++++++--------- .../PathResolutionConsistency.expected | 6 - .../dataflow/taint/inline-taint-flow.expected | 8 + .../test/library-tests/dataflow/taint/main.rs | 4 +- .../type-inference/overloading.rs | 4 +- .../type-inference/type-inference.expected | 186 -- .../BrokenCryptoAlgorithm.expected | 6 + .../PathResolutionConsistency.expected | 2 - .../BrokenCryptoAlgorithm/test_cipher.rs | 12 +- shared/util/codeql/util/Option.qll | 3 + 14 files changed, 1273 insertions(+), 1444 deletions(-) delete mode 100644 rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected diff --git a/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll index 298e07f4b3e..3ff04276c63 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll @@ -33,5 +33,11 @@ module Impl { result = "impl " + trait + this.getSelfTy().toAbbreviatedString() + " { ... }" ) } + + /** + * Holds if this is an inherent `impl` block, that is, one that does not implement a trait. + */ + pragma[nomagic] + predicate isInherent() { not this.hasTrait() } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll index e5dd4cdaee6..412a3b51ae8 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll @@ -6,7 +6,7 @@ module Impl { private newtype TArgumentPosition = TPositionalArgumentPosition(int i) { - i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] + i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()])] } or TSelfArgumentPosition() or TTypeQualifierArgumentPosition() diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll b/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll index 51781a47305..db1402280d4 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll @@ -41,16 +41,19 @@ private predicate hasFirstNonTrivialTraitBound(TypeParamItemNode tp, Trait trait */ pragma[nomagic] predicate isBlanketLike(ImplItemNode i, TypePath blanketSelfPath, TypeParam blanketTypeParam) { - blanketTypeParam = i.getBlanketImplementationTypeParam() and - blanketSelfPath.isEmpty() - or - exists(TypeMention tm, Type root, TypeParameter tp | - tm = i.(Impl).getSelfTy() and - complexSelfRoot(root, tp) and - tm.getType() = root and - tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and - blanketSelfPath = TypePath::singleton(tp) and - hasFirstNonTrivialTraitBound(blanketTypeParam, _) + i.(Impl).hasTrait() and + ( + blanketTypeParam = i.getBlanketImplementationTypeParam() and + blanketSelfPath.isEmpty() + or + exists(TypeMention tm, Type root, TypeParameter tp | + tm = i.(Impl).getSelfTy() and + complexSelfRoot(root, tp) and + tm.getType() = root and + tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and + blanketSelfPath = TypePath::singleton(tp) and + hasFirstNonTrivialTraitBound(blanketTypeParam, _) + ) ) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index f8611ce2a3c..841f165d2c3 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -5,60 +5,112 @@ private import TypeAbstraction private import TypeMention private import TypeInference -private newtype TFunctionPosition = - TArgumentFunctionPosition(ArgumentPosition pos) or - TReturnFunctionPosition() +private signature predicate includeSelfSig(); + +// We construct `FunctionPosition` and `FunctionPositionAdj` using two different underlying +// `newtype`s in order to prevent unintended mixing of the two +private module MkFunctionPosition { + private newtype TFunctionPosition = + TArgumentFunctionPosition(ArgumentPosition pos) { + if pos.isSelf() then includeSelf() else any() + } or + TReturnFunctionPosition() + + class FunctionPosition extends TFunctionPosition { + int asPosition() { result = this.asArgumentPosition().asPosition() } + + predicate isPosition() { exists(this.asPosition()) } + + ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) } + + predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() } + + predicate isReturn() { this = TReturnFunctionPosition() } + + TypeMention getTypeMention(Function f) { + result = f.getParam(this.asPosition()).getTypeRepr() + or + this.isReturn() and + result = getReturnTypeMention(f) + } + + string toString() { + result = this.asArgumentPosition().toString() + or + this.isReturn() and + result = "(return)" + } + } +} + +private predicate any_() { any() } /** * A position of a type related to a function. * * Either `self`, `return`, or a positional parameter index. */ -class FunctionPosition extends TFunctionPosition { +final class FunctionPosition extends MkFunctionPosition::FunctionPosition { predicate isSelf() { this.asArgumentPosition().isSelf() } - int asPosition() { result = this.asArgumentPosition().asPosition() } - - predicate isPosition() { exists(this.asPosition()) } - - ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) } - - predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() } - predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() } - predicate isReturn() { this = TReturnFunctionPosition() } - - /** Gets the corresponding position when `f` is invoked via a function call. */ - bindingset[f] - FunctionPosition getFunctionCallAdjusted(Function f) { - this.isReturn() and - result = this + override TypeMention getTypeMention(Function f) { + result = super.getTypeMention(f) or - if f.hasSelfParam() - then - this.isSelf() and result.asPosition() = 0 - or - result.asPosition() = this.asPosition() + 1 - else result = this - } - - TypeMention getTypeMention(Function f) { this.isSelf() and result = getSelfParamTypeMention(f.getSelfParam()) - or - result = f.getParam(this.asPosition()).getTypeRepr() - or - this.isReturn() and - result = getReturnTypeMention(f) } - string toString() { - result = this.asArgumentPosition().toString() + /** + * Gets the corresponding position when function call syntax is used, assuming + * this position is for a method. + */ + pragma[nomagic] + FunctionPositionAdj getFunctionCallAdjusted() { + this.isReturn() and result.isReturn() or - this.isReturn() and - result = "(return)" + this.isTypeQualifier() and + result.isTypeQualifier() + or + this.isSelf() and result.asPosition() = 0 + or + result.asPosition() = this.asPosition() + 1 } + + /** + * Gets the corresponding position when function call syntax is used, assuming + * this position is _not_ for a method. + */ + pragma[nomagic] + FunctionPositionAdj asAdjusted() { + this.isReturn() and result.isReturn() + or + this.isTypeQualifier() and + result.isTypeQualifier() + or + result.asPosition() = this.asPosition() + } + + /** + * Gets the corresponding position when `f` is invoked via function call + * syntax. + */ + bindingset[f] + FunctionPositionAdj getFunctionCallAdjusted(Function f) { + if f.hasSelfParam() then result = this.getFunctionCallAdjusted() else result = this.asAdjusted() + } +} + +private predicate none_() { none() } + +/** + * A function-call adjust position of a type related to a function. + * + * Either `return` or a positional parameter index. + */ +final class FunctionPositionAdj extends MkFunctionPosition::FunctionPosition { + FunctionPosition asNonAdjusted() { this = result.asAdjusted() } } /** @@ -75,6 +127,20 @@ module FunctionPositionMatchingInput { } } +/** + * A helper module for implementing `Matching(WithEnvironment)InputSig` with + * `DeclarationPosition = AccessPosition = FunctionPositionAdj`. + */ +module FunctionPositionAdjMatchingInput { + class DeclarationPosition = FunctionPositionAdj; + + class AccessPosition = DeclarationPosition; + + predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { + apos = dpos + } +} + private newtype TAssocFunctionType = /** An associated function `f` in `parent` should be specialized for `i` at `pos`. */ MkAssocFunctionType( @@ -197,8 +263,7 @@ class AssocFunctionType extends MkAssocFunctionType { exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) | result = pos.getTypeMention(f) or - pos.isSelf() and - not f.hasSelfParam() and + pos.isTypeQualifier() and result = [i.(Impl).getSelfTy().(AstNode), i.(Trait).getName()] ) } @@ -209,7 +274,7 @@ class AssocFunctionType extends MkAssocFunctionType { } pragma[nomagic] -private Trait getALookupTrait(Type t) { +Trait getALookupTrait(Type t) { result = t.(TypeParamTypeParameter).getTypeParam().(TypeParamItemNode).resolveABound() or result = t.(SelfTypeParameter).getTrait() @@ -310,12 +375,13 @@ signature module ArgsAreInstantiationsOfInputSig { * Holds if `f` inside `i` needs to have the type corresponding to type parameter * `tp` checked. * - * If `i` is an inherent implementation, `tp` is a type parameter of the type being - * implemented, otherwise `tp` is a type parameter of the trait (being implemented). + * `tp` is a type parameter of the trait being implemented by `f` or the trait to which + * `f` belongs. * - * `pos` is one of the positions in `f` in which the relevant type occours. + * `posAdj` is one of the function-call adjusted positions in `f` in which the relevant + * type occurs. */ - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos); + predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPositionAdj posAdj); /** A call whose argument types are to be checked. */ class Call { @@ -323,7 +389,7 @@ signature module ArgsAreInstantiationsOfInputSig { Location getLocation(); - Type getArgType(FunctionPosition pos, TypePath path); + Type getArgType(FunctionPositionAdj posAdj, TypePath path); predicate hasTargetCand(ImplOrTraitItemNode i, Function f); } @@ -337,9 +403,9 @@ signature module ArgsAreInstantiationsOfInputSig { module ArgsAreInstantiationsOf { pragma[nomagic] private predicate toCheckRanked( - ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, int rnk + ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPositionAdj posAdj, int rnk ) { - Input::toCheck(i, f, tp, pos) and + Input::toCheck(i, f, tp, posAdj) and tp = rank[rnk + 1](TypeParameter tp0, int j | Input::toCheck(i, f, tp0, _) and @@ -351,53 +417,59 @@ module ArgsAreInstantiationsOf { pragma[nomagic] private predicate toCheck( - ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, AssocFunctionType t + ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPositionAdj posAdj, + AssocFunctionType t ) { - Input::toCheck(i, f, tp, pos) and - t.appliesTo(f, i, pos) + exists(FunctionPosition pos | + Input::toCheck(i, f, tp, posAdj) and + t.appliesTo(f, i, pos) and + posAdj = pos.getFunctionCallAdjusted(f) + ) } - private newtype TCallAndPos = - MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) } + private newtype TCallAndPosAdj = + MkCallAndPosAdj(Input::Call call, FunctionPositionAdj posAdj) { + exists(call.getArgType(posAdj, _)) + } - /** A call tagged with a position. */ - private class CallAndPos extends MkCallAndPos { + /** A call tagged with a function-call adjusted position. */ + private class CallAndPosAdj extends MkCallAndPosAdj { Input::Call call; - FunctionPosition pos; + FunctionPositionAdj posAdj; - CallAndPos() { this = MkCallAndPos(call, pos) } + CallAndPosAdj() { this = MkCallAndPosAdj(call, posAdj) } Input::Call getCall() { result = call } - FunctionPosition getPos() { result = pos } + FunctionPositionAdj getPosAdj() { result = posAdj } Location getLocation() { result = call.getLocation() } - Type getTypeAt(TypePath path) { result = call.getArgType(pos, path) } + Type getTypeAt(TypePath path) { result = call.getArgType(posAdj, path) } - string toString() { result = call.toString() + " [arg " + pos + "]" } + string toString() { result = call.toString() + " [arg " + posAdj + "]" } } pragma[nomagic] private predicate potentialInstantiationOf0( - CallAndPos cp, Input::Call call, TypeParameter tp, FunctionPosition pos, Function f, + CallAndPosAdj cp, Input::Call call, TypeParameter tp, FunctionPositionAdj posAdj, Function f, TypeAbstraction abs, AssocFunctionType constraint ) { - cp = MkCallAndPos(call, pragma[only_bind_into](pos)) and + cp = MkCallAndPosAdj(call, pragma[only_bind_into](posAdj)) and call.hasTargetCand(abs, f) and - toCheck(abs, f, tp, pragma[only_bind_into](pos), constraint) + toCheck(abs, f, tp, pragma[only_bind_into](posAdj), constraint) } private module ArgIsInstantiationOfToIndexInput implements - IsInstantiationOfInputSig + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint + CallAndPosAdj cp, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(Input::Call call, TypeParameter tp, FunctionPosition pos, int rnk, Function f | - potentialInstantiationOf0(cp, call, tp, pos, f, abs, constraint) and - toCheckRanked(abs, f, tp, pos, rnk) + exists(Input::Call call, TypeParameter tp, FunctionPositionAdj posAdj, int rnk, Function f | + potentialInstantiationOf0(cp, call, tp, posAdj, f, abs, constraint) and + toCheckRanked(abs, f, tp, posAdj, rnk) | rnk = 0 or @@ -409,24 +481,25 @@ module ArgsAreInstantiationsOf { } private module ArgIsInstantiationOfToIndex = - ArgIsInstantiationOf; + ArgIsInstantiationOf; pragma[nomagic] private predicate argIsInstantiationOf( - Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i, Function f, int rnk + Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and - toCheckRanked(i, f, _, pos, rnk) + exists(FunctionPositionAdj posAdj | + ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPosAdj(call, posAdj), i, _) and + toCheckRanked(i, f, _, posAdj, rnk) + ) } pragma[nomagic] private predicate argsAreInstantiationsOfToIndex( Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - exists(FunctionPosition pos | - argIsInstantiationOf(call, pos, i, f, rnk) and - call.hasTargetCand(i, f) - | + argIsInstantiationOf(call, i, f, rnk) and + call.hasTargetCand(i, f) and + ( rnk = 0 or argsAreInstantiationsOfToIndex(call, i, f, rnk - 1) @@ -448,11 +521,11 @@ module ArgsAreInstantiationsOf { } private module ArgsAreNotInstantiationOfInput implements - IsInstantiationOfInputSig + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint + CallAndPosAdj cp, TypeAbstraction abs, AssocFunctionType constraint ) { potentialInstantiationOf0(cp, _, _, _, _, abs, constraint) } @@ -461,13 +534,13 @@ module ArgsAreInstantiationsOf { } private module ArgsAreNotInstantiationOf = - ArgIsInstantiationOf; + ArgIsInstantiationOf; pragma[nomagic] private predicate argsAreNotInstantiationsOf0( - Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i + Input::Call call, FunctionPositionAdj posAdj, ImplOrTraitItemNode i ) { - ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _) + ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPosAdj(call, posAdj), i, _, _) } /** @@ -478,10 +551,10 @@ module ArgsAreInstantiationsOf { */ pragma[nomagic] predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) { - exists(FunctionPosition pos | - argsAreNotInstantiationsOf0(call, pos, i) and + exists(FunctionPositionAdj posAdj | + argsAreNotInstantiationsOf0(call, posAdj, i) and call.hasTargetCand(i, f) and - Input::toCheck(i, f, _, pos) + Input::toCheck(i, f, _, posAdj) ) } } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 70dfe9e9005..295b5b84b2c 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -298,14 +298,17 @@ private class FunctionDeclaration extends Function { } pragma[nomagic] - Type getParameterType(ImplOrTraitItemNodeOption i, FunctionPosition pos, TypePath path) { + Type getParameterType(ImplOrTraitItemNodeOption i, FunctionPositionAdj posAdj, TypePath path) { i = parent and ( - not pos.isReturn() and - result = getAssocFunctionTypeAt(this, i.asSome(), pos, path) + exists(FunctionPosition pos | + not pos.isReturn() and + result = getAssocFunctionTypeAt(this, i.asSome(), pos, path) and + posAdj = pos.getFunctionCallAdjusted(this) + ) or i.isNone() and - result = this.getParam(pos.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) + result = this.getParam(posAdj.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) ) } @@ -343,6 +346,10 @@ private class FunctionDeclaration extends Function { } } +private class AssocFunction extends FunctionDeclaration { + AssocFunction() { this.isAssoc(_) } +} + pragma[nomagic] private TypeMention getCallExprTypeMentionArgument(CallExpr ce, TypeArgumentPosition apos) { exists(Path p, int i | p = CallExprImpl::getFunctionPath(ce) | @@ -1106,6 +1113,43 @@ private Trait getCallExprTraitQualifier(CallExpr ce) { ) } +pragma[nomagic] +private predicate nonAssocFunction(ItemNode i) { not i instanceof AssocFunction } + +/** + * A call expression that can resolve to something that is not an associated + * function, and hence does not need type inference for resolution. + */ +private class NonAssocCallExpr extends CallExpr { + NonAssocCallExpr() { + forex(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | nonAssocFunction(i)) + } + + /** + * Gets the target of this call, which can be resolved using only path resolution. + */ + ItemNode resolveCallTargetViaPathResolution() { result = CallExprImpl::getResolvedFunction(this) } + + pragma[nomagic] + Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = getCallExprTypeArgument(this, apos, path) + } + + AstNode getNodeAt(FunctionPosition pos) { + result = this.getSyntacticArgument(pos.asArgumentPosition()) + or + result = this and pos.isReturn() + } + + pragma[nomagic] + Type getInferredType(FunctionPosition pos, TypePath path) { + pos.isTypeQualifier() and + result = getCallExprTypeQualifier(this, path, false) + or + result = inferType(this.getNodeAt(pos), path) + } +} + /** * Provides functionality related to context-based typing of calls. */ @@ -1236,42 +1280,6 @@ private module ContextTyping { } } -/** - * Holds if function `f` with the name `name` and the arity `arity` exists in - * `i`, and the type at position `pos` is `t`. - */ -pragma[nomagic] -private predicate assocFunctionInfo( - Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos, - AssocFunctionType t -) { - f = i.getASuccessor(name) and - arity = f.getParamList().getNumberOfParams() and - t.appliesTo(f, i, pos) -} - -/** - * Holds if function `f` with the name `name` and the arity `arity` exists in - * blanket (like) implementation `impl` of `trait`, and the type at position - * `pos` is `t`. - * - * `blanketPath` points to the type `blanketTypeParam` inside `t`, which - * is the type parameter used in the blanket implementation. - */ -pragma[nomagic] -private predicate functionInfoBlanketLike( - Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition pos, - AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam -) { - exists(TypePath blanketSelfPath | - assocFunctionInfo(f, name, arity, impl, pos, t) and - TTypeParamTypeParameter(blanketTypeParam) = t.getTypeAt(blanketPath) and - blanketPath = any(string s) + blanketSelfPath and - BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) and - trait = impl.resolveTraitTy() - ) -} - /** * Holds if the type path `path` pointing to `type` is stripped of any leading * complex root type allowed for `self` parameters, such as `&`, `Box`, `Rc`, @@ -1327,7 +1335,7 @@ private class BorrowKind extends TBorrowKind { } /** - * Provides logic for resolving calls to methods. + * Provides logic for resolving calls to associated functions. * * When resolving a method call, a list of [candidate receiver types][1] is constructed * @@ -1361,190 +1369,356 @@ private class BorrowKind extends TBorrowKind { * * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ -private module MethodResolution { +private module AssocFunctionResolution { /** - * Holds if method `m` with the name `name` and the arity `arity` exists in - * `i`, and the type of the `self` parameter is `selfType`. + * Holds if function `f` with the name `name` and the arity `arity` exists in + * `i`, and the type at function-call adjusted position `posAdj` is `t`. + */ + pragma[nomagic] + private predicate assocFunctionInfo( + Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPositionAdj posAdj, + AssocFunctionType t + ) { + exists(FunctionPosition pos | + f = i.getASuccessor(name) and + arity = f.getNumberOfParamsInclSelf() and + t.appliesTo(f, i, pos) and + posAdj = pos.getFunctionCallAdjusted(f) + ) + } + + /** + * Holds if the non-method trait function `f` mentions the implicit `Self` type + * parameter at position `pos`. + */ + pragma[nomagic] + private predicate traitSelfTypeParameterOccurrence( + TraitItemNode trait, NonMethodFunction f, FunctionPosition pos + ) { + FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _, TSelfTypeParameter(trait)) + } + + /** + * Holds if the non-method function `f` implements a trait function that mentions + * the implicit `Self` type parameter at position `pos`. + */ + pragma[nomagic] + private predicate traitImplSelfTypeParameterOccurrence( + ImplItemNode impl, NonMethodFunction f, FunctionPosition pos + ) { + exists(NonMethodFunction traitFunction | + f = impl.getAnAssocItem() and + f.implements(traitFunction) and + traitSelfTypeParameterOccurrence(_, traitFunction, pos) + ) + } + + private module TypeOption = Option; + + private class TypeOption = TypeOption::Option; + + /** + * Holds if function `f` with the name `name` and the arity `arity` exists in + * `i`, and the type at function-call adjusted position `selfPosAdj` is `selfType`. * - * `strippedTypePath` points to the type `strippedType` inside `selfType`, - * which is the (possibly complex-stripped) root type of `selfType`. For example, - * if `m` has a `&self` parameter, then `strippedTypePath` is `getRefSharedTypeParameter()` + * `selfPosAdj` is a position relevant for call resolution: either a position + * corresponding to the `self` parameter of `f` (if present); a type qualifier + * position; or a position where the implicit `Self` type parameter of some trait + * is mentioned in some non-method function `f_trait`, and either `f = f_trait` + * or `f` implements `f_trait`. + * + * `strippedTypePath` points to the type `strippedType` inside `selfType`, which + * is the (possibly complex-stripped) root type of `selfType`. For example, if + * `f` has a `&self` parameter, then `strippedTypePath` is `getRefSharedTypeParameter()` * and `strippedType` is the type inside the reference. + * + * `implType` is the type being implemented by `i` (`None` when `i` is a trait). + * + * `trait` is the trait being implemented by `i` or `i` itself (`None` when `i` is inherent). + * + * `isMethod` indicates whether `f` is a method. */ pragma[nomagic] - private predicate methodInfo( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType + private predicate assocFunctionInfo( + Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, TypeOption implType, + TypeOption trait, boolean isMethod ) { - assocFunctionInfo(m, name, arity, i, selfPos, selfType) and + assocFunctionInfo(f, name, arity, i, selfPosAdj, selfType) and strippedType = selfType.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - selfPos.isSelfOrTypeQualifier() - } - - pragma[nomagic] - private predicate methodInfoTypeParam( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, TypeParam tp - ) { - methodInfo(m, name, arity, selfPos, i, selfType, strippedTypePath, TTypeParamTypeParameter(tp)) - } - - /** - * Same as `methodInfo`, but restricted to non-blanket implementations, and - * allowing for any `strippedType` when the corresponding type inside `m` is - * a type parameter. - */ - pragma[inline] - private predicate methodInfoNonBlanket( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType - ) { ( - methodInfo(m, name, arity, selfPos, i, selfType, strippedTypePath, strippedType) or - methodInfoTypeParam(m, name, arity, selfPos, i, selfType, strippedTypePath, _) + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPosAdj.isTypeQualifier() and strippedTypePath.isEmpty() ) and - not BlanketImplementation::isBlanketLike(i, _, _) + ( + f instanceof Method and + selfPosAdj.asPosition() = 0 + or + selfPosAdj.isTypeQualifier() + or + exists(FunctionPosition pos | selfPosAdj = pos.asAdjusted() | + traitSelfTypeParameterOccurrence(i, f, pos) + or + traitImplSelfTypeParameterOccurrence(i, f, pos) + ) + ) and + ( + implType.asSome() = resolveImplSelfTypeAt(i, TypePath::nil()) + or + i instanceof Trait and + implType.isNone() + ) and + ( + trait.asSome() = + [ + TTrait(i).(Type), + TTrait(i.(ImplItemNode).resolveTraitTy()).(Type) + ] + or + i.(Impl).isInherent() and trait.isNone() + ) and + if f instanceof Method then isMethod = true else isMethod = false } /** - * Holds if method `m` with the name `name` and the arity `arity` exists in - * blanket (like) implementation `impl` of `trait`, and the type of the `self` - * parameter is `selfType`. + * Holds if function `f` with the name `name` and the arity `arity` exists in + * blanket (like) implementation `impl`, and the type at function-call adjusted + * position `selfPosAdj` is `selfType`. + * + * `selfPosAdj` is a position relevant for call resolution: either a position + * corresponding to the `self` parameter of `f` (if present); a type qualifier + * position; or a position where the implicit `Self` type parameter of some trait + * is mentioned in some non-method function `f_trait`, and `f` implements `f_trait`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. + * + * `implType` is the type being implemented by `i`. + * + * `trait` is the trait being implemented by `i`. + * + * `isMethod` indicates whether `f` is a method. */ pragma[nomagic] - private predicate methodInfoBlanketLike( - Method m, string name, int arity, FunctionPosition selfPos, ImplItemNode impl, Trait trait, - AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam + private predicate assocFunctionInfoBlanketLike( + Function f, string name, int arity, ImplItemNode impl, TypeOption implType, TypeOption trait, + FunctionPositionAdj selfPosAdj, AssocFunctionType selfType, TypePath blanketPath, + TypeParam blanketTypeParam, boolean isMethod ) { - functionInfoBlanketLike(m, name, arity, impl, trait, selfPos, selfType, blanketPath, - blanketTypeParam) and - selfPos.isSelfOrTypeQualifier() + exists(TypePath blanketSelfPath | + assocFunctionInfo(f, name, arity, selfPosAdj, impl, selfType, _, _, implType, trait, isMethod) and + TTypeParamTypeParameter(blanketTypeParam) = selfType.getTypeAt(blanketPath) and + blanketPath = any(string s) + blanketSelfPath and + BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) + ) } pragma[nomagic] - private predicate methodTraitInfo(string name, int arity, Trait trait) { + private predicate assocFunctionTraitInfo(string name, int arity, Trait trait) { exists(ImplItemNode i | - methodInfo(_, name, arity, _, i, _, _, _) and + assocFunctionInfo(_, name, arity, i, _, _) and trait = i.resolveTraitTy() ) or - methodInfo(_, name, arity, _, trait, _, _, _) + assocFunctionInfo(_, name, arity, trait, _, _) } pragma[nomagic] - private predicate methodCallTraitCandidate(Element mc, Trait trait) { - mc = - any(MethodCall mc0 | + private predicate assocFunctionCallTraitCandidate(Element afc, Trait trait) { + afc = + any(AssocFunctionCall afc0 | exists(string name, int arity | - mc0.hasNameAndArity(name, arity) and - methodTraitInfo(name, arity, trait) - | - not mc0.hasTrait() - or - trait = mc0.getTrait() + afc0.hasNameAndArity(name, arity) and + assocFunctionTraitInfo(name, arity, trait) and + // we only need to check visibility of traits that are not mentioned explicitly + not afc0.hasATrait() ) ) } - private module MethodTraitIsVisible = TraitIsVisible; + private module AssocFunctionTraitIsVisible = TraitIsVisible; - private predicate methodCallVisibleTraitCandidate = MethodTraitIsVisible::traitIsVisible/2; - - bindingset[mc, impl] + bindingset[afc, impl] pragma[inline_late] - private predicate methodCallVisibleImplTraitCandidate(MethodCall mc, ImplItemNode impl) { - methodCallVisibleTraitCandidate(mc, impl.resolveTraitTy()) + private predicate callVisibleImplTraitCandidate(AssocFunctionCall afc, ImplItemNode impl) { + AssocFunctionTraitIsVisible::traitIsVisible(afc, impl.resolveTraitTy()) } /** - * Holds if method call `mc` may target a method in `i` with `self` parameter having - * type `selfType`. + * Checks that the explicit type qualifier of a call (if any), `typeQualifier`, + * matches the type being implemented by the target, `implType`. + */ + bindingset[implType] + private predicate callTypeQualifierCheck(TypeOption implType, TypeOption typeQualifier) { + typeQualifier = [implType, TypeOption::none_()] + } + + /** + * Checks that the explicit trait qualifier of a call (if any), `traitQualifier`, + * matches the trait being implemented by the target (or in which the target is defined), + * `trait`, and that when a receiver is present in the call, the target is a method. + */ + bindingset[trait, isMethod] + pragma[inline_late] + private predicate callTraitQualifierAndReceiverCheck( + TypeOption trait, Boolean isMethod, TypeOption traitQualifier, boolean hasReceiver + ) { + traitQualifier = [trait, TypeOption::none_()] and + hasReceiver = [isMethod, false] + } + + bindingset[implType, trait, isMethod] + private predicate callCheck( + TypeOption implType, TypeOption trait, Boolean isMethod, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + callTypeQualifierCheck(implType, typeQualifier) and + callTraitQualifierAndReceiverCheck(trait, isMethod, traitQualifier, hasReceiver) + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeCheck( + Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver + ) { + exists(TypeOption implType, TypeOption trait, boolean isMethod | + assocFunctionInfo(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, strippedType, + implType, trait, isMethod) and + not BlanketImplementation::isBlanketLike(i, _, _) and + callCheck(implType, trait, isMethod, typeQualifier, traitQualifier, hasReceiver) + ) + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeTypeParamCheck( + Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, + TTypeParamTypeParameter(_), typeQualifier, traitQualifier, hasReceiver) + } + + /** + * Holds if call `afc` may target function `f` in `i` with type `selfType` at + * function-call adjusted position `selfPosAdj`. * * `strippedTypePath` points to the type `strippedType` inside `selfType`, * which is the (possibly complex-stripped) root type of `selfType`. - * - * This predicate only checks for matching method names and arities, and whether - * the trait being implemented by `i` (when `i` is not a trait itself) is visible - * at `mc`. */ - bindingset[mc, strippedTypePath, strippedType] + bindingset[afc, strippedTypePath, strippedType] pragma[inline_late] - private predicate methodCallNonBlanketCandidate( - MethodCall mc, Method m, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType self, TypePath strippedTypePath, Type strippedType + private predicate nonBlanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoNonBlanket(m, name, arity, selfPos, i, self, strippedTypePath, strippedType) + exists( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver | - i = - any(Impl impl | - not impl.hasTrait() - or - methodCallVisibleImplTraitCandidate(mc, impl) - ) + afc.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and + if not afc.hasATrait() and i.(Impl).hasTrait() + then callVisibleImplTraitCandidate(afc, i) + else any() + | + assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPosAdj, i, selfType, + strippedTypePath, strippedType, typeQualifier, traitQualifier, hasReceiver) or - methodCallVisibleTraitCandidate(mc, i) - or - i.(ImplItemNode).resolveTraitTy() = mc.getTrait() + assocFunctionInfoNonBlanketLikeTypeParamCheck(f, name, arity, selfPosAdj, i, selfType, + strippedTypePath, typeQualifier, traitQualifier, hasReceiver) + ) + } + + bindingset[name, arity, typeQualifier, traitQualifier, hasReceiver] + pragma[inline_late] + private predicate assocFunctionInfoBlanketLikeCheck( + Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplItemNode impl, + AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver + ) { + exists(TypeOption implType, TypeOption trait, boolean isMethod | + assocFunctionInfoBlanketLike(f, name, arity, impl, implType, trait, selfPosAdj, selfType, + blanketPath, blanketTypeParam, isMethod) and + callTraitQualifierAndReceiverCheck(trait, isMethod, traitQualifier, hasReceiver) and + if impl.isBlanketImplementation() + then any() + else callTypeQualifierCheck(implType, typeQualifier) ) } /** - * Holds if method call `mc` may target a method in blanket (like) implementation - * `impl` with `self` parameter having type `selfType`. + * Holds if call `afc` may target function `f` in blanket (like) implementation + * `impl` with type `selfType` at function-call adjusted position `selfPosAdj`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. - * - * This predicate only checks for matching method names and arities, and whether - * the trait being implemented by `i` (when `i` is not a trait itself) is visible - * at `mc`. */ - bindingset[mc] + bindingset[afc] pragma[inline_late] - private predicate methodCallBlanketLikeCandidate( - MethodCall mc, Method m, FunctionPosition selfPos, ImplItemNode impl, AssocFunctionType self, - TypePath blanketPath, TypeParam blanketTypeParam + private predicate blanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPositionAdj selfPosAdj, ImplItemNode impl, + AssocFunctionType self, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoBlanketLike(m, name, arity, selfPos, impl, _, self, blanketPath, blanketTypeParam) + exists( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver | - methodCallVisibleImplTraitCandidate(mc, impl) - or - impl.resolveTraitTy() = mc.getTrait() + afc.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and + assocFunctionInfoBlanketLikeCheck(f, name, arity, selfPosAdj, impl, self, blanketPath, + blanketTypeParam, typeQualifier, traitQualifier, hasReceiver) + | + if not afc.hasATrait() then callVisibleImplTraitCandidate(afc, impl) else any() ) } /** - * A (potential) method call. + * A (potential) call to an associated function. * * This is either: * - * 1. `MethodCallMethodCallExpr`: an actual method call, `x.m()`; - * 2. `MethodCallIndexExpr`: an index expression, `x[i]`, which is [syntactic sugar][1] + * 1. `AssocFunctionCallMethodCallExpr`: a method call, `x.m()`; + * 2. `AssocFunctionCallIndexExpr`: an index expression, `x[i]`, which is [syntactic sugar][1] * for `*x.index(i)`; - * 3. `MethodCallCallExpr`: a qualified function call, `Q::m(x)`, where `m` is a method; - * or - * 4. `MethodCallOperation`: an operation expression, `x + y`, which is syntactic sugar + * 3. `AssocFunctionCallCallExpr`: a qualified function call, `Q::f(x)`; or + * 4. `AssocFunctionCallOperation`: an operation expression, `x + y`, which is syntactic sugar * for `Add::add(x, y)`. * * Note that only in case 1 and 2 is auto-dereferencing and borrowing allowed. * - * Note also that only case 4 is a _potential_ method call; in all other cases, we are - * guaranteed that the target is a method. + * Note also that only case 3 is a _potential_ call; in all other cases, we are guaranteed that + * the target is an associated function (in fact, a method). * * [1]: https://doc.rust-lang.org/std/ops/trait.Index.html */ - abstract class MethodCall extends Expr { + abstract class AssocFunctionCall extends Expr { + /** + * Holds if this call targets a function named `name` with `arity` parameters + * (including `self`). + */ + pragma[nomagic] abstract predicate hasNameAndArity(string name, int arity); - abstract Expr getArg(ArgumentPosition pos); + abstract Expr getNonReturnNodeAt(FunctionPosition pos); + + FunctionPositionAdj getFunctionCallAdjustedPosition(FunctionPosition pos) { + if this.hasReceiver() + then result = pos.getFunctionCallAdjusted() + else result = pos.asAdjusted() + } + + AstNode getNodeAt(FunctionPositionAdj posAdj) { + exists(FunctionPosition pos | + result = this.getNonReturnNodeAt(pos) and + posAdj = this.getFunctionCallAdjustedPosition(pos) + ) + or + result = this and posAdj.isReturn() + } + + /** Holds if this call has a receiver and hence must target a method. */ + abstract predicate hasReceiver(); abstract predicate supportsAutoDerefAndBorrow(); @@ -1554,163 +1728,242 @@ private module MethodResolution { /** Holds if this call targets a trait. */ predicate hasTrait() { exists(this.getTrait()) } - AstNode getNodeAt(FunctionPosition apos) { - result = this.getArg(apos.asArgumentPosition()) + Trait getATrait() { + result = this.getTrait() or - result = this and apos.isReturn() + result = getALookupTrait(getCallExprTypeQualifier(this, TypePath::nil(), _)) } - Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = inferType(this.getArg(pos), path) + predicate hasATrait() { exists(this.getATrait()) } + + private Type getNonTypeParameterTypeQualifier() { + result = getCallExprTypeQualifier(this, TypePath::nil(), _) and + not result instanceof TypeParameter } /** - * Same as `getACandidateReceiverTypeAt`, but without borrows. + * Holds if this call has the given purely syntactic information, that is, + * information that does not rely on type inference. */ pragma[nomagic] - Type getACandidateReceiverTypeAtNoBorrow( - FunctionPosition selfPos, DerefChain derefChain, TypePath path + predicate hasSyntacticInfo( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver ) { - result = this.getArgumentTypeAt(selfPos.asArgumentPosition(), path) and - selfPos.isSelfOrTypeQualifier() and - derefChain.isEmpty() - or - exists(DerefImplItemNode impl, DerefChain suffix | - result = - ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPos, impl, suffix, path) and - derefChain = DerefChain::cons(impl, suffix) + this.hasNameAndArity(name, arity) and + (if this.hasReceiver() then hasReceiver = true else hasReceiver = false) and + ( + typeQualifier.asSome() = this.getNonTypeParameterTypeQualifier() + or + not exists(this.getNonTypeParameterTypeQualifier()) and + typeQualifier.isNone() + ) and + ( + traitQualifier.asSome() = TTrait(this.getATrait()) + or + not this.hasATrait() and + traitQualifier.isNone() ) } + Type getTypeAt(FunctionPositionAdj posAdj, TypePath path) { + result = inferType(this.getNodeAt(posAdj), path) + } + /** - * Holds if the method inside `i` with matching name and arity can be ruled + * Holds if `selfPosAdj` is a potentially relevant function-call adjusted position + * for resolving this call. + * + * Only holds when we don't know for sure that the target is a method (in those + * cases we rely on the receiver only). + */ + pragma[nomagic] + private predicate isRelevantSelfPosAdj(FunctionPositionAdj selfPosAdj) { + not this.hasReceiver() and + exists(TypePath strippedTypePath, Type strippedType | + strippedType = substituteLookupTraits(this.getTypeAt(selfPosAdj, strippedTypePath)) and + strippedType != TNeverType() and + strippedType != TUnknownType() + | + nonBlanketLikeCandidate(this, _, selfPosAdj, _, _, strippedTypePath, strippedType) + or + blanketLikeCandidate(this, _, selfPosAdj, _, _, strippedTypePath, _) + ) + } + + predicate hasReceiverAtPos(FunctionPositionAdj posAdj) { + this.hasReceiver() and posAdj.asPosition() = 0 + } + + /** + * Holds if the function inside `i` with matching name and arity can be ruled * out as a target of this call, because the candidate receiver type represented - * by `derefChain` and `borrow` is incompatible with the `self` parameter type. + * by `derefChain` and `borrow` is incompatible with the type at function-call + * adjusted position `selfPosAdj`. * * The types are incompatible because they disagree on a concrete type somewhere * inside `root`. */ pragma[nomagic] private predicate hasIncompatibleTarget( - ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, - Type root + ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, DerefChain derefChain, + BorrowKind borrow, Type root ) { exists(TypePath path | - ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, selfPos, - derefChain, borrow), i, _, path) and + SelfArgIsInstantiationOf::argIsNotInstantiationOf(this, i, selfPosAdj, derefChain, borrow, + path) and path.isCons(root.getATypeParameter(), _) ) + or + exists(AssocFunctionType selfType | + SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, selfPosAdj, derefChain, borrow, + selfType) and + OverloadedCallArgsAreInstantiationsOf::argsAreNotInstantiationsOf(this, i) and + root = selfType.getTypeAt(TypePath::nil()) + ) } /** - * Holds if the method inside blanket-like implementation `impl` with matching name + * Holds if the function inside blanket-like implementation `impl` with matching name * and arity can be ruled out as a target of this call, either because the candidate - * receiver type represented by `derefChain` and `borrow` is incompatible with the `self` - * parameter type, or because the blanket constraint is not satisfied. + * receiver type represented by `derefChain` and `borrow` is incompatible with the type + * at function-call adjusted position `selfPosAdj`, or because the blanket constraint + * is not satisfied. */ pragma[nomagic] private predicate hasIncompatibleBlanketLikeTarget( - ImplItemNode impl, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ImplItemNode impl, FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow ) { - ReceiverIsNotInstantiationOfBlanketLikeSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, - selfPos, derefChain, borrow), impl, _, _) + SelfArgIsNotInstantiationOfBlanketLike::argIsNotInstantiationOf(MkAssocFunctionCallCand(this, + selfPosAdj, derefChain, borrow), impl, _, _) or - ReceiverSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkMethodCallCand(this, - selfPos, derefChain, borrow), impl) + ArgSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkAssocFunctionCallCand(this, + selfPosAdj, derefChain, borrow), impl) + } + + pragma[nomagic] + private predicate hasNoInherentTargetCheck( + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow + ) { + MkAssocFunctionCallCand(this, selfPosAdj, derefChain, borrow) + .(AssocFunctionCallCand) + .hasNoInherentTargetCheck() + } + + pragma[nomagic] + private predicate hasNoInherentTargetTypeQualifierCheck() { + exists(FunctionPositionAdj typeQualifierPos | + typeQualifierPos.isTypeQualifier() and + this.hasNoInherentTargetCheck(typeQualifierPos, DerefChain::nil(), TNoBorrowKind()) + ) + } + + pragma[nomagic] + predicate hasNoInherentTarget( + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow + ) { + this.hasNoInherentTargetCheck(selfPosAdj, derefChain, borrow) and + if exists(this.getNonTypeParameterTypeQualifier()) and not selfPosAdj.isTypeQualifier() + then + // If this call is of the form `Foo::bar(x)` and we are resolving with respect to the type + // of `x`, then we additionally need to check that the type qualifier does not give rise + // to an inherent target + this.hasNoInherentTargetTypeQualifierCheck() + else any() } /** - * Same as `getACandidateReceiverTypeAt`, but excludes pseudo types `!` and `unknown`. + * Same as `getSelfTypeAt`, but excludes pseudo types `!` and `unknown`. */ pragma[nomagic] - Type getANonPseudoCandidateReceiverTypeAt( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path + Type getANonPseudoSelfTypeAt( + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAt(selfPos, derefChain, borrow, path) and + result = this.getSelfTypeAt(selfPosAdj, derefChain, borrow, path) and result != TNeverType() and result != TUnknownType() } pragma[nomagic] - private Type getComplexStrippedType( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath + private Type getComplexStrippedSelfType( + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath ) { - result = - this.getANonPseudoCandidateReceiverTypeAt(selfPos, derefChain, borrow, strippedTypePath) and - isComplexRootStripped(strippedTypePath, result) + result = this.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, strippedTypePath) and + ( + isComplexRootStripped(strippedTypePath, result) + or + selfPosAdj.isTypeQualifier() and strippedTypePath.isEmpty() + ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketLikeTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType ) { forall(ImplOrTraitItemNode i | - methodCallNonBlanketCandidate(this, _, selfPos, i, _, strippedTypePath, strippedType) + nonBlanketLikeCandidate(this, _, selfPosAdj, i, _, strippedTypePath, strippedType) | - this.hasIncompatibleTarget(i, selfPos, derefChain, borrow, strippedType) + this.hasIncompatibleTarget(i, selfPosAdj, derefChain, borrow, strippedType) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, - strippedType) and - forall(ImplItemNode i | methodCallBlanketLikeCandidate(this, _, selfPos, i, _, _, _) | - this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, borrow, + strippedTypePath, strippedType) and + forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) | + this.hasIncompatibleBlanketLikeTarget(i, selfPosAdj, derefChain, borrow) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, - strippedType) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, borrow, + strippedTypePath, strippedType) and forall(ImplItemNode i | - methodCallBlanketLikeCandidate(this, _, selfPos, i, _, _, _) and + blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) and not i.isBlanketImplementation() | - this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) + this.hasIncompatibleBlanketLikeTarget(i, selfPosAdj, derefChain, borrow) ) } // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetNoBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - ( - this.supportsAutoDerefAndBorrow() - or - // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - derefChain.isEmpty() - ) and + this.supportsAutoDerefAndBorrow() and + this.hasReceiverAtPos(selfPosAdj) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, - n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) + this.hasNoCompatibleTargetNoBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, + strippedType, n - 1) and + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleTargetCheck(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain` does not - * have a matching method target. + * have a matching call target at function-call adjusted position `selfPosAdj`. */ pragma[nomagic] - predicate hasNoCompatibleTargetNoBorrow(FunctionPosition selfPos, DerefChain derefChain) { + predicate hasNoCompatibleTargetNoBorrow(FunctionPositionAdj selfPosAdj, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleTargetNoBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1718,38 +1971,44 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { ( - this.supportsAutoDerefAndBorrow() + this.supportsAutoDerefAndBorrow() and + this.hasReceiverAtPos(selfPosAdj) or - // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - derefChain.isEmpty() + // needed for the `hasNoCompatibleNonBlanketTarget` check in + // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` + exists(ImplItemNode i | + derefChain.isEmpty() and + blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) and + i.isBlanketImplementation() + ) ) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TNoBorrowKind(), + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain` does not have - * a matching non-blanket method target. + * a matching non-blanket call target at function-call adjusted position `selfPosAdj`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetNoBorrow( - FunctionPosition selfPos, DerefChain derefChain + FunctionPositionAdj selfPosAdj, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1757,30 +2016,35 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetSharedBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), - strippedTypePath, t) + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, + TSomeBorrowKind(false), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching method target. + * by a shared borrow, does not have a matching call target at function-call + * adjusted position `selfPosAdj`. */ pragma[nomagic] - predicate hasNoCompatibleTargetSharedBorrow(FunctionPosition selfPos, DerefChain derefChain) { + predicate hasNoCompatibleTargetSharedBorrow( + FunctionPositionAdj selfPosAdj, DerefChain derefChain + ) { exists(Type strippedType | - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1788,30 +2052,33 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetMutBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(true), + strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching method target. + * by a `mut` borrow, does not have a matching call target at function-call + * adjusted position `selfPosAdj`. */ pragma[nomagic] - predicate hasNoCompatibleTargetMutBorrow(FunctionPosition selfPos, DerefChain derefChain) { + predicate hasNoCompatibleTargetMutBorrow(FunctionPositionAdj selfPosAdj, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1819,32 +2086,35 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPosAdj, derefChain, + strippedTypePath, strippedType, n - 1) and + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching non-blanket method target. + * by a shared borrow, does not have a matching non-blanket call target at + * function-call adjusted position `selfPosAdj`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetSharedBorrow( - FunctionPosition selfPos, DerefChain derefChain + FunctionPositionAdj selfPosAdj, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, _, + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1852,38 +2122,68 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and + this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(true), + strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching non-blanket method target. + * by a `mut` borrow, does not have a matching non-blanket call target at + * function-call adjusted position `selfPosAdj`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetMutBorrow( - FunctionPosition selfPos, DerefChain derefChain + FunctionPositionAdj selfPosAdj, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(strippedType)) + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPosAdj, derefChain, _, + strippedType, getLastLookupTypeIndex(strippedType)) ) } /** - * Gets a [candidate receiver type][1] of this method call at `path`. + * Same as `getSelfTypeAt`, but without borrows. + */ + pragma[nomagic] + Type getSelfTypeAtNoBorrow(FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath path) { + result = this.getTypeAt(selfPosAdj, path) and + derefChain.isEmpty() and + ( + this.hasReceiverAtPos(selfPosAdj) + or + selfPosAdj.isTypeQualifier() + or + this.isRelevantSelfPosAdj(selfPosAdj) + ) + or + exists(DerefImplItemNode impl, DerefChain suffix | + result = + ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPosAdj, impl, suffix, path) and + derefChain = DerefChain::cons(impl, suffix) + ) + } + + /** + * Gets the type of this call at function-call adjusted position `selfPosAdj` and + * type path `path`. + * + * In case this call supports auto-dereferencing and borrowing and `selfPosAdj` is + * position 0 (corresponding to the receiver), the result is a + * [candidate receiver type][1]: * * The type is obtained by repeatedly dereferencing the receiver expression's type, * as long as the method cannot be resolved in an earlier candidate type, and possibly @@ -1895,20 +2195,19 @@ private module MethodResolution { * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ pragma[nomagic] - Type getACandidateReceiverTypeAt( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path + Type getSelfTypeAt( + FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, path) and + result = this.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, path) and borrow.isNoBorrow() or exists(RefType rt | // first try shared borrow - this.supportsAutoDerefAndBorrow() and - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and borrow.isSharedBorrow() or // then try mutable borrow - this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPosAdj, derefChain) and borrow.isMutableBorrow() | rt = borrow.getRefType() and @@ -1917,7 +2216,7 @@ private module MethodResolution { result = rt or exists(TypePath suffix | - result = this.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, suffix) and + result = this.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, suffix) and path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) ) ) @@ -1925,15 +2224,18 @@ private module MethodResolution { } /** - * Gets a method that this call resolves to after having applied a sequence of - * dereferences and possibly a borrow on the receiver type, encoded in `derefChain` - * and `borrow`. + * Gets a function that this call resolves to after having applied a sequence of + * dereferences and possibly a borrow on the receiver type at `selfPosAdj`, encoded + * in `derefChain` and `borrow`. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow) { - exists(MethodCallCand mcc | - mcc = MkMethodCallCand(this, _, derefChain, borrow) and - result = mcc.resolveCallTarget(i) + AssocFunction resolveCallTarget( + ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, DerefChain derefChain, + BorrowKind borrow + ) { + exists(AssocFunctionCallCand afcc | + afcc = MkAssocFunctionCallCand(this, selfPosAdj, derefChain, borrow) and + result = afcc.resolveCallTarget(i) ) } @@ -1943,21 +2245,25 @@ private module MethodResolution { * resolve the call target. */ predicate argumentHasImplicitDerefChainBorrow(Expr arg, DerefChain derefChain, BorrowKind borrow) { - exists(this.resolveCallTarget(_, derefChain, borrow)) and - arg = this.getArg(any(ArgumentPosition apos | apos.isSelf())) and - not (derefChain.isEmpty() and borrow.isNoBorrow()) + exists(FunctionPositionAdj selfAdj | + this.hasReceiverAtPos(selfAdj) and + exists(this.resolveCallTarget(_, selfAdj, derefChain, borrow)) and + arg = this.getNodeAt(selfAdj) and + not (derefChain.isEmpty() and borrow.isNoBorrow()) + ) } } - private class MethodCallMethodCallExpr extends MethodCall instanceof MethodCallExpr { - pragma[nomagic] + private class AssocFunctionCallMethodCallExpr extends AssocFunctionCall instanceof MethodCallExpr { override predicate hasNameAndArity(string name, int arity) { name = super.getIdentifier().getText() and - arity = super.getArgList().getNumberOfArgs() + arity = super.getNumberOfSyntacticArguments() } - override Expr getArg(ArgumentPosition pos) { - result = MethodCallExpr.super.getSyntacticArgument(pos) + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = super.getSyntacticArgument(pos.asArgumentPosition()) } override predicate supportsAutoDerefAndBorrow() { any() } @@ -1965,24 +2271,25 @@ private module MethodResolution { override Trait getTrait() { none() } } - private class MethodCallIndexExpr extends MethodCall instanceof IndexExpr { + private class AssocFunctionCallIndexExpr extends AssocFunctionCall, IndexExpr { private predicate isInMutableContext() { // todo: does not handle all cases yet VariableImpl::assignmentOperationDescendant(_, this) } - pragma[nomagic] override predicate hasNameAndArity(string name, int arity) { (if this.isInMutableContext() then name = "index_mut" else name = "index") and - arity = 1 + arity = 2 } - override Expr getArg(ArgumentPosition pos) { + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { pos.isSelf() and - result = super.getBase() + result = this.getBase() or pos.asPosition() = 0 and - result = super.getIndex() + result = this.getIndex() } override predicate supportsAutoDerefAndBorrow() { any() } @@ -1994,95 +2301,88 @@ private module MethodResolution { } } - private class MethodCallCallExpr extends MethodCall instanceof CallExpr { - MethodCallCallExpr() { + private class AssocFunctionCallCallExpr extends AssocFunctionCall, CallExpr { + AssocFunctionCallCallExpr() { exists(getCallExprPathQualifier(this)) and - // even if a method cannot be resolved by path resolution, it may still + // even if a target cannot be resolved by path resolution, it may still // be possible to resolve a blanket implementation (so not `forex`) - forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof Method) + forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof AssocFunction) } - pragma[nomagic] override predicate hasNameAndArity(string name, int arity) { name = CallExprImpl::getFunctionPath(this).getText() and - arity = super.getArgList().getNumberOfArgs() - 1 + arity = this.getNumberOfSyntacticArguments() } - override Expr getArg(ArgumentPosition pos) { - pos.isSelf() and - result = super.getSyntacticPositionalArgument(0) - or - result = super.getSyntacticPositionalArgument(pos.asPosition() + 1) + override predicate hasReceiver() { none() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = this.getSyntacticPositionalArgument(pos.asPosition()) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = super.getArgumentTypeAt(pos, path) + override Type getTypeAt(FunctionPositionAdj posAdj, TypePath path) { + result = super.getTypeAt(posAdj, path) or - pos.isTypeQualifier() and + posAdj.isTypeQualifier() and result = getCallExprTypeQualifier(this, path, _) } - pragma[nomagic] - predicate hasNoInherentTarget() { - // `_` is fine below, because auto-deref/borrow is not supported - MkMethodCallCand(this, _, _, _).(MethodCallCand).hasNoInherentTarget() - } - override predicate supportsAutoDerefAndBorrow() { none() } override Trait getTrait() { result = getCallExprTraitQualifier(this) } } - final class MethodCallOperation extends MethodCall instanceof Operation { - pragma[nomagic] + final class AssocFunctionCallOperation extends AssocFunctionCall, Operation { override predicate hasNameAndArity(string name, int arity) { - super.isOverloaded(_, name, _) and - arity = super.getNumberOfOperands() - 1 + this.isOverloaded(_, name, _) and + arity = this.getNumberOfOperands() } - override Expr getArg(ArgumentPosition pos) { + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { pos.isSelf() and - result = super.getOperand(0) + result = this.getOperand(0) or - result = super.getOperand(pos.asPosition() + 1) + result = this.getOperand(pos.asPosition() + 1) } - private predicate implicitBorrowAt(ArgumentPosition pos, boolean isMutable) { - exists(int borrows | super.isOverloaded(_, _, borrows) | - pos.isSelf() and + private predicate implicitBorrowAt(FunctionPositionAdj posAdj, boolean isMutable) { + exists(int borrows | this.isOverloaded(_, _, borrows) | + posAdj.asPosition() = 0 and borrows >= 1 and if this instanceof CompoundAssignmentExpr then isMutable = true else isMutable = false or - pos.asPosition() = 0 and + posAdj.asPosition() = 1 and borrows = 2 and isMutable = false ) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { + override Type getTypeAt(FunctionPositionAdj posAdj, TypePath path) { exists(boolean isMutable, RefType rt | - this.implicitBorrowAt(pos, isMutable) and + this.implicitBorrowAt(posAdj, isMutable) and rt = getRefType(isMutable) | result = rt and path.isEmpty() or exists(TypePath path0 | - result = inferType(this.getArg(pos), path0) and + result = inferType(this.getNodeAt(posAdj), path0) and path = TypePath::cons(rt.getPositionalTypeParameter(0), path0) ) ) or - not this.implicitBorrowAt(pos, _) and - result = inferType(this.getArg(pos), path) + not this.implicitBorrowAt(posAdj, _) and + result = inferType(this.getNodeAt(posAdj), path) } override predicate argumentHasImplicitDerefChainBorrow( Expr arg, DerefChain derefChain, BorrowKind borrow ) { - exists(ArgumentPosition apos, boolean isMutable | - this.implicitBorrowAt(apos, isMutable) and - arg = this.getArg(apos) and + exists(FunctionPositionAdj posAdj, boolean isMutable | + this.implicitBorrowAt(posAdj, isMutable) and + arg = this.getNodeAt(posAdj) and derefChain = DerefChain::nil() and borrow = TSomeBorrowKind(isMutable) ) @@ -2090,164 +2390,194 @@ private module MethodResolution { override predicate supportsAutoDerefAndBorrow() { none() } - override Trait getTrait() { super.isOverloaded(result, _, _) } + override Trait getTrait() { this.isOverloaded(result, _, _) } } pragma[nomagic] - private Method getMethodSuccessor(ImplOrTraitItemNode i, string name, int arity) { + private AssocFunction getAssocFunctionSuccessor(ImplOrTraitItemNode i, string name, int arity) { result = i.getASuccessor(name) and - arity = result.getParamList().getNumberOfParams() + arity = result.getNumberOfParamsInclSelf() } - private newtype TMethodCallCand = - MkMethodCallCand( - MethodCall mc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + private newtype TAssocFunctionCallCand = + MkAssocFunctionCallCand( + AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, DerefChain derefChain, + BorrowKind borrow ) { - exists(mc.getACandidateReceiverTypeAt(selfPos, derefChain, borrow, _)) + exists(afc.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, _)) } - /** A method call with a dereference chain and a potential borrow. */ - private class MethodCallCand extends MkMethodCallCand { - MethodCall mc_; - FunctionPosition selfPos; + /** A call with a dereference chain and a potential borrow at a given position. */ + final private class AssocFunctionCallCand extends MkAssocFunctionCallCand { + AssocFunctionCall afc_; + FunctionPositionAdj selfPosAdj_; DerefChain derefChain; BorrowKind borrow; - MethodCallCand() { this = MkMethodCallCand(mc_, selfPos, derefChain, borrow) } + AssocFunctionCallCand() { + this = MkAssocFunctionCallCand(afc_, selfPosAdj_, derefChain, borrow) + } - MethodCall getMethodCall() { result = mc_ } + AssocFunctionCall getAssocFunctionCall() { result = afc_ } Type getTypeAt(TypePath path) { result = - substituteLookupTraits(mc_.getANonPseudoCandidateReceiverTypeAt(selfPos, derefChain, borrow, - path)) + substituteLookupTraits(afc_.getANonPseudoSelfTypeAt(selfPosAdj_, derefChain, borrow, path)) } pragma[nomagic] predicate hasNoCompatibleNonBlanketTarget() { - mc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPosAdj_, derefChain) and borrow.isSharedBorrow() or - mc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPosAdj_, derefChain) and borrow.isMutableBorrow() or - mc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPosAdj_, derefChain) and borrow.isNoBorrow() } pragma[nomagic] predicate hasSignature( - MethodCall mc, FunctionPosition selfPos_, TypePath strippedTypePath, Type strippedType, - string name, int arity + AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, TypePath strippedTypePath, + Type strippedType, string name, int arity ) { strippedType = this.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - mc = mc_ and - mc.hasNameAndArity(name, arity) and - selfPos = selfPos_ + ( + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPosAdj_.isTypeQualifier() and strippedTypePath.isEmpty() + ) and + afc = afc_ and + afc.hasNameAndArity(name, arity) and + selfPosAdj = selfPosAdj_ } /** - * Holds if the inherent method inside `impl` with matching name and arity can be + * Holds if the inherent function inside `impl` with matching name and arity can be * ruled out as a candidate for this call. */ pragma[nomagic] private predicate hasIncompatibleInherentTarget(Impl impl) { - ReceiverIsNotInstantiationOfInherentSelfParam::argIsNotInstantiationOf(this, impl, _, _) + SelfArgIsNotInstantiationOfInherent::argIsNotInstantiationOf(this, impl, _, _) } - /** - * Holds if this method call has no inherent target, i.e., it does not - * resolve to a method in an `impl` block for the type of the receiver. - */ pragma[nomagic] - predicate hasNoInherentTarget() { - mc_.hasTrait() - or - exists(TypePath strippedTypePath, Type strippedType, string name, int arity | - this.hasSignature(_, selfPos, strippedTypePath, strippedType, name, arity) and + predicate hasNoInherentTargetCheck() { + exists( + TypePath strippedTypePath, Type strippedType, string name, int arity, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver, + boolean targetMustBeMethod + | + // Calls to inherent functions are always of the form `x.m(...)` or `Foo::bar(...)`, + // where `Foo` is a type. In case `bar` is a method, we can use both the type qualifier + // and the type of the first argument to rule out candidates + selfPosAdj_.isTypeQualifier() and targetMustBeMethod = false + or + selfPosAdj_.asPosition() = 0 and targetMustBeMethod = true + | + afc_.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and + (if hasReceiver = true then targetMustBeMethod = true else any()) and + this.hasSignature(_, selfPosAdj_, strippedTypePath, strippedType, name, arity) and forall(Impl i | - methodInfoNonBlanket(_, name, arity, selfPos, i, _, strippedTypePath, strippedType) and - not i.hasTrait() + i.isInherent() and + ( + assocFunctionInfoNonBlanketLikeCheck(_, name, arity, selfPosAdj_, i, _, + strippedTypePath, strippedType, typeQualifier, traitQualifier, targetMustBeMethod) + or + assocFunctionInfoNonBlanketLikeTypeParamCheck(_, name, arity, selfPosAdj_, i, _, + strippedTypePath, typeQualifier, traitQualifier, targetMustBeMethod) + ) | this.hasIncompatibleInherentTarget(i) ) ) } + /** + * Holds if this function call has no inherent target, i.e., it does not + * resolve to a function in an `impl` block for the type of the receiver. + */ pragma[nomagic] - private predicate argIsInstantiationOf(ImplOrTraitItemNode i, string name, int arity) { - ReceiverIsInstantiationOfSelfParam::argIsInstantiationOf(this, i, _) and - mc_.hasNameAndArity(name, arity) + predicate hasNoInherentTarget() { + afc_.hasTrait() + or + afc_.hasNoInherentTarget(selfPosAdj_, derefChain, borrow) } pragma[nomagic] - Method resolveCallTargetCand(ImplOrTraitItemNode i) { + private predicate selfArgIsInstantiationOf(ImplOrTraitItemNode i, string name, int arity) { + SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, _) and + afc_.hasNameAndArity(name, arity) + } + + pragma[nomagic] + AssocFunction resolveCallTargetCand(ImplOrTraitItemNode i) { exists(string name, int arity | - this.argIsInstantiationOf(i, name, arity) and - result = getMethodSuccessor(i, name, arity) + this.selfArgIsInstantiationOf(i, name, arity) and + result = getAssocFunctionSuccessor(i, name, arity) ) } - /** Gets a method that matches this method call. */ + /** Gets the associated function targeted by this call, if any. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i) { + AssocFunction resolveCallTarget(ImplOrTraitItemNode i) { result = this.resolveCallTargetCand(i) and not FunctionOverloading::functionResolutionDependsOnArgument(i, result, _, _) or - MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) + OverloadedCallArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) } string toString() { - result = mc_.toString() + " [" + derefChain.toString() + "; " + borrow + "]" + result = afc_ + " at " + selfPosAdj_ + " [" + derefChain.toString() + "; " + borrow + "]" } - Location getLocation() { result = mc_.getLocation() } + Location getLocation() { result = afc_.getLocation() } } /** * Provides logic for resolving implicit `Deref::deref` calls. */ private module ImplicitDeref { - private newtype TMethodCallDerefCand = - MkMethodCallDerefCand(MethodCall mc, FunctionPosition selfPos, DerefChain derefChain) { - mc.supportsAutoDerefAndBorrow() and - mc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and - exists(mc.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) + private newtype TCallDerefCand = + MkCallDerefCand(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, DerefChain derefChain) { + afc.supportsAutoDerefAndBorrow() and + afc.hasReceiverAtPos(selfPosAdj) and + afc.hasNoCompatibleTargetMutBorrow(selfPosAdj, derefChain) and + exists(afc.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, TypePath::nil())) } - /** A method call with a dereference chain. */ - private class MethodCallDerefCand extends MkMethodCallDerefCand { - MethodCall mc; - FunctionPosition selfPos; + /** A call with a dereference chain. */ + private class CallDerefCand extends MkCallDerefCand { + AssocFunctionCall afc; + FunctionPositionAdj selfPosAdj; DerefChain derefChain; - MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, selfPos, derefChain) } + CallDerefCand() { this = MkCallDerefCand(afc, selfPosAdj, derefChain) } Type getTypeAt(TypePath path) { - result = - substituteLookupTraits(mc.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, path)) and + result = substituteLookupTraits(afc.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, path)) and result != TNeverType() and result != TUnknownType() } - string toString() { result = mc.toString() + " [" + derefChain.toString() + "]" } + string toString() { result = afc + " [" + derefChain.toString() + "]" } - Location getLocation() { result = mc.getLocation() } + Location getLocation() { result = afc.getLocation() } } - private module MethodCallSatisfiesDerefConstraintInput implements - SatisfiesConstraintInputSig + private module CallSatisfiesDerefConstraintInput implements + SatisfiesConstraintInputSig { pragma[nomagic] - predicate relevantConstraint(MethodCallDerefCand mc, Type constraint) { + predicate relevantConstraint(CallDerefCand mc, Type constraint) { exists(mc) and constraint.(TraitType).getTrait() instanceof DerefTrait } } - private module MethodCallSatisfiesDerefConstraint = - SatisfiesConstraint; + private module CallSatisfiesDerefConstraint = + SatisfiesConstraint; pragma[nomagic] private AssociatedTypeTypeParameter getDerefTargetTypeParameter() { @@ -2255,38 +2585,38 @@ private module MethodResolution { } /** - * Gets the type of the receiver of `mc` at `path` after applying the implicit + * Gets the type of the receiver of `afc` at `path` after applying the implicit * dereference inside `impl`, following the existing dereference chain `derefChain`. */ pragma[nomagic] Type getDereferencedCandidateReceiverType( - MethodCall mc, FunctionPosition selfPos, DerefImplItemNode impl, DerefChain derefChain, - TypePath path + AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, DerefImplItemNode impl, + DerefChain derefChain, TypePath path ) { - exists(MethodCallDerefCand mcc, TypePath exprPath | - mcc = MkMethodCallDerefCand(mc, selfPos, derefChain) and - MethodCallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(mcc, impl, _, exprPath, - result) and + exists(CallDerefCand cdc, TypePath exprPath | + cdc = MkCallDerefCand(afc, selfPosAdj, derefChain) and + CallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(cdc, impl, _, exprPath, result) and exprPath.isCons(getDerefTargetTypeParameter(), path) ) } } - private module ReceiverSatisfiesBlanketLikeConstraintInput implements - BlanketImplementation::SatisfiesBlanketConstraintInputSig + private module ArgSatisfiesBlanketLikeConstraintInput implements + BlanketImplementation::SatisfiesBlanketConstraintInputSig { pragma[nomagic] predicate hasBlanketCandidate( - MethodCallCand mcc, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam + AssocFunctionCallCand afcc, ImplItemNode impl, TypePath blanketPath, + TypeParam blanketTypeParam ) { - exists(MethodCall mc, FunctionPosition selfPos, BorrowKind borrow | - mcc = MkMethodCallCand(mc, selfPos, _, borrow) and - methodCallBlanketLikeCandidate(mc, _, selfPos, impl, _, blanketPath, blanketTypeParam) and + exists(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, BorrowKind borrow | + afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, borrow) and + blanketLikeCandidate(afc, _, selfPosAdj, impl, _, blanketPath, blanketTypeParam) and // Only apply blanket implementations when no other implementations are possible; // this is to account for codebases that use the (unstable) specialization feature // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as // cases where our blanket implementation filtering is not precise enough. - (mcc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation()) + if impl.isBlanketImplementation() then afcc.hasNoCompatibleNonBlanketTarget() else any() | borrow.isNoBorrow() or @@ -2295,116 +2625,147 @@ private module MethodResolution { } } - private module ReceiverSatisfiesBlanketLikeConstraint = - BlanketImplementation::SatisfiesBlanketConstraint; + private module ArgSatisfiesBlanketLikeConstraint = + BlanketImplementation::SatisfiesBlanketConstraint; /** - * A configuration for matching the type of a receiver against the type of - * a `self` parameter. + * A configuration for matching the type of an argument against the type of + * a function at a function-call adjusted position relevant for dispatch + * (such as a `self` parameter). */ - private module ReceiverIsInstantiationOfSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsInstantiationOfInput implements + IsInstantiationOfInputSig { pragma[nomagic] additional predicate potentialInstantiationOf0( - MethodCallCand mcc, ImplOrTraitItemNode i, AssocFunctionType selfType + AssocFunctionCallCand afcc, ImplOrTraitItemNode i, AssocFunctionType selfType ) { exists( - MethodCall mc, FunctionPosition selfPos, Method m, TypePath strippedTypePath, - Type strippedType + AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, Function f, + TypePath strippedTypePath, Type strippedType | - mcc.hasSignature(mc, selfPos, strippedTypePath, strippedType, _, _) + afcc.hasSignature(afc, selfPosAdj, strippedTypePath, strippedType, _, _) | - methodCallNonBlanketCandidate(mc, m, selfPos, i, selfType, strippedTypePath, strippedType) + nonBlanketLikeCandidate(afc, f, selfPosAdj, i, selfType, strippedTypePath, strippedType) or - methodCallBlanketLikeCandidate(mc, m, selfPos, i, selfType, _, _) and - ReceiverSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(mcc, i) + blanketLikeCandidate(afc, f, selfPosAdj, i, selfType, _, _) and + ArgSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(afcc, i) ) } pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - potentialInstantiationOf0(mcc, abs, constraint) and + potentialInstantiationOf0(afcc, abs, constraint) and if abs.(Impl).hasTrait() then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - mcc.hasNoInherentTarget() + // inherent functions take precedence over trait functions, so only allow + // trait functions when there are no matching inherent functions + afcc.hasNoInherentTarget() else any() } predicate relevantConstraint(AssocFunctionType constraint) { - methodInfo(_, _, _, _, _, constraint, _, _) + assocFunctionInfo(_, _, _, _, _, constraint, _, _, _, _, _) } } - private module ReceiverIsInstantiationOfSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsInstantiationOf { + import ArgIsInstantiationOf + + pragma[nomagic] + predicate argIsNotInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, + DerefChain derefChain, BorrowKind borrow, TypePath path + ) { + argIsNotInstantiationOf(MkAssocFunctionCallCand(afc, selfPosAdj, derefChain, borrow), i, _, + path) + } + + pragma[nomagic] + predicate argIsInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, + DerefChain derefChain, BorrowKind borrow, AssocFunctionType selfType + ) { + argIsInstantiationOf(MkAssocFunctionCallCand(afc, selfPosAdj, derefChain, borrow), i, selfType) + } + } /** - * A configuration for anti-matching the type of a receiver against the type of - * a `self` parameter belonging to a blanket (like) implementation. + * A configuration for anti-matching the type of an argument against the type of + * a function at a function-call adjusted position relevant for dispatch + * (such as a `self` parameter) in a blanket (like) implementation. */ - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsNotInstantiationOfBlanketLikeInput implements + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(MethodCall mc, FunctionPosition selfPos | - mcc = MkMethodCallCand(mc, selfPos, _, _) and - methodCallBlanketLikeCandidate(mc, _, selfPos, abs, constraint, _, _) and + exists(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj | + afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, _) and + blanketLikeCandidate(afc, _, selfPosAdj, abs, constraint, _, _) and if abs.(Impl).hasTrait() then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - mcc.hasNoInherentTarget() + // inherent functions take precedence over trait functions, so only allow + // trait functions when there are no matching inherent functions + afcc.hasNoInherentTarget() else any() ) } } - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsNotInstantiationOfBlanketLike = + ArgIsInstantiationOf; /** - * A configuration for anti-matching the type of a receiver against the type of - * a `self` parameter in an inherent method. + * A configuration for anti-matching the type of an argument against the type of + * a function at a function-call adjusted position relevant for dispatch (such as + * a `self` parameter) in an inherent function. */ - private module ReceiverIsNotInstantiationOfInherentSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsNotInstantiationOfInherentInput implements + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - ReceiverIsInstantiationOfSelfParamInput::potentialInstantiationOf0(mcc, abs, constraint) and - abs = any(Impl i | not i.hasTrait()) + SelfArgIsInstantiationOfInput::potentialInstantiationOf0(afcc, abs, constraint) and + abs.(Impl).isInherent() and + exists(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj | + afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, _) + | + selfPosAdj.isTypeQualifier() or + afc.hasReceiverAtPos(selfPosAdj) + ) } } - private module ReceiverIsNotInstantiationOfInherentSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsNotInstantiationOfInherent = + ArgIsInstantiationOf; /** * A configuration for matching the types of positional arguments against the * types of parameters, when needed to disambiguate the call. */ - private module MethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { - FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) + private module OverloadedCallArgsAreInstantiationsOfInput implements + ArgsAreInstantiationsOfInputSig + { + predicate toCheck( + ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPositionAdj posAdj + ) { + exists(FunctionPosition pos | + FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) and + posAdj = pos.getFunctionCallAdjusted(f) + ) } - class Call extends MethodCallCand { - Type getArgType(FunctionPosition pos, TypePath path) { - result = mc_.getArgumentTypeAt(pos.asArgumentPosition(), path) - or - pos.isReturn() and - result = inferType(mc_.getNodeAt(pos), path) + class Call extends AssocFunctionCallCand { + Type getArgType(FunctionPositionAdj posAdj, TypePath path) { + result = this.getAssocFunctionCall().getTypeAt(posAdj, path) } predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { @@ -2413,50 +2774,55 @@ private module MethodResolution { } } - private module MethodArgsAreInstantiationsOf = - ArgsAreInstantiationsOf; + private module OverloadedCallArgsAreInstantiationsOf { + import ArgsAreInstantiationsOf + + pragma[nomagic] + predicate argsAreNotInstantiationsOf(AssocFunctionCall afc, ImplOrTraitItemNode i) { + argsAreNotInstantiationsOf(MkAssocFunctionCallCand(afc, _, _, _), i, _) + } + } } /** - * A matching configuration for resolving types of method call expressions - * like `foo.bar(baz)`. + * A matching configuration for resolving types of function call expressions + * like `foo.bar(baz)` and `Foo::bar(baz)`. */ -private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSig { - import FunctionPositionMatchingInput - - private class MethodDeclaration extends Method, FunctionDeclaration { } +private module FunctionCallMatchingInput implements MatchingWithEnvironmentInputSig { + import FunctionPositionAdjMatchingInput private newtype TDeclaration = - TMethodFunctionDeclaration(ImplOrTraitItemNode i, MethodDeclaration m) { m.isAssoc(i) } + TFunctionDeclaration(ImplOrTraitItemNodeOption i, FunctionDeclaration f) { f.isFor(i) } - final class Declaration extends TMethodFunctionDeclaration { - ImplOrTraitItemNode parent; - ImplOrTraitItemNodeOption someParent; - MethodDeclaration m; + final class Declaration extends TFunctionDeclaration { + ImplOrTraitItemNodeOption i; + FunctionDeclaration f; - Declaration() { - this = TMethodFunctionDeclaration(parent, m) and - someParent.asSome() = parent - } + Declaration() { this = TFunctionDeclaration(i, f) } - predicate isMethod(ImplOrTraitItemNode i, Method method) { - this = TMethodFunctionDeclaration(i, method) + predicate isAssocFunction(ImplOrTraitItemNode i_, Function f_) { + i_ = i.asSome() and + f_ = f } TypeParameter getTypeParameter(TypeParameterPosition ppos) { - result = m.getTypeParameter(someParent, ppos) + result = f.getTypeParameter(i, ppos) } - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - result = m.getParameterType(someParent, dpos, path) + Type getDeclaredType(FunctionPositionAdj posAdj, TypePath path) { + result = f.getParameterType(i, posAdj, path) or - dpos.isReturn() and - result = m.getReturnType(someParent, path) + posAdj.isReturn() and + result = f.getReturnType(i, path) } - string toString() { result = m.toStringExt(parent) } + string toString() { + i.isNone() and result = f.toString() + or + result = f.toStringExt(i.asSome()) + } - Location getLocation() { result = m.getLocation() } + Location getLocation() { result = f.getLocation() } } class AccessEnvironment = string; @@ -2477,10 +2843,34 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi ) } - final private class MethodCallFinal = MethodResolution::MethodCall; + private string noDerefChainBorrow() { + exists(DerefChain derefChain, BorrowKind borrow | + derefChain.isEmpty() and + borrow.isNoBorrow() and + result = encodeDerefChainBorrow(derefChain, borrow) + ) + } - class Access extends MethodCallFinal, ContextTyping::ContextTypedCallCand { - Access() { + abstract class Access extends ContextTyping::ContextTypedCallCand { + abstract AstNode getNodeAt(FunctionPositionAdj posAdj); + + bindingset[derefChainBorrow] + abstract Type getInferredType(string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path); + + abstract Declaration getTarget(string derefChainBorrow); + + /** + * Holds if the return type of this call at `path` may have to be inferred + * from the context. + */ + abstract predicate hasUnknownTypeAt( + string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path + ); + } + + private class AssocFunctionCallAccess extends Access instanceof AssocFunctionResolution::AssocFunctionCall + { + AssocFunctionCallAccess() { // handled in the `OperationMatchingInput` module not this instanceof Operation } @@ -2497,99 +2887,166 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi result = getCallExprTypeArgument(this, apos, path) } + override AstNode getNodeAt(FunctionPositionAdj posAdj) { + result = AssocFunctionResolution::AssocFunctionCall.super.getNodeAt(posAdj) + } + pragma[nomagic] - private Type getInferredSelfType(AccessPosition apos, string derefChainBorrow, TypePath path) { + private Type getInferredSelfType( + FunctionPositionAdj posAdj, string derefChainBorrow, TypePath path + ) { exists(DerefChain derefChain, BorrowKind borrow | - result = this.getACandidateReceiverTypeAt(apos, derefChain, borrow, path) and - derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) + result = super.getSelfTypeAt(posAdj, derefChain, borrow, path) and + derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and + super.hasReceiverAtPos(posAdj) ) } pragma[nomagic] - Type getInferredNonSelfType(AccessPosition apos, TypePath path) { + private Type getInferredNonSelfType(FunctionPositionAdj posAdj, TypePath path) { if // index expression `x[i]` desugars to `*x.index(i)`, so we must account for // the implicit deref - apos.isReturn() and + posAdj.isReturn() and this instanceof IndexExpr then path.isEmpty() and result instanceof RefType or exists(TypePath suffix | - result = inferType(this.getNodeAt(apos), suffix) and + result = super.getTypeAt(posAdj, suffix) and path = TypePath::cons(getRefTypeParameter(_), suffix) ) else ( - not apos.isSelf() and - result = inferType(this.getNodeAt(apos), path) + not super.hasReceiverAtPos(posAdj) and + result = super.getTypeAt(posAdj, path) ) } bindingset[derefChainBorrow] - Type getInferredType(string derefChainBorrow, AccessPosition apos, TypePath path) { - result = this.getInferredSelfType(apos, derefChainBorrow, path) + override Type getInferredType(string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path) { + result = this.getInferredSelfType(posAdj, derefChainBorrow, path) or - result = this.getInferredNonSelfType(apos, path) + result = this.getInferredNonSelfType(posAdj, path) } - Method getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { + private AssocFunction getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { exists(DerefChain derefChain, BorrowKind borrow | derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and - result = this.resolveCallTarget(i, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa + result = super.resolveCallTarget(i, _, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa ) } - Declaration getTarget(string derefChainBorrow) { - exists(ImplOrTraitItemNode i, Method m | - m = this.getTarget(i, derefChainBorrow) and - result = TMethodFunctionDeclaration(i, m) + override Declaration getTarget(string derefChainBorrow) { + exists(ImplOrTraitItemNodeOption i, AssocFunction f | + f = this.getTarget(i.asSome(), derefChainBorrow) and + result = TFunctionDeclaration(i, f) ) } - /** - * Holds if the return type of this call at `path` may have to be inferred - * from the context. - */ pragma[nomagic] - predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { - exists(ImplOrTraitItemNode i | - this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path) + override predicate hasUnknownTypeAt( + string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path + ) { + exists(FunctionPosition pos | posAdj = super.getFunctionCallAdjustedPosition(pos) | + exists(ImplOrTraitItemNode i | + this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path) + ) + or + derefChainBorrow = noDerefChainBorrow() and + forex(ImplOrTraitItemNode i, Function f | + f = CallExprImpl::getResolvedFunction(this) and + f = i.getAnAssocItem() + | + this.hasUnknownTypeAt(i, f, pos, path) + ) + ) + } + } + + private class NonAssocFunctionCallAccess extends Access instanceof NonAssocCallExpr { + pragma[nomagic] + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = NonAssocCallExpr.super.getTypeArgument(apos, path) + } + + override AstNode getNodeAt(FunctionPositionAdj posAdj) { + result = NonAssocCallExpr.super.getNodeAt(posAdj.asNonAdjusted()) + } + + pragma[nomagic] + private Type getInferredType(FunctionPositionAdj posAdj, TypePath path) { + result = super.getInferredType(posAdj.asNonAdjusted(), path) + } + + bindingset[derefChainBorrow] + override Type getInferredType(string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path) { + exists(derefChainBorrow) and + result = this.getInferredType(posAdj, path) + } + + pragma[nomagic] + private Declaration getTarget() { + exists(ImplOrTraitItemNodeOption i, FunctionDeclaration f | + f = super.resolveCallTargetViaPathResolution() and + f.isDirectlyFor(i) and + result = TFunctionDeclaration(i, f) + ) + } + + override Declaration getTarget(string derefChainBorrow) { + result = this.getTarget() and + derefChainBorrow = noDerefChainBorrow() + } + + pragma[nomagic] + override predicate hasUnknownTypeAt( + string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path + ) { + derefChainBorrow = noDerefChainBorrow() and + exists(ImplOrTraitItemNodeOption i, FunctionDeclaration f | + TFunctionDeclaration(i, f) = this.getTarget() and + this.hasUnknownTypeAt(i.asSome(), f, posAdj.asNonAdjusted(), path) ) } } } -private module MethodCallMatching = MatchingWithEnvironment; +private module FunctionCallMatching = MatchingWithEnvironment; pragma[nomagic] -private Type inferMethodCallType0( - MethodCallMatchingInput::Access a, MethodCallMatchingInput::AccessPosition apos, AstNode n, - string derefChainBorrow, TypePath path +private Type inferFunctionCallType0( + FunctionCallMatchingInput::Access call, FunctionPositionAdj posAdj, AstNode n, + DerefChain derefChain, BorrowKind borrow, TypePath path ) { exists(TypePath path0 | - n = a.getNodeAt(apos) and - ( - result = MethodCallMatching::inferAccessType(a, derefChainBorrow, apos, path0) + n = call.getNodeAt(posAdj) and + exists(string derefChainBorrow | + FunctionCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow) + | + result = FunctionCallMatching::inferAccessType(call, derefChainBorrow, posAdj, path0) or - a.hasUnknownTypeAt(derefChainBorrow, apos, path0) and + call.hasUnknownTypeAt(derefChainBorrow, posAdj, path0) and result = TUnknownType() ) | if // index expression `x[i]` desugars to `*x.index(i)`, so we must account for // the implicit deref - apos.isReturn() and - a instanceof IndexExpr + posAdj.isReturn() and + call instanceof IndexExpr then path0.isCons(getRefTypeParameter(_), path) else path = path0 ) } pragma[nomagic] -private Type inferMethodCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePath path) { - result = inferMethodCallType0(_, pos, n, _, path) and - not pos.isSelf() +private Type inferFunctionCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePath path) { + exists(FunctionCallMatchingInput::Access call, FunctionPositionAdj posAdj | + posAdj = pos.asAdjusted() and + result = inferFunctionCallType0(call, posAdj, n, _, _, path) and + not call.(AssocFunctionResolution::AssocFunctionCall).hasReceiverAtPos(posAdj) + ) } /** @@ -2600,14 +3057,12 @@ private Type inferMethodCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePat * empty, at which point the inferred type can be applied back to `n`. */ pragma[nomagic] -private Type inferMethodCallTypeSelf(MethodCall mc, AstNode n, DerefChain derefChain, TypePath path) { - exists( - MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow, BorrowKind borrow, - TypePath path0 - | - result = inferMethodCallType0(mc, apos, n, derefChainBorrow, path0) and - apos.isSelf() and - MethodCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow) +private Type inferFunctionCallTypeSelf( + FunctionCallMatchingInput::Access call, AstNode n, DerefChain derefChain, TypePath path +) { + exists(FunctionPositionAdj posAdj, BorrowKind borrow, TypePath path0 | + call.(AssocFunctionResolution::AssocFunctionCall).hasReceiverAtPos(posAdj) and + result = inferFunctionCallType0(call, posAdj, n, derefChain, borrow, path0) | borrow.isNoBorrow() and path = path0 @@ -2624,7 +3079,7 @@ private Type inferMethodCallTypeSelf(MethodCall mc, AstNode n, DerefChain derefC DerefChain derefChain0, Type t0, TypePath path0, DerefImplItemNode impl, Type selfParamType, TypePath selfPath | - t0 = inferMethodCallTypeSelf(mc, n, derefChain0, path0) and + t0 = inferFunctionCallTypeSelf(call, n, derefChain0, path0) and derefChain0.isCons(impl, derefChain) and selfParamType = impl.resolveSelfTypeAt(selfPath) | @@ -2641,445 +3096,23 @@ private Type inferMethodCallTypeSelf(MethodCall mc, AstNode n, DerefChain derefC ) } -private Type inferMethodCallTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { - result = inferMethodCallTypeNonSelf(n, pos, path) +private Type inferFunctionCallTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { + result = inferFunctionCallTypeNonSelf(n, pos, path) or - exists(MethodCall mc | - result = inferMethodCallTypeSelf(mc, n, DerefChain::nil(), path) and - if mc instanceof CallExpr then pos.asPosition() = 0 else pos.isSelf() + exists(FunctionCallMatchingInput::Access a | + result = inferFunctionCallTypeSelf(a, n, DerefChain::nil(), path) and + if a.(AssocFunctionResolution::AssocFunctionCall).hasReceiver() + then pos.isSelf() + else pos.asPosition() = 0 ) } /** - * Gets the type of `n` at `path`, where `n` is either a method call or an - * argument/receiver of a method call. + * Gets the type of `n` at `path`, where `n` is either a function call or an + * argument/receiver of a function call. */ -private predicate inferMethodCallType = - ContextTyping::CheckContextTyping::check/2; - -/** - * Provides logic for resolving calls to non-method items. This includes - * "calls" to tuple variants and tuple structs. - */ -private module NonMethodResolution { - pragma[nomagic] - private predicate traitFunctionResolutionDependsOnArgument0( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, ImplItemNode impl, - NonMethodFunction implFunction, TypePath path, TypeParameter traitTp - ) { - implFunction = impl.getAnAssocItem() and - implFunction.implements(traitFunction) and - FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, traitTp) and - ( - traitTp = TSelfTypeParameter(trait) - or - FunctionOverloading::functionResolutionDependsOnArgument(impl, implFunction, traitTp, pos) - ) - } - - /** - * Holds if resolving the function `implFunction` in `impl` requires inspecting - * the type of applied _arguments_ or possibly knowing the return type. - * - * `traitTp` is a type parameter of the trait being implemented by `impl`, and - * we need to check that the type of `f` corresponding to `traitTp` is satisfied - * at any one of the positions `pos` in which that type occurs in `f` (at `path`). - * - * As for method resolution, we always check the type being implemented (corresponding - * to `traitTp` being the special `Self` type parameter). - */ - pragma[nomagic] - private predicate traitFunctionResolutionDependsOnArgument( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, ImplItemNode impl, - NonMethodFunction implFunction, TypePath path, TypeParameter traitTp - ) { - traitFunctionResolutionDependsOnArgument0(trait, traitFunction, pos, impl, implFunction, path, - traitTp) and - // Exclude functions where we cannot resolve all relevant type mentions; this allows - // for blanket implementations to be applied in those cases - forall(TypeParameter traitTp0 | - traitFunctionResolutionDependsOnArgument0(trait, traitFunction, _, impl, implFunction, _, - traitTp0) - | - exists(FunctionPosition pos0, TypePath path0 | - traitFunctionResolutionDependsOnArgument0(trait, traitFunction, pos0, impl, implFunction, - path0, traitTp0) and - exists(getAssocFunctionTypeAt(implFunction, impl, pos0, path0)) - ) - ) - } - - /** - * Holds if `f` inside `i` either implements trait function `traitFunction` inside `trait` - * or is equal to `traitFunction`, and the type of `f` at `pos` and `path` is `t`, which - * corresponds to the `Self` type parameter of `trait`. - */ - pragma[nomagic] - private predicate traitFunctionHasSelfType( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, TypePath path, - Type t, ImplOrTraitItemNode i, NonMethodFunction f - ) { - exists(ImplItemNode impl, NonMethodFunction implFunction, AssocFunctionType aft | - traitFunctionResolutionDependsOnArgument(trait, traitFunction, pos, impl, implFunction, path, - TSelfTypeParameter(trait)) and - aft.appliesTo(f, i, pos) and - t = aft.getTypeAt(path) - | - i = trait and - f = traitFunction - or - i = impl and - f = implFunction and - not BlanketImplementation::isBlanketLike(i, _, _) - ) - } - - pragma[nomagic] - private predicate functionResolutionDependsOnArgument( - ImplItemNode impl, NonMethodFunction f, FunctionPosition pos, TypeParameter tp - ) { - traitFunctionResolutionDependsOnArgument(_, _, pos, impl, f, _, tp) - or - // For inherent implementations of generic types, we also need to check the type being - // implemented. We arbitrarily choose the first type parameter of the type being implemented - // to represent this case. - f = impl.getAnAssocItem() and - not impl.(Impl).hasTrait() and - tp = TTypeParamTypeParameter(impl.resolveSelfTy().getTypeParam(0)) and - pos.isTypeQualifier() - } - - pragma[nomagic] - private predicate functionInfoBlanketLikeRelevantPos( - NonMethodFunction f, string name, int arity, ImplItemNode impl, Trait trait, - FunctionPosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam - ) { - functionInfoBlanketLike(f, name, arity, impl, trait, pos, t, blanketPath, blanketTypeParam) and - ( - if pos.isReturn() - then - // We only check that the context of the call provides relevant type information - // when no argument can - not exists(FunctionPosition pos0 | - functionInfoBlanketLike(f, name, arity, impl, trait, pos0, _, _, _) and - not pos0.isReturn() - ) - else any() - ) - } - - pragma[nomagic] - private predicate blanketLikeCallTraitCandidate(Element fc, Trait trait) { - fc = - any(NonMethodCall nmc | - exists(string name, int arity | - nmc.hasNameAndArity(name, arity) and - functionInfoBlanketLikeRelevantPos(_, name, arity, _, trait, _, _, _, _) - | - not nmc.hasTrait() - or - trait = nmc.getTrait() - ) - ) - } - - private module BlanketTraitIsVisible = TraitIsVisible; - - /** A (potential) non-method call, `f(x)`. */ - final class NonMethodCall extends CallExpr { - NonMethodCall() { - // even if a function cannot be resolved by path resolution, it may still - // be possible to resolve a blanket implementation (so not `forex`) - forall(Function f | f = CallExprImpl::getResolvedFunction(this) | - f instanceof NonMethodFunction - ) - } - - pragma[nomagic] - predicate hasNameAndArity(string name, int arity) { - name = CallExprImpl::getFunctionPath(this).getText() and - arity = this.getArgList().getNumberOfArgs() - } - - /** - * Gets the item that this function call resolves to using path resolution, - * if any. - */ - private ItemNode getPathResolutionResolved() { - result = CallExprImpl::getResolvedFunction(this) and - not result.(Function).hasSelfParam() - } - - /** - * Gets the associated function that this function call resolves to using path - * resolution, if any. - */ - pragma[nomagic] - NonMethodFunction getPathResolutionResolved(ImplOrTraitItemNode i) { - result = this.getPathResolutionResolved() and - result = i.getAnAssocItem() - } - - /** - * Gets the blanket function that this call may resolve to, if any. - */ - pragma[nomagic] - NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) { - exists(string name | - this.hasNameAndArity(pragma[only_bind_into](name), _) and - ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and - result = impl.getASuccessor(pragma[only_bind_into](name)) - ) - } - - /** Gets the trait targeted by this call, if any. */ - Trait getTrait() { result = getCallExprTraitQualifier(this) } - - /** Holds if this call targets a trait. */ - predicate hasTrait() { exists(this.getTrait()) } - - AstNode getNodeAt(FunctionPosition pos) { - result = this.getSyntacticArgument(pos.asArgumentPosition()) - or - result = this and pos.isReturn() - } - - Type getTypeAt(FunctionPosition pos, TypePath path) { - result = inferType(this.getNodeAt(pos), path) - } - - pragma[nomagic] - NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) { - not this.hasTrait() and - result = this.getPathResolutionResolved(i) and - not exists(this.resolveCallTargetViaPathResolution()) and - functionResolutionDependsOnArgument(i, result, _, _) - } - - pragma[nomagic] - predicate resolveCallTargetBlanketLikeCand( - ImplItemNode impl, FunctionPosition pos, TypePath blanketPath, TypeParam blanketTypeParam - ) { - exists(string name, int arity, Trait trait, AssocFunctionType t | - this.hasNameAndArity(name, arity) and - exists(this.getTypeAt(pos, blanketPath)) and - functionInfoBlanketLikeRelevantPos(_, name, arity, impl, trait, pos, t, blanketPath, - blanketTypeParam) and - BlanketTraitIsVisible::traitIsVisible(this, trait) - | - not this.hasTrait() - or - trait = this.getTrait() - ) - } - - pragma[nomagic] - predicate hasTraitResolved(TraitItemNode trait, NonMethodFunction resolved) { - resolved = this.getPathResolutionResolved() and - trait = this.getTrait() - } - - /** - * Holds if this call has no compatible non-blanket target, and it has some - * candidate blanket target. - */ - pragma[nomagic] - predicate hasNoCompatibleNonBlanketTarget() { - this.resolveCallTargetBlanketLikeCand(_, _, _, _) and - not exists(this.resolveCallTargetViaPathResolution()) and - forall(ImplOrTraitItemNode i, Function f | f = this.resolveCallTargetNonBlanketCand(i) | - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f) - ) and - ( - not this.hasTraitResolved(_, _) - or - exists( - TraitItemNode trait, NonMethodFunction resolved, FunctionPosition pos, TypePath path, - Type t - | - this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call) - .hasTraitResolvedSelfType(trait, resolved, pos, path, t) - | - forall(ImplOrTraitItemNode i, Function f | - traitFunctionHasSelfType(trait, resolved, pos, path, t, i, f) - | - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f) - ) - ) - ) - } - - /** - * Gets the target of this call, which can be resolved using only path resolution. - */ - pragma[nomagic] - ItemNode resolveCallTargetViaPathResolution() { - not this.hasTrait() and - result = this.getPathResolutionResolved() and - not functionResolutionDependsOnArgument(_, result, _, _) - } - - /** - * Gets the target of this call, which can be resolved using type inference. - */ - pragma[nomagic] - NonMethodFunction resolveCallTargetViaTypeInference(ImplOrTraitItemNode i) { - result = this.resolveCallTargetBlanketCand(i) and - not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _) - or - NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result) - or - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result) - } - } - - private newtype TCallAndBlanketPos = - MkCallAndBlanketPos(NonMethodCall fc, FunctionPosition pos) { - fc.resolveCallTargetBlanketLikeCand(_, pos, _, _) - } - - /** A call tagged with a position. */ - private class CallAndBlanketPos extends MkCallAndBlanketPos { - NonMethodCall fc; - FunctionPosition pos; - - CallAndBlanketPos() { this = MkCallAndBlanketPos(fc, pos) } - - Location getLocation() { result = fc.getLocation() } - - Type getTypeAt(TypePath path) { result = fc.getTypeAt(pos, path) } - - string toString() { result = fc.toString() + " [arg " + pos + "]" } - } - - private module ArgSatisfiesBlanketConstraintInput implements - BlanketImplementation::SatisfiesBlanketConstraintInputSig - { - pragma[nomagic] - predicate hasBlanketCandidate( - CallAndBlanketPos fcp, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam - ) { - exists(NonMethodCall fc, FunctionPosition pos | - fcp = MkCallAndBlanketPos(fc, pos) and - fc.resolveCallTargetBlanketLikeCand(impl, pos, blanketPath, blanketTypeParam) and - // Only apply blanket implementations when no other implementations are possible; - // this is to account for codebases that use the (unstable) specialization feature - // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as - // cases where our blanket implementation filtering is not precise enough. - (fc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation()) - ) - } - } - - private module ArgSatisfiesBlanketConstraint = - BlanketImplementation::SatisfiesBlanketConstraint; - - /** - * A configuration for matching the type of an argument against the type of - * a parameter that mentions a satisfied blanket type parameter. - */ - private module ArgIsInstantiationOfBlanketParamInput implements - IsInstantiationOfInputSig - { - pragma[nomagic] - predicate potentialInstantiationOf( - CallAndBlanketPos fcp, TypeAbstraction abs, AssocFunctionType constraint - ) { - exists(FunctionPosition pos | - ArgSatisfiesBlanketConstraint::satisfiesBlanketConstraint(fcp, abs) and - fcp = MkCallAndBlanketPos(_, pos) and - functionInfoBlanketLikeRelevantPos(_, _, _, abs, _, pos, constraint, _, _) - ) - } - - predicate relevantConstraint(AssocFunctionType constraint) { - functionInfoBlanketLikeRelevantPos(_, _, _, _, _, _, constraint, _, _) - } - } - - private module ArgIsInstantiationOfBlanketParam = - ArgIsInstantiationOf; - - private Type getArgType( - NonMethodCall call, FunctionPosition pos, TypePath path, boolean isDefaultTypeArg - ) { - result = inferType(call.getNodeAt(pos), path) and - isDefaultTypeArg = false - or - result = getCallExprTypeQualifier(call, path, isDefaultTypeArg) and - pos.isTypeQualifier() - } - - private module NonMethodArgsAreInstantiationsOfBlanketInput implements - ArgsAreInstantiationsOfInputSig - { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos) { - functionResolutionDependsOnArgument(i, f, pos, tp) - } - - final class Call extends NonMethodCall { - Type getArgType(FunctionPosition pos, TypePath path) { - result = getArgType(this, pos, path, false) - } - - predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { - f = this.resolveCallTargetBlanketCand(i) - } - } - } - - private module NonMethodArgsAreInstantiationsOfBlanket = - ArgsAreInstantiationsOf; - - private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements - ArgsAreInstantiationsOfInputSig - { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { - functionResolutionDependsOnArgument(i, f, pos, traitTp) - or - // Also match against the trait function itself - FunctionOverloading::traitTypeParameterOccurrence(i, f, _, pos, _, traitTp) and - traitTp = TSelfTypeParameter(i) - } - - class Call extends NonMethodCall { - Type getArgType(FunctionPosition pos, TypePath path) { - result = getArgType(this, pos, path, _) - } - - /** - * Holds if this call is of the form `Trait::function(args)`, and the type at `pos` and - * `path` matches the `Self` type parameter of `Trait`. - */ - pragma[nomagic] - predicate hasTraitResolvedSelfType( - TraitItemNode trait, NonMethodFunction function, FunctionPosition pos, TypePath path, Type t - ) { - this.hasTraitResolved(trait, function) and - FunctionOverloading::traitTypeParameterOccurrence(trait, function, _, pos, path, - TSelfTypeParameter(trait)) and - t = substituteLookupTraits(this.getArgType(pos, path)) and - t != TUnknownType() - } - - predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { - f = this.resolveCallTargetNonBlanketCand(i) - or - exists( - TraitItemNode trait, NonMethodFunction resolved, FunctionPosition pos, TypePath path, - Type t - | - this.hasTraitResolvedSelfType(trait, resolved, pos, path, t) and - traitFunctionHasSelfType(trait, resolved, pos, path, t, i, f) - ) - } - } - } - - private module NonMethodArgsAreInstantiationsOfNonBlanket = - ArgsAreInstantiationsOf; -} +private predicate inferFunctionCallType = + ContextTyping::CheckContextTyping::check/2; abstract private class TupleLikeConstructor extends Addressable { final TypeParameter getTypeParameter(TypeParameterPosition ppos) { @@ -3130,140 +3163,30 @@ private class TupleLikeVariant extends TupleLikeConstructor instanceof Variant { } /** - * A matching configuration for resolving types of calls like - * `foo::bar(baz)` where the target is not a method. - * - * This also includes "calls" to tuple variants and tuple structs such - * as `Result::Ok(42)`. + * A matching configuration for resolving types of tuple-like variants and tuple + * structs such as `Result::Ok(42)`. */ -private module NonMethodCallMatchingInput implements MatchingInputSig { +private module TupleLikeConstructionMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput - private class NonMethodFunctionDeclaration extends NonMethodFunction, FunctionDeclaration { } + class Declaration = TupleLikeConstructor; - private newtype TDeclaration = - TNonMethodFunctionDeclaration(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f) { - f.isFor(i) - } or - TTupleLikeConstructorDeclaration(TupleLikeConstructor tc) - - abstract class Declaration extends TDeclaration { - abstract TypeParameter getTypeParameter(TypeParameterPosition ppos); - - pragma[nomagic] - abstract Type getParameterType(DeclarationPosition dpos, TypePath path); - - abstract Type getReturnType(TypePath path); - - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - result = this.getParameterType(dpos, path) - or - dpos.isReturn() and - result = this.getReturnType(path) - } - - abstract string toString(); - - abstract Location getLocation(); - } - - private class NonMethodFunctionDecl extends Declaration, TNonMethodFunctionDeclaration { - private ImplOrTraitItemNodeOption i; - private NonMethodFunctionDeclaration f; - - NonMethodFunctionDecl() { this = TNonMethodFunctionDeclaration(i, f) } - - override TypeParameter getTypeParameter(TypeParameterPosition ppos) { - result = f.getTypeParameter(i, ppos) - } - - override Type getParameterType(DeclarationPosition dpos, TypePath path) { - result = f.getParameterType(i, dpos, path) - } - - override Type getReturnType(TypePath path) { result = f.getReturnType(i, path) } - - override string toString() { - i.isNone() and result = f.toString() - or - result = f.toStringExt(i.asSome()) - } - - override Location getLocation() { result = f.getLocation() } - } - - private class TupleLikeConstructorDeclaration extends Declaration, - TTupleLikeConstructorDeclaration - { - TupleLikeConstructor tc; - - TupleLikeConstructorDeclaration() { this = TTupleLikeConstructorDeclaration(tc) } - - override TypeParameter getTypeParameter(TypeParameterPosition ppos) { - result = tc.getTypeParameter(ppos) - } - - override Type getParameterType(DeclarationPosition dpos, TypePath path) { - result = tc.getParameterType(dpos, path) - } - - override Type getReturnType(TypePath path) { result = tc.getReturnType(path) } - - override string toString() { result = tc.toString() } - - override Location getLocation() { result = tc.getLocation() } - } - - class Access extends NonMethodResolution::NonMethodCall, ContextTyping::ContextTypedCallCand { - pragma[nomagic] + class Access extends NonAssocCallExpr, ContextTyping::ContextTypedCallCand { override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - result = getCallExprTypeArgument(this, apos, path) + result = NonAssocCallExpr.super.getTypeArgument(apos, path) } - pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - apos.isTypeQualifier() and - result = getCallExprTypeQualifier(this, path, false) - or - result = inferType(this.getNodeAt(apos), path) - } - - pragma[inline] - Declaration getTarget() { - exists(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f | - result = TNonMethodFunctionDeclaration(i, f) - | - f = this.resolveCallTargetViaTypeInference(i.asSome()) // mutual recursion; resolving some associated function calls requires resolving types - or - f = this.resolveCallTargetViaPathResolution() and - f.isDirectlyFor(i) - ) - or - exists(ItemNode i | i = this.resolveCallTargetViaPathResolution() | - result = TTupleLikeConstructorDeclaration(i) - ) - } + Declaration getTarget() { result = this.resolveCallTargetViaPathResolution() } /** - * Holds if the return type of this call at `path` may have to be inferred - * from the context. + * Holds if the return type of this tuple-like construction at `path` may have to be inferred + * from the context, for example in `Result::Ok(42)` the error type has to be inferred from the + * context. */ pragma[nomagic] predicate hasUnknownTypeAt(FunctionPosition pos, TypePath path) { - exists(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f | - TNonMethodFunctionDeclaration(i, f) = this.getTarget() and - this.hasUnknownTypeAt(i.asSome(), f, pos, path) - ) - or - forex(ImplOrTraitItemNode i, NonMethodFunctionDeclaration f | - f = this.getPathResolutionResolved(i) - | - this.hasUnknownTypeAt(i, f, pos, path) - ) - or - // Tuple declarations, such as `Result::Ok(...)`, may also be context typed exists(TupleLikeConstructor tc, TypeParameter tp | - tc = this.resolveCallTargetViaPathResolution() and + tc = this.getTarget() and pos.isReturn() and tp = tc.getReturnType(path) and not tp = tc.getParameterType(_, _) and @@ -3277,44 +3200,44 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { } } -private module NonMethodCallMatching = Matching; +private module TupleLikeConstructionMatching = Matching; pragma[nomagic] -private Type inferNonMethodCallType0(AstNode n, FunctionPosition pos, TypePath path) { - exists(NonMethodCallMatchingInput::Access a | n = a.getNodeAt(pos) | - result = NonMethodCallMatching::inferAccessType(a, pos, path) +private Type inferTupleLikeConstructionTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { + exists(TupleLikeConstructionMatchingInput::Access a | n = a.getNodeAt(pos) | + result = TupleLikeConstructionMatching::inferAccessType(a, pos, path) or a.hasUnknownTypeAt(pos, path) and result = TUnknownType() ) } -private predicate inferNonMethodCallType = - ContextTyping::CheckContextTyping::check/2; +private predicate inferTupleLikeConstructionType = + ContextTyping::CheckContextTyping::check/2; /** * A matching configuration for resolving types of operations like `a + b`. */ private module OperationMatchingInput implements MatchingInputSig { private import codeql.rust.elements.internal.OperationImpl::Impl as OperationImpl - import FunctionPositionMatchingInput + import FunctionPositionAdjMatchingInput - class Declaration extends MethodCallMatchingInput::Declaration { + class Declaration extends FunctionCallMatchingInput::Declaration { private Method getSelfOrImpl() { - result = m + result = f or - m.implements(result) + f.implements(result) } pragma[nomagic] - private predicate borrowsAt(DeclarationPosition pos) { + private predicate borrowsAt(FunctionPositionAdj posAdj) { exists(TraitItemNode t, string path, string method | this.getSelfOrImpl() = t.getAssocItem(method) and path = t.getCanonicalPath(_) and exists(int borrows | OperationImpl::isOverloaded(_, _, path, method, borrows) | - pos.isSelf() and borrows >= 1 + posAdj.asPosition() = 0 and borrows >= 1 or - pos.asPosition() = 0 and + posAdj.asPosition() = 1 and borrows >= 2 ) ) @@ -3323,30 +3246,30 @@ private module OperationMatchingInput implements MatchingInputSig { pragma[nomagic] private predicate derefsReturn() { this.getSelfOrImpl() = any(DerefTrait t).getDerefFunction() } - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { + Type getDeclaredType(FunctionPositionAdj posAdj, TypePath path) { exists(TypePath path0 | - result = super.getDeclaredType(dpos, path0) and + result = super.getDeclaredType(posAdj, path0) and if - this.borrowsAt(dpos) + this.borrowsAt(posAdj) or - dpos.isReturn() and this.derefsReturn() + posAdj.isReturn() and this.derefsReturn() then path0.isCons(getRefTypeParameter(_), path) else path0 = path ) } } - class Access extends MethodResolution::MethodCallOperation { + class Access extends AssocFunctionResolution::AssocFunctionCallOperation { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) + Type getInferredType(FunctionPositionAdj posAdj, TypePath path) { + result = inferType(this.getNodeAt(posAdj), path) } Declaration getTarget() { exists(ImplOrTraitItemNode i | - result.isMethod(i, this.resolveCallTarget(i, _, _)) // mutual recursion + result.isAssocFunction(i, this.resolveCallTarget(i, _, _, _)) // mutual recursion ) } } @@ -3355,15 +3278,16 @@ private module OperationMatchingInput implements MatchingInputSig { private module OperationMatching = Matching; pragma[nomagic] -private Type inferOperationType0(AstNode n, FunctionPosition pos, TypePath path) { - exists(OperationMatchingInput::Access a | - n = a.getNodeAt(pos) and - result = OperationMatching::inferAccessType(a, pos, path) +private Type inferOperationTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { + exists(OperationMatchingInput::Access a, FunctionPositionAdj posAdj | + n = a.getNodeAt(posAdj) and + posAdj = pos.getFunctionCallAdjusted() and + result = OperationMatching::inferAccessType(a, posAdj, path) ) } private predicate inferOperationType = - ContextTyping::CheckContextTyping::check/2; + ContextTyping::CheckContextTyping::check/2; pragma[nomagic] private Type getFieldExprLookupType(FieldExpr fe, string name, DerefChain derefChain) { @@ -4057,7 +3981,8 @@ private module Cached { cached predicate implicitDerefChainBorrow(Expr e, DerefChain derefChain, boolean borrow) { exists(BorrowKind bk | - any(MethodResolution::MethodCall mc).argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and + any(AssocFunctionResolution::AssocFunctionCall afc) + .argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and if bk.isNoBorrow() then borrow = false else borrow = true ) or @@ -4082,15 +4007,14 @@ private module Cached { cached Addressable resolveCallTarget(InvocationExpr call, boolean dispatch) { dispatch = false and - result = call.(NonMethodResolution::NonMethodCall).resolveCallTargetViaPathResolution() + result = call.(NonAssocCallExpr).resolveCallTargetViaPathResolution() or exists(ImplOrTraitItemNode i | i instanceof TraitItemNode and dispatch = true or i instanceof ImplItemNode and dispatch = false | - result = call.(MethodResolution::MethodCall).resolveCallTarget(i, _, _) or - result = call.(NonMethodResolution::NonMethodCall).resolveCallTargetViaTypeInference(i) + result = call.(AssocFunctionResolution::AssocFunctionCall).resolveCallTarget(i, _, _, _) ) } @@ -4179,9 +4103,9 @@ private module Cached { or result = inferStructExprType(n, path) or - result = inferMethodCallType(n, path) + result = inferFunctionCallType(n, path) or - result = inferNonMethodCallType(n, path) + result = inferTupleLikeConstructionType(n, path) or result = inferOperationType(n, path) or @@ -4249,14 +4173,14 @@ private module Debug { t = self.getTypeAt(path) } - predicate debugInferMethodCallType(AstNode n, TypePath path, Type t) { + predicate debugInferFunctionCallType(AstNode n, TypePath path, Type t) { n = getRelevantLocatable() and - t = inferMethodCallType(n, path) + t = inferFunctionCallType(n, path) } - predicate debugInferNonMethodCallType(AstNode n, TypePath path, Type t) { + predicate debugInferTupleLikeConstructionType(AstNode n, TypePath path, Type t) { n = getRelevantLocatable() and - t = inferNonMethodCallType(n, path) + t = inferTupleLikeConstructionType(n, path) } predicate debugTypeMention(TypeMention tm, TypePath path, Type type) { diff --git a/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected index 8ca58acd1d0..e69de29bb2d 100644 --- a/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected @@ -1,6 +0,0 @@ -multipleResolvedTargets -| test.rs:389:30:389:67 | pinned.poll_read(...) | -| test.rs:416:26:416:54 | pinned.poll_fill_buf(...) | -| test.rs:423:27:423:71 | ... .poll_fill_buf(...) | -| test.rs:447:30:447:67 | pinned.poll_read(...) | -| test.rs:470:26:470:54 | pinned.poll_fill_buf(...) | diff --git a/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected index 255af4cc86e..763bff966d3 100644 --- a/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected @@ -100,7 +100,9 @@ edges | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | provenance | MaD:30 | | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | provenance | MaD:30 | | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | provenance | MaD:19 | +| main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | provenance | MaD:19 | | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | provenance | MaD:19 | +| main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | provenance | MaD:19 | | main.rs:170:5:170:5 | [post] a | main.rs:171:5:171:5 | a | provenance | | | main.rs:170:5:170:5 | [post] a | main.rs:172:5:172:5 | a | provenance | | | main.rs:170:5:170:5 | [post] a | main.rs:173:5:173:5 | a | provenance | | @@ -351,8 +353,12 @@ nodes | main.rs:162:19:162:27 | source(...) | semmle.label | source(...) | | main.rs:164:10:164:18 | source(...) | semmle.label | source(...) | | main.rs:164:10:164:30 | ... .bitor(...) | semmle.label | ... .bitor(...) | +| main.rs:165:10:165:18 | source(...) | semmle.label | source(...) | +| main.rs:165:10:165:27 | ... .bitor(...) | semmle.label | ... .bitor(...) | | main.rs:166:10:166:30 | 1i64.bitor(...) | semmle.label | 1i64.bitor(...) | | main.rs:166:21:166:29 | source(...) | semmle.label | source(...) | +| main.rs:167:10:167:27 | 1.bitor(...) | semmle.label | 1.bitor(...) | +| main.rs:167:18:167:26 | source(...) | semmle.label | source(...) | | main.rs:170:5:170:5 | [post] a | semmle.label | [post] a | | main.rs:170:18:170:26 | source(...) | semmle.label | source(...) | | main.rs:171:5:171:5 | [post] a | semmle.label | [post] a | @@ -516,7 +522,9 @@ testFailures | main.rs:161:10:161:25 | ... .shr(...) | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | $@ | main.rs:161:10:161:18 | source(...) | source(...) | | main.rs:162:10:162:28 | 1i64.shr(...) | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | $@ | main.rs:162:19:162:27 | source(...) | source(...) | | main.rs:164:10:164:30 | ... .bitor(...) | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | $@ | main.rs:164:10:164:18 | source(...) | source(...) | +| main.rs:165:10:165:27 | ... .bitor(...) | main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | $@ | main.rs:165:10:165:18 | source(...) | source(...) | | main.rs:166:10:166:30 | 1i64.bitor(...) | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | $@ | main.rs:166:21:166:29 | source(...) | source(...) | +| main.rs:167:10:167:27 | 1.bitor(...) | main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | $@ | main.rs:167:18:167:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:170:18:170:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:170:18:170:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:171:18:171:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:171:18:171:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:172:18:172:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:172:18:172:26 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/taint/main.rs b/rust/ql/test/library-tests/dataflow/taint/main.rs index 07770cc7118..05dbd1eb702 100644 --- a/rust/ql/test/library-tests/dataflow/taint/main.rs +++ b/rust/ql/test/library-tests/dataflow/taint/main.rs @@ -162,9 +162,9 @@ fn std_ops() { sink(1i64.shr(source(2))); // $ hasTaintFlow=2 sink(source(1).bitor(2i64)); // $ hasTaintFlow=1 - sink(source(1).bitor(2)); // $ MISSING: hasTaintFlow=1 + sink(source(1).bitor(2)); // $ hasTaintFlow=1 sink(1i64.bitor(source(2))); // $ hasTaintFlow=2 - sink(1.bitor(source(2))); // $ MISSING: hasTaintFlow=2 + sink(1.bitor(source(2))); // $ hasTaintFlow=2 let mut a: i64 = 1; a.add_assign(source(2)); diff --git a/rust/ql/test/library-tests/type-inference/overloading.rs b/rust/ql/test/library-tests/type-inference/overloading.rs index 9d5e0f39cf7..94b5a8b69e4 100644 --- a/rust/ql/test/library-tests/type-inference/overloading.rs +++ b/rust/ql/test/library-tests/type-inference/overloading.rs @@ -421,7 +421,7 @@ mod inherent_before_trait { // _as_Trait>::foo fn foo(&self) { S::foo(self); // $ MISSING: target=S::foo - S::::foo(self); // $ MISSING: target=S::foo + S::::foo(self); // $ target=S::foo self.foo() // $ target=_as_Trait>::foo } @@ -437,7 +437,7 @@ mod inherent_before_trait { // _as_Trait>::foo fn foo(&self) { // `S::foo(self);` is not valid - S::::foo(self); // $ MISSING: target=_as_Trait>::foo + S::::foo(self); // $ target=_as_Trait>::foo self.foo() // $ target=_as_Trait>::foo } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index c9b948939ac..bd3b0490f18 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -14974,202 +14974,16 @@ inferType | regressions.rs:99:22:99:22 | x | | regressions.rs:99:18:99:19 | T2 | | regressions.rs:103:5:107:5 | { ... } | | regressions.rs:99:18:99:19 | T2 | | regressions.rs:104:13:104:13 | y | | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T | {EXTERNAL LOCATION} | Option | | regressions.rs:104:13:104:13 | y | T | regressions.rs:99:14:99:15 | T1 | | regressions.rs:104:13:104:13 | y | T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:13:104:13 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | | regressions.rs:104:17:104:34 | ...::my_from(...) | | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T | {EXTERNAL LOCATION} | Option | | regressions.rs:104:17:104:34 | ...::my_from(...) | T | regressions.rs:99:14:99:15 | T1 | | regressions.rs:104:17:104:34 | ...::my_from(...) | T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:104:17:104:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | | regressions.rs:104:33:104:33 | x | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | | regressions.rs:99:14:99:15 | T1 | | regressions.rs:105:13:105:13 | z | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:13:105:13 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | | regressions.rs:99:14:99:15 | T1 | | regressions.rs:105:17:105:34 | ...::my_from(...) | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:17:105:34 | ...::my_from(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | | regressions.rs:105:33:105:33 | y | | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T | {EXTERNAL LOCATION} | Option | | regressions.rs:105:33:105:33 | y | T | regressions.rs:99:14:99:15 | T1 | | regressions.rs:105:33:105:33 | y | T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:105:33:105:33 | y | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | | regressions.rs:99:14:99:15 | T1 | | regressions.rs:106:9:106:9 | z | | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T.T | {EXTERNAL LOCATION} | Option | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:14:99:15 | T1 | -| regressions.rs:106:9:106:9 | z | T.T.T.T.T.T.T.T.T.T | regressions.rs:99:18:99:19 | T2 | testFailures diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected index ef0a9e0d806..a04fd96739c 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected @@ -21,3 +21,9 @@ | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 | | test_cipher.rs:114:23:114:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:50 | ...::new(...) | The cryptographic algorithm RC5 | | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:136:23:136:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:136:23:136:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:139:23:139:64 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:139:23:139:64 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | The cryptographic algorithm DES | +| test_cipher.rs:145:23:145:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:145:23:145:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:171:23:171:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:171:23:171:65 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:175:23:175:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:175:23:175:65 | ...::new(...) | The cryptographic algorithm RC2 | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected deleted file mode 100644 index 18400b7ab59..00000000000 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleResolvedTargets -| test_cipher.rs:114:23:114:50 | ...::new(...) | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs index 17db0f9ceb1..81964436720 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs @@ -133,16 +133,16 @@ fn test_cbc( _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // des (broken) - let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); } @@ -168,10 +168,10 @@ fn test_ecb( _ = aes_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); // des with ECB (broken cipher + weak block mode) - let des_cipher1 = ecb::Encryptor::::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = ecb::Encryptor::::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // rc2 with ECB (broken cipher + weak block mode) - let rc2_cipher1 = ecb::Encryptor::::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc2_cipher1 = ecb::Encryptor::::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = rc2_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); } diff --git a/shared/util/codeql/util/Option.qll b/shared/util/codeql/util/Option.qll index 77cc89504f5..2be9e10fef5 100644 --- a/shared/util/codeql/util/Option.qll +++ b/shared/util/codeql/util/Option.qll @@ -56,6 +56,9 @@ module Option { /** Gets the given element wrapped as an `Option`. */ Some some(T c) { result = TSome(c) } + + /** Gets the `None` value. */ + None none_() { any() } } /** From 22e012c6f41174c14620e6db27762efca479f9f3 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 11 Mar 2026 11:41:43 +0000 Subject: [PATCH 21/72] Expand `isTypeExprTopDown` We should be using all subtypes of `FieldBase`. This allows us to find more type expressions, and is also simpler to evaluate. --- go/ql/lib/semmle/go/Expr.qll | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index 4a4ab00f053..a7cb36be71f 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -2145,20 +2145,12 @@ private predicate isTypeExprTopDown(Expr e) { or e = any(ArrayTypeExpr ae).getElement() or - e = any(FieldDecl f).getTypeExpr() - or - e = any(ParameterDecl pd).getTypeExpr() + e = any(FieldBase fb).getTypeExpr() or e = any(TypeParamDecl tpd).getTypeConstraintExpr() or e = any(TypeParamDecl tpd).getNameExpr(_) or - e = any(ReceiverDecl rd).getTypeExpr() - or - e = any(ResultVariableDecl rvd).getTypeExpr() - or - e = any(MethodSpec md).getTypeExpr() - or e = any(MapTypeExpr mt).getKeyTypeExpr() or e = any(MapTypeExpr mt).getValueTypeExpr() From 39e038208914fda087b0dc85391c32bbb680a083 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 11 Mar 2026 12:20:10 +0000 Subject: [PATCH 22/72] Improve QLDoc for `isTypeExprTopDown` --- go/ql/lib/semmle/go/Expr.qll | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index a7cb36be71f..ffadbe3ad78 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -2131,11 +2131,12 @@ private predicate isTypeExprBottomUp(Expr e) { * Holds if `e` must be a type expression because it either occurs in a syntactic * position where a type is expected, or it is part of a larger type expression. * - * This predicate is only needed on snapshots for which type information is - * incomplete. It is an underapproximation; in cases where it is syntactically ambiguous - * whether an expression refers to a type or a value, we conservatively assume that - * it may be the latter and so this predicate does not consider the expression to be - * a type expression. + * This predicate is only needed on databases for which type information is + * incomplete - for example, when some dependencies could not be reached during + * extraction. It is an underapproximation; in cases where it is syntactically + * ambiguous whether an expression refers to a type or a value, we conservatively + * assume that it may be the latter and so this predicate does not consider the + * expression to be a type expression. */ pragma[nomagic] private predicate isTypeExprTopDown(Expr e) { From a16c43881b8b49364621dd8cc63c6c32ed8447c0 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 11 Mar 2026 14:06:53 +0000 Subject: [PATCH 23/72] Use "database" instead of "snapshot" in QLDocs --- go/ql/lib/semmle/go/Expr.qll | 4 ++-- go/ql/lib/semmle/go/controlflow/IR.qll | 2 +- go/ql/src/filters/ClassifyFiles.ql | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index ffadbe3ad78..54fec79e080 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -829,7 +829,7 @@ class ConversionExpr extends CallOrConversionExpr { /** * A function call expression. * - * On snapshots with incomplete type information, type conversions may be misclassified + * On databases with incomplete type information, type conversions may be misclassified * as function call expressions. * * Examples: @@ -2093,7 +2093,7 @@ class LabelName extends Name { * Holds if `e` is a type expression, as determined by a bottom-up syntactic * analysis starting with `TypeName`s. * - * On a snapshot with full type information, this predicate covers all type + * On a database with full type information, this predicate covers all type * expressions. However, if type information is missing then not all type names * may be identified as such, so not all type expressions can be determined by * a bottom-up analysis. In such cases, `isTypeExprTopDown` below is useful. diff --git a/go/ql/lib/semmle/go/controlflow/IR.qll b/go/ql/lib/semmle/go/controlflow/IR.qll index 144f0df6e7d..c6433900a73 100644 --- a/go/ql/lib/semmle/go/controlflow/IR.qll +++ b/go/ql/lib/semmle/go/controlflow/IR.qll @@ -294,7 +294,7 @@ module IR { /** * An IR instruction that reads the value of a field. * - * On snapshots with incomplete type information, method expressions may sometimes be + * On databases with incomplete type information, method expressions may sometimes be * misclassified as field reads. */ class FieldReadInstruction extends ComponentReadInstruction { diff --git a/go/ql/src/filters/ClassifyFiles.ql b/go/ql/src/filters/ClassifyFiles.ql index f5ac1258375..8e353740c1a 100644 --- a/go/ql/src/filters/ClassifyFiles.ql +++ b/go/ql/src/filters/ClassifyFiles.ql @@ -1,6 +1,6 @@ /** * @name Classify files - * @description This query produces a list of all files in a snapshot that are classified as + * @description This query produces a list of all files in a database that are classified as * generated code, test code or vendored-in library code. * @kind file-classifier * @id go/file-classifier From c27175598512499ec5a8008272c08d791f2290d9 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 10 Mar 2026 22:04:06 +0000 Subject: [PATCH 24/72] Add and use `exprRefersToNil` predicate --- go/ql/lib/semmle/go/Expr.qll | 5 ++++- go/ql/lib/semmle/go/dataflow/Properties.qll | 2 +- go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll | 6 +++--- go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll | 2 +- go/ql/src/RedundantCode/UnreachableStatement.ql | 2 +- go/ql/src/experimental/CWE-203/Timing.ql | 6 +++--- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index 4a4ab00f053..53097c7a962 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -2035,6 +2035,9 @@ class ConstantName extends ValueName { override string getAPrimaryQlClass() { result = "ConstantName" } } +/** Holds if `e` is an expression that refers to the `nil` constant. */ +predicate exprRefersToNil(Expr e) { e.(ConstantName).getTarget() = Builtin::nil() } + /** * A name referring to a variable. * @@ -2175,7 +2178,7 @@ private predicate isTypeExprTopDown(Expr e) { or e = any(TypeSwitchStmt s).getACase().getExpr(_) and // special case: `nil` is allowed in a type case but isn't a type - not e = Builtin::nil().getAReference() + not exprRefersToNil(e) or e = any(SelectorExpr sel | isTypeExprTopDown(sel)).getBase() or diff --git a/go/ql/lib/semmle/go/dataflow/Properties.qll b/go/ql/lib/semmle/go/dataflow/Properties.qll index f7df3391f40..735deb19c9f 100644 --- a/go/ql/lib/semmle/go/dataflow/Properties.qll +++ b/go/ql/lib/semmle/go/dataflow/Properties.qll @@ -22,7 +22,7 @@ class Property extends TProperty { isTrue = eq.getPolarity().booleanXor(e.getBoolValue().booleanXor(outcome)) or this = IsNil(isTrue) and - e = Builtin::nil().getAReference() and + exprRefersToNil(e) and isTrue = eq.getPolarity().booleanXor(outcome).booleanNot() ) or diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll index 404eca4b4a2..ea1fc575076 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll @@ -560,7 +560,7 @@ private predicate onlyPossibleReturnOfBool(FuncDecl fd, FunctionOutput res, Node */ predicate possiblyReturnsNonNil(FuncDecl fd, FunctionOutput res, Node ret) { ret = res.getEntryNode(fd) and - not ret.asExpr() = Builtin::nil().getAReference() + not exprRefersToNil(ret.asExpr()) } /** @@ -570,7 +570,7 @@ predicate possiblyReturnsNonNil(FuncDecl fd, FunctionOutput res, Node ret) { private predicate onlyPossibleReturnOfNonNil(FuncDecl fd, FunctionOutput res, Node ret) { possiblyReturnsNonNil(fd, res, ret) and forall(Node otherRet | otherRet = res.getEntryNode(fd) and otherRet != ret | - otherRet.asExpr() = Builtin::nil().getAReference() + exprRefersToNil(otherRet.asExpr()) ) } @@ -609,7 +609,7 @@ private predicate isCertainlyNotNil(DataFlow::Node node) { */ private predicate onlyPossibleReturnOfNil(FuncDecl fd, FunctionOutput res, DataFlow::Node ret) { ret = res.getEntryNode(fd) and - ret.asExpr() = Builtin::nil().getAReference() and + exprRefersToNil(ret.asExpr()) and forall(DataFlow::Node otherRet | otherRet = res.getEntryNode(fd) and otherRet != ret | isCertainlyNotNil(otherRet) ) diff --git a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll index af28f7f4020..adb3d5dcac7 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll @@ -418,7 +418,7 @@ predicate functionEnsuresInputIsConstant( forex(DataFlow::Node ret, IR::ReturnInstruction ri | ret = outp.getEntryNode(fd) and ri.getReturnStmt().getAnExpr() = ret.asExpr() and - ret.asExpr() = Builtin::nil().getAReference() + exprRefersToNil(ret.asExpr()) | DataFlow::localFlow(inp.getExitNode(fd), _) and mustPassConstantCaseTestToReach(ri, inp.getExitNode(fd)) diff --git a/go/ql/src/RedundantCode/UnreachableStatement.ql b/go/ql/src/RedundantCode/UnreachableStatement.ql index c177705a86f..12b035049e9 100644 --- a/go/ql/src/RedundantCode/UnreachableStatement.ql +++ b/go/ql/src/RedundantCode/UnreachableStatement.ql @@ -26,7 +26,7 @@ ControlFlow::Node nonGuardPredecessor(ControlFlow::Node nd) { * Matches if `retval` is a constant or a struct composed wholly of constants. */ predicate isAllowedReturnValue(Expr retval) { - retval = Builtin::nil().getAReference() + exprRefersToNil(retval) or retval = Builtin::true_().getAReference() or diff --git a/go/ql/src/experimental/CWE-203/Timing.ql b/go/ql/src/experimental/CWE-203/Timing.ql index e488adf2f97..30ce6952e06 100644 --- a/go/ql/src/experimental/CWE-203/Timing.ql +++ b/go/ql/src/experimental/CWE-203/Timing.ql @@ -36,7 +36,7 @@ private class SensitiveStringCompareSink extends Sink { not op1 = nonSensitiveOperand and not ( // Comparisons with `nil` should be excluded. - nonSensitiveOperand = Builtin::nil().getAReference() + exprRefersToNil(nonSensitiveOperand) or // Comparisons with empty string should also be excluded. nonSensitiveOperand.getStringValue().length() = 0 @@ -60,7 +60,7 @@ private class SensitiveCompareSink extends Sink { not op1 = op2 and not ( // Comparisons with `nil` should be excluded. - op2 = Builtin::nil().getAReference() + exprRefersToNil(op2) or // Comparisons with empty string should also be excluded. op2.getStringValue().length() = 0 @@ -85,7 +85,7 @@ private class SensitiveStringSink extends Sink { not op1 = op2 and not ( // Comparisons with `nil` should be excluded. - op2 = Builtin::nil().getAReference() + exprRefersToNil(op2) or // Comparisons with empty string should also be excluded. op2.getStringValue().length() = 0 From 48bf4fd82aea7075c4e7576fe301938099ebdd90 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 11 Mar 2026 16:01:47 +0000 Subject: [PATCH 25/72] Python: Add test for missing relative import in namespace packages --- .../pkg/caller.py | 5 +++ .../pkg/helper.py | 2 ++ .../test.expected | 1 + .../test.ql | 35 +++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py create mode 100644 python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py create mode 100644 python/ql/test/experimental/import-resolution-namespace-relative/test.expected create mode 100644 python/ql/test/experimental/import-resolution-namespace-relative/test.ql diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py new file mode 100644 index 00000000000..f30065eec99 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/caller.py @@ -0,0 +1,5 @@ +from . import helper + +def use_relative(): + tainted = source() + helper.process(tainted) diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py new file mode 100644 index 00000000000..43167b8cfa7 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py @@ -0,0 +1,2 @@ +def process(value): + sink(value) #$ MISSING: prints=source diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/test.expected b/python/ql/test/experimental/import-resolution-namespace-relative/test.expected new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/test.expected @@ -0,0 +1 @@ + diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/test.ql b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql new file mode 100644 index 00000000000..f826c02e423 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql @@ -0,0 +1,35 @@ +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import utils.test.InlineExpectationsTest + +private module TestConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + node.(DataFlow::CallCfgNode).getFunction().asCfgNode().(NameNode).getId() = "source" + } + + predicate isSink(DataFlow::Node node) { + exists(DataFlow::CallCfgNode call | + call.getFunction().asCfgNode().(NameNode).getId() = "sink" and + node = call.getArg(0) + ) + } +} + +private module TestFlow = TaintTracking::Global; + +module FlowTest implements TestSig { + string getARelevantTag() { result = "prints" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node sink | + TestFlow::flow(_, sink) and + tag = "prints" and + location = sink.getLocation() and + value = "source" and + element = sink.toString() + ) + } +} + +import MakeTest From e16bb226c08c8131e10748d7e4990a03e4d0220f Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 11 Mar 2026 23:02:09 +0000 Subject: [PATCH 26/72] Python: Fix resolution of relative imports from namespace packages The fix may look a bit obscure, so here's what's going on. When we see `from . import helper`, we create an `ImportExpr` with level equal to 1 (corresponding to the number of dots). To resolve such imports, we compute the name of the enclosing package, as part of `ImportExpr.qualifiedTopName()`. For this form of import expression, it is equivalent to `this.getEnclosingModule().getPackageName()`. But `qualifiedTopName` requires that `valid_module_name` holds for its result, and this was _not_ the case for namespace packages. To fix this, we extend `valid_module_name` to include the module names of _any_ folder, not just regular package (which are the ones where there's a `__init__.py` in the folder). Note that this doesn't simply include all folders -- only the ones that result in valid module names in Python. --- python/ql/lib/semmle/python/Import.qll | 4 ++++ .../import-resolution-namespace-relative/pkg/helper.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/Import.qll b/python/ql/lib/semmle/python/Import.qll index e8a7facccad..2f7fae95539 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -17,6 +17,10 @@ private predicate valid_module_name(string name) { exists(Module m | m.getName() = name) or exists(Builtin cmod | cmod.getClass() = Builtin::special("ModuleType") and cmod.getName() = name) + or + // Namespace packages may not have a corresponding Module entity, + // but their names are still valid for the purpose of import resolution. + name = moduleNameFromFile(any(Folder f)) } /** An artificial expression representing an import */ diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py index 43167b8cfa7..b9407161e08 100644 --- a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py @@ -1,2 +1,2 @@ def process(value): - sink(value) #$ MISSING: prints=source + sink(value) #$ prints=source From 3ee369b7109fc4debf92272fbc9554e8b680a4cb Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 11 Mar 2026 23:14:57 +0000 Subject: [PATCH 27/72] Python: Add change note --- .../2026-03-11-fix-unresolved-relative-imports.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md diff --git a/python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md b/python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md new file mode 100644 index 00000000000..15290fb3d66 --- /dev/null +++ b/python/ql/lib/change-notes/2026-03-11-fix-unresolved-relative-imports.md @@ -0,0 +1,5 @@ +--- +category: fix +--- + +- Fixed the resolution of relative imports such as `from . import helper` inside namespace packages (directories without an `__init__.py` file), which previously did not work correctly, leading to missing flow. From ee3674cb805b461c95a7e36fa00e0cf50047f73e Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 12 Mar 2026 11:37:44 +0100 Subject: [PATCH 28/72] Swift: Disable stack protector pass --- swift/extractor/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index 8019d1bfc66..d76f956fba7 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -81,6 +81,7 @@ static void turnOffSilVerifications(swift::SILOptions& options) { options.VerifyExclusivity = false; options.VerifyNone = true; options.VerifySILOwnership = false; + options.EnableStackProtection = false; // Causes crashes on Linux } codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state); From b9c0aca11af887963d4e9b31946f1911f2d25c0b Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 12 Mar 2026 15:00:18 +0100 Subject: [PATCH 29/72] Swift: Fix formatting --- swift/extractor/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index d76f956fba7..2d51f88bb0b 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -81,7 +81,7 @@ static void turnOffSilVerifications(swift::SILOptions& options) { options.VerifyExclusivity = false; options.VerifyNone = true; options.VerifySILOwnership = false; - options.EnableStackProtection = false; // Causes crashes on Linux + options.EnableStackProtection = false; // Causes crashes on Linux } codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state); From 12e0f3f3597d8dfb9ee980ec2b3a1ee532196c06 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 12 Mar 2026 15:46:23 +0100 Subject: [PATCH 30/72] Swift: Limit successfully extracted lines --- swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql | 2 +- .../query-tests/Diagnostics/SuccessfullyExtractedLines.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql index 5aec16da4ef..0de0cb1ae1a 100644 --- a/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql +++ b/swift/ql/src/diagnostics/SuccessfullyExtractedLines.ql @@ -9,4 +9,4 @@ import swift -select sum(File f | | f.getNumberOfLinesOfCode()) +select sum(File f | exists(f.getRelativePath()) | f.getNumberOfLinesOfCode()) diff --git a/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected b/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected index beaf5bb6a1f..b5a514b9ffa 100644 --- a/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected +++ b/swift/ql/test/query-tests/Diagnostics/SuccessfullyExtractedLines.expected @@ -1 +1 @@ -| 299 | +| 4 | From ba3fadbf202316b88d297e6c5ba07186d3f41a69 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 12 Mar 2026 16:37:13 +0100 Subject: [PATCH 31/72] Swift: Rename function --- swift/extractor/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index 2d51f88bb0b..6da464d7194 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -76,7 +76,7 @@ static void processFrontendOptions(codeql::SwiftExtractorState& state, } } -static void turnOffSilVerifications(swift::SILOptions& options) { +static void turnOffSilVerificationsAndStackProtection(swift::SILOptions& options) { options.VerifyAll = false; options.VerifyExclusivity = false; options.VerifyNone = true; @@ -99,7 +99,7 @@ class Observer : public swift::FrontendObserver { options.KeepASTContext = true; lockOutputSwiftModuleTraps(state, options); processFrontendOptions(state, options); - turnOffSilVerifications(invocation.getSILOptions()); + turnOffSilVerificationsAndStackProtection(invocation.getSILOptions()); } void configuredCompiler(swift::CompilerInstance& instance) override { From c9e0927992ea08e8671b5e96c56f076e4c323656 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 03:04:44 +0000 Subject: [PATCH 32/72] Bump the extractor-dependencies group across 1 directory with 2 updates Bumps the extractor-dependencies group with 2 updates in the /go/extractor directory: [golang.org/x/mod](https://github.com/golang/mod) and [golang.org/x/tools](https://github.com/golang/tools). Updates `golang.org/x/mod` from 0.33.0 to 0.34.0 - [Commits](https://github.com/golang/mod/compare/v0.33.0...v0.34.0) Updates `golang.org/x/tools` from 0.42.0 to 0.43.0 - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.42.0...v0.43.0) --- updated-dependencies: - dependency-name: golang.org/x/mod dependency-version: 0.34.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: extractor-dependencies - dependency-name: golang.org/x/tools dependency-version: 0.43.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: extractor-dependencies ... Signed-off-by: dependabot[bot] --- go/extractor/go.mod | 6 +++--- go/extractor/go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go/extractor/go.mod b/go/extractor/go.mod index 46d189d005e..ae43e8a51bd 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -9,8 +9,8 @@ toolchain go1.26.0 // when adding or removing dependencies, run // bazel mod tidy require ( - golang.org/x/mod v0.33.0 - golang.org/x/tools v0.42.0 + golang.org/x/mod v0.34.0 + golang.org/x/tools v0.43.0 ) require github.com/stretchr/testify v1.11.1 @@ -18,6 +18,6 @@ require github.com/stretchr/testify v1.11.1 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sync v0.19.0 // indirect + golang.org/x/sync v0.20.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go/extractor/go.sum b/go/extractor/go.sum index ade080a41ad..8bb3f3dc9fc 100644 --- a/go/extractor/go.sum +++ b/go/extractor/go.sum @@ -6,12 +6,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 8c1c039edf8bc0f951e2f3fa1eec0a9c98a714dd Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Mar 2026 10:25:49 +0100 Subject: [PATCH 33/72] C#: Delete PreBasicBlocks. --- .../ql/consistency-queries/CfgConsistency.ql | 58 ------ .../controlflow/internal/PreBasicBlocks.qll | 175 ------------------ 2 files changed, 233 deletions(-) delete mode 100644 csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll diff --git a/csharp/ql/consistency-queries/CfgConsistency.ql b/csharp/ql/consistency-queries/CfgConsistency.ql index d7f0c091538..4b0d15f8a81 100644 --- a/csharp/ql/consistency-queries/CfgConsistency.ql +++ b/csharp/ql/consistency-queries/CfgConsistency.ql @@ -1,63 +1,5 @@ import csharp import semmle.code.csharp.controlflow.internal.Completion -import semmle.code.csharp.controlflow.internal.PreBasicBlocks import ControlFlow import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::Consistency import semmle.code.csharp.controlflow.internal.Splitting - -private predicate splitBB(ControlFlow::BasicBlock bb) { - exists(ControlFlow::Node first | - first = bb.getFirstNode() and - first.isJoin() and - strictcount(first.getAPredecessor().getAstNode()) = 1 - ) -} - -private class RelevantBasicBlock extends ControlFlow::BasicBlock { - RelevantBasicBlock() { not splitBB(this) } -} - -predicate bbStartInconsistency(ControlFlowElement cfe) { - exists(RelevantBasicBlock bb | bb.getFirstNode() = cfe.getAControlFlowNode()) and - not cfe = any(PreBasicBlock bb).getFirstElement() -} - -predicate bbSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) { - exists(RelevantBasicBlock predBB, RelevantBasicBlock succBB | - predBB.getLastNode() = pred.getAControlFlowNode() and - succBB = predBB.getASuccessor() and - succBB.getFirstNode() = succ.getAControlFlowNode() - ) and - not exists(PreBasicBlock predBB, PreBasicBlock succBB | - predBB.getLastNode() = pred and - succBB = predBB.getASuccessor() and - succBB.getFirstElement() = succ - ) -} - -predicate bbIntraSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) { - exists(ControlFlow::BasicBlock bb, int i | - pred.getAControlFlowNode() = bb.getNode(i) and - succ.getAControlFlowNode() = bb.getNode(i + 1) - ) and - not exists(PreBasicBlock bb | - bb.getLastNode() = pred and - bb.getASuccessor().getFirstElement() = succ - ) and - not exists(PreBasicBlock bb, int i | - bb.getNode(i) = pred and - bb.getNode(i + 1) = succ - ) -} - -query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowElement cfe2, string s) { - bbStartInconsistency(cfe1) and - cfe2 = cfe1 and - s = "start inconsistency" - or - bbSuccInconsistency(cfe1, cfe2) and - s = "succ inconsistency" - or - bbIntraSuccInconsistency(cfe1, cfe2) and - s = "intra succ inconsistency" -} diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll deleted file mode 100644 index 38eca378edf..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll +++ /dev/null @@ -1,175 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides a basic block implementation on control flow elements. That is, - * a "pre-CFG" where the nodes are (unsplit) control flow elements and the - * successor relation is `succ = succ(pred, _)`. - * - * The logic is duplicated from the implementation in `BasicBlocks.qll`, and - * being an internal class, all predicate documentation has been removed. - */ - -import csharp -private import Completion -private import ControlFlowGraphImpl -private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg -private import codeql.controlflow.BasicBlock as BB - -private predicate startsBB(ControlFlowElement cfe) { - not succ(_, cfe, _) and - ( - succ(cfe, _, _) - or - scopeLast(_, cfe, _) - ) - or - strictcount(ControlFlowElement pred, Completion c | succ(pred, cfe, c)) > 1 - or - succ(_, cfe, any(ConditionalCompletion c)) - or - exists(ControlFlowElement pred, int i | - succ(pred, cfe, _) and - i = count(ControlFlowElement succ, Completion c | succ(pred, succ, c)) - | - i > 1 - or - i = 1 and - scopeLast(_, pred, _) - ) -} - -private predicate intraBBSucc(ControlFlowElement pred, ControlFlowElement succ) { - succ(pred, succ, _) and - not startsBB(succ) -} - -private predicate bbIndex(ControlFlowElement bbStart, ControlFlowElement cfe, int i) = - shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfe, i) - -private predicate succBB(PreBasicBlock pred, PreBasicBlock succ) { succ = pred.getASuccessor() } - -private predicate entryBB(PreBasicBlock bb) { scopeFirst(_, bb) } - -private predicate bbIDominates(PreBasicBlock dom, PreBasicBlock bb) = - idominance(entryBB/1, succBB/2)(_, dom, bb) - -class PreBasicBlock extends ControlFlowElement { - PreBasicBlock() { startsBB(this) } - - PreBasicBlock getASuccessor(Cfg::SuccessorType t) { - succ(this.getLastNode(), result, any(Completion c | t = c.getAMatchingSuccessorType())) - } - - deprecated PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) { - result = this.getASuccessor(t) - } - - PreBasicBlock getASuccessor() { result = this.getASuccessor(_) } - - PreBasicBlock getAPredecessor() { result.getASuccessor() = this } - - ControlFlowElement getNode(int pos) { bbIndex(this, result, pos) } - - deprecated ControlFlowElement getElement(int pos) { result = this.getNode(pos) } - - ControlFlowElement getAnElement() { result = this.getNode(_) } - - ControlFlowElement getFirstElement() { result = this } - - ControlFlowElement getLastNode() { result = this.getNode(this.length() - 1) } - - deprecated ControlFlowElement getLastElement() { result = this.getLastNode() } - - int length() { result = strictcount(this.getAnElement()) } - - PreBasicBlock getImmediateDominator() { bbIDominates(result, this) } - - predicate immediatelyDominates(PreBasicBlock bb) { bbIDominates(this, bb) } - - pragma[inline] - predicate strictlyDominates(PreBasicBlock bb) { this.immediatelyDominates+(bb) } - - pragma[inline] - predicate dominates(PreBasicBlock bb) { - bb = this - or - this.strictlyDominates(bb) - } - - predicate inDominanceFrontier(PreBasicBlock df) { - this = df.getAPredecessor() and not bbIDominates(this, df) - or - exists(PreBasicBlock prev | prev.inDominanceFrontier(df) | - bbIDominates(this, prev) and - not bbIDominates(this, df) - ) - } - - /** Unsupported. Do not use. */ - predicate strictlyPostDominates(PreBasicBlock bb) { none() } - - /** Unsupported. Do not use. */ - predicate postDominates(PreBasicBlock bb) { - this.strictlyPostDominates(bb) or - this = bb - } -} - -private Completion getConditionalCompletion(ConditionalCompletion cc) { - result.getInnerCompletion() = cc -} - -pragma[nomagic] -private predicate conditionBlockImmediatelyControls( - ConditionBlock cond, PreBasicBlock succ, ConditionalCompletion cc -) { - exists(ControlFlowElement last, Completion c | - last = cond.getLastNode() and - c = getConditionalCompletion(cc) and - succ(last, succ, c) and - // In the pre-CFG, we need to account for case where one predecessor node has - // two edges to the same successor node. Assertion expressions are examples of - // such nodes. - not exists(Completion other | - succ(last, succ, other) and - other != c - ) and - forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != cond | - succ.dominates(pred) - ) - ) -} - -class ConditionBlock extends PreBasicBlock { - ConditionBlock() { - exists(Completion c | c = getConditionalCompletion(_) | - succ(this.getLastNode(), _, c) - or - scopeLast(_, this.getLastNode(), c) - ) - } - - pragma[nomagic] - predicate controls(PreBasicBlock controlled, Cfg::ConditionalSuccessor s) { - exists(PreBasicBlock succ, ConditionalCompletion c | - conditionBlockImmediatelyControls(this, succ, c) - | - succ.dominates(controlled) and - s = c.getAMatchingSuccessorType() - ) - } -} - -module PreCfg implements BB::CfgSig { - class ControlFlowNode = ControlFlowElement; - - class BasicBlock = PreBasicBlock; - - class EntryBasicBlock extends BasicBlock { - EntryBasicBlock() { entryBB(this) } - } - - predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { - conditionBlockImmediatelyControls(bb1, bb2, _) - } -} From f58a6e5d3a3e76dd06de0472cc48ff67280ef33e Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 13 Mar 2026 10:01:02 +0000 Subject: [PATCH 34/72] Change @security-severity for XSS queries from 6.1 to 7.8 --- cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql | 2 +- csharp/ql/src/Security Features/CWE-079/XSS.ql | 2 +- go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql | 2 +- go/ql/src/Security/CWE-079/ReflectedXss.ql | 2 +- go/ql/src/Security/CWE-079/StoredXss.ql | 2 +- .../CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql | 2 +- .../CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql | 2 +- java/ql/src/Security/CWE/CWE-079/XSS.ql | 2 +- python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql | 2 +- python/ql/src/Security/CWE-079/ReflectedXss.ql | 2 +- ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql | 2 +- ruby/ql/src/queries/security/cwe-079/StoredXSS.ql | 2 +- ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql | 2 +- rust/ql/src/queries/security/CWE-079/XSS.ql | 2 +- swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 994aba733d2..0e4a8f9741c 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id cpp/cgi-xss * @tags security diff --git a/csharp/ql/src/Security Features/CWE-079/XSS.ql b/csharp/ql/src/Security Features/CWE-079/XSS.ql index 8735d89ef50..b819ed06bf8 100644 --- a/csharp/ql/src/Security Features/CWE-079/XSS.ql +++ b/csharp/ql/src/Security Features/CWE-079/XSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id cs/web/xss * @tags security diff --git a/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql b/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql index 15373ee85ed..f556630965c 100644 --- a/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql +++ b/go/ql/src/Security/CWE-079/HtmlTemplateEscapingBypassXss.ql @@ -5,7 +5,7 @@ * scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id go/html-template-escaping-bypass-xss * @tags security diff --git a/go/ql/src/Security/CWE-079/ReflectedXss.ql b/go/ql/src/Security/CWE-079/ReflectedXss.ql index 0fca12ac285..ebabb69f0a4 100644 --- a/go/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/go/ql/src/Security/CWE-079/ReflectedXss.ql @@ -4,7 +4,7 @@ * a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id go/reflected-xss * @tags security diff --git a/go/ql/src/Security/CWE-079/StoredXss.ql b/go/ql/src/Security/CWE-079/StoredXss.ql index 83628b31042..dcae0a5f9c1 100644 --- a/go/ql/src/Security/CWE-079/StoredXss.ql +++ b/go/ql/src/Security/CWE-079/StoredXss.ql @@ -4,7 +4,7 @@ * a stored cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision low * @id go/stored-xss * @tags security diff --git a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql index 4368b537ab7..3b4abcaa7f6 100644 --- a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql +++ b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewAddJavascriptInterface.ql @@ -4,7 +4,7 @@ * @description Exposing a Java object in a WebView with a JavaScript interface can lead to malicious JavaScript controlling the application. * @kind problem * @problem.severity warning - * @security-severity 6.1 + * @security-severity 7.8 * @precision medium * @tags security * external/cwe/cwe-079 diff --git a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql index 561b2af8de0..3ea2b207c04 100644 --- a/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql +++ b/java/ql/src/Security/CWE/CWE-079/AndroidWebViewSettingsEnabledJavaScript.ql @@ -4,7 +4,7 @@ * @kind problem * @id java/android/websettings-javascript-enabled * @problem.severity warning - * @security-severity 6.1 + * @security-severity 7.8 * @precision medium * @tags security * external/cwe/cwe-079 diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql index 9ae92a7e362..f1261ebff74 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id java/xss * @tags security diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql index 97bbb72edec..fd03ba433a1 100644 --- a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql +++ b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql @@ -4,7 +4,7 @@ * cause a cross-site scripting vulnerability. * @kind problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision medium * @id py/jinja2/autoescape-false * @tags security diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.ql b/python/ql/src/Security/CWE-079/ReflectedXss.ql index 11ebad00e37..286dbece126 100644 --- a/python/ql/src/Security/CWE-079/ReflectedXss.ql +++ b/python/ql/src/Security/CWE-079/ReflectedXss.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @sub-severity high * @precision high * @id py/reflective-xss diff --git a/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql b/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql index 8cc60618cc5..04eed164046 100644 --- a/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql +++ b/ruby/ql/src/queries/security/cwe-079/ReflectedXSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @sub-severity high * @precision high * @id rb/reflected-xss diff --git a/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql b/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql index a621aee00b0..a2a1752f7f4 100644 --- a/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql +++ b/ruby/ql/src/queries/security/cwe-079/StoredXSS.ql @@ -4,7 +4,7 @@ * a stored cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id rb/stored-xss * @tags security diff --git a/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql b/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql index c1527783fc3..3fa40cd6f91 100644 --- a/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql +++ b/ruby/ql/src/queries/security/cwe-079/UnsafeHtmlConstruction.ql @@ -4,7 +4,7 @@ * user to perform a cross-site scripting attack. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id rb/html-constructed-from-input * @tags security diff --git a/rust/ql/src/queries/security/CWE-079/XSS.ql b/rust/ql/src/queries/security/CWE-079/XSS.ql index 3c43f5043c7..e7609196b3e 100644 --- a/rust/ql/src/queries/security/CWE-079/XSS.ql +++ b/rust/ql/src/queries/security/CWE-079/XSS.ql @@ -4,7 +4,7 @@ * allows for a cross-site scripting vulnerability. * @kind path-problem * @problem.severity error - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id rust/xss * @tags security diff --git a/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql b/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql index 7243d2216a5..3a2de3fa80a 100644 --- a/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql +++ b/swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql @@ -3,7 +3,7 @@ * @description Fetching data in a WebView without restricting the base URL may allow an attacker to access sensitive local data, or enable cross-site scripting attack. * @kind path-problem * @problem.severity warning - * @security-severity 6.1 + * @security-severity 7.8 * @precision high * @id swift/unsafe-webview-fetch * @tags security From 056aa342fee99d9367f4041db89beee59417d3b7 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 13 Mar 2026 10:02:01 +0000 Subject: [PATCH 35/72] Change @security-severity for log injection queries from 7.8 to 6.1 --- csharp/ql/src/Security Features/CWE-117/LogForging.ql | 2 +- go/ql/src/Security/CWE-117/LogInjection.ql | 2 +- java/ql/src/Security/CWE/CWE-117/LogInjection.ql | 2 +- python/ql/src/Security/CWE-117/LogInjection.ql | 2 +- ruby/ql/src/queries/security/cwe-117/LogInjection.ql | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/csharp/ql/src/Security Features/CWE-117/LogForging.ql b/csharp/ql/src/Security Features/CWE-117/LogForging.ql index 9494af33570..a922f1c02f8 100644 --- a/csharp/ql/src/Security Features/CWE-117/LogForging.ql +++ b/csharp/ql/src/Security Features/CWE-117/LogForging.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision high * @id cs/log-forging * @tags security diff --git a/go/ql/src/Security/CWE-117/LogInjection.ql b/go/ql/src/Security/CWE-117/LogInjection.ql index 5b6586c8e4e..08febfd842e 100644 --- a/go/ql/src/Security/CWE-117/LogInjection.ql +++ b/go/ql/src/Security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id go/log-injection * @tags security diff --git a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql index dd4ffb6a10a..f3efb578f76 100644 --- a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql +++ b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by malicious users. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id java/log-injection * @tags security diff --git a/python/ql/src/Security/CWE-117/LogInjection.ql b/python/ql/src/Security/CWE-117/LogInjection.ql index f1b72faaccb..64b29e142e0 100644 --- a/python/ql/src/Security/CWE-117/LogInjection.ql +++ b/python/ql/src/Security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id py/log-injection * @tags security diff --git a/ruby/ql/src/queries/security/cwe-117/LogInjection.ql b/ruby/ql/src/queries/security/cwe-117/LogInjection.ql index 624c2f90e64..50a4a718e32 100644 --- a/ruby/ql/src/queries/security/cwe-117/LogInjection.ql +++ b/ruby/ql/src/queries/security/cwe-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 7.8 + * @security-severity 6.1 * @precision medium * @id rb/log-injection * @tags security From 52809133f56a3ebf5a1bd1aae259fb024477492a Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 13 Mar 2026 11:10:43 +0000 Subject: [PATCH 36/72] Add change notes --- .../2026-03-13-adjust-xss-and-log-injection-severity.md | 4 ++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 5 +++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 5 +++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 5 +++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 5 +++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 5 +++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 4 ++++ .../2026-03-13-adjust-xss-and-log-injection-severity.md | 4 ++++ 8 files changed, 37 insertions(+) create mode 100644 cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md create mode 100644 swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md diff --git a/cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..0810e9c49ba --- /dev/null +++ b/cpp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `cpp/cgi-xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..c317194bc25 --- /dev/null +++ b/csharp/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `cs/log-forging` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `cs/web/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..45320bcd719 --- /dev/null +++ b/go/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `go/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `go/html-template-escaping-bypass-xss`, `go/reflected-xss` and `go/stored-xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..fa1288af16e --- /dev/null +++ b/java/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `java/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `java/android/webview-addjavascriptinterface`, `java/android/websettings-javascript-enabled` and `java/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..4278d0171e3 --- /dev/null +++ b/python/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `py/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `py/jinja2/autoescape-false` and `py/reflective-xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..459c2ce7f91 --- /dev/null +++ b/ruby/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,5 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `rb/log-injection` has been reduced from 7.8 (high) to 6.1 (medium). +* The `@security-severity` metadata of `rb/reflected-xss`, `rb/stored-xss` and `rb/html-constructed-from-input` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..7c24d4147a5 --- /dev/null +++ b/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `rust/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md new file mode 100644 index 00000000000..a46302ed146 --- /dev/null +++ b/swift/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The `@security-severity` metadata of `swift/unsafe-webview-fetch` has been increased from 6.1 (medium) to 7.8 (high). From 7094fb07a463d9411329f8f6cabca9b628cf0e12 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 13 Mar 2026 14:31:08 +0100 Subject: [PATCH 37/72] Rust: Replace `FunctionPosition` with `FunctionPositionAdj` --- .../typeinference/FunctionOverloading.qll | 3 +- .../internal/typeinference/FunctionType.qll | 219 ++---- .../internal/typeinference/TypeInference.qll | 718 +++++++++--------- 3 files changed, 413 insertions(+), 527 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll index 0f65d21dcf7..6e4cc6e2c2e 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll @@ -124,7 +124,8 @@ private predicate functionResolutionDependsOnArgumentCand( implHasSibling(impl, trait) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, traitTp) and f = impl.getASuccessor(functionName) and - not pos.isSelfOrTypeQualifier() + not pos.isTypeQualifier() and + not (f instanceof Method and pos.asPosition() = 0) ) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index 841f165d2c3..37df796a7be 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -5,112 +5,49 @@ private import TypeAbstraction private import TypeMention private import TypeInference -private signature predicate includeSelfSig(); - -// We construct `FunctionPosition` and `FunctionPositionAdj` using two different underlying -// `newtype`s in order to prevent unintended mixing of the two -private module MkFunctionPosition { - private newtype TFunctionPosition = - TArgumentFunctionPosition(ArgumentPosition pos) { - if pos.isSelf() then includeSelf() else any() - } or - TReturnFunctionPosition() - - class FunctionPosition extends TFunctionPosition { - int asPosition() { result = this.asArgumentPosition().asPosition() } - - predicate isPosition() { exists(this.asPosition()) } - - ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) } - - predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() } - - predicate isReturn() { this = TReturnFunctionPosition() } - - TypeMention getTypeMention(Function f) { - result = f.getParam(this.asPosition()).getTypeRepr() - or - this.isReturn() and - result = getReturnTypeMention(f) - } - - string toString() { - result = this.asArgumentPosition().toString() - or - this.isReturn() and - result = "(return)" - } - } -} - -private predicate any_() { any() } +private newtype TFunctionPosition = + TArgumentFunctionPosition(ArgumentPosition pos) { not pos.isSelf() } or + TReturnFunctionPosition() /** - * A position of a type related to a function. + * A function-call adjusted position of a type related to a function. * - * Either `self`, `return`, or a positional parameter index. + * Either `return` or a positional parameter index, where `self` is translated + * to position `0` and subsequent positional parameters at index `i` are + * translated to position `i + 1`. */ -final class FunctionPosition extends MkFunctionPosition::FunctionPosition { - predicate isSelf() { this.asArgumentPosition().isSelf() } +class FunctionPosition extends TFunctionPosition { + int asPosition() { result = this.asArgumentPosition().asPosition() } - predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() } + predicate isPosition() { exists(this.asPosition()) } - override TypeMention getTypeMention(Function f) { - result = super.getTypeMention(f) + ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) } + + predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() } + + predicate isReturn() { this = TReturnFunctionPosition() } + + TypeMention getTypeMention(Function f) { + ( + if f instanceof Method + then + result = f.getParam(this.asPosition() - 1).getTypeRepr() + or + result = getSelfParamTypeMention(f.getSelfParam()) and + this.asPosition() = 0 + else result = f.getParam(this.asPosition()).getTypeRepr() + ) or - this.isSelf() and - result = getSelfParamTypeMention(f.getSelfParam()) + this.isReturn() and + result = getReturnTypeMention(f) } - /** - * Gets the corresponding position when function call syntax is used, assuming - * this position is for a method. - */ - pragma[nomagic] - FunctionPositionAdj getFunctionCallAdjusted() { - this.isReturn() and result.isReturn() + string toString() { + result = this.asArgumentPosition().toString() or - this.isTypeQualifier() and - result.isTypeQualifier() - or - this.isSelf() and result.asPosition() = 0 - or - result.asPosition() = this.asPosition() + 1 + this.isReturn() and + result = "(return)" } - - /** - * Gets the corresponding position when function call syntax is used, assuming - * this position is _not_ for a method. - */ - pragma[nomagic] - FunctionPositionAdj asAdjusted() { - this.isReturn() and result.isReturn() - or - this.isTypeQualifier() and - result.isTypeQualifier() - or - result.asPosition() = this.asPosition() - } - - /** - * Gets the corresponding position when `f` is invoked via function call - * syntax. - */ - bindingset[f] - FunctionPositionAdj getFunctionCallAdjusted(Function f) { - if f.hasSelfParam() then result = this.getFunctionCallAdjusted() else result = this.asAdjusted() - } -} - -private predicate none_() { none() } - -/** - * A function-call adjust position of a type related to a function. - * - * Either `return` or a positional parameter index. - */ -final class FunctionPositionAdj extends MkFunctionPosition::FunctionPosition { - FunctionPosition asNonAdjusted() { this = result.asAdjusted() } } /** @@ -127,20 +64,6 @@ module FunctionPositionMatchingInput { } } -/** - * A helper module for implementing `Matching(WithEnvironment)InputSig` with - * `DeclarationPosition = AccessPosition = FunctionPositionAdj`. - */ -module FunctionPositionAdjMatchingInput { - class DeclarationPosition = FunctionPositionAdj; - - class AccessPosition = DeclarationPosition; - - predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos = dpos - } -} - private newtype TAssocFunctionType = /** An associated function `f` in `parent` should be specialized for `i` at `pos`. */ MkAssocFunctionType( @@ -378,10 +301,10 @@ signature module ArgsAreInstantiationsOfInputSig { * `tp` is a type parameter of the trait being implemented by `f` or the trait to which * `f` belongs. * - * `posAdj` is one of the function-call adjusted positions in `f` in which the relevant + * `pos` is one of the function-call adjusted positions in `f` in which the relevant * type occurs. */ - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPositionAdj posAdj); + predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos); /** A call whose argument types are to be checked. */ class Call { @@ -389,7 +312,7 @@ signature module ArgsAreInstantiationsOfInputSig { Location getLocation(); - Type getArgType(FunctionPositionAdj posAdj, TypePath path); + Type getArgType(FunctionPosition pos, TypePath path); predicate hasTargetCand(ImplOrTraitItemNode i, Function f); } @@ -403,9 +326,9 @@ signature module ArgsAreInstantiationsOfInputSig { module ArgsAreInstantiationsOf { pragma[nomagic] private predicate toCheckRanked( - ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPositionAdj posAdj, int rnk + ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, int rnk ) { - Input::toCheck(i, f, tp, posAdj) and + Input::toCheck(i, f, tp, pos) and tp = rank[rnk + 1](TypeParameter tp0, int j | Input::toCheck(i, f, tp0, _) and @@ -417,59 +340,53 @@ module ArgsAreInstantiationsOf { pragma[nomagic] private predicate toCheck( - ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPositionAdj posAdj, - AssocFunctionType t + ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, AssocFunctionType t ) { - exists(FunctionPosition pos | - Input::toCheck(i, f, tp, posAdj) and - t.appliesTo(f, i, pos) and - posAdj = pos.getFunctionCallAdjusted(f) - ) + Input::toCheck(i, f, tp, pos) and + t.appliesTo(f, i, pos) } - private newtype TCallAndPosAdj = - MkCallAndPosAdj(Input::Call call, FunctionPositionAdj posAdj) { - exists(call.getArgType(posAdj, _)) - } + private newtype TCallAndPos = + MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) } /** A call tagged with a function-call adjusted position. */ - private class CallAndPosAdj extends MkCallAndPosAdj { + private class CallAndPos extends MkCallAndPos { Input::Call call; - FunctionPositionAdj posAdj; + FunctionPosition pos; - CallAndPosAdj() { this = MkCallAndPosAdj(call, posAdj) } + CallAndPos() { this = MkCallAndPos(call, pos) } Input::Call getCall() { result = call } - FunctionPositionAdj getPosAdj() { result = posAdj } + FunctionPosition getPos() { result = pos } Location getLocation() { result = call.getLocation() } - Type getTypeAt(TypePath path) { result = call.getArgType(posAdj, path) } + Type getTypeAt(TypePath path) { result = call.getArgType(pos, path) } - string toString() { result = call.toString() + " [arg " + posAdj + "]" } + string toString() { result = call.toString() + " [arg " + pos + "]" } } pragma[nomagic] private predicate potentialInstantiationOf0( - CallAndPosAdj cp, Input::Call call, TypeParameter tp, FunctionPositionAdj posAdj, Function f, + CallAndPos cp, Input::Call call, TypeParameter tp, FunctionPosition pos, Function f, TypeAbstraction abs, AssocFunctionType constraint ) { - cp = MkCallAndPosAdj(call, pragma[only_bind_into](posAdj)) and + cp = MkCallAndPos(call, pragma[only_bind_into](pos)) and call.hasTargetCand(abs, f) and - toCheck(abs, f, tp, pragma[only_bind_into](posAdj), constraint) + toCheck(abs, f, tp, pragma[only_bind_into](pos), constraint) } private module ArgIsInstantiationOfToIndexInput implements - IsInstantiationOfInputSig + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - CallAndPosAdj cp, TypeAbstraction abs, AssocFunctionType constraint + CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(Input::Call call, TypeParameter tp, FunctionPositionAdj posAdj, int rnk, Function f | - potentialInstantiationOf0(cp, call, tp, posAdj, f, abs, constraint) and - toCheckRanked(abs, f, tp, posAdj, rnk) + exists(Input::Call call, TypeParameter tp, FunctionPosition pos, int rnk, Function f | + potentialInstantiationOf0(cp, call, tp, pos, f, abs, constraint) and + toCheckRanked(abs, f, tp, pos, rnk) | rnk = 0 or @@ -481,15 +398,15 @@ module ArgsAreInstantiationsOf { } private module ArgIsInstantiationOfToIndex = - ArgIsInstantiationOf; + ArgIsInstantiationOf; pragma[nomagic] private predicate argIsInstantiationOf( Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - exists(FunctionPositionAdj posAdj | - ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPosAdj(call, posAdj), i, _) and - toCheckRanked(i, f, _, posAdj, rnk) + exists(FunctionPosition pos | + ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and + toCheckRanked(i, f, _, pos, rnk) ) } @@ -521,11 +438,11 @@ module ArgsAreInstantiationsOf { } private module ArgsAreNotInstantiationOfInput implements - IsInstantiationOfInputSig + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - CallAndPosAdj cp, TypeAbstraction abs, AssocFunctionType constraint + CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint ) { potentialInstantiationOf0(cp, _, _, _, _, abs, constraint) } @@ -534,13 +451,13 @@ module ArgsAreInstantiationsOf { } private module ArgsAreNotInstantiationOf = - ArgIsInstantiationOf; + ArgIsInstantiationOf; pragma[nomagic] private predicate argsAreNotInstantiationsOf0( - Input::Call call, FunctionPositionAdj posAdj, ImplOrTraitItemNode i + Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i ) { - ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPosAdj(call, posAdj), i, _, _) + ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _) } /** @@ -551,10 +468,10 @@ module ArgsAreInstantiationsOf { */ pragma[nomagic] predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) { - exists(FunctionPositionAdj posAdj | - argsAreNotInstantiationsOf0(call, posAdj, i) and + exists(FunctionPosition pos | + argsAreNotInstantiationsOf0(call, pos, i) and call.hasTargetCand(i, f) and - Input::toCheck(i, f, _, posAdj) + Input::toCheck(i, f, _, pos) ) } } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 295b5b84b2c..2720f9b25f3 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -298,17 +298,14 @@ private class FunctionDeclaration extends Function { } pragma[nomagic] - Type getParameterType(ImplOrTraitItemNodeOption i, FunctionPositionAdj posAdj, TypePath path) { + Type getParameterType(ImplOrTraitItemNodeOption i, FunctionPosition pos, TypePath path) { i = parent and ( - exists(FunctionPosition pos | - not pos.isReturn() and - result = getAssocFunctionTypeAt(this, i.asSome(), pos, path) and - posAdj = pos.getFunctionCallAdjusted(this) - ) + not pos.isReturn() and + result = getAssocFunctionTypeAt(this, i.asSome(), pos, path) or i.isNone() and - result = this.getParam(posAdj.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) + result = this.getParam(pos.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) ) } @@ -1035,9 +1032,12 @@ private module StructExprMatchingInput implements MatchingInputSig { private module StructExprMatching = Matching; pragma[nomagic] -private Type inferStructExprType0(AstNode n, FunctionPosition pos, TypePath path) { +private Type inferStructExprType0( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path +) { exists(StructExprMatchingInput::Access a, StructExprMatchingInput::AccessPosition apos | n = a.getNodeAt(apos) and + hasReceiver = false and if apos.isStructPos() then pos.isReturn() else pos.asPosition() = 0 // the actual position doesn't matter, as long as it is positional | result = StructExprMatching::inferAccessType(a, apos, path) @@ -1052,7 +1052,7 @@ private Type inferStructExprType0(AstNode n, FunctionPosition pos, TypePath path * a field expression of a struct expression. */ private predicate inferStructExprType = - ContextTyping::CheckContextTyping::check/2; + ContextTyping::CheckContextTyping::check/2; pragma[nomagic] private TupleType inferTupleRootType(AstNode n) { @@ -1240,7 +1240,9 @@ private module ContextTyping { pragma[nomagic] private predicate hasUnknownType(AstNode n) { hasUnknownTypeAt(n, _) } - signature Type inferCallTypeSig(AstNode n, FunctionPosition pos, TypePath path); + signature Type inferCallTypeSig( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path + ); /** * Given a predicate `inferCallType` for inferring the type of a call at a given @@ -1248,33 +1250,35 @@ private module ContextTyping { * predicate and checks that types are only propagated into arguments when they * are context-typed. */ - module CheckContextTyping { + module CheckContextTyping { pragma[nomagic] - private Type inferCallNonReturnType(AstNode n, FunctionPosition pos, TypePath path) { - result = inferCallType(n, pos, path) and + private Type inferCallNonReturnType( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path + ) { + result = inferCallType(n, pos, hasReceiver, path) and not pos.isReturn() } pragma[nomagic] private Type inferCallNonReturnType( - AstNode n, FunctionPosition pos, TypePath prefix, TypePath path + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath prefix, TypePath path ) { - result = inferCallNonReturnType(n, pos, path) and + result = inferCallNonReturnType(n, pos, hasReceiver, path) and hasUnknownType(n) and prefix = path.getAPrefix() } pragma[nomagic] Type check(AstNode n, TypePath path) { - result = inferCallType(n, any(FunctionPosition pos | pos.isReturn()), path) + result = inferCallType(n, any(FunctionPosition pos | pos.isReturn()), _, path) or - exists(FunctionPosition pos, TypePath prefix | - result = inferCallNonReturnType(n, pos, prefix, path) and + exists(FunctionPosition pos, boolean hasReceiver, TypePath prefix | + result = inferCallNonReturnType(n, pos, hasReceiver, prefix, path) and hasUnknownTypeAt(n, prefix) | // Never propagate type information directly into the receiver, since its type // must already have been known in order to resolve the call - if pos.isSelf() then not prefix.isEmpty() else any() + if pos.asPosition() = 0 and hasReceiver = true then not prefix.isEmpty() else any() ) } } @@ -1372,19 +1376,16 @@ private class BorrowKind extends TBorrowKind { private module AssocFunctionResolution { /** * Holds if function `f` with the name `name` and the arity `arity` exists in - * `i`, and the type at function-call adjusted position `posAdj` is `t`. + * `i`, and the type at function-call adjusted position `pos` is `t`. */ pragma[nomagic] private predicate assocFunctionInfo( - Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPositionAdj posAdj, + Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos, AssocFunctionType t ) { - exists(FunctionPosition pos | - f = i.getASuccessor(name) and - arity = f.getNumberOfParamsInclSelf() and - t.appliesTo(f, i, pos) and - posAdj = pos.getFunctionCallAdjusted(f) - ) + f = i.getASuccessor(name) and + arity = f.getNumberOfParamsInclSelf() and + t.appliesTo(f, i, pos) } /** @@ -1419,9 +1420,9 @@ private module AssocFunctionResolution { /** * Holds if function `f` with the name `name` and the arity `arity` exists in - * `i`, and the type at function-call adjusted position `selfPosAdj` is `selfType`. + * `i`, and the type at function-call adjusted position `selfPos` is `selfType`. * - * `selfPosAdj` is a position relevant for call resolution: either a position + * `selfPos` is a position relevant for call resolution: either a position * corresponding to the `self` parameter of `f` (if present); a type qualifier * position; or a position where the implicit `Self` type parameter of some trait * is mentioned in some non-method function `f_trait`, and either `f = f_trait` @@ -1440,28 +1441,26 @@ private module AssocFunctionResolution { */ pragma[nomagic] private predicate assocFunctionInfo( - Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + Function f, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, TypeOption implType, TypeOption trait, boolean isMethod ) { - assocFunctionInfo(f, name, arity, i, selfPosAdj, selfType) and + assocFunctionInfo(f, name, arity, i, selfPos, selfType) and strippedType = selfType.getTypeAt(strippedTypePath) and ( isComplexRootStripped(strippedTypePath, strippedType) or - selfPosAdj.isTypeQualifier() and strippedTypePath.isEmpty() + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() ) and ( f instanceof Method and - selfPosAdj.asPosition() = 0 + selfPos.asPosition() = 0 or - selfPosAdj.isTypeQualifier() + selfPos.isTypeQualifier() or - exists(FunctionPosition pos | selfPosAdj = pos.asAdjusted() | - traitSelfTypeParameterOccurrence(i, f, pos) - or - traitImplSelfTypeParameterOccurrence(i, f, pos) - ) + traitSelfTypeParameterOccurrence(i, f, selfPos) + or + traitImplSelfTypeParameterOccurrence(i, f, selfPos) ) and ( implType.asSome() = resolveImplSelfTypeAt(i, TypePath::nil()) @@ -1484,9 +1483,9 @@ private module AssocFunctionResolution { /** * Holds if function `f` with the name `name` and the arity `arity` exists in * blanket (like) implementation `impl`, and the type at function-call adjusted - * position `selfPosAdj` is `selfType`. + * position `selfPos` is `selfType`. * - * `selfPosAdj` is a position relevant for call resolution: either a position + * `selfPos` is a position relevant for call resolution: either a position * corresponding to the `self` parameter of `f` (if present); a type qualifier * position; or a position where the implicit `Self` type parameter of some trait * is mentioned in some non-method function `f_trait`, and `f` implements `f_trait`. @@ -1503,11 +1502,11 @@ private module AssocFunctionResolution { pragma[nomagic] private predicate assocFunctionInfoBlanketLike( Function f, string name, int arity, ImplItemNode impl, TypeOption implType, TypeOption trait, - FunctionPositionAdj selfPosAdj, AssocFunctionType selfType, TypePath blanketPath, + FunctionPosition selfPos, AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam, boolean isMethod ) { exists(TypePath blanketSelfPath | - assocFunctionInfo(f, name, arity, selfPosAdj, impl, selfType, _, _, implType, trait, isMethod) and + assocFunctionInfo(f, name, arity, selfPos, impl, selfType, _, _, implType, trait, isMethod) and TTypeParamTypeParameter(blanketTypeParam) = selfType.getTypeAt(blanketPath) and blanketPath = any(string s) + blanketSelfPath and BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) @@ -1579,12 +1578,12 @@ private module AssocFunctionResolution { pragma[nomagic] private predicate assocFunctionInfoNonBlanketLikeCheck( - Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + Function f, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver ) { exists(TypeOption implType, TypeOption trait, boolean isMethod | - assocFunctionInfo(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, strippedType, + assocFunctionInfo(f, name, arity, selfPos, i, selfType, strippedTypePath, strippedType, implType, trait, isMethod) and not BlanketImplementation::isBlanketLike(i, _, _) and callCheck(implType, trait, isMethod, typeQualifier, traitQualifier, hasReceiver) @@ -1593,17 +1592,17 @@ private module AssocFunctionResolution { pragma[nomagic] private predicate assocFunctionInfoNonBlanketLikeTypeParamCheck( - Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + Function f, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver ) { - assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, + assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPos, i, selfType, strippedTypePath, TTypeParamTypeParameter(_), typeQualifier, traitQualifier, hasReceiver) } /** * Holds if call `afc` may target function `f` in `i` with type `selfType` at - * function-call adjusted position `selfPosAdj`. + * function-call adjusted position `selfPos`. * * `strippedTypePath` points to the type `strippedType` inside `selfType`, * which is the (possibly complex-stripped) root type of `selfType`. @@ -1611,7 +1610,7 @@ private module AssocFunctionResolution { bindingset[afc, strippedTypePath, strippedType] pragma[inline_late] private predicate nonBlanketLikeCandidate( - AssocFunctionCall afc, Function f, FunctionPositionAdj selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionCall afc, Function f, FunctionPosition selfPos, ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType ) { exists( @@ -1623,10 +1622,10 @@ private module AssocFunctionResolution { then callVisibleImplTraitCandidate(afc, i) else any() | - assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPosAdj, i, selfType, - strippedTypePath, strippedType, typeQualifier, traitQualifier, hasReceiver) + assocFunctionInfoNonBlanketLikeCheck(f, name, arity, selfPos, i, selfType, strippedTypePath, + strippedType, typeQualifier, traitQualifier, hasReceiver) or - assocFunctionInfoNonBlanketLikeTypeParamCheck(f, name, arity, selfPosAdj, i, selfType, + assocFunctionInfoNonBlanketLikeTypeParamCheck(f, name, arity, selfPos, i, selfType, strippedTypePath, typeQualifier, traitQualifier, hasReceiver) ) } @@ -1634,12 +1633,12 @@ private module AssocFunctionResolution { bindingset[name, arity, typeQualifier, traitQualifier, hasReceiver] pragma[inline_late] private predicate assocFunctionInfoBlanketLikeCheck( - Function f, string name, int arity, FunctionPositionAdj selfPosAdj, ImplItemNode impl, + Function f, string name, int arity, FunctionPosition selfPos, ImplItemNode impl, AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam, TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver ) { exists(TypeOption implType, TypeOption trait, boolean isMethod | - assocFunctionInfoBlanketLike(f, name, arity, impl, implType, trait, selfPosAdj, selfType, + assocFunctionInfoBlanketLike(f, name, arity, impl, implType, trait, selfPos, selfType, blanketPath, blanketTypeParam, isMethod) and callTraitQualifierAndReceiverCheck(trait, isMethod, traitQualifier, hasReceiver) and if impl.isBlanketImplementation() @@ -1650,7 +1649,7 @@ private module AssocFunctionResolution { /** * Holds if call `afc` may target function `f` in blanket (like) implementation - * `impl` with type `selfType` at function-call adjusted position `selfPosAdj`. + * `impl` with type `selfType` at function-call adjusted position `selfPos`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. @@ -1658,7 +1657,7 @@ private module AssocFunctionResolution { bindingset[afc] pragma[inline_late] private predicate blanketLikeCandidate( - AssocFunctionCall afc, Function f, FunctionPositionAdj selfPosAdj, ImplItemNode impl, + AssocFunctionCall afc, Function f, FunctionPosition selfPos, ImplItemNode impl, AssocFunctionType self, TypePath blanketPath, TypeParam blanketTypeParam ) { exists( @@ -1666,7 +1665,7 @@ private module AssocFunctionResolution { boolean hasReceiver | afc.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and - assocFunctionInfoBlanketLikeCheck(f, name, arity, selfPosAdj, impl, self, blanketPath, + assocFunctionInfoBlanketLikeCheck(f, name, arity, selfPos, impl, self, blanketPath, blanketTypeParam, typeQualifier, traitQualifier, hasReceiver) | if not afc.hasATrait() then callVisibleImplTraitCandidate(afc, impl) else any() @@ -1702,19 +1701,10 @@ private module AssocFunctionResolution { abstract Expr getNonReturnNodeAt(FunctionPosition pos); - FunctionPositionAdj getFunctionCallAdjustedPosition(FunctionPosition pos) { - if this.hasReceiver() - then result = pos.getFunctionCallAdjusted() - else result = pos.asAdjusted() - } - - AstNode getNodeAt(FunctionPositionAdj posAdj) { - exists(FunctionPosition pos | - result = this.getNonReturnNodeAt(pos) and - posAdj = this.getFunctionCallAdjustedPosition(pos) - ) + AstNode getNodeAt(FunctionPosition pos) { + result = this.getNonReturnNodeAt(pos) or - result = this and posAdj.isReturn() + result = this and pos.isReturn() } /** Holds if this call has a receiver and hence must target a method. */ @@ -1766,57 +1756,54 @@ private module AssocFunctionResolution { ) } - Type getTypeAt(FunctionPositionAdj posAdj, TypePath path) { - result = inferType(this.getNodeAt(posAdj), path) + Type getTypeAt(FunctionPosition pos, TypePath path) { + result = inferType(this.getNodeAt(pos), path) } /** - * Holds if `selfPosAdj` is a potentially relevant function-call adjusted position + * Holds if `selfPos` is a potentially relevant function-call adjusted position * for resolving this call. * * Only holds when we don't know for sure that the target is a method (in those * cases we rely on the receiver only). */ pragma[nomagic] - private predicate isRelevantSelfPosAdj(FunctionPositionAdj selfPosAdj) { + private predicate isRelevantSelfPos(FunctionPosition selfPos) { not this.hasReceiver() and exists(TypePath strippedTypePath, Type strippedType | - strippedType = substituteLookupTraits(this.getTypeAt(selfPosAdj, strippedTypePath)) and + strippedType = substituteLookupTraits(this.getTypeAt(selfPos, strippedTypePath)) and strippedType != TNeverType() and strippedType != TUnknownType() | - nonBlanketLikeCandidate(this, _, selfPosAdj, _, _, strippedTypePath, strippedType) + nonBlanketLikeCandidate(this, _, selfPos, _, _, strippedTypePath, strippedType) or - blanketLikeCandidate(this, _, selfPosAdj, _, _, strippedTypePath, _) + blanketLikeCandidate(this, _, selfPos, _, _, strippedTypePath, _) ) } - predicate hasReceiverAtPos(FunctionPositionAdj posAdj) { - this.hasReceiver() and posAdj.asPosition() = 0 - } + predicate hasReceiverAtPos(FunctionPosition pos) { this.hasReceiver() and pos.asPosition() = 0 } /** * Holds if the function inside `i` with matching name and arity can be ruled * out as a target of this call, because the candidate receiver type represented * by `derefChain` and `borrow` is incompatible with the type at function-call - * adjusted position `selfPosAdj`. + * adjusted position `selfPos`. * * The types are incompatible because they disagree on a concrete type somewhere * inside `root`. */ pragma[nomagic] private predicate hasIncompatibleTarget( - ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, DerefChain derefChain, - BorrowKind borrow, Type root + ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + Type root ) { exists(TypePath path | - SelfArgIsInstantiationOf::argIsNotInstantiationOf(this, i, selfPosAdj, derefChain, borrow, - path) and + SelfArgIsInstantiationOf::argIsNotInstantiationOf(this, i, selfPos, derefChain, borrow, path) and path.isCons(root.getATypeParameter(), _) ) or exists(AssocFunctionType selfType | - SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, selfPosAdj, derefChain, borrow, + SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, selfPos, derefChain, borrow, selfType) and OverloadedCallArgsAreInstantiationsOf::argsAreNotInstantiationsOf(this, i) and root = selfType.getTypeAt(TypePath::nil()) @@ -1827,43 +1814,41 @@ private module AssocFunctionResolution { * Holds if the function inside blanket-like implementation `impl` with matching name * and arity can be ruled out as a target of this call, either because the candidate * receiver type represented by `derefChain` and `borrow` is incompatible with the type - * at function-call adjusted position `selfPosAdj`, or because the blanket constraint + * at function-call adjusted position `selfPos`, or because the blanket constraint * is not satisfied. */ pragma[nomagic] private predicate hasIncompatibleBlanketLikeTarget( - ImplItemNode impl, FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow + ImplItemNode impl, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { SelfArgIsNotInstantiationOfBlanketLike::argIsNotInstantiationOf(MkAssocFunctionCallCand(this, - selfPosAdj, derefChain, borrow), impl, _, _) + selfPos, derefChain, borrow), impl, _, _) or ArgSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkAssocFunctionCallCand(this, - selfPosAdj, derefChain, borrow), impl) + selfPos, derefChain, borrow), impl) } pragma[nomagic] private predicate hasNoInherentTargetCheck( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - MkAssocFunctionCallCand(this, selfPosAdj, derefChain, borrow) + MkAssocFunctionCallCand(this, selfPos, derefChain, borrow) .(AssocFunctionCallCand) .hasNoInherentTargetCheck() } pragma[nomagic] private predicate hasNoInherentTargetTypeQualifierCheck() { - exists(FunctionPositionAdj typeQualifierPos | + exists(FunctionPosition typeQualifierPos | typeQualifierPos.isTypeQualifier() and this.hasNoInherentTargetCheck(typeQualifierPos, DerefChain::nil(), TNoBorrowKind()) ) } pragma[nomagic] - predicate hasNoInherentTarget( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow - ) { - this.hasNoInherentTargetCheck(selfPosAdj, derefChain, borrow) and - if exists(this.getNonTypeParameterTypeQualifier()) and not selfPosAdj.isTypeQualifier() + predicate hasNoInherentTarget(FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow) { + this.hasNoInherentTargetCheck(selfPos, derefChain, borrow) and + if exists(this.getNonTypeParameterTypeQualifier()) and not selfPos.isTypeQualifier() then // If this call is of the form `Foo::bar(x)` and we are resolving with respect to the type // of `x`, then we additionally need to check that the type qualifier does not give rise @@ -1877,93 +1862,92 @@ private module AssocFunctionResolution { */ pragma[nomagic] Type getANonPseudoSelfTypeAt( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, TypePath path + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getSelfTypeAt(selfPosAdj, derefChain, borrow, path) and + result = this.getSelfTypeAt(selfPos, derefChain, borrow, path) and result != TNeverType() and result != TUnknownType() } pragma[nomagic] private Type getComplexStrippedSelfType( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, - TypePath strippedTypePath + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath ) { - result = this.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, strippedTypePath) and + result = this.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, strippedTypePath) and ( isComplexRootStripped(strippedTypePath, result) or - selfPosAdj.isTypeQualifier() and strippedTypePath.isEmpty() + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketLikeTargetCheck( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, - TypePath strippedTypePath, Type strippedType + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, + Type strippedType ) { forall(ImplOrTraitItemNode i | - nonBlanketLikeCandidate(this, _, selfPosAdj, i, _, strippedTypePath, strippedType) + nonBlanketLikeCandidate(this, _, selfPos, i, _, strippedTypePath, strippedType) | - this.hasIncompatibleTarget(i, selfPosAdj, derefChain, borrow, strippedType) + this.hasIncompatibleTarget(i, selfPos, derefChain, borrow, strippedType) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleTargetCheck( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, - TypePath strippedTypePath, Type strippedType + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, + Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, borrow, - strippedTypePath, strippedType) and - forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) | - this.hasIncompatibleBlanketLikeTarget(i, selfPosAdj, derefChain, borrow) + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, + strippedType) and + forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPos, i, _, _, _) | + this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketTargetCheck( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, - TypePath strippedTypePath, Type strippedType + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, + Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, borrow, - strippedTypePath, strippedType) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, + strippedType) and forall(ImplItemNode i | - blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) and + blanketLikeCandidate(this, _, selfPos, i, _, _, _) and not i.isBlanketImplementation() | - this.hasIncompatibleBlanketLikeTarget(i, selfPosAdj, derefChain, borrow) + this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) ) } // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetNoBorrowToIndex( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, - Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { this.supportsAutoDerefAndBorrow() and - this.hasReceiverAtPos(selfPosAdj) and + this.hasReceiverAtPos(selfPos) and strippedType = - this.getComplexStrippedSelfType(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetNoBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, - strippedType, n - 1) and + this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, + n - 1) and exists(Type t | t = getNthLookupType(strippedType, n) and - this.hasNoCompatibleTargetCheck(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath, t) + this.hasNoCompatibleTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain` does not - * have a matching call target at function-call adjusted position `selfPosAdj`. + * have a matching call target at function-call adjusted position `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleTargetNoBorrow(FunctionPositionAdj selfPosAdj, DerefChain derefChain) { + predicate hasNoCompatibleTargetNoBorrow(FunctionPosition selfPos, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetNoBorrowToIndex(selfPosAdj, derefChain, _, strippedType, + this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1971,44 +1955,44 @@ private module AssocFunctionResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndex( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, - Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { ( this.supportsAutoDerefAndBorrow() and - this.hasReceiverAtPos(selfPosAdj) + this.hasReceiverAtPos(selfPos) or // needed for the `hasNoCompatibleNonBlanketTarget` check in // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` exists(ImplItemNode i | derefChain.isEmpty() and - blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) and + blanketLikeCandidate(this, _, selfPos, i, _, _, _) and i.isBlanketImplementation() ) ) and strippedType = - this.getComplexStrippedSelfType(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and exists(Type t | t = getNthLookupType(strippedType, n) and - this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TNoBorrowKind(), + this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain` does not have - * a matching non-blanket call target at function-call adjusted position `selfPosAdj`. + * a matching non-blanket call target at function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetNoBorrow( - FunctionPositionAdj selfPosAdj, DerefChain derefChain + FunctionPosition selfPos, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPosAdj, derefChain, _, strippedType, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -2016,35 +2000,33 @@ private module AssocFunctionResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetSharedBorrowToIndex( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, - Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(false), + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and exists(Type t | t = getNthLookupType(strippedType, n) and - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, - TSomeBorrowKind(false), strippedTypePath, t) + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), + strippedTypePath, t) ) } /** * Holds if the candidate receiver type represented by `derefChain`, followed * by a shared borrow, does not have a matching call target at function-call - * adjusted position `selfPosAdj`. + * adjusted position `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleTargetSharedBorrow( - FunctionPositionAdj selfPosAdj, DerefChain derefChain - ) { + predicate hasNoCompatibleTargetSharedBorrow(FunctionPosition selfPos, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPosAdj, derefChain, _, strippedType, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -2052,20 +2034,19 @@ private module AssocFunctionResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetMutBorrowToIndex( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, - Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleTargetSharedBorrow(selfPosAdj, derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(true), - strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetMutBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and exists(Type t | t = getNthLookupType(strippedType, n) and - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(true), + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } @@ -2073,12 +2054,12 @@ private module AssocFunctionResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed * by a `mut` borrow, does not have a matching call target at function-call - * adjusted position `selfPosAdj`. + * adjusted position `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleTargetMutBorrow(FunctionPositionAdj selfPosAdj, DerefChain derefChain) { + predicate hasNoCompatibleTargetMutBorrow(FunctionPosition selfPos, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetMutBorrowToIndex(selfPosAdj, derefChain, _, strippedType, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -2086,20 +2067,20 @@ private module AssocFunctionResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndex( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, - Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(false), + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPosAdj, derefChain, - strippedTypePath, strippedType, n - 1) and + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, + strippedType, n - 1) and exists(Type t | t = getNthLookupType(strippedType, n) and - this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(false), + this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) } @@ -2107,14 +2088,14 @@ private module AssocFunctionResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed * by a shared borrow, does not have a matching non-blanket call target at - * function-call adjusted position `selfPosAdj`. + * function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetSharedBorrow( - FunctionPositionAdj selfPosAdj, DerefChain derefChain + FunctionPosition selfPos, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPosAdj, derefChain, _, + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -2122,20 +2103,19 @@ private module AssocFunctionResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndex( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, - Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPosAdj, derefChain) and + this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(true), - strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, n - 1) and exists(Type t | t = getNthLookupType(strippedType, n) and - this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(true), + this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } @@ -2143,15 +2123,15 @@ private module AssocFunctionResolution { /** * Holds if the candidate receiver type represented by `derefChain`, followed * by a `mut` borrow, does not have a matching non-blanket call target at - * function-call adjusted position `selfPosAdj`. + * function-call adjusted position `selfPos`. */ pragma[nomagic] predicate hasNoCompatibleNonBlanketTargetMutBorrow( - FunctionPositionAdj selfPosAdj, DerefChain derefChain + FunctionPosition selfPos, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPosAdj, derefChain, _, - strippedType, getLastLookupTypeIndex(strippedType)) + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, + getLastLookupTypeIndex(strippedType)) ) } @@ -2159,29 +2139,29 @@ private module AssocFunctionResolution { * Same as `getSelfTypeAt`, but without borrows. */ pragma[nomagic] - Type getSelfTypeAtNoBorrow(FunctionPositionAdj selfPosAdj, DerefChain derefChain, TypePath path) { - result = this.getTypeAt(selfPosAdj, path) and + Type getSelfTypeAtNoBorrow(FunctionPosition selfPos, DerefChain derefChain, TypePath path) { + result = this.getTypeAt(selfPos, path) and derefChain.isEmpty() and ( - this.hasReceiverAtPos(selfPosAdj) + this.hasReceiverAtPos(selfPos) or - selfPosAdj.isTypeQualifier() + selfPos.isTypeQualifier() or - this.isRelevantSelfPosAdj(selfPosAdj) + this.isRelevantSelfPos(selfPos) ) or exists(DerefImplItemNode impl, DerefChain suffix | result = - ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPosAdj, impl, suffix, path) and + ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPos, impl, suffix, path) and derefChain = DerefChain::cons(impl, suffix) ) } /** - * Gets the type of this call at function-call adjusted position `selfPosAdj` and + * Gets the type of this call at function-call adjusted position `selfPos` and * type path `path`. * - * In case this call supports auto-dereferencing and borrowing and `selfPosAdj` is + * In case this call supports auto-dereferencing and borrowing and `selfPos` is * position 0 (corresponding to the receiver), the result is a * [candidate receiver type][1]: * @@ -2196,18 +2176,18 @@ private module AssocFunctionResolution { */ pragma[nomagic] Type getSelfTypeAt( - FunctionPositionAdj selfPosAdj, DerefChain derefChain, BorrowKind borrow, TypePath path + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, path) and + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, path) and borrow.isNoBorrow() or exists(RefType rt | // first try shared borrow - this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and borrow.isSharedBorrow() or // then try mutable borrow - this.hasNoCompatibleTargetSharedBorrow(selfPosAdj, derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and borrow.isMutableBorrow() | rt = borrow.getRefType() and @@ -2216,7 +2196,7 @@ private module AssocFunctionResolution { result = rt or exists(TypePath suffix | - result = this.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, suffix) and + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, suffix) and path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) ) ) @@ -2225,16 +2205,15 @@ private module AssocFunctionResolution { /** * Gets a function that this call resolves to after having applied a sequence of - * dereferences and possibly a borrow on the receiver type at `selfPosAdj`, encoded + * dereferences and possibly a borrow on the receiver type at `selfPos`, encoded * in `derefChain` and `borrow`. */ pragma[nomagic] AssocFunction resolveCallTarget( - ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, DerefChain derefChain, - BorrowKind borrow + ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { exists(AssocFunctionCallCand afcc | - afcc = MkAssocFunctionCallCand(this, selfPosAdj, derefChain, borrow) and + afcc = MkAssocFunctionCallCand(this, selfPos, derefChain, borrow) and result = afcc.resolveCallTarget(i) ) } @@ -2245,7 +2224,7 @@ private module AssocFunctionResolution { * resolve the call target. */ predicate argumentHasImplicitDerefChainBorrow(Expr arg, DerefChain derefChain, BorrowKind borrow) { - exists(FunctionPositionAdj selfAdj | + exists(FunctionPosition selfAdj | this.hasReceiverAtPos(selfAdj) and exists(this.resolveCallTarget(_, selfAdj, derefChain, borrow)) and arg = this.getNodeAt(selfAdj) and @@ -2263,7 +2242,10 @@ private module AssocFunctionResolution { override predicate hasReceiver() { any() } override Expr getNonReturnNodeAt(FunctionPosition pos) { - result = super.getSyntacticArgument(pos.asArgumentPosition()) + result = super.getReceiver() and + pos.asPosition() = 0 + or + result = super.getPositionalArgument(pos.asPosition() - 1) } override predicate supportsAutoDerefAndBorrow() { any() } @@ -2285,10 +2267,10 @@ private module AssocFunctionResolution { override predicate hasReceiver() { any() } override Expr getNonReturnNodeAt(FunctionPosition pos) { - pos.isSelf() and + pos.asPosition() = 0 and result = this.getBase() or - pos.asPosition() = 0 and + pos.asPosition() = 1 and result = this.getIndex() } @@ -2320,10 +2302,10 @@ private module AssocFunctionResolution { result = this.getSyntacticPositionalArgument(pos.asPosition()) } - override Type getTypeAt(FunctionPositionAdj posAdj, TypePath path) { - result = super.getTypeAt(posAdj, path) + override Type getTypeAt(FunctionPosition pos, TypePath path) { + result = super.getTypeAt(pos, path) or - posAdj.isTypeQualifier() and + pos.isTypeQualifier() and result = getCallExprTypeQualifier(this, path, _) } @@ -2341,48 +2323,45 @@ private module AssocFunctionResolution { override predicate hasReceiver() { any() } override Expr getNonReturnNodeAt(FunctionPosition pos) { - pos.isSelf() and - result = this.getOperand(0) - or - result = this.getOperand(pos.asPosition() + 1) + result = this.getOperand(pos.asPosition()) } - private predicate implicitBorrowAt(FunctionPositionAdj posAdj, boolean isMutable) { + private predicate implicitBorrowAt(FunctionPosition pos, boolean isMutable) { exists(int borrows | this.isOverloaded(_, _, borrows) | - posAdj.asPosition() = 0 and + pos.asPosition() = 0 and borrows >= 1 and if this instanceof CompoundAssignmentExpr then isMutable = true else isMutable = false or - posAdj.asPosition() = 1 and + pos.asPosition() = 1 and borrows = 2 and isMutable = false ) } - override Type getTypeAt(FunctionPositionAdj posAdj, TypePath path) { + override Type getTypeAt(FunctionPosition pos, TypePath path) { exists(boolean isMutable, RefType rt | - this.implicitBorrowAt(posAdj, isMutable) and + this.implicitBorrowAt(pos, isMutable) and rt = getRefType(isMutable) | result = rt and path.isEmpty() or exists(TypePath path0 | - result = inferType(this.getNodeAt(posAdj), path0) and + result = inferType(this.getNodeAt(pos), path0) and path = TypePath::cons(rt.getPositionalTypeParameter(0), path0) ) ) or - not this.implicitBorrowAt(posAdj, _) and - result = inferType(this.getNodeAt(posAdj), path) + not this.implicitBorrowAt(pos, _) and + result = inferType(this.getNodeAt(pos), path) } override predicate argumentHasImplicitDerefChainBorrow( Expr arg, DerefChain derefChain, BorrowKind borrow ) { - exists(FunctionPositionAdj posAdj, boolean isMutable | - this.implicitBorrowAt(posAdj, isMutable) and - arg = this.getNodeAt(posAdj) and + exists(FunctionPosition pos, boolean isMutable | + this.implicitBorrowAt(pos, isMutable) and + arg = this.getNodeAt(pos) and derefChain = DerefChain::nil() and borrow = TSomeBorrowKind(isMutable) ) @@ -2401,56 +2380,53 @@ private module AssocFunctionResolution { private newtype TAssocFunctionCallCand = MkAssocFunctionCallCand( - AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, DerefChain derefChain, - BorrowKind borrow + AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - exists(afc.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, _)) + exists(afc.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, _)) } /** A call with a dereference chain and a potential borrow at a given position. */ final private class AssocFunctionCallCand extends MkAssocFunctionCallCand { AssocFunctionCall afc_; - FunctionPositionAdj selfPosAdj_; + FunctionPosition selfPos_; DerefChain derefChain; BorrowKind borrow; - AssocFunctionCallCand() { - this = MkAssocFunctionCallCand(afc_, selfPosAdj_, derefChain, borrow) - } + AssocFunctionCallCand() { this = MkAssocFunctionCallCand(afc_, selfPos_, derefChain, borrow) } AssocFunctionCall getAssocFunctionCall() { result = afc_ } Type getTypeAt(TypePath path) { result = - substituteLookupTraits(afc_.getANonPseudoSelfTypeAt(selfPosAdj_, derefChain, borrow, path)) + substituteLookupTraits(afc_.getANonPseudoSelfTypeAt(selfPos_, derefChain, borrow, path)) } pragma[nomagic] predicate hasNoCompatibleNonBlanketTarget() { - afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPosAdj_, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos_, derefChain) and borrow.isSharedBorrow() or - afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPosAdj_, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos_, derefChain) and borrow.isMutableBorrow() or - afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPosAdj_, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos_, derefChain) and borrow.isNoBorrow() } pragma[nomagic] predicate hasSignature( - AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, TypePath strippedTypePath, - Type strippedType, string name, int arity + AssocFunctionCall afc, FunctionPosition selfPos, TypePath strippedTypePath, Type strippedType, + string name, int arity ) { strippedType = this.getTypeAt(strippedTypePath) and ( isComplexRootStripped(strippedTypePath, strippedType) or - selfPosAdj_.isTypeQualifier() and strippedTypePath.isEmpty() + selfPos_.isTypeQualifier() and strippedTypePath.isEmpty() ) and afc = afc_ and afc.hasNameAndArity(name, arity) and - selfPosAdj = selfPosAdj_ + selfPos = selfPos_ } /** @@ -2472,20 +2448,20 @@ private module AssocFunctionResolution { // Calls to inherent functions are always of the form `x.m(...)` or `Foo::bar(...)`, // where `Foo` is a type. In case `bar` is a method, we can use both the type qualifier // and the type of the first argument to rule out candidates - selfPosAdj_.isTypeQualifier() and targetMustBeMethod = false + selfPos_.isTypeQualifier() and targetMustBeMethod = false or - selfPosAdj_.asPosition() = 0 and targetMustBeMethod = true + selfPos_.asPosition() = 0 and targetMustBeMethod = true | afc_.hasSyntacticInfo(name, arity, typeQualifier, traitQualifier, hasReceiver) and (if hasReceiver = true then targetMustBeMethod = true else any()) and - this.hasSignature(_, selfPosAdj_, strippedTypePath, strippedType, name, arity) and + this.hasSignature(_, selfPos_, strippedTypePath, strippedType, name, arity) and forall(Impl i | i.isInherent() and ( - assocFunctionInfoNonBlanketLikeCheck(_, name, arity, selfPosAdj_, i, _, - strippedTypePath, strippedType, typeQualifier, traitQualifier, targetMustBeMethod) + assocFunctionInfoNonBlanketLikeCheck(_, name, arity, selfPos_, i, _, strippedTypePath, + strippedType, typeQualifier, traitQualifier, targetMustBeMethod) or - assocFunctionInfoNonBlanketLikeTypeParamCheck(_, name, arity, selfPosAdj_, i, _, + assocFunctionInfoNonBlanketLikeTypeParamCheck(_, name, arity, selfPos_, i, _, strippedTypePath, typeQualifier, traitQualifier, targetMustBeMethod) ) | @@ -2502,7 +2478,7 @@ private module AssocFunctionResolution { predicate hasNoInherentTarget() { afc_.hasTrait() or - afc_.hasNoInherentTarget(selfPosAdj_, derefChain, borrow) + afc_.hasNoInherentTarget(selfPos_, derefChain, borrow) } pragma[nomagic] @@ -2529,7 +2505,7 @@ private module AssocFunctionResolution { } string toString() { - result = afc_ + " at " + selfPosAdj_ + " [" + derefChain.toString() + "; " + borrow + "]" + result = afc_ + " at " + selfPos_ + " [" + derefChain.toString() + "; " + borrow + "]" } Location getLocation() { result = afc_.getLocation() } @@ -2540,23 +2516,23 @@ private module AssocFunctionResolution { */ private module ImplicitDeref { private newtype TCallDerefCand = - MkCallDerefCand(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, DerefChain derefChain) { + MkCallDerefCand(AssocFunctionCall afc, FunctionPosition selfPos, DerefChain derefChain) { afc.supportsAutoDerefAndBorrow() and - afc.hasReceiverAtPos(selfPosAdj) and - afc.hasNoCompatibleTargetMutBorrow(selfPosAdj, derefChain) and - exists(afc.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, TypePath::nil())) + afc.hasReceiverAtPos(selfPos) and + afc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and + exists(afc.getSelfTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) } /** A call with a dereference chain. */ private class CallDerefCand extends MkCallDerefCand { AssocFunctionCall afc; - FunctionPositionAdj selfPosAdj; + FunctionPosition selfPos; DerefChain derefChain; - CallDerefCand() { this = MkCallDerefCand(afc, selfPosAdj, derefChain) } + CallDerefCand() { this = MkCallDerefCand(afc, selfPos, derefChain) } Type getTypeAt(TypePath path) { - result = substituteLookupTraits(afc.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, path)) and + result = substituteLookupTraits(afc.getSelfTypeAtNoBorrow(selfPos, derefChain, path)) and result != TNeverType() and result != TUnknownType() } @@ -2590,11 +2566,11 @@ private module AssocFunctionResolution { */ pragma[nomagic] Type getDereferencedCandidateReceiverType( - AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, DerefImplItemNode impl, + AssocFunctionCall afc, FunctionPosition selfPos, DerefImplItemNode impl, DerefChain derefChain, TypePath path ) { exists(CallDerefCand cdc, TypePath exprPath | - cdc = MkCallDerefCand(afc, selfPosAdj, derefChain) and + cdc = MkCallDerefCand(afc, selfPos, derefChain) and CallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(cdc, impl, _, exprPath, result) and exprPath.isCons(getDerefTargetTypeParameter(), path) ) @@ -2609,9 +2585,9 @@ private module AssocFunctionResolution { AssocFunctionCallCand afcc, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, BorrowKind borrow | - afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, borrow) and - blanketLikeCandidate(afc, _, selfPosAdj, impl, _, blanketPath, blanketTypeParam) and + exists(AssocFunctionCall afc, FunctionPosition selfPos, BorrowKind borrow | + afcc = MkAssocFunctionCallCand(afc, selfPos, _, borrow) and + blanketLikeCandidate(afc, _, selfPos, impl, _, blanketPath, blanketTypeParam) and // Only apply blanket implementations when no other implementations are possible; // this is to account for codebases that use the (unstable) specialization feature // (https://rust-lang.github.io/rfcs/1210-impl-specialization.html), as well as @@ -2642,14 +2618,14 @@ private module AssocFunctionResolution { AssocFunctionCallCand afcc, ImplOrTraitItemNode i, AssocFunctionType selfType ) { exists( - AssocFunctionCall afc, FunctionPositionAdj selfPosAdj, Function f, - TypePath strippedTypePath, Type strippedType + AssocFunctionCall afc, FunctionPosition selfPos, Function f, TypePath strippedTypePath, + Type strippedType | - afcc.hasSignature(afc, selfPosAdj, strippedTypePath, strippedType, _, _) + afcc.hasSignature(afc, selfPos, strippedTypePath, strippedType, _, _) | - nonBlanketLikeCandidate(afc, f, selfPosAdj, i, selfType, strippedTypePath, strippedType) + nonBlanketLikeCandidate(afc, f, selfPos, i, selfType, strippedTypePath, strippedType) or - blanketLikeCandidate(afc, f, selfPosAdj, i, selfType, _, _) and + blanketLikeCandidate(afc, f, selfPos, i, selfType, _, _) and ArgSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(afcc, i) ) } @@ -2677,19 +2653,18 @@ private module AssocFunctionResolution { pragma[nomagic] predicate argIsNotInstantiationOf( - AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, - DerefChain derefChain, BorrowKind borrow, TypePath path + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, + BorrowKind borrow, TypePath path ) { - argIsNotInstantiationOf(MkAssocFunctionCallCand(afc, selfPosAdj, derefChain, borrow), i, _, - path) + argIsNotInstantiationOf(MkAssocFunctionCallCand(afc, selfPos, derefChain, borrow), i, _, path) } pragma[nomagic] predicate argIsInstantiationOf( - AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPositionAdj selfPosAdj, - DerefChain derefChain, BorrowKind borrow, AssocFunctionType selfType + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, + BorrowKind borrow, AssocFunctionType selfType ) { - argIsInstantiationOf(MkAssocFunctionCallCand(afc, selfPosAdj, derefChain, borrow), i, selfType) + argIsInstantiationOf(MkAssocFunctionCallCand(afc, selfPos, derefChain, borrow), i, selfType) } } @@ -2705,9 +2680,9 @@ private module AssocFunctionResolution { predicate potentialInstantiationOf( AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj | - afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, _) and - blanketLikeCandidate(afc, _, selfPosAdj, abs, constraint, _, _) and + exists(AssocFunctionCall afc, FunctionPosition selfPos | + afcc = MkAssocFunctionCallCand(afc, selfPos, _, _) and + blanketLikeCandidate(afc, _, selfPos, abs, constraint, _, _) and if abs.(Impl).hasTrait() then // inherent functions take precedence over trait functions, so only allow @@ -2735,11 +2710,11 @@ private module AssocFunctionResolution { ) { SelfArgIsInstantiationOfInput::potentialInstantiationOf0(afcc, abs, constraint) and abs.(Impl).isInherent() and - exists(AssocFunctionCall afc, FunctionPositionAdj selfPosAdj | - afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, _) + exists(AssocFunctionCall afc, FunctionPosition selfPos | + afcc = MkAssocFunctionCallCand(afc, selfPos, _, _) | - selfPosAdj.isTypeQualifier() or - afc.hasReceiverAtPos(selfPosAdj) + selfPos.isTypeQualifier() or + afc.hasReceiverAtPos(selfPos) ) } } @@ -2754,18 +2729,13 @@ private module AssocFunctionResolution { private module OverloadedCallArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { - predicate toCheck( - ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPositionAdj posAdj - ) { - exists(FunctionPosition pos | - FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) and - posAdj = pos.getFunctionCallAdjusted(f) - ) + predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { + FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) } class Call extends AssocFunctionCallCand { - Type getArgType(FunctionPositionAdj posAdj, TypePath path) { - result = this.getAssocFunctionCall().getTypeAt(posAdj, path) + Type getArgType(FunctionPosition pos, TypePath path) { + result = this.getAssocFunctionCall().getTypeAt(pos, path) } predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { @@ -2789,7 +2759,7 @@ private module AssocFunctionResolution { * like `foo.bar(baz)` and `Foo::bar(baz)`. */ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInputSig { - import FunctionPositionAdjMatchingInput + import FunctionPositionMatchingInput private newtype TDeclaration = TFunctionDeclaration(ImplOrTraitItemNodeOption i, FunctionDeclaration f) { f.isFor(i) } @@ -2809,10 +2779,10 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput result = f.getTypeParameter(i, ppos) } - Type getDeclaredType(FunctionPositionAdj posAdj, TypePath path) { - result = f.getParameterType(i, posAdj, path) + Type getDeclaredType(FunctionPosition pos, TypePath path) { + result = f.getParameterType(i, pos, path) or - posAdj.isReturn() and + pos.isReturn() and result = f.getReturnType(i, path) } @@ -2852,10 +2822,10 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput } abstract class Access extends ContextTyping::ContextTypedCallCand { - abstract AstNode getNodeAt(FunctionPositionAdj posAdj); + abstract AstNode getNodeAt(FunctionPosition pos); bindingset[derefChainBorrow] - abstract Type getInferredType(string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path); + abstract Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path); abstract Declaration getTarget(string derefChainBorrow); @@ -2863,9 +2833,7 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput * Holds if the return type of this call at `path` may have to be inferred * from the context. */ - abstract predicate hasUnknownTypeAt( - string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path - ); + abstract predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path); } private class AssocFunctionCallAccess extends Access instanceof AssocFunctionResolution::AssocFunctionCall @@ -2887,47 +2855,45 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput result = getCallExprTypeArgument(this, apos, path) } - override AstNode getNodeAt(FunctionPositionAdj posAdj) { - result = AssocFunctionResolution::AssocFunctionCall.super.getNodeAt(posAdj) + override AstNode getNodeAt(FunctionPosition pos) { + result = AssocFunctionResolution::AssocFunctionCall.super.getNodeAt(pos) } pragma[nomagic] - private Type getInferredSelfType( - FunctionPositionAdj posAdj, string derefChainBorrow, TypePath path - ) { + private Type getInferredSelfType(FunctionPosition pos, string derefChainBorrow, TypePath path) { exists(DerefChain derefChain, BorrowKind borrow | - result = super.getSelfTypeAt(posAdj, derefChain, borrow, path) and + result = super.getSelfTypeAt(pos, derefChain, borrow, path) and derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and - super.hasReceiverAtPos(posAdj) + super.hasReceiverAtPos(pos) ) } pragma[nomagic] - private Type getInferredNonSelfType(FunctionPositionAdj posAdj, TypePath path) { + private Type getInferredNonSelfType(FunctionPosition pos, TypePath path) { if // index expression `x[i]` desugars to `*x.index(i)`, so we must account for // the implicit deref - posAdj.isReturn() and + pos.isReturn() and this instanceof IndexExpr then path.isEmpty() and result instanceof RefType or exists(TypePath suffix | - result = super.getTypeAt(posAdj, suffix) and + result = super.getTypeAt(pos, suffix) and path = TypePath::cons(getRefTypeParameter(_), suffix) ) else ( - not super.hasReceiverAtPos(posAdj) and - result = super.getTypeAt(posAdj, path) + not super.hasReceiverAtPos(pos) and + result = super.getTypeAt(pos, path) ) } bindingset[derefChainBorrow] - override Type getInferredType(string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path) { - result = this.getInferredSelfType(posAdj, derefChainBorrow, path) + override Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) { + result = this.getInferredSelfType(pos, derefChainBorrow, path) or - result = this.getInferredNonSelfType(posAdj, path) + result = this.getInferredNonSelfType(pos, path) } private AssocFunction getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { @@ -2945,21 +2911,17 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput } pragma[nomagic] - override predicate hasUnknownTypeAt( - string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path - ) { - exists(FunctionPosition pos | posAdj = super.getFunctionCallAdjustedPosition(pos) | - exists(ImplOrTraitItemNode i | - this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path) - ) - or - derefChainBorrow = noDerefChainBorrow() and - forex(ImplOrTraitItemNode i, Function f | - f = CallExprImpl::getResolvedFunction(this) and - f = i.getAnAssocItem() - | - this.hasUnknownTypeAt(i, f, pos, path) - ) + override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { + exists(ImplOrTraitItemNode i | + this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path) + ) + or + derefChainBorrow = noDerefChainBorrow() and + forex(ImplOrTraitItemNode i, Function f | + f = CallExprImpl::getResolvedFunction(this) and + f = i.getAnAssocItem() + | + this.hasUnknownTypeAt(i, f, pos, path) ) } } @@ -2970,19 +2932,19 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput result = NonAssocCallExpr.super.getTypeArgument(apos, path) } - override AstNode getNodeAt(FunctionPositionAdj posAdj) { - result = NonAssocCallExpr.super.getNodeAt(posAdj.asNonAdjusted()) + override AstNode getNodeAt(FunctionPosition pos) { + result = NonAssocCallExpr.super.getNodeAt(pos) } pragma[nomagic] - private Type getInferredType(FunctionPositionAdj posAdj, TypePath path) { - result = super.getInferredType(posAdj.asNonAdjusted(), path) + private Type getInferredType(FunctionPosition pos, TypePath path) { + result = super.getInferredType(pos, path) } bindingset[derefChainBorrow] - override Type getInferredType(string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path) { + override Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) { exists(derefChainBorrow) and - result = this.getInferredType(posAdj, path) + result = this.getInferredType(pos, path) } pragma[nomagic] @@ -3000,13 +2962,11 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput } pragma[nomagic] - override predicate hasUnknownTypeAt( - string derefChainBorrow, FunctionPositionAdj posAdj, TypePath path - ) { + override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { derefChainBorrow = noDerefChainBorrow() and exists(ImplOrTraitItemNodeOption i, FunctionDeclaration f | TFunctionDeclaration(i, f) = this.getTarget() and - this.hasUnknownTypeAt(i.asSome(), f, posAdj.asNonAdjusted(), path) + this.hasUnknownTypeAt(i.asSome(), f, pos, path) ) } } @@ -3016,24 +2976,24 @@ private module FunctionCallMatching = MatchingWithEnvironment::check/2; + ContextTyping::CheckContextTyping::check/2; abstract private class TupleLikeConstructor extends Addressable { final TypeParameter getTypeParameter(TypeParameterPosition ppos) { @@ -3132,17 +3095,17 @@ abstract private class TupleLikeConstructor extends Addressable { } Type getDeclaredType(FunctionPosition pos, TypePath path) { - result = this.getParameterType(pos, path) + result = this.getParameterType(pos.asPosition(), path) or pos.isReturn() and result = this.getReturnType(path) or - pos.isSelf() and + pos.isTypeQualifier() and result = this.getReturnType(path) } - Type getParameterType(FunctionPosition pos, TypePath path) { - result = this.getTupleField(pos.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) + Type getParameterType(int pos, TypePath path) { + result = this.getTupleField(pos).getTypeRepr().(TypeMention).getTypeAt(path) } } @@ -3203,7 +3166,10 @@ private module TupleLikeConstructionMatchingInput implements MatchingInputSig { private module TupleLikeConstructionMatching = Matching; pragma[nomagic] -private Type inferTupleLikeConstructionTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { +private Type inferTupleLikeConstructionTypePreCheck( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path +) { + hasReceiver = false and exists(TupleLikeConstructionMatchingInput::Access a | n = a.getNodeAt(pos) | result = TupleLikeConstructionMatching::inferAccessType(a, pos, path) or @@ -3213,14 +3179,14 @@ private Type inferTupleLikeConstructionTypePreCheck(AstNode n, FunctionPosition } private predicate inferTupleLikeConstructionType = - ContextTyping::CheckContextTyping::check/2; + ContextTyping::CheckContextTyping::check/2; /** * A matching configuration for resolving types of operations like `a + b`. */ private module OperationMatchingInput implements MatchingInputSig { private import codeql.rust.elements.internal.OperationImpl::Impl as OperationImpl - import FunctionPositionAdjMatchingInput + import FunctionPositionMatchingInput class Declaration extends FunctionCallMatchingInput::Declaration { private Method getSelfOrImpl() { @@ -3230,14 +3196,14 @@ private module OperationMatchingInput implements MatchingInputSig { } pragma[nomagic] - private predicate borrowsAt(FunctionPositionAdj posAdj) { + private predicate borrowsAt(FunctionPosition pos) { exists(TraitItemNode t, string path, string method | this.getSelfOrImpl() = t.getAssocItem(method) and path = t.getCanonicalPath(_) and exists(int borrows | OperationImpl::isOverloaded(_, _, path, method, borrows) | - posAdj.asPosition() = 0 and borrows >= 1 + pos.asPosition() = 0 and borrows >= 1 or - posAdj.asPosition() = 1 and + pos.asPosition() = 1 and borrows >= 2 ) ) @@ -3246,13 +3212,13 @@ private module OperationMatchingInput implements MatchingInputSig { pragma[nomagic] private predicate derefsReturn() { this.getSelfOrImpl() = any(DerefTrait t).getDerefFunction() } - Type getDeclaredType(FunctionPositionAdj posAdj, TypePath path) { + Type getDeclaredType(FunctionPosition pos, TypePath path) { exists(TypePath path0 | - result = super.getDeclaredType(posAdj, path0) and + result = super.getDeclaredType(pos, path0) and if - this.borrowsAt(posAdj) + this.borrowsAt(pos) or - posAdj.isReturn() and this.derefsReturn() + pos.isReturn() and this.derefsReturn() then path0.isCons(getRefTypeParameter(_), path) else path0 = path ) @@ -3263,8 +3229,8 @@ private module OperationMatchingInput implements MatchingInputSig { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } pragma[nomagic] - Type getInferredType(FunctionPositionAdj posAdj, TypePath path) { - result = inferType(this.getNodeAt(posAdj), path) + Type getInferredType(FunctionPosition pos, TypePath path) { + result = inferType(this.getNodeAt(pos), path) } Declaration getTarget() { @@ -3278,16 +3244,18 @@ private module OperationMatchingInput implements MatchingInputSig { private module OperationMatching = Matching; pragma[nomagic] -private Type inferOperationTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { - exists(OperationMatchingInput::Access a, FunctionPositionAdj posAdj | - n = a.getNodeAt(posAdj) and - posAdj = pos.getFunctionCallAdjusted() and - result = OperationMatching::inferAccessType(a, posAdj, path) +private Type inferOperationTypePreCheck( + AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path +) { + exists(OperationMatchingInput::Access a | + n = a.getNodeAt(pos) and + result = OperationMatching::inferAccessType(a, pos, path) and + hasReceiver = true ) } private predicate inferOperationType = - ContextTyping::CheckContextTyping::check/2; + ContextTyping::CheckContextTyping::check/2; pragma[nomagic] private Type getFieldExprLookupType(FieldExpr fe, string name, DerefChain derefChain) { @@ -3764,7 +3732,7 @@ private module TupleStructPatMatchingInput implements MatchingInputSig { result = this.getField(apos.asPosition()) or result = this and - apos.isSelf() + apos.isReturn() } Type getInferredType(AccessPosition apos, TypePath path) { @@ -3772,7 +3740,7 @@ private module TupleStructPatMatchingInput implements MatchingInputSig { or // The struct/enum type is supplied explicitly as a type qualifier, e.g. // `let Option::::Some(x) = ...`. - apos.isSelf() and + apos.isTypeQualifier() and result = this.getPath().(TypeMention).getTypeAt(path) } From 821cc0e875550262e6d55a8e8398b9f0b89e2acf Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 13 Mar 2026 14:58:04 +0100 Subject: [PATCH 38/72] JS: Address PR review comments - Fix misplaced semicolons in test files (was inside comment, moved before it) - Update QLdoc comments to reference new browser source kind names - Update docs to list browser source kinds and fix outdated 'only remote' note Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../customizing-library-models-for-javascript.rst | 13 +++++++++++-- .../security/dataflow/RemoteFlowSources.qll | 8 ++++---- .../test/query-tests/Security/CWE-918/clientSide.js | 2 +- .../test/query-tests/Security/CWE-918/serverSide.js | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst index 413471be885..a0c2e916281 100644 --- a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst @@ -406,7 +406,7 @@ Adds a new taint source. Most taint-tracking queries will use the new source. - **type**: Name of a type from which to evaluate **path**. - **path**: Access path leading to the source. -- **kind**: Kind of source to add. Currently only **remote** is used. +- **kind**: Kind of source to add. See the section on :ref:`source kinds ` for supported values. Example: @@ -553,7 +553,16 @@ Kinds Source kinds ~~~~~~~~~~~~ -See documentation below for :ref:`Threat models `. +- **remote**: A general source of remote flow. +- **browser**: A source in the browser environment that does not fit a more specific browser kind. +- **browser-url-query**: A source derived from the query parameters of the browser URL, such as ``location.search``. +- **browser-url-fragment**: A source derived from the fragment part of the browser URL, such as ``location.hash``. +- **browser-url-path**: A source derived from the pathname of the browser URL, such as ``location.pathname``. +- **browser-url**: A source derived from the browser URL, where the untrusted part is prefixed by trusted data such as the scheme and hostname. +- **browser-window-name**: A source derived from the window name, such as ``window.name``. +- **browser-message-event**: A source derived from cross-window message passing, such as ``event`` in ``window.onmessage = event => {...}``. + +See also :ref:`Threat models `. Sink kinds ~~~~~~~~~~ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll index 5b1424fb86e..8791382180a 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll @@ -85,16 +85,16 @@ class ClientSideRemoteFlowKind extends string { */ predicate isUrl() { this = "browser-url" } - /** Holds if this is the `query` or `fragment` kind. */ + /** Holds if this is the `browser-url-query` or `browser-url-fragment` kind. */ predicate isQueryOrFragment() { this.isQuery() or this.isFragment() } - /** Holds if this is the `path`, `query`, or `fragment` kind. */ + /** Holds if this is the `browser-url-path`, `browser-url-query`, or `browser-url-fragment` kind. */ predicate isPathOrQueryOrFragment() { this.isPath() or this.isQuery() or this.isFragment() } - /** Holds if this is the `path` or `url` kind. */ + /** Holds if this is the `browser-url-path` or `browser-url` kind. */ predicate isPathOrUrl() { this.isPath() or this.isUrl() } - /** Holds if this is the `name` kind, describing sources derived from the window name, such as `window.name`. */ + /** Holds if this is the `browser-window-name` kind, describing sources derived from the window name, such as `window.name`. */ predicate isWindowName() { this = "browser-window-name" } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js b/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js index 1651fb01f44..a8e29602f1f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/clientSide.js @@ -24,5 +24,5 @@ export function MyComponent() { request(window.location.href + '?q=123'); const custom = require('testlib').getBrowserSource(); // $ Source[js/client-side-request-forgery] - request(custom) // $ Alert[js/client-side-request-forgery]; + request(custom); // $ Alert[js/client-side-request-forgery] } diff --git a/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js b/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js index 7cf16ccb1ed..c359312738b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js +++ b/javascript/ql/test/query-tests/Security/CWE-918/serverSide.js @@ -148,4 +148,4 @@ var server2 = http.createServer(function (req, res) { }); const custom = require('testlib').getServerSource(); // $ Source[js/request-forgery] -request(custom) // $ Alert[js/request-forgery]; +request(custom); // $ Alert[js/request-forgery] From dfa6d20072119d55137b1c464b573b2db9f2419d Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 13 Mar 2026 15:05:07 +0100 Subject: [PATCH 39/72] JS: Replace broken link with plain text --- .../customizing-library-models-for-javascript.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst index a0c2e916281..b8f064c7574 100644 --- a/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-javascript.rst @@ -406,7 +406,7 @@ Adds a new taint source. Most taint-tracking queries will use the new source. - **type**: Name of a type from which to evaluate **path**. - **path**: Access path leading to the source. -- **kind**: Kind of source to add. See the section on :ref:`source kinds ` for supported values. +- **kind**: Kind of source to add. See the section on source kinds for a list of supported kinds. Example: From 7a6ab700915a4ca05175b244dc9d7bf773dc076d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 13 Mar 2026 15:32:25 +0100 Subject: [PATCH 40/72] Rust: Add test for free function with context-based typing --- .../PathResolutionConsistency.expected | 2 +- .../test/library-tests/type-inference/main.rs | 7 + .../type-inference/type-inference.expected | 727 +++++++++--------- 3 files changed, 376 insertions(+), 360 deletions(-) diff --git a/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected index a753b733ba3..2ac439e085b 100644 --- a/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected @@ -1,4 +1,4 @@ multipleResolvedTargets | main.rs:2223:9:2223:31 | ... .my_add(...) | | main.rs:2225:9:2225:29 | ... .my_add(...) | -| main.rs:2733:13:2733:17 | x.f() | +| main.rs:2740:13:2740:17 | x.f() | diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index f342d3897f4..ad77bd9febd 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2643,6 +2643,10 @@ mod context_typed { fn f(self) {} } + fn free_function() -> T { + Default::default() // $ target=default + } + pub fn f() { let x = None; // $ type=x:T.i32 let x: Option = x; @@ -2693,6 +2697,9 @@ mod context_typed { let s = Default::default(); // $ target=default type=s:S S::f(s); // $ target=f + + let z = free_function(); // $ target=free_function MISSING: type=z:i32 + x.push(z); // $ target=push } } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index bd3b0490f18..6921fbde3de 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -3630,130 +3630,133 @@ inferCertainType | main.rs:2633:29:2633:29 | a | | {EXTERNAL LOCATION} | () | | main.rs:2643:14:2643:17 | SelfParam | | main.rs:2639:5:2640:13 | S | | main.rs:2643:20:2643:21 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2646:16:2696:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2648:13:2648:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2648:13:2648:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2652:26:2652:28 | opt | | {EXTERNAL LOCATION} | Option | -| main.rs:2652:26:2652:28 | opt | T | main.rs:2652:23:2652:23 | T | -| main.rs:2652:42:2652:42 | x | | main.rs:2652:23:2652:23 | T | -| main.rs:2652:48:2652:49 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2655:9:2655:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2662:13:2662:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2662:17:2662:39 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:13:2663:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:13:2663:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:13:2663:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2663:40:2663:40 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:13:2664:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:13:2664:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:17:2664:52 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:17:2664:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2666:13:2666:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2666:13:2666:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2667:20:2667:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2670:29:2670:29 | e | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2670:29:2670:29 | e | T1 | main.rs:2670:26:2670:26 | T | -| main.rs:2670:29:2670:29 | e | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2670:53:2670:53 | x | | main.rs:2670:26:2670:26 | T | -| main.rs:2670:59:2670:60 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2673:13:2673:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2673:17:2675:9 | ...::B {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2674:20:2674:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2676:9:2676:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2676:23:2676:23 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2679:13:2679:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2679:13:2679:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2679:13:2679:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2683:29:2683:31 | res | | {EXTERNAL LOCATION} | Result | -| main.rs:2683:29:2683:31 | res | E | main.rs:2683:26:2683:26 | E | -| main.rs:2683:29:2683:31 | res | T | main.rs:2683:23:2683:23 | T | -| main.rs:2683:48:2683:48 | x | | main.rs:2683:26:2683:26 | E | -| main.rs:2683:54:2683:55 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2686:9:2686:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2686:23:2686:27 | false | | {EXTERNAL LOCATION} | bool | -| main.rs:2688:17:2688:17 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:17:2688:17 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2688:21:2688:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:21:2688:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2689:9:2689:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2689:9:2689:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2692:9:2692:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2692:9:2692:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2695:9:2695:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2702:14:2702:17 | SelfParam | | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:14:2705:18 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2705:14:2705:18 | SelfParam | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:21:2705:25 | other | | {EXTERNAL LOCATION} | & | -| main.rs:2705:21:2705:25 | other | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:44:2707:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2705:44:2707:9 | { ... } | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2706:13:2706:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2706:13:2706:16 | self | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2712:14:2712:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | -| main.rs:2712:28:2714:9 | { ... } | | {EXTERNAL LOCATION} | i32 | -| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | i32 | -| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | usize | -| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | usize | -| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2726:14:2726:17 | SelfParam | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2726:28:2728:9 | { ... } | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2727:13:2727:16 | self | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2731:25:2735:5 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2737:12:2745:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2738:13:2738:13 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2739:13:2739:13 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2739:17:2739:18 | &1 | | {EXTERNAL LOCATION} | & | -| main.rs:2740:17:2740:17 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2740:21:2740:21 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2743:13:2743:13 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2744:23:2744:23 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2755:11:2790:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2756:5:2756:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2757:5:2757:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:5:2758:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:20:2758:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:41:2758:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2759:5:2759:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2760:5:2760:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2761:5:2761:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2762:5:2762:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2646:41:2648:5 | { ... } | | main.rs:2646:22:2646:31 | T | +| main.rs:2650:16:2703:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2652:13:2652:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2652:13:2652:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2656:26:2656:28 | opt | | {EXTERNAL LOCATION} | Option | +| main.rs:2656:26:2656:28 | opt | T | main.rs:2656:23:2656:23 | T | +| main.rs:2656:42:2656:42 | x | | main.rs:2656:23:2656:23 | T | +| main.rs:2656:48:2656:49 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2659:9:2659:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2666:13:2666:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2666:17:2666:39 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:13:2667:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:13:2667:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:13:2667:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2667:40:2667:40 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:13:2668:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:13:2668:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:17:2668:52 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:17:2668:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2670:13:2670:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:13:2670:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2671:20:2671:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2674:29:2674:29 | e | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2674:29:2674:29 | e | T1 | main.rs:2674:26:2674:26 | T | +| main.rs:2674:29:2674:29 | e | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2674:53:2674:53 | x | | main.rs:2674:26:2674:26 | T | +| main.rs:2674:59:2674:60 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2677:13:2677:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2677:17:2679:9 | ...::B {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2678:20:2678:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2680:9:2680:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2680:23:2680:23 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2683:13:2683:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2683:13:2683:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2683:13:2683:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2687:29:2687:31 | res | | {EXTERNAL LOCATION} | Result | +| main.rs:2687:29:2687:31 | res | E | main.rs:2687:26:2687:26 | E | +| main.rs:2687:29:2687:31 | res | T | main.rs:2687:23:2687:23 | T | +| main.rs:2687:48:2687:48 | x | | main.rs:2687:26:2687:26 | E | +| main.rs:2687:54:2687:55 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2690:9:2690:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2690:23:2690:27 | false | | {EXTERNAL LOCATION} | bool | +| main.rs:2692:17:2692:17 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:17:2692:17 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2692:21:2692:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:21:2692:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2693:9:2693:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2693:9:2693:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2696:9:2696:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2696:9:2696:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2699:9:2699:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2702:9:2702:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2702:9:2702:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2709:14:2709:17 | SelfParam | | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:14:2712:18 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2712:14:2712:18 | SelfParam | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:21:2712:25 | other | | {EXTERNAL LOCATION} | & | +| main.rs:2712:21:2712:25 | other | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:44:2714:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2712:44:2714:9 | { ... } | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2713:13:2713:16 | self | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | +| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | i32 | +| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | i32 | +| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | usize | +| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | usize | +| main.rs:2733:14:2733:17 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2733:14:2733:17 | SelfParam | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2733:28:2735:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2733:28:2735:9 | { ... } | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2734:13:2734:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2734:13:2734:16 | self | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2738:25:2742:5 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2744:12:2752:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2745:13:2745:13 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2746:13:2746:13 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2746:17:2746:18 | &1 | | {EXTERNAL LOCATION} | & | +| main.rs:2747:17:2747:17 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2747:21:2747:21 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2750:13:2750:13 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2751:23:2751:23 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2762:11:2797:1 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2763:5:2763:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2764:5:2764:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2765:5:2765:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2766:5:2766:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2767:5:2767:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2768:5:2768:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2769:5:2769:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2770:5:2770:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2771:5:2771:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2772:5:2772:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2773:5:2773:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2774:5:2774:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2774:5:2774:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2775:5:2775:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2776:5:2776:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2777:5:2777:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2778:5:2778:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2779:5:2779:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2780:5:2780:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2782:5:2782:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2783:5:2783:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2784:5:2784:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2785:5:2785:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2786:5:2786:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2787:5:2787:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2788:5:2788:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2788:5:2788:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2788:5:2788:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | -| main.rs:2788:5:2788:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2788:16:2788:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2789:5:2789:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2764:5:2764:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:5:2765:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:20:2765:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:41:2765:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2766:5:2766:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2767:5:2767:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2768:5:2768:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2769:5:2769:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2770:5:2770:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2771:5:2771:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2772:5:2772:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2773:5:2773:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2774:5:2774:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2775:5:2775:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2776:5:2776:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2777:5:2777:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2778:5:2778:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2779:5:2779:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2780:5:2780:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2781:5:2781:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2782:5:2782:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2783:5:2783:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2784:5:2784:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2785:5:2785:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2786:5:2786:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2787:5:2787:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2788:5:2788:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2789:5:2789:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2790:5:2790:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2791:5:2791:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2792:5:2792:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2793:5:2793:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2794:5:2794:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2795:5:2795:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2795:5:2795:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2795:5:2795:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | +| main.rs:2795:5:2795:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2795:16:2795:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2796:5:2796:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | @@ -12051,249 +12054,255 @@ inferType | main.rs:2634:9:2634:9 | 0 | | {EXTERNAL LOCATION} | i32 | | main.rs:2643:14:2643:17 | SelfParam | | main.rs:2639:5:2640:13 | S | | main.rs:2643:20:2643:21 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2646:16:2696:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2647:13:2647:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2647:13:2647:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2647:17:2647:20 | None | | {EXTERNAL LOCATION} | Option | -| main.rs:2647:17:2647:20 | None | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2648:13:2648:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2648:13:2648:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2648:30:2648:30 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2648:30:2648:30 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2649:13:2649:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2649:13:2649:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2649:17:2649:35 | ...::None | | {EXTERNAL LOCATION} | Option | -| main.rs:2649:17:2649:35 | ...::None | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2650:13:2650:13 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2650:13:2650:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2650:17:2650:35 | ...::None::<...> | | {EXTERNAL LOCATION} | Option | -| main.rs:2650:17:2650:35 | ...::None::<...> | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2652:26:2652:28 | opt | | {EXTERNAL LOCATION} | Option | -| main.rs:2652:26:2652:28 | opt | T | main.rs:2652:23:2652:23 | T | -| main.rs:2652:42:2652:42 | x | | main.rs:2652:23:2652:23 | T | -| main.rs:2652:48:2652:49 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2646:41:2648:5 | { ... } | | main.rs:2646:22:2646:31 | T | +| main.rs:2647:9:2647:26 | ...::default(...) | | main.rs:2646:22:2646:31 | T | +| main.rs:2650:16:2703:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2651:13:2651:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2651:13:2651:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2651:17:2651:20 | None | | {EXTERNAL LOCATION} | Option | +| main.rs:2651:17:2651:20 | None | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2652:13:2652:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2652:13:2652:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2652:30:2652:30 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2652:30:2652:30 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2653:13:2653:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2653:13:2653:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2653:17:2653:35 | ...::None | | {EXTERNAL LOCATION} | Option | +| main.rs:2653:17:2653:35 | ...::None | T | {EXTERNAL LOCATION} | i32 | | main.rs:2654:13:2654:13 | x | | {EXTERNAL LOCATION} | Option | | main.rs:2654:13:2654:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2654:17:2654:20 | None | | {EXTERNAL LOCATION} | Option | -| main.rs:2654:17:2654:20 | None | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2655:9:2655:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2655:20:2655:20 | x | | {EXTERNAL LOCATION} | Option | -| main.rs:2655:20:2655:20 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2655:23:2655:23 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2662:13:2662:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2662:13:2662:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2662:13:2662:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2662:17:2662:39 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2662:17:2662:39 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2662:17:2662:39 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2662:37:2662:37 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:13:2663:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:13:2663:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:13:2663:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2663:40:2663:40 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2663:40:2663:40 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2663:40:2663:40 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:13:2664:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:13:2664:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2664:13:2664:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:17:2664:52 | ...::A {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2664:17:2664:52 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2664:17:2664:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2664:50:2664:50 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2666:13:2666:13 | x | | main.rs:2657:9:2660:9 | MyEither | +| main.rs:2654:17:2654:35 | ...::None::<...> | | {EXTERNAL LOCATION} | Option | +| main.rs:2654:17:2654:35 | ...::None::<...> | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2656:26:2656:28 | opt | | {EXTERNAL LOCATION} | Option | +| main.rs:2656:26:2656:28 | opt | T | main.rs:2656:23:2656:23 | T | +| main.rs:2656:42:2656:42 | x | | main.rs:2656:23:2656:23 | T | +| main.rs:2656:48:2656:49 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2658:13:2658:13 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2658:13:2658:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2658:17:2658:20 | None | | {EXTERNAL LOCATION} | Option | +| main.rs:2658:17:2658:20 | None | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2659:9:2659:24 | pin_option(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2659:20:2659:20 | x | | {EXTERNAL LOCATION} | Option | +| main.rs:2659:20:2659:20 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2659:23:2659:23 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2666:13:2666:13 | x | | main.rs:2661:9:2664:9 | MyEither | | main.rs:2666:13:2666:13 | x | T1 | {EXTERNAL LOCATION} | i32 | | main.rs:2666:13:2666:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2666:17:2668:9 | ...::B::<...> {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2667:20:2667:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2670:29:2670:29 | e | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2670:29:2670:29 | e | T1 | main.rs:2670:26:2670:26 | T | -| main.rs:2670:29:2670:29 | e | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2670:53:2670:53 | x | | main.rs:2670:26:2670:26 | T | -| main.rs:2670:59:2670:60 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2673:13:2673:13 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2673:13:2673:13 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2673:13:2673:13 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2673:17:2675:9 | ...::B {...} | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2673:17:2675:9 | ...::B {...} | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2673:17:2675:9 | ...::B {...} | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2674:20:2674:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | -| main.rs:2676:9:2676:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2676:23:2676:23 | x | | main.rs:2657:9:2660:9 | MyEither | -| main.rs:2676:23:2676:23 | x | T1 | {EXTERNAL LOCATION} | i32 | -| main.rs:2676:23:2676:23 | x | T2 | {EXTERNAL LOCATION} | String | -| main.rs:2676:26:2676:26 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2678:13:2678:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2678:13:2678:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2678:13:2678:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2678:17:2678:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2678:17:2678:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | -| main.rs:2678:17:2678:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2678:28:2678:28 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2679:13:2679:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2679:13:2679:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2679:13:2679:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2679:38:2679:38 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2679:38:2679:38 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2679:38:2679:38 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2680:13:2680:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2680:13:2680:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2680:13:2680:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2680:17:2680:44 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2680:17:2680:44 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | -| main.rs:2680:17:2680:44 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2680:43:2680:43 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2681:13:2681:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2681:13:2681:13 | x | E | {EXTERNAL LOCATION} | String | -| main.rs:2681:13:2681:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2681:17:2681:44 | ...::Ok::<...>(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2681:17:2681:44 | ...::Ok::<...>(...) | E | {EXTERNAL LOCATION} | String | -| main.rs:2681:17:2681:44 | ...::Ok::<...>(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2681:43:2681:43 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2683:29:2683:31 | res | | {EXTERNAL LOCATION} | Result | -| main.rs:2683:29:2683:31 | res | E | main.rs:2683:26:2683:26 | E | -| main.rs:2683:29:2683:31 | res | T | main.rs:2683:23:2683:23 | T | -| main.rs:2683:48:2683:48 | x | | main.rs:2683:26:2683:26 | E | -| main.rs:2683:54:2683:55 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2666:17:2666:39 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2666:17:2666:39 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2666:17:2666:39 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2666:37:2666:37 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:13:2667:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:13:2667:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:13:2667:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2667:40:2667:40 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2667:40:2667:40 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2667:40:2667:40 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:13:2668:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:13:2668:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2668:13:2668:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:17:2668:52 | ...::A {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2668:17:2668:52 | ...::A {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2668:17:2668:52 | ...::A {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2668:50:2668:50 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:13:2670:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:13:2670:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:13:2670:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2670:17:2672:9 | ...::B::<...> {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2671:20:2671:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2674:29:2674:29 | e | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2674:29:2674:29 | e | T1 | main.rs:2674:26:2674:26 | T | +| main.rs:2674:29:2674:29 | e | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2674:53:2674:53 | x | | main.rs:2674:26:2674:26 | T | +| main.rs:2674:59:2674:60 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2677:13:2677:13 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2677:13:2677:13 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2677:13:2677:13 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2677:17:2679:9 | ...::B {...} | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2677:17:2679:9 | ...::B {...} | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2677:17:2679:9 | ...::B {...} | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2678:20:2678:32 | ...::new(...) | | {EXTERNAL LOCATION} | String | +| main.rs:2680:9:2680:27 | pin_my_either(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2680:23:2680:23 | x | | main.rs:2661:9:2664:9 | MyEither | +| main.rs:2680:23:2680:23 | x | T1 | {EXTERNAL LOCATION} | i32 | +| main.rs:2680:23:2680:23 | x | T2 | {EXTERNAL LOCATION} | String | +| main.rs:2680:26:2680:26 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2682:13:2682:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2682:13:2682:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2682:13:2682:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2682:17:2682:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2682:17:2682:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | +| main.rs:2682:17:2682:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2682:28:2682:28 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2683:13:2683:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2683:13:2683:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2683:13:2683:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2683:38:2683:38 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2683:38:2683:38 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2683:38:2683:38 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2684:13:2684:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2684:13:2684:13 | x | E | {EXTERNAL LOCATION} | String | +| main.rs:2684:13:2684:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2684:17:2684:44 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2684:17:2684:44 | ...::Ok(...) | E | {EXTERNAL LOCATION} | String | +| main.rs:2684:17:2684:44 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2684:43:2684:43 | 0 | | {EXTERNAL LOCATION} | i32 | | main.rs:2685:13:2685:13 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2685:13:2685:13 | x | E | {EXTERNAL LOCATION} | bool | +| main.rs:2685:13:2685:13 | x | E | {EXTERNAL LOCATION} | String | | main.rs:2685:13:2685:13 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2685:17:2685:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | -| main.rs:2685:17:2685:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | bool | -| main.rs:2685:17:2685:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2685:28:2685:28 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2686:9:2686:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2686:20:2686:20 | x | | {EXTERNAL LOCATION} | Result | -| main.rs:2686:20:2686:20 | x | E | {EXTERNAL LOCATION} | bool | -| main.rs:2686:20:2686:20 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2686:23:2686:27 | false | | {EXTERNAL LOCATION} | bool | -| main.rs:2688:17:2688:17 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:17:2688:17 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2688:17:2688:17 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2688:21:2688:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | -| main.rs:2688:21:2688:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2688:21:2688:30 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2689:9:2689:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2689:9:2689:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2689:9:2689:9 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2689:9:2689:17 | x.push(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2689:16:2689:16 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2691:13:2691:13 | y | | {EXTERNAL LOCATION} | i32 | -| main.rs:2691:17:2691:34 | ...::default(...) | | {EXTERNAL LOCATION} | i32 | -| main.rs:2692:9:2692:9 | x | | {EXTERNAL LOCATION} | Vec | -| main.rs:2692:9:2692:9 | x | A | {EXTERNAL LOCATION} | Global | -| main.rs:2692:9:2692:9 | x | T | {EXTERNAL LOCATION} | i32 | -| main.rs:2692:9:2692:17 | x.push(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2692:16:2692:16 | y | | {EXTERNAL LOCATION} | i32 | -| main.rs:2694:13:2694:13 | s | | main.rs:2639:5:2640:13 | S | -| main.rs:2694:17:2694:34 | ...::default(...) | | main.rs:2639:5:2640:13 | S | -| main.rs:2695:9:2695:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2695:14:2695:14 | s | | main.rs:2639:5:2640:13 | S | -| main.rs:2702:14:2702:17 | SelfParam | | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:14:2705:18 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2705:14:2705:18 | SelfParam | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:21:2705:25 | other | | {EXTERNAL LOCATION} | & | -| main.rs:2705:21:2705:25 | other | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2705:44:2707:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2705:44:2707:9 | { ... } | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2706:13:2706:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2706:13:2706:16 | self | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2706:13:2706:20 | self.f() | | {EXTERNAL LOCATION} | & | -| main.rs:2706:13:2706:20 | self.f() | TRef | main.rs:2700:5:2708:5 | Self [trait MyTrait] | -| main.rs:2712:14:2712:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | -| main.rs:2712:28:2714:9 | { ... } | | {EXTERNAL LOCATION} | i32 | -| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | i32 | -| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | usize | -| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | usize | -| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | & | -| main.rs:2726:14:2726:17 | SelfParam | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | & | -| main.rs:2726:28:2728:9 | { ... } | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | & | -| main.rs:2727:13:2727:16 | self | TRef | main.rs:2724:10:2724:10 | T | -| main.rs:2731:25:2735:5 | { ... } | | {EXTERNAL LOCATION} | usize | -| main.rs:2732:17:2732:17 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2732:17:2732:17 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2732:21:2732:21 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2732:21:2732:21 | 0 | | {EXTERNAL LOCATION} | usize | -| main.rs:2733:9:2733:9 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2733:9:2733:9 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2733:9:2733:17 | ... = ... | | {EXTERNAL LOCATION} | () | -| main.rs:2733:13:2733:13 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2733:13:2733:13 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2733:13:2733:17 | x.f() | | {EXTERNAL LOCATION} | i32 | -| main.rs:2733:13:2733:17 | x.f() | | {EXTERNAL LOCATION} | usize | -| main.rs:2734:9:2734:9 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2734:9:2734:9 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2737:12:2745:5 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2738:13:2738:13 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2738:24:2738:24 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2738:24:2738:24 | 0 | | {EXTERNAL LOCATION} | usize | -| main.rs:2739:13:2739:13 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2739:13:2739:13 | y | TRef | {EXTERNAL LOCATION} | i32 | -| main.rs:2739:17:2739:18 | &1 | | {EXTERNAL LOCATION} | & | -| main.rs:2739:17:2739:18 | &1 | TRef | {EXTERNAL LOCATION} | i32 | -| main.rs:2739:18:2739:18 | 1 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2740:13:2740:13 | z | | {EXTERNAL LOCATION} | & | -| main.rs:2740:13:2740:13 | z | TRef | {EXTERNAL LOCATION} | usize | -| main.rs:2740:17:2740:17 | x | | {EXTERNAL LOCATION} | usize | -| main.rs:2740:17:2740:22 | x.g(...) | | {EXTERNAL LOCATION} | & | -| main.rs:2740:17:2740:22 | x.g(...) | TRef | {EXTERNAL LOCATION} | usize | -| main.rs:2740:21:2740:21 | y | | {EXTERNAL LOCATION} | & | -| main.rs:2740:21:2740:21 | y | TRef | {EXTERNAL LOCATION} | i32 | -| main.rs:2742:13:2742:13 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2742:17:2742:17 | 0 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2743:13:2743:13 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2743:24:2743:24 | 1 | | {EXTERNAL LOCATION} | i32 | -| main.rs:2743:24:2743:24 | 1 | | {EXTERNAL LOCATION} | usize | -| main.rs:2744:13:2744:13 | z | | {EXTERNAL LOCATION} | i32 | -| main.rs:2744:17:2744:17 | x | | {EXTERNAL LOCATION} | i32 | -| main.rs:2744:17:2744:24 | x.max(...) | | {EXTERNAL LOCATION} | i32 | -| main.rs:2744:23:2744:23 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2755:11:2790:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2756:5:2756:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2757:5:2757:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:5:2758:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:20:2758:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2758:41:2758:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2759:5:2759:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2760:5:2760:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2761:5:2761:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2762:5:2762:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2685:17:2685:44 | ...::Ok::<...>(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2685:17:2685:44 | ...::Ok::<...>(...) | E | {EXTERNAL LOCATION} | String | +| main.rs:2685:17:2685:44 | ...::Ok::<...>(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2685:43:2685:43 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2687:29:2687:31 | res | | {EXTERNAL LOCATION} | Result | +| main.rs:2687:29:2687:31 | res | E | main.rs:2687:26:2687:26 | E | +| main.rs:2687:29:2687:31 | res | T | main.rs:2687:23:2687:23 | T | +| main.rs:2687:48:2687:48 | x | | main.rs:2687:26:2687:26 | E | +| main.rs:2687:54:2687:55 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2689:13:2689:13 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2689:13:2689:13 | x | E | {EXTERNAL LOCATION} | bool | +| main.rs:2689:13:2689:13 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2689:17:2689:29 | ...::Ok(...) | | {EXTERNAL LOCATION} | Result | +| main.rs:2689:17:2689:29 | ...::Ok(...) | E | {EXTERNAL LOCATION} | bool | +| main.rs:2689:17:2689:29 | ...::Ok(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2689:28:2689:28 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2690:9:2690:28 | pin_result(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2690:20:2690:20 | x | | {EXTERNAL LOCATION} | Result | +| main.rs:2690:20:2690:20 | x | E | {EXTERNAL LOCATION} | bool | +| main.rs:2690:20:2690:20 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2690:23:2690:27 | false | | {EXTERNAL LOCATION} | bool | +| main.rs:2692:17:2692:17 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:17:2692:17 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2692:17:2692:17 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2692:21:2692:30 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2692:21:2692:30 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2692:21:2692:30 | ...::new(...) | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2693:9:2693:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2693:9:2693:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2693:9:2693:9 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2693:9:2693:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2693:16:2693:16 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2695:13:2695:13 | y | | {EXTERNAL LOCATION} | i32 | +| main.rs:2695:17:2695:34 | ...::default(...) | | {EXTERNAL LOCATION} | i32 | +| main.rs:2696:9:2696:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2696:9:2696:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2696:9:2696:9 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2696:9:2696:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2696:16:2696:16 | y | | {EXTERNAL LOCATION} | i32 | +| main.rs:2698:13:2698:13 | s | | main.rs:2639:5:2640:13 | S | +| main.rs:2698:17:2698:34 | ...::default(...) | | main.rs:2639:5:2640:13 | S | +| main.rs:2699:9:2699:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2699:14:2699:14 | s | | main.rs:2639:5:2640:13 | S | +| main.rs:2702:9:2702:9 | x | | {EXTERNAL LOCATION} | Vec | +| main.rs:2702:9:2702:9 | x | A | {EXTERNAL LOCATION} | Global | +| main.rs:2702:9:2702:9 | x | T | {EXTERNAL LOCATION} | i32 | +| main.rs:2702:9:2702:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2709:14:2709:17 | SelfParam | | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:14:2712:18 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2712:14:2712:18 | SelfParam | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:21:2712:25 | other | | {EXTERNAL LOCATION} | & | +| main.rs:2712:21:2712:25 | other | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2712:44:2714:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2712:44:2714:9 | { ... } | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2713:13:2713:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2713:13:2713:16 | self | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2713:13:2713:20 | self.f() | | {EXTERNAL LOCATION} | & | +| main.rs:2713:13:2713:20 | self.f() | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | +| main.rs:2719:14:2719:17 | SelfParam | | {EXTERNAL LOCATION} | i32 | +| main.rs:2719:28:2721:9 | { ... } | | {EXTERNAL LOCATION} | i32 | +| main.rs:2720:13:2720:16 | self | | {EXTERNAL LOCATION} | i32 | +| main.rs:2726:14:2726:17 | SelfParam | | {EXTERNAL LOCATION} | usize | +| main.rs:2726:28:2728:9 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2727:13:2727:16 | self | | {EXTERNAL LOCATION} | usize | +| main.rs:2733:14:2733:17 | SelfParam | | {EXTERNAL LOCATION} | & | +| main.rs:2733:14:2733:17 | SelfParam | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2733:28:2735:9 | { ... } | | {EXTERNAL LOCATION} | & | +| main.rs:2733:28:2735:9 | { ... } | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2734:13:2734:16 | self | | {EXTERNAL LOCATION} | & | +| main.rs:2734:13:2734:16 | self | TRef | main.rs:2731:10:2731:10 | T | +| main.rs:2738:25:2742:5 | { ... } | | {EXTERNAL LOCATION} | usize | +| main.rs:2739:17:2739:17 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2739:17:2739:17 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2739:21:2739:21 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2739:21:2739:21 | 0 | | {EXTERNAL LOCATION} | usize | +| main.rs:2740:9:2740:9 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2740:9:2740:9 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2740:9:2740:17 | ... = ... | | {EXTERNAL LOCATION} | () | +| main.rs:2740:13:2740:13 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2740:13:2740:13 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2740:13:2740:17 | x.f() | | {EXTERNAL LOCATION} | i32 | +| main.rs:2740:13:2740:17 | x.f() | | {EXTERNAL LOCATION} | usize | +| main.rs:2741:9:2741:9 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2741:9:2741:9 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2744:12:2752:5 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2745:13:2745:13 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2745:24:2745:24 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2745:24:2745:24 | 0 | | {EXTERNAL LOCATION} | usize | +| main.rs:2746:13:2746:13 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2746:13:2746:13 | y | TRef | {EXTERNAL LOCATION} | i32 | +| main.rs:2746:17:2746:18 | &1 | | {EXTERNAL LOCATION} | & | +| main.rs:2746:17:2746:18 | &1 | TRef | {EXTERNAL LOCATION} | i32 | +| main.rs:2746:18:2746:18 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2747:13:2747:13 | z | | {EXTERNAL LOCATION} | & | +| main.rs:2747:13:2747:13 | z | TRef | {EXTERNAL LOCATION} | usize | +| main.rs:2747:17:2747:17 | x | | {EXTERNAL LOCATION} | usize | +| main.rs:2747:17:2747:22 | x.g(...) | | {EXTERNAL LOCATION} | & | +| main.rs:2747:17:2747:22 | x.g(...) | TRef | {EXTERNAL LOCATION} | usize | +| main.rs:2747:21:2747:21 | y | | {EXTERNAL LOCATION} | & | +| main.rs:2747:21:2747:21 | y | TRef | {EXTERNAL LOCATION} | i32 | +| main.rs:2749:13:2749:13 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2749:17:2749:17 | 0 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2750:13:2750:13 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2750:24:2750:24 | 1 | | {EXTERNAL LOCATION} | i32 | +| main.rs:2750:24:2750:24 | 1 | | {EXTERNAL LOCATION} | usize | +| main.rs:2751:13:2751:13 | z | | {EXTERNAL LOCATION} | i32 | +| main.rs:2751:17:2751:17 | x | | {EXTERNAL LOCATION} | i32 | +| main.rs:2751:17:2751:24 | x.max(...) | | {EXTERNAL LOCATION} | i32 | +| main.rs:2751:23:2751:23 | y | | {EXTERNAL LOCATION} | usize | +| main.rs:2762:11:2797:1 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2763:5:2763:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2764:5:2764:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2765:5:2765:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2766:5:2766:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2767:5:2767:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2768:5:2768:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2769:5:2769:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2770:5:2770:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2771:5:2771:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2772:5:2772:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2773:5:2773:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2774:5:2774:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2774:5:2774:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2775:5:2775:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2776:5:2776:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2777:5:2777:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2778:5:2778:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2779:5:2779:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2780:5:2780:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2782:5:2782:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2783:5:2783:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2784:5:2784:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2785:5:2785:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2786:5:2786:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2787:5:2787:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2788:5:2788:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2788:5:2788:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2788:5:2788:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | -| main.rs:2788:5:2788:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2788:16:2788:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2789:5:2789:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2764:5:2764:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:5:2765:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:20:2765:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2765:41:2765:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2766:5:2766:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2767:5:2767:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2768:5:2768:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2769:5:2769:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2770:5:2770:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2771:5:2771:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2772:5:2772:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2773:5:2773:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2774:5:2774:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2775:5:2775:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2776:5:2776:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2777:5:2777:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2778:5:2778:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2779:5:2779:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2780:5:2780:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2781:5:2781:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2781:5:2781:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2782:5:2782:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2783:5:2783:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2784:5:2784:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2785:5:2785:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2786:5:2786:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2787:5:2787:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2788:5:2788:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2789:5:2789:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2790:5:2790:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2791:5:2791:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2792:5:2792:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2793:5:2793:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2794:5:2794:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2795:5:2795:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2795:5:2795:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2795:5:2795:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | +| main.rs:2795:5:2795:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2795:16:2795:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2796:5:2796:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | From ca2838b361b87910512f480b85e515cbe2bffb47 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 13 Mar 2026 15:32:47 +0100 Subject: [PATCH 41/72] Address review comments --- .../elements/internal/InvocationExprImpl.qll | 3 + .../internal/typeinference/TypeInference.qll | 63 +++++++++++-------- .../test/library-tests/type-inference/main.rs | 2 +- .../type-inference/type-inference.expected | 3 + 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll index 412a3b51ae8..685eee1e43a 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll @@ -6,6 +6,9 @@ module Impl { private newtype TArgumentPosition = TPositionalArgumentPosition(int i) { + // For the type `FunctionPosition` used by type inference, we work with function-call syntax + // adjusted positions, so a call like `x.m(a, b, c)` needs positions `0` through `3`; for this + // reason, there is no `- 1` after `max(...)` below. i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()])] } or TSelfArgumentPosition() or diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 2720f9b25f3..c194531a078 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -343,8 +343,8 @@ private class FunctionDeclaration extends Function { } } -private class AssocFunction extends FunctionDeclaration { - AssocFunction() { this.isAssoc(_) } +private class AssocFunctionDeclaration extends FunctionDeclaration { + AssocFunctionDeclaration() { this.isAssoc(_) } } pragma[nomagic] @@ -1114,10 +1114,10 @@ private Trait getCallExprTraitQualifier(CallExpr ce) { } pragma[nomagic] -private predicate nonAssocFunction(ItemNode i) { not i instanceof AssocFunction } +private predicate nonAssocFunction(ItemNode i) { not i instanceof AssocFunctionDeclaration } /** - * A call expression that can resolve to something that is not an associated + * A call expression that can only resolve to something that is not an associated * function, and hence does not need type inference for resolution. */ private class NonAssocCallExpr extends CallExpr { @@ -1201,9 +1201,7 @@ private module ContextTyping { abstract class ContextTypedCallCand extends AstNode { abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path); - private predicate hasTypeArgument(TypeArgumentPosition apos) { - exists(this.getTypeArgument(apos, _)) - } + predicate hasTypeArgument(TypeArgumentPosition apos) { exists(this.getTypeArgument(apos, _)) } /** * Holds if this call resolves to `target` inside `i`, and the return type @@ -2209,7 +2207,7 @@ private module AssocFunctionResolution { * in `derefChain` and `borrow`. */ pragma[nomagic] - AssocFunction resolveCallTarget( + AssocFunctionDeclaration resolveCallTarget( ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { exists(AssocFunctionCallCand afcc | @@ -2288,7 +2286,9 @@ private module AssocFunctionResolution { exists(getCallExprPathQualifier(this)) and // even if a target cannot be resolved by path resolution, it may still // be possible to resolve a blanket implementation (so not `forex`) - forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof AssocFunction) + forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | + i instanceof AssocFunctionDeclaration + ) } override predicate hasNameAndArity(string name, int arity) { @@ -2373,7 +2373,9 @@ private module AssocFunctionResolution { } pragma[nomagic] - private AssocFunction getAssocFunctionSuccessor(ImplOrTraitItemNode i, string name, int arity) { + private AssocFunctionDeclaration getAssocFunctionSuccessor( + ImplOrTraitItemNode i, string name, int arity + ) { result = i.getASuccessor(name) and arity = result.getNumberOfParamsInclSelf() } @@ -2488,7 +2490,7 @@ private module AssocFunctionResolution { } pragma[nomagic] - AssocFunction resolveCallTargetCand(ImplOrTraitItemNode i) { + AssocFunctionDeclaration resolveCallTargetCand(ImplOrTraitItemNode i) { exists(string name, int arity | this.selfArgIsInstantiationOf(i, name, arity) and result = getAssocFunctionSuccessor(i, name, arity) @@ -2497,7 +2499,7 @@ private module AssocFunctionResolution { /** Gets the associated function targeted by this call, if any. */ pragma[nomagic] - AssocFunction resolveCallTarget(ImplOrTraitItemNode i) { + AssocFunctionDeclaration resolveCallTarget(ImplOrTraitItemNode i) { result = this.resolveCallTargetCand(i) and not FunctionOverloading::functionResolutionDependsOnArgument(i, result, _, _) or @@ -2896,7 +2898,7 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput result = this.getInferredNonSelfType(pos, path) } - private AssocFunction getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { + private AssocFunctionDeclaration getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { exists(DerefChain derefChain, BorrowKind borrow | derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and result = super.resolveCallTarget(i, _, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa @@ -2904,10 +2906,7 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput } override Declaration getTarget(string derefChainBorrow) { - exists(ImplOrTraitItemNodeOption i, AssocFunction f | - f = this.getTarget(i.asSome(), derefChainBorrow) and - result = TFunctionDeclaration(i, f) - ) + exists(ImplOrTraitItemNode i | result.isAssocFunction(i, this.getTarget(i, derefChainBorrow))) } pragma[nomagic] @@ -2926,7 +2925,9 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput } } - private class NonAssocFunctionCallAccess extends Access instanceof NonAssocCallExpr { + private class NonAssocFunctionCallAccess extends Access instanceof NonAssocCallExpr, + CallExprImpl::CallExprCall + { pragma[nomagic] override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { result = NonAssocCallExpr.super.getTypeArgument(apos, path) @@ -2949,11 +2950,9 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput pragma[nomagic] private Declaration getTarget() { - exists(ImplOrTraitItemNodeOption i, FunctionDeclaration f | - f = super.resolveCallTargetViaPathResolution() and - f.isDirectlyFor(i) and - result = TFunctionDeclaration(i, f) - ) + result = + TFunctionDeclaration(ImplOrTraitItemNodeOption::none_(), + super.resolveCallTargetViaPathResolution()) } override Declaration getTarget(string derefChainBorrow) { @@ -2964,9 +2963,16 @@ private module FunctionCallMatchingInput implements MatchingWithEnvironmentInput pragma[nomagic] override predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) { derefChainBorrow = noDerefChainBorrow() and - exists(ImplOrTraitItemNodeOption i, FunctionDeclaration f | - TFunctionDeclaration(i, f) = this.getTarget() and - this.hasUnknownTypeAt(i.asSome(), f, pos, path) + exists(FunctionDeclaration f, TypeParameter tp | + f = super.resolveCallTargetViaPathResolution() and + pos.isReturn() and + tp = f.getReturnType(_, path) and + not tp = f.getParameterType(_, _, _) and + // check that no explicit type arguments have been supplied for `tp` + not exists(TypeArgumentPosition tapos | + this.hasTypeArgument(tapos) and + TTypeParamTypeParameter(tapos.asTypeParam()) = tp + ) ) } } @@ -3135,6 +3141,11 @@ private module TupleLikeConstructionMatchingInput implements MatchingInputSig { class Declaration = TupleLikeConstructor; class Access extends NonAssocCallExpr, ContextTyping::ContextTypedCallCand { + Access() { + this instanceof CallExprImpl::TupleStructExpr or + this instanceof CallExprImpl::TupleVariantExpr + } + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { result = NonAssocCallExpr.super.getTypeArgument(apos, path) } diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index ad77bd9febd..6c9f2c801d5 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2698,7 +2698,7 @@ mod context_typed { let s = Default::default(); // $ target=default type=s:S S::f(s); // $ target=f - let z = free_function(); // $ target=free_function MISSING: type=z:i32 + let z = free_function(); // $ target=free_function type=z:i32 x.push(z); // $ target=push } } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 6921fbde3de..feba4891a66 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -12195,10 +12195,13 @@ inferType | main.rs:2698:17:2698:34 | ...::default(...) | | main.rs:2639:5:2640:13 | S | | main.rs:2699:9:2699:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | | main.rs:2699:14:2699:14 | s | | main.rs:2639:5:2640:13 | S | +| main.rs:2701:13:2701:13 | z | | {EXTERNAL LOCATION} | i32 | +| main.rs:2701:17:2701:31 | free_function(...) | | {EXTERNAL LOCATION} | i32 | | main.rs:2702:9:2702:9 | x | | {EXTERNAL LOCATION} | Vec | | main.rs:2702:9:2702:9 | x | A | {EXTERNAL LOCATION} | Global | | main.rs:2702:9:2702:9 | x | T | {EXTERNAL LOCATION} | i32 | | main.rs:2702:9:2702:17 | x.push(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2702:16:2702:16 | z | | {EXTERNAL LOCATION} | i32 | | main.rs:2709:14:2709:17 | SelfParam | | main.rs:2707:5:2715:5 | Self [trait MyTrait] | | main.rs:2712:14:2712:18 | SelfParam | | {EXTERNAL LOCATION} | & | | main.rs:2712:14:2712:18 | SelfParam | TRef | main.rs:2707:5:2715:5 | Self [trait MyTrait] | From 7ef60a864974c8c790766fa0fbd877cbb5bd63e3 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 11 Mar 2026 13:15:31 +0100 Subject: [PATCH 42/72] Update the overlay annotation script for go The Go libraries follow their own naming convention for "query libraries". These need to be exempted from automatic `overlay[local?]` annotations since otherwise it appears that too many predicates are evaluated, possibly because of inadequate use of sentinels. --- config/add-overlay-annotations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config/add-overlay-annotations.py b/config/add-overlay-annotations.py index 0a30eee5799..4fbd9a2b7fc 100644 --- a/config/add-overlay-annotations.py +++ b/config/add-overlay-annotations.py @@ -199,6 +199,7 @@ def annotate_as_appropriate(filename, lines): # as overlay[local?]. It is not clear that these heuristics are exactly what we want, # but they seem to work well enough for now (as determined by speed and accuracy numbers). if (filename.endswith("Test.qll") or + re.search(r"go/ql/lib/semmle/go/security/[^/]+[.]qll$", filename.replace(os.sep, "/")) or ((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and any("implements DataFlow::ConfigSig" in line for line in lines))): return None From c56feb764489a3ef2f098590a395e9d985a35077 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 11 Mar 2026 13:17:49 +0100 Subject: [PATCH 43/72] Go: annotate the standard library with for overlay This commit is auto-generated with: python3 config/add-overlay-annotations.py go --- go/ql/lib/Customizations.qll | 2 ++ go/ql/lib/go.qll | 2 ++ go/ql/lib/ideContextual.qll | 2 ++ go/ql/lib/semmle/go/AST.qll | 2 ++ go/ql/lib/semmle/go/Architectures.qll | 2 ++ go/ql/lib/semmle/go/Comments.qll | 2 ++ go/ql/lib/semmle/go/Concepts.qll | 2 ++ go/ql/lib/semmle/go/Decls.qll | 2 ++ go/ql/lib/semmle/go/DiagnosticsReporting.qll | 2 ++ go/ql/lib/semmle/go/Errors.qll | 2 ++ go/ql/lib/semmle/go/Expr.qll | 2 ++ go/ql/lib/semmle/go/Files.qll | 2 ++ go/ql/lib/semmle/go/GoMod.qll | 2 ++ go/ql/lib/semmle/go/HTML.qll | 2 ++ go/ql/lib/semmle/go/Locations.qll | 2 ++ go/ql/lib/semmle/go/Packages.qll | 2 ++ go/ql/lib/semmle/go/PrintAst.qll | 2 ++ go/ql/lib/semmle/go/Scopes.qll | 2 ++ go/ql/lib/semmle/go/Stmt.qll | 2 ++ go/ql/lib/semmle/go/StringOps.qll | 2 ++ go/ql/lib/semmle/go/Types.qll | 2 ++ go/ql/lib/semmle/go/Util.qll | 2 ++ go/ql/lib/semmle/go/VariableWithFields.qll | 2 ++ go/ql/lib/semmle/go/concepts/GeneratedFile.qll | 2 ++ go/ql/lib/semmle/go/concepts/HTTP.qll | 2 ++ go/ql/lib/semmle/go/controlflow/BasicBlocks.qll | 2 ++ go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll | 3 +++ go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll | 2 ++ go/ql/lib/semmle/go/controlflow/IR.qll | 2 ++ go/ql/lib/semmle/go/dataflow/DataFlow.qll | 2 ++ go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 2 ++ go/ql/lib/semmle/go/dataflow/FlowSummary.qll | 2 ++ go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll | 2 ++ go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll | 2 ++ go/ql/lib/semmle/go/dataflow/Properties.qll | 2 ++ go/ql/lib/semmle/go/dataflow/SSA.qll | 2 ++ go/ql/lib/semmle/go/dataflow/SsaImpl.qll | 2 ++ go/ql/lib/semmle/go/dataflow/TaintTracking.qll | 2 ++ .../dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll | 2 ++ .../lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll | 2 ++ go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll | 2 ++ go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll | 2 ++ go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll | 5 +++++ go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll | 3 +++ go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll | 3 +++ .../semmle/go/dataflow/internal/DataFlowImplConsistency.qll | 2 ++ .../lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll | 2 ++ go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll | 3 +++ go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll | 4 ++++ go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll | 3 +++ .../semmle/go/dataflow/internal/ExternalFlowExtensions.qll | 2 ++ go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll | 2 ++ .../go/dataflow/internal/TaintTrackingImplSpecific.qll | 2 ++ go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll | 4 ++++ go/ql/lib/semmle/go/dependencies/Dependencies.qll | 2 ++ go/ql/lib/semmle/go/dependencies/SemVer.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Afero.qll | 2 ++ go/ql/lib/semmle/go/frameworks/AwsLambda.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Beego.qll | 2 ++ go/ql/lib/semmle/go/frameworks/BeegoOrm.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Bun.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Couchbase.qll | 2 ++ go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Echo.qll | 2 ++ go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Email.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Encoding.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Fasthttp.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Gin.qll | 2 ++ go/ql/lib/semmle/go/frameworks/GinCors.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Glog.qll | 2 ++ go/ql/lib/semmle/go/frameworks/GoJose.qll | 2 ++ go/ql/lib/semmle/go/frameworks/GoKit.qll | 2 ++ go/ql/lib/semmle/go/frameworks/GoMicro.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Gorqlite.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Gqlgen.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Jwt.qll | 2 ++ go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll | 2 ++ .../lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll | 2 ++ go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Logrus.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Macaron.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Mux.qll | 2 ++ go/ql/lib/semmle/go/frameworks/NoSQL.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Protobuf.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Revel.qll | 2 ++ go/ql/lib/semmle/go/frameworks/RsCors.qll | 2 ++ go/ql/lib/semmle/go/frameworks/SQL.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Spew.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Squirrel.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Stdlib.qll | 2 ++ go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Testing.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Twirp.qll | 2 ++ go/ql/lib/semmle/go/frameworks/WebSocket.qll | 2 ++ go/ql/lib/semmle/go/frameworks/XNetHtml.qll | 2 ++ go/ql/lib/semmle/go/frameworks/XPath.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Yaml.qll | 2 ++ go/ql/lib/semmle/go/frameworks/Zap.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Html.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Io.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Log.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll | 2 ++ .../lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Net.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Os.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Path.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll | 2 ++ go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll | 2 ++ go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll | 3 +++ 139 files changed, 291 insertions(+) diff --git a/go/ql/lib/Customizations.qll b/go/ql/lib/Customizations.qll index 127840de9dd..56824bc03eb 100644 --- a/go/ql/lib/Customizations.qll +++ b/go/ql/lib/Customizations.qll @@ -8,5 +8,7 @@ * `FileSystemAccess`, or the `Source` and `Sink` classes associated with the security queries * to model frameworks that are not covered by the standard library. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/go.qll b/go/ql/lib/go.qll index 1b8bf94a0d2..af9f676e013 100644 --- a/go/ql/lib/go.qll +++ b/go/ql/lib/go.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with Go programs. */ +overlay[local?] +module; import Customizations import semmle.go.Architectures diff --git a/go/ql/lib/ideContextual.qll b/go/ql/lib/ideContextual.qll index b28a23a6e00..2f96afdeffe 100644 --- a/go/ql/lib/ideContextual.qll +++ b/go/ql/lib/ideContextual.qll @@ -2,6 +2,8 @@ * Provides classes and predicates related to contextual queries * in the code viewer. */ +overlay[local?] +module; import go private import codeql.util.FileSystem diff --git a/go/ql/lib/semmle/go/AST.qll b/go/ql/lib/semmle/go/AST.qll index 6a840f81cbb..bbe93ed345b 100644 --- a/go/ql/lib/semmle/go/AST.qll +++ b/go/ql/lib/semmle/go/AST.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with AST nodes. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Architectures.qll b/go/ql/lib/semmle/go/Architectures.qll index bb4face2407..b90501a5d36 100644 --- a/go/ql/lib/semmle/go/Architectures.qll +++ b/go/ql/lib/semmle/go/Architectures.qll @@ -1,4 +1,6 @@ /** Provides classes for working with architectures. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Comments.qll b/go/ql/lib/semmle/go/Comments.qll index b55810311f8..f232d4b9378 100644 --- a/go/ql/lib/semmle/go/Comments.qll +++ b/go/ql/lib/semmle/go/Comments.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with code comments. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll index 4e328ed76c4..ffa48ea9654 100644 --- a/go/ql/lib/semmle/go/Concepts.qll +++ b/go/ql/lib/semmle/go/Concepts.qll @@ -3,6 +3,8 @@ * access or system command execution, for which individual framework libraries * provide concrete subclasses. */ +overlay[local?] +module; import go import semmle.go.dataflow.FunctionInputsAndOutputs diff --git a/go/ql/lib/semmle/go/Decls.qll b/go/ql/lib/semmle/go/Decls.qll index 9d1e4d2611a..d3282b59f69 100644 --- a/go/ql/lib/semmle/go/Decls.qll +++ b/go/ql/lib/semmle/go/Decls.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with declarations. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/DiagnosticsReporting.qll b/go/ql/lib/semmle/go/DiagnosticsReporting.qll index 691c430aa73..0cbc98cdd83 100644 --- a/go/ql/lib/semmle/go/DiagnosticsReporting.qll +++ b/go/ql/lib/semmle/go/DiagnosticsReporting.qll @@ -1,4 +1,6 @@ /** Provides classes for working with errors and warnings recorded during extraction. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Errors.qll b/go/ql/lib/semmle/go/Errors.qll index 2e138e8de61..54e1ea98863 100644 --- a/go/ql/lib/semmle/go/Errors.qll +++ b/go/ql/lib/semmle/go/Errors.qll @@ -1,4 +1,6 @@ /** Provides classes for working with Go frontend errors recorded during extraction. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index 9b34f592083..9e006aed54c 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with expressions. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Files.qll b/go/ql/lib/semmle/go/Files.qll index cda168482ca..8252357bcc2 100644 --- a/go/ql/lib/semmle/go/Files.qll +++ b/go/ql/lib/semmle/go/Files.qll @@ -1,4 +1,6 @@ /** Provides classes for working with files and folders. */ +overlay[local?] +module; import go private import codeql.util.FileSystem diff --git a/go/ql/lib/semmle/go/GoMod.qll b/go/ql/lib/semmle/go/GoMod.qll index 119339c18eb..e357ae616cf 100644 --- a/go/ql/lib/semmle/go/GoMod.qll +++ b/go/ql/lib/semmle/go/GoMod.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with go.mod files. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/HTML.qll b/go/ql/lib/semmle/go/HTML.qll index 2f0e411a88d..41bb47e0ba5 100644 --- a/go/ql/lib/semmle/go/HTML.qll +++ b/go/ql/lib/semmle/go/HTML.qll @@ -1,4 +1,6 @@ /** Provides classes for working with HTML documents. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Locations.qll b/go/ql/lib/semmle/go/Locations.qll index 7503421c0ff..03105fbdf25 100644 --- a/go/ql/lib/semmle/go/Locations.qll +++ b/go/ql/lib/semmle/go/Locations.qll @@ -1,4 +1,6 @@ /** Provides classes for working with locations and program elements that have locations. */ +overlay[local?] +module; import go private import semmle.go.Overlay diff --git a/go/ql/lib/semmle/go/Packages.qll b/go/ql/lib/semmle/go/Packages.qll index d1163350446..8926d0e17f1 100644 --- a/go/ql/lib/semmle/go/Packages.qll +++ b/go/ql/lib/semmle/go/Packages.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/PrintAst.qll b/go/ql/lib/semmle/go/PrintAst.qll index bee97008dbd..c7c9bb5b4b7 100644 --- a/go/ql/lib/semmle/go/PrintAst.qll +++ b/go/ql/lib/semmle/go/PrintAst.qll @@ -1,6 +1,8 @@ /** * Provides queries to pretty-print a Go AST as a graph. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Scopes.qll b/go/ql/lib/semmle/go/Scopes.qll index 2ab08b5b5b4..1933c33230c 100644 --- a/go/ql/lib/semmle/go/Scopes.qll +++ b/go/ql/lib/semmle/go/Scopes.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with scopes and declared objects. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Stmt.qll b/go/ql/lib/semmle/go/Stmt.qll index 8719ad543cf..befc60e73c6 100644 --- a/go/ql/lib/semmle/go/Stmt.qll +++ b/go/ql/lib/semmle/go/Stmt.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with statements. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/StringOps.qll b/go/ql/lib/semmle/go/StringOps.qll index 3463e4fdf87..6af2946f95c 100644 --- a/go/ql/lib/semmle/go/StringOps.qll +++ b/go/ql/lib/semmle/go/StringOps.qll @@ -1,6 +1,8 @@ /** * Provides predicates and classes for working with string operations. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index d377cb2c9d8..cd4d5a4120f 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with Go types. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/Util.qll b/go/ql/lib/semmle/go/Util.qll index 02175f2d66a..4879cb0cbe7 100644 --- a/go/ql/lib/semmle/go/Util.qll +++ b/go/ql/lib/semmle/go/Util.qll @@ -1,4 +1,6 @@ /** This module provides general utility classes and predicates. */ +overlay[local?] +module; /** * A Boolean value. diff --git a/go/ql/lib/semmle/go/VariableWithFields.qll b/go/ql/lib/semmle/go/VariableWithFields.qll index 0fce5247dcd..920c4313de4 100644 --- a/go/ql/lib/semmle/go/VariableWithFields.qll +++ b/go/ql/lib/semmle/go/VariableWithFields.qll @@ -1,4 +1,6 @@ /** Provides the `VariableWithFields` class, for working with variables with a chain of field or element accesses chained to it. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll index d1067b60ad0..575ede7fdee 100644 --- a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll +++ b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll @@ -1,4 +1,6 @@ /** Provides a class for generated files. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/concepts/HTTP.qll b/go/ql/lib/semmle/go/concepts/HTTP.qll index b3990edd084..73f3bfb8784 100644 --- a/go/ql/lib/semmle/go/concepts/HTTP.qll +++ b/go/ql/lib/semmle/go/concepts/HTTP.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with HTTP-related concepts such as requests and responses. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll index 43b8c7e8dd3..cc1b0c6292c 100644 --- a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll +++ b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with basic blocks. */ +overlay[local?] +module; import go private import ControlFlowGraphImpl diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll index 88adb88c026..c7dbe776a8e 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with a CFG-based program representation. */ +overlay[local?] +module; import go private import ControlFlowGraphImpl @@ -62,6 +64,7 @@ module ControlFlow { BasicBlock getBasicBlock() { result.getANode() = this } /** Holds if this node dominates `dominee` in the control-flow graph. */ + overlay[caller?] pragma[inline] predicate dominatesNode(ControlFlow::Node dominee) { exists(ReachableBasicBlock thisbb, ReachableBasicBlock dbb, int i, int j | diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll index 71bd0ea561f..125ad7fdec2 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll @@ -3,6 +3,8 @@ * * Provides predicates for building intra-procedural CFGs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/controlflow/IR.qll b/go/ql/lib/semmle/go/controlflow/IR.qll index c6433900a73..e3ed7cadbad 100644 --- a/go/ql/lib/semmle/go/controlflow/IR.qll +++ b/go/ql/lib/semmle/go/controlflow/IR.qll @@ -9,6 +9,8 @@ * Each instruction is also a control-flow node, but there are control-flow nodes that are not * instructions (synthetic entry and exit nodes, as well as no-op skip nodes). */ +overlay[local?] +module; import go private import semmle.go.controlflow.ControlFlowGraphImpl diff --git a/go/ql/lib/semmle/go/dataflow/DataFlow.qll b/go/ql/lib/semmle/go/dataflow/DataFlow.qll index c26adbfd2c2..bc0d310566e 100644 --- a/go/ql/lib/semmle/go/dataflow/DataFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/DataFlow.qll @@ -14,6 +14,8 @@ * (intraprocedural) data flow, invoke `DataFlow::localFlow` or * `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index 388921224ad..e1170aeda24 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -84,6 +84,8 @@ * "taint" indicates a default additional taint step and "value" indicates a * globally applicable value-preserving step. */ +overlay[local?] +module; private import go private import internal.ExternalFlowExtensions::Extensions as Extensions diff --git a/go/ql/lib/semmle/go/dataflow/FlowSummary.qll b/go/ql/lib/semmle/go/dataflow/FlowSummary.qll index 749e1c92e06..632697b341f 100644 --- a/go/ql/lib/semmle/go/dataflow/FlowSummary.qll +++ b/go/ql/lib/semmle/go/dataflow/FlowSummary.qll @@ -1,6 +1,8 @@ /** * Provides classes and predicates for defining flow summaries. */ +overlay[local?] +module; import go private import internal.FlowSummaryImpl as Impl diff --git a/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll b/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll index 89d3c297fed..42d17006d64 100644 --- a/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll +++ b/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll @@ -2,6 +2,8 @@ * Provides QL classes for indicating data flow through a function parameter, return value, * or receiver. */ +overlay[local?] +module; import go private import semmle.go.dataflow.internal.DataFlowPrivate diff --git a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll index e566ca41c2f..0b08d5a4b8f 100644 --- a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll +++ b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll @@ -29,6 +29,8 @@ * common reason for this is that the analysis cannot prove that there * are no side-effects that might cause the computed value to change. */ +overlay[local?] +module; /* * Note to developers: the correctness of this module depends on the diff --git a/go/ql/lib/semmle/go/dataflow/Properties.qll b/go/ql/lib/semmle/go/dataflow/Properties.qll index 735deb19c9f..6794eee5fcd 100644 --- a/go/ql/lib/semmle/go/dataflow/Properties.qll +++ b/go/ql/lib/semmle/go/dataflow/Properties.qll @@ -1,6 +1,8 @@ /** * Provides a class for representing and reasoning about properties of data-flow nodes. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/SSA.qll b/go/ql/lib/semmle/go/dataflow/SSA.qll index 69fffa393c1..c3d759a70fe 100644 --- a/go/ql/lib/semmle/go/dataflow/SSA.qll +++ b/go/ql/lib/semmle/go/dataflow/SSA.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with static single assignment form (SSA). */ +overlay[local?] +module; import go private import SsaImpl diff --git a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll index 026c8114f9f..bf530108d4b 100644 --- a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll @@ -3,6 +3,8 @@ * * Provides predicates for constructing an SSA representation for functions. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/TaintTracking.qll b/go/ql/lib/semmle/go/dataflow/TaintTracking.qll index c469574b3b9..89b43de0738 100644 --- a/go/ql/lib/semmle/go/dataflow/TaintTracking.qll +++ b/go/ql/lib/semmle/go/dataflow/TaintTracking.qll @@ -2,6 +2,8 @@ * Provides classes for performing local (intra-procedural) and * global (inter-procedural) taint-tracking analyses. */ +overlay[local?] +module; import semmle.go.dataflow.DataFlow diff --git a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll index d185f9f78f3..cd5490e63c0 100644 --- a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll +++ b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll @@ -1,6 +1,8 @@ /** * Provides an implementation of a commonly used barrier guard for sanitizing untrusted URLs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll index 8cdc3b2e1ac..4b669a305f5 100644 --- a/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll +++ b/go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll @@ -1,6 +1,8 @@ /** * Provides an implementation of a commonly used barrier guard for sanitizing untrusted URLs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll b/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll index 8abcfb327cc..8a105cc8fa9 100644 --- a/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll +++ b/go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll @@ -1,6 +1,8 @@ /** * Provides an implementation of a commonly used barrier guard for sanitizing untrusted URLs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll b/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll index e978cb3e587..05897354061 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/ContainerFlow.qll @@ -1,4 +1,6 @@ /** Contains predicates for dealing with container flow. */ +overlay[local?] +module; import go private import DataFlowNodes diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll index a06edad0be2..10455f84edb 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go private import DataFlowPrivate @@ -119,6 +122,7 @@ class ArgumentPosition extends int { } /** Holds if arguments at position `apos` match parameters at position `ppos`. */ +overlay[caller?] pragma[inline] predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos } @@ -130,6 +134,7 @@ private predicate isInterfaceMethod(Method c) { * Holds if `call` is passing `arg` to param `p` in any circumstance except passing * a receiver parameter to a concrete method. */ +overlay[caller?] pragma[inline] predicate golangSpecificParamArgFilter( DataFlowCall call, DataFlow::ParameterNode p, DataFlow::ArgumentNode arg diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll index c9761d21702..ae10681799f 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import DataFlowImplSpecific private import codeql.dataflow.internal.DataFlowImpl private import semmle.go.Locations diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll index 6df86bde023..27db6081e49 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplCommon.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import DataFlowImplSpecific private import codeql.dataflow.internal.DataFlowImplCommon private import semmle.go.Locations diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll index b4d92771150..cf4794a9715 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplConsistency.qll @@ -2,6 +2,8 @@ * Provides consistency queries for checking invariants in the language-specific * data-flow classes and predicates. */ +overlay[local?] +module; private import go private import DataFlowImplSpecific as Impl diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll index c680778ce4d..c2c6b0b7c43 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImplSpecific.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the data flow library. */ +overlay[local?] +module; private import codeql.dataflow.DataFlow private import semmle.go.Locations diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index 4fb767e548c..f5115656675 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go private import semmle.go.dataflow.FunctionInputsAndOutputs private import semmle.go.dataflow.FlowSummary diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index 76b0ef363e3..33149bf0057 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go private import DataFlowUtil private import DataFlowImplCommon @@ -478,5 +481,6 @@ predicate allowParameterReturnInSelf(ParameterNode p) { class ContentApprox = Unit; /** Gets an approximated value for content `c`. */ +overlay[caller?] pragma[inline] ContentApprox getContentApprox(Content c) { any() } diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll index ea1fc575076..b29ff7d5ea8 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the data flow library. */ +overlay[local?] +module; private import go private import semmle.go.dataflow.FunctionInputsAndOutputs @@ -147,6 +149,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) { * Holds if data flows from `source` to `sink` in zero or more local * (intra-procedural) steps. */ +overlay[caller?] pragma[inline] predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } diff --git a/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll b/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll index 2e962299f3e..5d43cf674c1 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll @@ -1,6 +1,8 @@ /** * This module provides extensible predicates for defining MaD models. */ +overlay[local?] +module; private import codeql.mad.static.ModelsAsData as SharedMaD diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll index f09f42872ea..240665bd492 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll @@ -1,6 +1,8 @@ /** * Provides classes and predicates for defining flow summaries. */ +overlay[local?] +module; private import go private import codeql.dataflow.internal.FlowSummaryImpl diff --git a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll index b9795bb14d3..e0c416087fd 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingImplSpecific.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the taint tracking library. */ +overlay[local?] +module; private import codeql.dataflow.TaintTracking private import DataFlowImplSpecific diff --git a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll index adb3d5dcac7..f9f14874493 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll @@ -1,6 +1,8 @@ /** * Provides Go-specific definitions for use in the taint-tracking library. */ +overlay[local?] +module; private import go private import FlowSummaryImpl as FlowSummaryImpl @@ -11,6 +13,7 @@ private import DataFlowPrivate as DataFlowPrivate * Holds if taint can flow from `src` to `sink` in zero or more * local (intra-procedural) steps. */ +overlay[caller?] pragma[inline] predicate localTaint(DataFlow::Node src, DataFlow::Node sink) { localTaintStep*(src, sink) } @@ -18,6 +21,7 @@ predicate localTaint(DataFlow::Node src, DataFlow::Node sink) { localTaintStep*( * Holds if taint can flow from `src` to `sink` in zero or more * local (intra-procedural) steps. */ +overlay[caller?] pragma[inline] predicate localExprTaint(Expr src, Expr sink) { localTaint(DataFlow::exprNode(src), DataFlow::exprNode(sink)) diff --git a/go/ql/lib/semmle/go/dependencies/Dependencies.qll b/go/ql/lib/semmle/go/dependencies/Dependencies.qll index d8c8ee52d29..6c9537c72c4 100644 --- a/go/ql/lib/semmle/go/dependencies/Dependencies.qll +++ b/go/ql/lib/semmle/go/dependencies/Dependencies.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling go.mod dependencies. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/dependencies/SemVer.qll b/go/ql/lib/semmle/go/dependencies/SemVer.qll index 88d37563931..290617781ec 100644 --- a/go/ql/lib/semmle/go/dependencies/SemVer.qll +++ b/go/ql/lib/semmle/go/dependencies/SemVer.qll @@ -1,6 +1,8 @@ /** * Provides classes for dealing with semantic versions, for dependency versions. */ +overlay[local?] +module; import semmle.go.dependencies.Dependencies diff --git a/go/ql/lib/semmle/go/frameworks/Afero.qll b/go/ql/lib/semmle/go/frameworks/Afero.qll index c03bf611433..22704a6af8e 100644 --- a/go/ql/lib/semmle/go/frameworks/Afero.qll +++ b/go/ql/lib/semmle/go/frameworks/Afero.qll @@ -2,6 +2,8 @@ * Provides classes for working with sinks and taint propagators * from the `github.com/spf13/afero` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/AwsLambda.qll b/go/ql/lib/semmle/go/frameworks/AwsLambda.qll index 28f21c9101b..f366a877097 100644 --- a/go/ql/lib/semmle/go/frameworks/AwsLambda.qll +++ b/go/ql/lib/semmle/go/frameworks/AwsLambda.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/aws/aws-lambda-go/lambda` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Beego.qll b/go/ql/lib/semmle/go/frameworks/Beego.qll index 383be8ec42a..5f3f2e986c2 100644 --- a/go/ql/lib/semmle/go/frameworks/Beego.qll +++ b/go/ql/lib/semmle/go/frameworks/Beego.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/beego/beego` package. */ +overlay[local?] +module; import go import semmle.go.security.Xss diff --git a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll index 925b0f19fa3..e1bc5c481bd 100644 --- a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll +++ b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/astaxie/beego/orm` subpackage. */ +overlay[local?] +module; import go private import semmle.go.security.StoredXssCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/Bun.qll b/go/ql/lib/semmle/go/frameworks/Bun.qll index 5be82d2cacc..8637c8f5704 100644 --- a/go/ql/lib/semmle/go/frameworks/Bun.qll +++ b/go/ql/lib/semmle/go/frameworks/Bun.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `Bun` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Couchbase.qll b/go/ql/lib/semmle/go/frameworks/Couchbase.qll index b5bfbcb22a2..d1be1a73205 100644 --- a/go/ql/lib/semmle/go/frameworks/Couchbase.qll +++ b/go/ql/lib/semmle/go/frameworks/Couchbase.qll @@ -1,6 +1,8 @@ /** * Provides models of commonly used functions in the official Couchbase Go SDK library. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll index 154ac82e7a2..7f0e52b449a 100644 --- a/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll +++ b/go/ql/lib/semmle/go/frameworks/CryptoLibraries.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling cryptographic libraries. */ +overlay[local?] +module; import go import semmle.go.Concepts::Cryptography diff --git a/go/ql/lib/semmle/go/frameworks/Echo.qll b/go/ql/lib/semmle/go/frameworks/Echo.qll index a2a6e7d846a..865d8c3972b 100644 --- a/go/ql/lib/semmle/go/frameworks/Echo.qll +++ b/go/ql/lib/semmle/go/frameworks/Echo.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, taint propagators, and HTTP sinks * from the `github.com/labstack/echo` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll index b1bf4571216..23f3a8c2d4d 100644 --- a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll +++ b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts relating to the [github.com/elazarl/goproxy](https://pkg.go.dev/github.com/elazarl/goproxy) package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Email.qll b/go/ql/lib/semmle/go/frameworks/Email.qll index ba4cf8be415..97894806f6f 100644 --- a/go/ql/lib/semmle/go/frameworks/Email.qll +++ b/go/ql/lib/semmle/go/frameworks/Email.qll @@ -1,4 +1,6 @@ /** Provides classes for working with email-related APIs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Encoding.qll b/go/ql/lib/semmle/go/frameworks/Encoding.qll index 201e2c9001d..45f83021a0c 100644 --- a/go/ql/lib/semmle/go/frameworks/Encoding.qll +++ b/go/ql/lib/semmle/go/frameworks/Encoding.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling taint propagation through marshalling and encoding functions. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Fasthttp.qll b/go/ql/lib/semmle/go/frameworks/Fasthttp.qll index 941e6b44945..2dea987ade6 100644 --- a/go/ql/lib/semmle/go/frameworks/Fasthttp.qll +++ b/go/ql/lib/semmle/go/frameworks/Fasthttp.qll @@ -2,6 +2,8 @@ * Provides classes for working with remote flow sources, sinks and taint propagators * from the `github.com/valyala/fasthttp` package. */ +overlay[local?] +module; import go private import semmle.go.security.RequestForgeryCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/Gin.qll b/go/ql/lib/semmle/go/frameworks/Gin.qll index 71ed5d931fa..f6d2bf8ff55 100644 --- a/go/ql/lib/semmle/go/frameworks/Gin.qll +++ b/go/ql/lib/semmle/go/frameworks/Gin.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling the `github.com/gin-gonic/gin` package. */ +overlay[local?] +module; import go import semmle.go.concepts.HTTP diff --git a/go/ql/lib/semmle/go/frameworks/GinCors.qll b/go/ql/lib/semmle/go/frameworks/GinCors.qll index cc993ea4dee..cd742ac9ba2 100644 --- a/go/ql/lib/semmle/go/frameworks/GinCors.qll +++ b/go/ql/lib/semmle/go/frameworks/GinCors.qll @@ -1,6 +1,8 @@ /** * Provides classes for modeling the `github.com/gin-contrib/cors` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Glog.qll b/go/ql/lib/semmle/go/frameworks/Glog.qll index 146b8a4f814..a9ffc432181 100644 --- a/go/ql/lib/semmle/go/frameworks/Glog.qll +++ b/go/ql/lib/semmle/go/frameworks/Glog.qll @@ -2,6 +2,8 @@ * Provides models of commonly used functions in the `github.com/golang/glog` and `k8s.io/klog` * packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/GoJose.qll b/go/ql/lib/semmle/go/frameworks/GoJose.qll index 509e289f586..6ee1feb5ab9 100644 --- a/go/ql/lib/semmle/go/frameworks/GoJose.qll +++ b/go/ql/lib/semmle/go/frameworks/GoJose.qll @@ -2,6 +2,8 @@ * Provides classes for working with the `gopkg.in/square/go-jose` and `github.com/go-jose/go-jose` * packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/GoKit.qll b/go/ql/lib/semmle/go/frameworks/GoKit.qll index e4a9e48d207..f56451b1b81 100644 --- a/go/ql/lib/semmle/go/frameworks/GoKit.qll +++ b/go/ql/lib/semmle/go/frameworks/GoKit.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts relating to the [github.com/go-kit/kit](https://pkg.go.dev/github.com/go-kit/kit) package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/GoMicro.qll b/go/ql/lib/semmle/go/frameworks/GoMicro.qll index f01dcde9f1e..723f58899ff 100644 --- a/go/ql/lib/semmle/go/frameworks/GoMicro.qll +++ b/go/ql/lib/semmle/go/frameworks/GoMicro.qll @@ -1,6 +1,8 @@ /** * Provides models of the [Go Micro library](https://github.com/go-micro/go-micro). */ +overlay[local?] +module; import go private import semmle.go.security.RequestForgeryCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/Gorqlite.qll b/go/ql/lib/semmle/go/frameworks/Gorqlite.qll index 65ac5d88bab..434c8148bd7 100644 --- a/go/ql/lib/semmle/go/frameworks/Gorqlite.qll +++ b/go/ql/lib/semmle/go/frameworks/Gorqlite.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `gorqlite` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Gqlgen.qll b/go/ql/lib/semmle/go/frameworks/Gqlgen.qll index 4edaab46b22..bcde5ce9a36 100644 --- a/go/ql/lib/semmle/go/frameworks/Gqlgen.qll +++ b/go/ql/lib/semmle/go/frameworks/Gqlgen.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions and types in the gqlgen packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Jwt.qll b/go/ql/lib/semmle/go/frameworks/Jwt.qll index 681ead26834..d139f48ae2b 100644 --- a/go/ql/lib/semmle/go/frameworks/Jwt.qll +++ b/go/ql/lib/semmle/go/frameworks/Jwt.qll @@ -2,6 +2,8 @@ * Provides classes and predicates for working with the `github.com/golang-jwt/jwt` and * `github.com/dgrijalva/jwt-go` packages. */ +overlay[local?] +module; import go private import semmle.go.security.MissingJwtSignatureCheckCustomizations::MissingJwtSignatureCheck diff --git a/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll b/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll index 6fe789dccc3..ea80d0eba37 100644 --- a/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll +++ b/go/ql/lib/semmle/go/frameworks/K8sIoApiCoreV1.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `k8s.io/api/core/v1` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll b/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll index 5c7481e5808..945904ba0ae 100644 --- a/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll +++ b/go/ql/lib/semmle/go/frameworks/K8sIoApimachineryPkgRuntime.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `k8s.io/apimachinery/pkg/runtime` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll b/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll index c087cc26ff8..f23d069f4c0 100644 --- a/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll +++ b/go/ql/lib/semmle/go/frameworks/K8sIoClientGo.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `k8s.io/client-go/kubernetes/typed/core/v1` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Logrus.qll b/go/ql/lib/semmle/go/frameworks/Logrus.qll index 83278a4cd9e..33287462c05 100644 --- a/go/ql/lib/semmle/go/frameworks/Logrus.qll +++ b/go/ql/lib/semmle/go/frameworks/Logrus.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions in the `github.com/sirupsen/logrus` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Macaron.qll b/go/ql/lib/semmle/go/frameworks/Macaron.qll index 41e95095aa2..1c088804263 100644 --- a/go/ql/lib/semmle/go/frameworks/Macaron.qll +++ b/go/ql/lib/semmle/go/frameworks/Macaron.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts relating to the Macaron web framework */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Mux.qll b/go/ql/lib/semmle/go/frameworks/Mux.qll index e9bb5968f70..a4790e3c5cd 100644 --- a/go/ql/lib/semmle/go/frameworks/Mux.qll +++ b/go/ql/lib/semmle/go/frameworks/Mux.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with concepts in the Mux HTTP middleware library. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/NoSQL.qll b/go/ql/lib/semmle/go/frameworks/NoSQL.qll index 2772182f4fc..463a3923496 100644 --- a/go/ql/lib/semmle/go/frameworks/NoSQL.qll +++ b/go/ql/lib/semmle/go/frameworks/NoSQL.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with NoSQL-related concepts such as queries. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Protobuf.qll b/go/ql/lib/semmle/go/frameworks/Protobuf.qll index 62443eb46af..246608159e5 100644 --- a/go/ql/lib/semmle/go/frameworks/Protobuf.qll +++ b/go/ql/lib/semmle/go/frameworks/Protobuf.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions and types in the protobuf packages. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Revel.qll b/go/ql/lib/semmle/go/frameworks/Revel.qll index a1eff5e736e..c6250c2f8a5 100644 --- a/go/ql/lib/semmle/go/frameworks/Revel.qll +++ b/go/ql/lib/semmle/go/frameworks/Revel.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with remote flow sources from the `github.com/revel/revel` package. */ +overlay[local?] +module; import go private import semmle.go.security.OpenUrlRedirectCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/RsCors.qll b/go/ql/lib/semmle/go/frameworks/RsCors.qll index 52b4a7fe6d0..7609b27b58a 100644 --- a/go/ql/lib/semmle/go/frameworks/RsCors.qll +++ b/go/ql/lib/semmle/go/frameworks/RsCors.qll @@ -1,4 +1,6 @@ /** Provides classes for modeling the `github.com/rs/cors` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/SQL.qll b/go/ql/lib/semmle/go/frameworks/SQL.qll index c5cf4989d1a..fad4722ad5c 100644 --- a/go/ql/lib/semmle/go/frameworks/SQL.qll +++ b/go/ql/lib/semmle/go/frameworks/SQL.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with SQL-related concepts such as queries. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Spew.qll b/go/ql/lib/semmle/go/frameworks/Spew.qll index f49a4aa4d89..4c8720868b7 100644 --- a/go/ql/lib/semmle/go/frameworks/Spew.qll +++ b/go/ql/lib/semmle/go/frameworks/Spew.qll @@ -1,6 +1,8 @@ /** * Provides models of commonly used functions in the `github.com/davecgh/go-spew/spew` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Squirrel.qll b/go/ql/lib/semmle/go/frameworks/Squirrel.qll index c7d75003cfe..28168c54107 100644 --- a/go/ql/lib/semmle/go/frameworks/Squirrel.qll +++ b/go/ql/lib/semmle/go/frameworks/Squirrel.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `squirrel` ORM package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Stdlib.qll b/go/ql/lib/semmle/go/frameworks/Stdlib.qll index 3b05627168d..4a8a2e8d0ea 100644 --- a/go/ql/lib/semmle/go/frameworks/Stdlib.qll +++ b/go/ql/lib/semmle/go/frameworks/Stdlib.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the standard libraries. */ +overlay[local?] +module; import go import semmle.go.frameworks.stdlib.ArchiveTar diff --git a/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll b/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll index 8abf2bbd368..d1bbbf41d89 100644 --- a/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll +++ b/go/ql/lib/semmle/go/frameworks/SystemCommandExecutors.qll @@ -2,6 +2,8 @@ * Provides concrete classes for data-flow nodes that execute an * operating system command, for instance by spawning a new process. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Testing.qll b/go/ql/lib/semmle/go/frameworks/Testing.qll index c0246c7df50..c6173ac099a 100644 --- a/go/ql/lib/semmle/go/frameworks/Testing.qll +++ b/go/ql/lib/semmle/go/frameworks/Testing.qll @@ -1,4 +1,6 @@ /** Provides classes for working with tests. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Twirp.qll b/go/ql/lib/semmle/go/frameworks/Twirp.qll index 254949ad772..2fcd44da2ff 100644 --- a/go/ql/lib/semmle/go/frameworks/Twirp.qll +++ b/go/ql/lib/semmle/go/frameworks/Twirp.qll @@ -1,4 +1,6 @@ /** Provides models of commonly used functions and types in the twirp packages. */ +overlay[local?] +module; import go private import semmle.go.security.RequestForgeryCustomizations diff --git a/go/ql/lib/semmle/go/frameworks/WebSocket.qll b/go/ql/lib/semmle/go/frameworks/WebSocket.qll index eb6160214cc..36c6db5c453 100644 --- a/go/ql/lib/semmle/go/frameworks/WebSocket.qll +++ b/go/ql/lib/semmle/go/frameworks/WebSocket.qll @@ -1,4 +1,6 @@ /** Provides classes for working with WebSocket-related APIs. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/XNetHtml.qll b/go/ql/lib/semmle/go/frameworks/XNetHtml.qll index 003c0e8570e..4eec0c9b331 100644 --- a/go/ql/lib/semmle/go/frameworks/XNetHtml.qll +++ b/go/ql/lib/semmle/go/frameworks/XNetHtml.qll @@ -6,6 +6,8 @@ * that were already untrusted. We do not yet model adding a child `Node` to a tree then calling `Render` * yielding an untrustworthy string. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/XPath.qll b/go/ql/lib/semmle/go/frameworks/XPath.qll index 0d8dc5d8176..d052a619c35 100644 --- a/go/ql/lib/semmle/go/frameworks/XPath.qll +++ b/go/ql/lib/semmle/go/frameworks/XPath.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with XPath-related concepts such as XPath expressions. */ +overlay[local?] +module; import go import semmle.go.dataflow.ExternalFlow diff --git a/go/ql/lib/semmle/go/frameworks/Yaml.qll b/go/ql/lib/semmle/go/frameworks/Yaml.qll index 22fc4f8c58c..160e5f18c6b 100644 --- a/go/ql/lib/semmle/go/frameworks/Yaml.qll +++ b/go/ql/lib/semmle/go/frameworks/Yaml.qll @@ -1,6 +1,8 @@ /** * Provides classes for working with the [gopkg.in/yaml](https://pkg.go.dev/gopkg.in/yaml.v3) package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/Zap.qll b/go/ql/lib/semmle/go/frameworks/Zap.qll index 0928d2b0595..b634d8e9795 100644 --- a/go/ql/lib/semmle/go/frameworks/Zap.qll +++ b/go/ql/lib/semmle/go/frameworks/Zap.qll @@ -1,6 +1,8 @@ /** * Provides models of commonly used functions in the `go.uber.org/zap` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll index 24d16f86b66..0798f187647 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `archive/tar` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll index ed4061700dc..273b8ddff2c 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveZip.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `archive/zip` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll index 1ddb7e0889c..e79a5f16a90 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Bufio.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `bufio` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll index 5df4ac972c9..1d63d0dda29 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressFlate.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/flate` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll index 29b731ec927..695c9ea5df5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressGzip.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/gzip` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll index 4d8e2d1de93..319c1d4dd93 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressLzw.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/lzw` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll index be8d7fa69a0..26a2872ae1c 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CompressZlib.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `compress/zlib` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll b/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll index 2bd85457cf8..a370f12c24d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/CryptoTls.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `crypto/tls` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll index f4132688796..1969724b486 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `database/sql` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll index 68d9655b11c..7a860608a90 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingAsn1.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/asn1` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll index 7606cdc16bd..283eeebacb6 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingCsv.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/csv` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll index ada9f167f8d..01db1ec539a 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingGob.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/gob` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll index f38db392bd0..bf6e25ff9f1 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingJson.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/json` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll index cb2383d428a..4ef997c7815 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingPem.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/pem` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll index b36f9007084..b5206754529 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/EncodingXml.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `encoding/xml` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll index 133a69795b8..d20d0c1837e 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `errors` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll index 6adbd542e9b..bc58441ada9 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `fmt` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll index 82e5f13e130..c26d329f625 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Html.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `html` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll b/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll index f61482c35d7..8d343bfa4fe 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/HtmlTemplate.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `html/template` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll index f44ca36ff85..41597e40f02 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Io.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `io` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll b/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll index de7fafc514f..b071e56cbb5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/IoFs.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the 'io/fs' package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll index ca74160bf0d..a5ebca68be5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `log` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll b/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll index ad60672e35e..d8c193d7f3e 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/MimeMultipart.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `mime/multipart` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll b/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll index 0cf54c107a7..64b3d4c1755 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/MimeQuotedprintable.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `mime/quotedprintable` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll index 5b66e523bad..9d3f4abf6bd 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Net.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll index a2aab2517d7..9bafe9721b7 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net/http` package. */ +overlay[local?] +module; import go private import semmle.go.dataflow.internal.DataFlowPrivate diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll index f914626c770..465181bb39f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttpHttputil.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net/http/httputil` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll index 9e19e719ce5..b1d314fdfd1 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetTextproto.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `net/textproto` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll index 72ea4cc6c57..0a633de08c8 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `os` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll index 98215ecd00a..0bdf0b67ff0 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Path.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `path` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll b/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll index 379c141fb2a..43deb8e1e7e 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/PathFilepath.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `path/filepath` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll index 62c09ef0c5e..9a4a74d70d5 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Reflect.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `reflect` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll index 17cc0249908..6a28cd1709f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Regexp.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `regexp` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll index 0f3d2f95cc7..7048ddcbe0d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Strconv.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `strconv` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll index 96b07f5de34..2f514bf28f4 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Strings.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `strings` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll index b93a991e8e3..cb74560809f 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Syscall.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `syscall` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll b/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll index 964afecb4e6..f0e78817c2d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/TextTabwriter.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `text/tabwriter` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll b/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll index c5a67f388f4..31d7f94ec57 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/TextTemplate.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `text/template` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll index d14598e6f79..307686feac6 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll @@ -1,6 +1,8 @@ /** * Provides classes modeling security-relevant aspects of the `unsafe` package. */ +overlay[local?] +module; import go diff --git a/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll b/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll index 1d185440772..3bdc948842c 100644 --- a/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll +++ b/go/ql/lib/utils/test/internal/InlineExpectationsTestImpl.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import go as G private import codeql.util.test.InlineExpectationsTest From f32f85399a748eef9285fc8f21e88a9b8df4900c Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 9 Mar 2026 17:29:17 +0000 Subject: [PATCH 44/72] Mark various files as `overlay[local]` --- go/ql/lib/semmle/go/AST.qll | 2 +- go/ql/lib/semmle/go/Architectures.qll | 2 +- go/ql/lib/semmle/go/Comments.qll | 2 +- go/ql/lib/semmle/go/Decls.qll | 2 +- go/ql/lib/semmle/go/DiagnosticsReporting.qll | 2 +- go/ql/lib/semmle/go/Errors.qll | 2 +- go/ql/lib/semmle/go/Expr.qll | 2 +- go/ql/lib/semmle/go/Files.qll | 2 +- go/ql/lib/semmle/go/GoMod.qll | 2 +- go/ql/lib/semmle/go/HTML.qll | 2 +- go/ql/lib/semmle/go/Locations.qll | 2 +- go/ql/lib/semmle/go/Packages.qll | 2 +- go/ql/lib/semmle/go/PrintAst.qll | 2 +- go/ql/lib/semmle/go/Scopes.qll | 2 +- go/ql/lib/semmle/go/Stmt.qll | 2 +- go/ql/lib/semmle/go/Types.qll | 2 +- go/ql/lib/semmle/go/Util.qll | 2 +- go/ql/lib/semmle/go/VariableWithFields.qll | 2 +- go/ql/lib/semmle/go/concepts/GeneratedFile.qll | 2 +- go/ql/lib/semmle/go/controlflow/BasicBlocks.qll | 2 +- go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll | 2 +- go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll | 2 +- go/ql/lib/semmle/go/controlflow/IR.qll | 2 +- go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll | 2 +- go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll | 2 +- go/ql/lib/semmle/go/dataflow/Properties.qll | 2 +- go/ql/lib/semmle/go/dataflow/SSA.qll | 2 +- go/ql/lib/semmle/go/dataflow/SsaImpl.qll | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/go/ql/lib/semmle/go/AST.qll b/go/ql/lib/semmle/go/AST.qll index bbe93ed345b..a0715f6ca0e 100644 --- a/go/ql/lib/semmle/go/AST.qll +++ b/go/ql/lib/semmle/go/AST.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with AST nodes. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Architectures.qll b/go/ql/lib/semmle/go/Architectures.qll index b90501a5d36..0daef5147b4 100644 --- a/go/ql/lib/semmle/go/Architectures.qll +++ b/go/ql/lib/semmle/go/Architectures.qll @@ -1,5 +1,5 @@ /** Provides classes for working with architectures. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Comments.qll b/go/ql/lib/semmle/go/Comments.qll index f232d4b9378..08a0fabc1ca 100644 --- a/go/ql/lib/semmle/go/Comments.qll +++ b/go/ql/lib/semmle/go/Comments.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with code comments. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Decls.qll b/go/ql/lib/semmle/go/Decls.qll index d3282b59f69..7588ab913be 100644 --- a/go/ql/lib/semmle/go/Decls.qll +++ b/go/ql/lib/semmle/go/Decls.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with declarations. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/DiagnosticsReporting.qll b/go/ql/lib/semmle/go/DiagnosticsReporting.qll index 0cbc98cdd83..c7d0b547a86 100644 --- a/go/ql/lib/semmle/go/DiagnosticsReporting.qll +++ b/go/ql/lib/semmle/go/DiagnosticsReporting.qll @@ -1,5 +1,5 @@ /** Provides classes for working with errors and warnings recorded during extraction. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Errors.qll b/go/ql/lib/semmle/go/Errors.qll index 54e1ea98863..4ea0ed2c015 100644 --- a/go/ql/lib/semmle/go/Errors.qll +++ b/go/ql/lib/semmle/go/Errors.qll @@ -1,5 +1,5 @@ /** Provides classes for working with Go frontend errors recorded during extraction. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index 9e006aed54c..0dcc707b19d 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with expressions. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Files.qll b/go/ql/lib/semmle/go/Files.qll index 8252357bcc2..ab4e2e084ed 100644 --- a/go/ql/lib/semmle/go/Files.qll +++ b/go/ql/lib/semmle/go/Files.qll @@ -1,5 +1,5 @@ /** Provides classes for working with files and folders. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/GoMod.qll b/go/ql/lib/semmle/go/GoMod.qll index e357ae616cf..6a899cd1d60 100644 --- a/go/ql/lib/semmle/go/GoMod.qll +++ b/go/ql/lib/semmle/go/GoMod.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with go.mod files. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/HTML.qll b/go/ql/lib/semmle/go/HTML.qll index 41bb47e0ba5..01f8a069fe9 100644 --- a/go/ql/lib/semmle/go/HTML.qll +++ b/go/ql/lib/semmle/go/HTML.qll @@ -1,5 +1,5 @@ /** Provides classes for working with HTML documents. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Locations.qll b/go/ql/lib/semmle/go/Locations.qll index 03105fbdf25..da55799e6df 100644 --- a/go/ql/lib/semmle/go/Locations.qll +++ b/go/ql/lib/semmle/go/Locations.qll @@ -1,5 +1,5 @@ /** Provides classes for working with locations and program elements that have locations. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Packages.qll b/go/ql/lib/semmle/go/Packages.qll index 8926d0e17f1..f37ddb0507e 100644 --- a/go/ql/lib/semmle/go/Packages.qll +++ b/go/ql/lib/semmle/go/Packages.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with packages. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/PrintAst.qll b/go/ql/lib/semmle/go/PrintAst.qll index c7c9bb5b4b7..6ea5fcc3971 100644 --- a/go/ql/lib/semmle/go/PrintAst.qll +++ b/go/ql/lib/semmle/go/PrintAst.qll @@ -1,7 +1,7 @@ /** * Provides queries to pretty-print a Go AST as a graph. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Scopes.qll b/go/ql/lib/semmle/go/Scopes.qll index 1933c33230c..4e9a13c8ea1 100644 --- a/go/ql/lib/semmle/go/Scopes.qll +++ b/go/ql/lib/semmle/go/Scopes.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with scopes and declared objects. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Stmt.qll b/go/ql/lib/semmle/go/Stmt.qll index befc60e73c6..aa6fe7c24de 100644 --- a/go/ql/lib/semmle/go/Stmt.qll +++ b/go/ql/lib/semmle/go/Stmt.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with statements. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index cd4d5a4120f..574d7568543 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with Go types. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/Util.qll b/go/ql/lib/semmle/go/Util.qll index 4879cb0cbe7..a6fe2a6b2b5 100644 --- a/go/ql/lib/semmle/go/Util.qll +++ b/go/ql/lib/semmle/go/Util.qll @@ -1,5 +1,5 @@ /** This module provides general utility classes and predicates. */ -overlay[local?] +overlay[local] module; /** diff --git a/go/ql/lib/semmle/go/VariableWithFields.qll b/go/ql/lib/semmle/go/VariableWithFields.qll index 920c4313de4..277a7dcc326 100644 --- a/go/ql/lib/semmle/go/VariableWithFields.qll +++ b/go/ql/lib/semmle/go/VariableWithFields.qll @@ -1,5 +1,5 @@ /** Provides the `VariableWithFields` class, for working with variables with a chain of field or element accesses chained to it. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll index 575ede7fdee..683a8be7e05 100644 --- a/go/ql/lib/semmle/go/concepts/GeneratedFile.qll +++ b/go/ql/lib/semmle/go/concepts/GeneratedFile.qll @@ -1,5 +1,5 @@ /** Provides a class for generated files. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll index cc1b0c6292c..dc52abb25ab 100644 --- a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll +++ b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with basic blocks. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll index c7dbe776a8e..77bb94d89f8 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with a CFG-based program representation. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll index 125ad7fdec2..a26ab3adaf5 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraphImpl.qll @@ -3,7 +3,7 @@ * * Provides predicates for building intra-procedural CFGs. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/controlflow/IR.qll b/go/ql/lib/semmle/go/controlflow/IR.qll index e3ed7cadbad..a4c73004108 100644 --- a/go/ql/lib/semmle/go/controlflow/IR.qll +++ b/go/ql/lib/semmle/go/controlflow/IR.qll @@ -9,7 +9,7 @@ * Each instruction is also a control-flow node, but there are control-flow nodes that are not * instructions (synthetic entry and exit nodes, as well as no-op skip nodes). */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll b/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll index 42d17006d64..5f437f81576 100644 --- a/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll +++ b/go/ql/lib/semmle/go/dataflow/FunctionInputsAndOutputs.qll @@ -2,7 +2,7 @@ * Provides QL classes for indicating data flow through a function parameter, return value, * or receiver. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll index 0b08d5a4b8f..88a659f6f82 100644 --- a/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll +++ b/go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll @@ -29,7 +29,7 @@ * common reason for this is that the analysis cannot prove that there * are no side-effects that might cause the computed value to change. */ -overlay[local?] +overlay[local] module; /* diff --git a/go/ql/lib/semmle/go/dataflow/Properties.qll b/go/ql/lib/semmle/go/dataflow/Properties.qll index 6794eee5fcd..573b001a3c3 100644 --- a/go/ql/lib/semmle/go/dataflow/Properties.qll +++ b/go/ql/lib/semmle/go/dataflow/Properties.qll @@ -1,7 +1,7 @@ /** * Provides a class for representing and reasoning about properties of data-flow nodes. */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/dataflow/SSA.qll b/go/ql/lib/semmle/go/dataflow/SSA.qll index c3d759a70fe..46ce4da3935 100644 --- a/go/ql/lib/semmle/go/dataflow/SSA.qll +++ b/go/ql/lib/semmle/go/dataflow/SSA.qll @@ -1,7 +1,7 @@ /** * Provides classes for working with static single assignment form (SSA). */ -overlay[local?] +overlay[local] module; import go diff --git a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll index bf530108d4b..9648335a6dd 100644 --- a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll @@ -3,7 +3,7 @@ * * Provides predicates for constructing an SSA representation for functions. */ -overlay[local?] +overlay[local] module; import go From e9df9147ad4e7c6deb768f37852a6d43d0b5e7bd Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 11 Mar 2026 15:00:50 +0000 Subject: [PATCH 45/72] Add overlay annotations in 4 PrintAst tests --- .../library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql | 1 + .../library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql | 1 + .../library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql | 1 + .../library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql | 1 + 4 files changed, 4 insertions(+) diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql index 4ca15c10ac5..bbcaa16f28b 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { any() } diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql index eaddceacaa3..b04be6edfac 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { func.getName() = "hasNested" } diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql index 83d27b9cf26..60cda4f5045 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { any() } diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql index 382fc397755..5b3501edc6c 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.ql @@ -5,6 +5,7 @@ import go import semmle.go.PrintAst +overlay[local] class Cfg extends PrintAstConfiguration { override predicate shouldPrintFunction(FuncDecl func) { func.getName() = "g" } From 99f4930e24c2c4892dcc9650f97b0ac9705d80d5 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 13 Mar 2026 15:23:39 +0000 Subject: [PATCH 46/72] Explicitly mark DataFlowNodes.qll as overlay[local] --- go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index f5115656675..8fca4bec8c6 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -1,4 +1,4 @@ -overlay[local?] +overlay[local] module; private import go From b8b841cfba8b66008e8538e7202f05fc0c662ffb Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 13 Mar 2026 16:18:50 +0000 Subject: [PATCH 47/72] Add `overlay[loca]` in 4 more tests --- .../semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql | 1 + .../semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql | 1 + .../semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql | 1 + .../semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql | 1 + 4 files changed, 4 insertions(+) diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql index 181c55b29df..2468a57cac0 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.ql @@ -34,6 +34,7 @@ module FlowTest implements TestSig { } } +overlay[local] class MyStep extends DataFlow::FunctionModel, Method { MyStep() { this.hasQualifiedName("github.com/nonexistent/test", "I1", "Step") } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql index e82a6cb4da1..788c8c028d2 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.ql @@ -44,6 +44,7 @@ module FlowTest implements TestSig { } } +overlay[local] class MyStep extends DataFlow::FunctionModel, Method { MyStep() { this.hasQualifiedName("github.com/nonexistent/test", "P1", "Step") } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql index c4124dcd10e..127fb0012a3 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.ql @@ -44,6 +44,7 @@ module FlowTest implements TestSig { } } +overlay[local] class MyStep extends DataFlow::FunctionModel, Method { MyStep() { this.hasQualifiedName("github.com/nonexistent/test", "S1", "Step") } diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql index 78e21d534e0..bbe5618b568 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql +++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql @@ -4,6 +4,7 @@ import ModelValidation import utils.test.InlineFlowTest import DefaultFlowTest +overlay[local] class SummaryModelTest extends DataFlow::FunctionModel { FunctionInput inp; FunctionOutput outp; From f9f1d9eecc057b9c394d7543fd42580d601dbd41 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 13 Mar 2026 11:11:29 +0100 Subject: [PATCH 48/72] Swift: Ignore some DB-CHECK results on Linux --- swift/ql/integration-tests/posix/deduplication/test.py | 2 ++ swift/ql/integration-tests/posix/hello-world/test.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/swift/ql/integration-tests/posix/deduplication/test.py b/swift/ql/integration-tests/posix/deduplication/test.py index d9915ed3770..3e52638fdc0 100644 --- a/swift/ql/integration-tests/posix/deduplication/test.py +++ b/swift/ql/integration-tests/posix/deduplication/test.py @@ -1,6 +1,8 @@ +import pytest import runs_on @runs_on.posix +@pytest.mark.ql_test("DB-CHECK", xfail=runs_on.linux) def test(codeql, swift): codeql.database.create(command="swift build", keep_trap=True) diff --git a/swift/ql/integration-tests/posix/hello-world/test.py b/swift/ql/integration-tests/posix/hello-world/test.py index 2b81f139383..eb0ccd23b46 100644 --- a/swift/ql/integration-tests/posix/hello-world/test.py +++ b/swift/ql/integration-tests/posix/hello-world/test.py @@ -1,9 +1,9 @@ import pytest - import runs_on @runs_on.posix +@pytest.mark.ql_test("DB-CHECK", xfail=runs_on.linux) def test(codeql, swift): codeql.database.create(command="swift build") From a5c8a5b5f865eb196d673fc748e7df50838468f4 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 08:07:45 +0100 Subject: [PATCH 49/72] C#: Remove splitting-awareness for taint steps. --- .../internal/TaintTrackingPrivate.qll | 124 +++++++----------- 1 file changed, 48 insertions(+), 76 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index bb08c8f7e2c..78dc2f98d6b 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -45,82 +45,58 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) ) } -private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration { - LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - isSuccessor = true and - ( - e1 = e2.(ElementAccess).getQualifier() and - scope = e2 - or - e1 = e2.(AddExpr).getAnOperand() and - scope = e2 - or - // A comparison expression where taint can flow from one of the - // operands if the other operand is a constant value. - exists(ComparisonTest ct, Expr other | - ct.getExpr() = e2 and - e1 = ct.getAnArgument() and - other = ct.getAnArgument() and - other.stripCasts().hasValue() and - e1 != other and - scope = e2 - ) - or - e1 = e2.(UnaryLogicalOperation).getAnOperand() and - scope = e2 - or - e1 = e2.(BinaryLogicalOperation).getAnOperand() and - scope = e2 - or - e1 = e2.(InterpolatedStringExpr).getAChild() and - scope = e2 - or - e1 = e2.(InterpolatedStringInsertExpr).getInsert() and - scope = e2 - or - e2 = - any(OperatorCall oc | - oc.getTarget().(ConversionOperator).fromLibrary() and - e1 = oc.getAnArgument() and - scope = e2 - ) - or - e1 = e2.(AwaitExpr).getExpr() and - scope = e2 - or - // Taint flows from the operand of a cast to the cast expression if the cast is to an interpolated string handler. - e2 = - any(CastExpr ce | - e1 = ce.getExpr() and - scope = ce and - ce.getTargetType() - .(Attributable) - .getAnAttribute() - .getType() - .hasFullyQualifiedName("System.Runtime.CompilerServices", - "InterpolatedStringHandlerAttribute") - ) - ) - } -} - -private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) { - exists(OperatorCall oc | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, oc, cfn) | - oc.getTarget() instanceof ImplicitConversionOperator +private predicate localTaintExprStep(Expr e1, Expr e2) { + e1 = e2.(ElementAccess).getQualifier() + or + e1 = e2.(AddExpr).getAnOperand() + or + // A comparison expression where taint can flow from one of the + // operands if the other operand is a constant value. + exists(ComparisonTest ct, Expr other | + ct.getExpr() = e2 and + e1 = ct.getAnArgument() and + other = ct.getAnArgument() and + other.stripCasts().hasValue() and + e1 != other ) + or + e1 = e2.(UnaryLogicalOperation).getAnOperand() + or + e1 = e2.(BinaryLogicalOperation).getAnOperand() + or + e1 = e2.(InterpolatedStringExpr).getAChild() + or + e1 = e2.(InterpolatedStringInsertExpr).getInsert() + or + e2 = + any(OperatorCall oc | + oc.getTarget().(ConversionOperator).fromLibrary() and + e1 = oc.getAnArgument() + ) + or + e1 = e2.(AwaitExpr).getExpr() + or + // Taint flows from the operand of a cast to the cast expression if the cast is to an interpolated string handler. + e2 = + any(CastExpr ce | + e1 = ce.getExpr() and + ce.getTargetType() + .(Attributable) + .getAnAttribute() + .getType() + .hasFullyQualifiedName("System.Runtime.CompilerServices", + "InterpolatedStringHandlerAttribute") + ) } -private ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) { - result = getALastEvalNode(e) +private Expr getALastEvalNode(OperatorCall oc) { + localTaintExprStep(result, oc) and oc.getTarget() instanceof ImplicitConversionOperator } +private Expr getPostUpdateReverseStep(Expr e) { result = getALastEvalNode(e) } + private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo) + localTaintExprStep(nodeFrom.asExpr(), nodeTo.asExpr()) } cached @@ -191,12 +167,8 @@ private module Cached { // Allow reverse update flow for implicit conversion operator calls. // This is needed to support flow out of method call arguments, where an implicit conversion is applied // to a call argument. - nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() = - getPostUpdateReverseStep(nodeFrom - .(PostUpdateNode) - .getPreUpdateNode() - .(DataFlow::ExprNode) - .getControlFlowNode()) + nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = + getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()) ) and model = "" or From 2160910d56ec2ce3dfb17b5e886cc2e7795e6aad Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 08:37:11 +0100 Subject: [PATCH 50/72] C#: Remove splitting-awareness for read steps. --- .../dataflow/internal/DataFlowPrivate.qll | 176 +++++------------- 1 file changed, 46 insertions(+), 130 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 70161a6fc47..8a9a47ab648 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2378,133 +2378,51 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepDelegateCall(node1, c, node2) } -pragma[nomagic] -private predicate isAssignExprLValueDescendant(Expr e) { - e = any(AssignExpr ae).getLValue() - or - exists(Expr parent | - isAssignExprLValueDescendant(parent) and - e = parent.getAChildExpr() - ) -} - -private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration { - ReadStepConfiguration() { this = "ReadStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - isSuccessor = true and - fieldOrPropertyRead(e1, _, e2) and - scope = e2 - or - exactScope = false and - isSuccessor = true and - dynamicPropertyRead(e1, _, e2) and - scope = e2 - or - exactScope = false and - isSuccessor = true and - arrayRead(e1, e2) and - scope = e2 - or - exactScope = false and - e1 = e2.(AwaitExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - exactScope = false and - e2 = e1.(TupleExpr).getAnArgument() and - scope = e1 and - isSuccessor = false - } - - override predicate candidateDef( - Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - exists(ForeachStmt fs | - e = fs.getIterableExpr() and - defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = - fs.getVariableDeclExpr() and - isSuccessor = true - | - scope = fs and - exactScope = true - or - scope = fs.getIterableExpr() and - exactScope = false - or - scope = fs.getVariableDeclExpr() and - exactScope = false - ) - or - scope = - any(AssignExpr ae | - ae = defTo.(AssignableDefinitions::TupleAssignmentDefinition).getAssignment() and - isAssignExprLValueDescendant(e.(TupleExpr)) and - exactScope = false and - isSuccessor = true - ) - or - scope = - any(TupleExpr te | - te.getAnArgument() = defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() and - e = te and - exactScope = false and - isSuccessor = false - ) - } -} - private predicate readContentStep(Node node1, Content c, Node node2) { - exists(ReadStepConfiguration x | - hasNodePath(x, node1, node2) and - arrayRead(node1.asExpr(), node2.asExpr()) and + arrayRead(node1.asExpr(), node2.asExpr()) and + c instanceof ElementContent + or + exists( + ForeachStmt fs, Ssa::ExplicitDefinition def, + AssignableDefinitions::LocalVariableDefinition defTo + | + node1.asExpr() = fs.getIterableExpr() and + defTo.getDeclaration() = fs.getVariableDeclExpr() and + def.getADefinition() = defTo and + node2.(SsaDefinitionNode).getDefinition() = def and c instanceof ElementContent + ) + or + node1 = + any(InstanceParameterAccessPreNode n | + n.getUnderlyingControlFlowNode() = node2.(ExprNode).getControlFlowNode() and + n.getParameter() = c.(PrimaryConstructorParameterContent).getParameter() + ) and + node2.asExpr() instanceof ParameterRead + or + // node1 = (..., node2, ...) + // node1.ItemX flows to node2 + exists(TupleExpr te, int i, Expr item | + te = node1.asExpr() and + not te.isConstruction() and + c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and + // node1 = (..., item, ...) + te.getArgument(i) = item + | + // item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...) + node2.asExpr().(TupleExpr) = item or - exists(ForeachStmt fs, Ssa::ExplicitDefinition def | - x.hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(), - def.getControlFlowNode()) and - node2.(SsaDefinitionNode).getDefinition() = def and - c instanceof ElementContent + // item = variable in node1 = (..., variable, ...) + exists(AssignableDefinitions::TupleAssignmentDefinition tad | + node2.(AssignableDefinitionNode).getDefinition() = tad and + tad.getLeaf() = item ) or - node1 = - any(InstanceParameterAccessPreNode n | - n.getUnderlyingControlFlowNode() = node2.(ExprNode).getControlFlowNode() and - n.getParameter() = c.(PrimaryConstructorParameterContent).getParameter() - ) and - node2.asExpr() instanceof ParameterRead - or - // node1 = (..., node2, ...) - // node1.ItemX flows to node2 - exists(TupleExpr te, int i, Expr item | - te = node1.asExpr() and - not te.isConstruction() and - c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and - // node1 = (..., item, ...) - te.getArgument(i) = item - | - // item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...) - node2.asExpr().(TupleExpr) = item and - hasNodePath(x, node1, node2) - or - // item = variable in node1 = (..., variable, ...) - exists(AssignableDefinitions::TupleAssignmentDefinition tad | - node2.(AssignableDefinitionNode).getDefinition() = tad and - tad.getLeaf() = item and - hasNodePath(x, node1, node2) - ) - or - // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) - isPatternExprDescendant(te) and - exists(AssignableDefinitions::LocalVariableDefinition lvd | - node2.(AssignableDefinitionNode).getDefinition() = lvd and - lvd.getDeclaration() = item and - hasNodePath(x, node1, node2) - ) + // item = variable in node1 = (..., variable, ...) in a case/is var (..., ...) + isPatternExprDescendant(te) and + exists(AssignableDefinitions::LocalVariableDefinition lvd | + node2.(AssignableDefinitionNode).getDefinition() = lvd and + lvd.getDeclaration() = item ) ) or @@ -2535,14 +2453,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) { c.isSingleton(cont) ) or - exists(ReadStepConfiguration x | hasNodePath(x, node1, node2) | - fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) - or - dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) - or - node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and - c = getResultContent() - ) + fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) + or + node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and + c = getResultContent() or FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c, node2.(FlowSummaryNode).getSummaryNode()) From bce0a4d2a7e5401ba0267892c8458517ecff2ac7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 08:53:41 +0100 Subject: [PATCH 51/72] C#: Remove splitting-awareness for store steps. --- .../dataflow/internal/DataFlowPrivate.qll | 101 ++++++------------ 1 file changed, 30 insertions(+), 71 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 8a9a47ab648..b9ffba13173 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -834,11 +834,11 @@ private class Argument extends Expr { } /** - * Holds if `e` is an assignment of `src` to field or property `c` of `q`. + * Holds if there is an assignment of `src` to field or property `c` of `q`. * * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, boolean postUpdate) { +private predicate fieldOrPropertyStore(ContentSet c, Expr src, Expr q, boolean postUpdate) { exists(FieldOrProperty f | c = f.getContentSet() and ( @@ -861,25 +861,20 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b f = fa.getTarget() and src = def.getSource() and q = fa.getQualifier() and - e = def.getExpr() and postUpdate = true ) or // `with` expression initializer, `x with { f = src }` - e = - any(WithExpr we | - exists(MemberInitializer mi | - q = we and - mi = we.getInitializer().getAMemberInitializer() and - f = mi.getInitializedMember() and - src = mi.getRValue() and - postUpdate = false - ) - ) + exists(WithExpr we, MemberInitializer mi | + q = we and + mi = we.getInitializer().getAMemberInitializer() and + f = mi.getInitializedMember() and + src = mi.getRValue() and + postUpdate = false + ) or // Object initializer, `new C() { f = src }` exists(MemberInitializer mi | - e = q and mi = q.(ObjectInitializer).getAMemberInitializer() and q.getParent() instanceof ObjectCreation and f = mi.getInitializedMember() and @@ -888,16 +883,13 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b ) or // Tuple element, `(..., src, ...)` `f` is `ItemX` of tuple `q` - e = - any(TupleExpr te | - exists(int i | - e = q and - src = te.getArgument(i) and - te.isConstruction() and - f = q.getType().(TupleType).getElement(i) and - postUpdate = false - ) - ) + exists(TupleExpr te, int i | + te = q and + src = te.getArgument(i) and + te.isConstruction() and + f = q.getType().(TupleType).getElement(i) and + postUpdate = false + ) ) or // A write to a dynamic property @@ -907,7 +899,6 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b c.isDynamicProperty(dp) and src = def.getSource() and q = dma.getQualifier() and - e = def.getExpr() and postUpdate = true ) } @@ -943,22 +934,20 @@ private predicate collectionStore(Expr src, CollectionExpression ce) { } /** - * Holds if `e` is an expression that adds `src` to array `a`. + * Holds if there is an expression that adds `src` to array `a`. * * `postUpdate` indicates whether the store targets a post-update node. */ -private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { +private predicate arrayStore(Expr src, Expr a, boolean postUpdate) { // Direct assignment, `a[i] = src` exists(AssignableDefinition def | a = def.getTargetAccess().(ArrayWrite).getQualifier() and src = def.getSource() and - e = def.getExpr() and postUpdate = true ) or // Array initializer, `new [] { src }` src = a.(ArrayInitializer).getAnElement() and - e = a and postUpdate = false or // Member initializer, `new C { Array = { [i] = src } }` @@ -966,7 +955,6 @@ private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) { mi = a.(ObjectInitializer).getAMemberInitializer() and mi.getLValue() instanceof ArrayAccess and mi.getRValue() = src and - e = a and postUpdate = false ) } @@ -1149,9 +1137,9 @@ private module Cached { exprMayHavePostUpdateNode(cfn.getExpr()) or exists(Expr e | e = cfn.getExpr() | - fieldOrPropertyStore(_, _, _, e, true) + fieldOrPropertyStore(_, _, e, true) or - arrayStore(_, _, e, true) + arrayStore(_, e, true) or // needed for reverse stores; e.g. `x.f1.f2 = y` induces // a store step of `f1` into `x` @@ -2236,30 +2224,6 @@ predicate jumpStep(Node pred, Node succ) { succ = pred.(LocalFunctionCreationNode).getAnAccess(false) } -private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration { - StoreStepConfiguration() { this = "StoreStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - fieldOrPropertyStore(scope, _, e1, e2, isSuccessor.booleanNot()) - or - exactScope = false and - arrayStore(scope, e1, e2, isSuccessor.booleanNot()) - or - exactScope = false and - isSuccessor = true and - collectionStore(e1, e2) and - scope = e2 - or - exactScope = false and - isSuccessor = true and - isParamsArg(e2, e1, _) and - scope = e2 - } -} - pragma[nomagic] private ContentSet getResultContent() { result.isProperty(any(SystemThreadingTasksTaskTClass c_).getResultProperty()) @@ -2282,21 +2246,17 @@ private predicate recordParameter(RecordType t, Parameter p, string name) { } private predicate storeContentStep(Node node1, Content c, Node node2) { - exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | - hasNodePath(x, node1, node) and + exists(ExprNode node, boolean postUpdate | if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 | - arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent + arrayStore(node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent ) or - exists(StoreStepConfiguration x | hasNodePath(x, node1, node2) | - collectionStore(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent - ) + collectionStore(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent or - exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn | - x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and - node2 = TParamsArgumentNode(callCfn) and - isParamsArg(_, arg, _) and + exists(Call call | + node2 = TParamsArgumentNode(call.getControlFlowNode()) and + isParamsArg(call, node1.asExpr(), _) and c instanceof ElementContent ) or @@ -2352,11 +2312,10 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { c.isSingleton(cont) ) or - exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate | - hasNodePath(x, node1, node) and + exists(ExprNode node, boolean postUpdate | if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2 | - fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate) + fieldOrPropertyStore(c, node1.asExpr(), node.getExpr(), postUpdate) ) or exists(Expr e | @@ -2492,9 +2451,9 @@ predicate clearsContent(Node n, ContentSet c) { c.isSingleton(cont) ) or - fieldOrPropertyStore(_, c, _, n.asExpr(), true) + fieldOrPropertyStore(c, _, n.asExpr(), true) or - fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false) + fieldOrPropertyStore(c, _, n.(ObjectInitializerNode).getInitializer(), false) or FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c) or From 1e8de0511b1d6adc69a2bddf0b073cb67ea9a9ff Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 13:00:43 +0100 Subject: [PATCH 52/72] C#: Remove splitting-awareness in lambda flow. --- .../dataflow/internal/DataFlowPrivate.qll | 49 ++++++------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index b9ffba13173..13075418232 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1154,7 +1154,7 @@ private module Cached { ) ) or - lambdaCallExpr(_, cfn) + lambdaCallExpr(_, _, cfn) } or TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) { sn.getSummarizedCallable() instanceof CallableUsedInSource @@ -1588,7 +1588,7 @@ private module ArgumentNodes { class DelegateSelfArgumentNode extends ArgumentNodeImpl, ExprNode { private DataFlowCall call_; - DelegateSelfArgumentNode() { lambdaCallExpr(call_, this.getControlFlowNode()) } + DelegateSelfArgumentNode() { lambdaCallExpr(call_, this.getExpr(), _) } override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { call = call_ and @@ -2855,45 +2855,26 @@ private predicate isLocalFunctionCallReceiver( f = receiver.getTarget().getUnboundDeclaration() } -private class LambdaConfiguration extends ControlFlowReachabilityConfiguration { - LambdaConfiguration() { this = "LambdaConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - e1 = e2.(DelegateLikeCall).getExpr() and - exactScope = false and - scope = e2 and - isSuccessor = true - or - e1 = e2.(DelegateCreation).getArgument() and - exactScope = false and - scope = e2 and - isSuccessor = true - or - isLocalFunctionCallReceiver(e2, e1, _) and - exactScope = false and - scope = e2 and - isSuccessor = true - } -} - -private predicate lambdaCallExpr(DataFlowCall call, ControlFlow::Node receiver) { - exists(LambdaConfiguration x, DelegateLikeCall dc | - x.hasExprPath(dc.getExpr(), receiver, dc, call.getControlFlowNode()) +private predicate lambdaCallExpr(DataFlowCall call, Expr receiver, ControlFlow::Node receiverCfn) { + exists(DelegateLikeCall dc | + call.(ExplicitDelegateLikeDataFlowCall).getCall() = dc and + receiver = dc.getExpr() and + receiverCfn = receiver.getControlFlowNode() ) or // In local function calls, `F()`, we use the local function access `F` // to represent the receiver. Only needed for flow through captured variables. - exists(LambdaConfiguration x, LocalFunctionCall fc | - x.hasExprPath(fc.getAChild(), receiver, fc, call.getControlFlowNode()) + exists(LocalFunctionCall fc | + receiver = fc.getAChild() and + receiverCfn = receiver.getControlFlowNode() and + fc.getControlFlowNode() = call.getControlFlowNode() ) } /** Holds if `call` is a lambda call where `receiver` is the lambda expression. */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { ( - lambdaCallExpr(call, receiver.(ExprNode).getControlFlowNode()) and + lambdaCallExpr(call, receiver.asExpr(), _) and // local function calls can be resolved directly without a flow analysis not call.getControlFlowNode().getAstNode() instanceof LocalFunctionCall or @@ -2903,9 +2884,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { } private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) { - exists(LambdaConfiguration x, DelegateCreation dc | - x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc, - nodeTo.(ExprNode).getControlFlowNode()) + exists(DelegateCreation dc | + dc.getArgument() = nodeFrom.asExpr() and + dc = nodeTo.asExpr() ) } From 659d8e7c9012942986a68cc42d48885fbe5924c1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 13:22:16 +0100 Subject: [PATCH 53/72] C#: Remove splitting-awareness in argumentOf. --- .../dataflow/internal/DataFlowPrivate.qll | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 13075418232..2237f3e5954 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1551,35 +1551,15 @@ abstract private class ArgumentNodeImpl extends Node { } private module ArgumentNodes { - private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration { - ArgumentConfiguration() { this = "ArgumentConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - e1.(Argument).isArgumentOf(e2, _) and - exactScope = false and - isSuccessor = true and - if e2 instanceof PropertyWrite - then - exists(AssignableDefinition def | - def.getTargetAccess() = e2 and - scope = def.getExpr() - ) - else scope = e2 - } - } - /** A data-flow node that represents an explicit call argument. */ class ExplicitArgumentNode extends ArgumentNodeImpl { ExplicitArgumentNode() { this.asExpr() instanceof Argument } override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { - exists(ArgumentConfiguration x, Expr c, Argument arg | + exists(Expr c, Argument arg | arg = this.asExpr() and c = call.getExpr() and - arg.isArgumentOf(c, pos) and - x.hasExprPath(_, this.getControlFlowNode(), _, call.getControlFlowNode()) + arg.isArgumentOf(c, pos) ) } } From c076992b83affe0fd18e9f42b6f3576178a47479 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 13:31:53 +0100 Subject: [PATCH 54/72] C#: Remove splitting-awareness in ObjectInitializerNode. --- .../dataflow/internal/DataFlowPrivate.qll | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 2237f3e5954..232b765c68a 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1825,27 +1825,6 @@ private module OutNodes { } } - class ObjectOrCollectionInitializerConfiguration extends ControlFlowReachabilityConfiguration { - ObjectOrCollectionInitializerConfiguration() { - this = "ObjectOrCollectionInitializerConfiguration" - } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - scope = e1 and - isSuccessor = true and - exists(ObjectOrCollectionInitializer init | init = e1.(ObjectCreation).getInitializer() | - // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` - e2 = init.(CollectionInitializer).getAnElementInitializer() - or - // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` - e2 = init.(ObjectInitializer).getAMemberInitializer().getLValue() - ) - } - } - /** * A data-flow node that reads a value returned by a callable using an * `out` or `ref` parameter. @@ -2672,8 +2651,13 @@ module PostUpdateNodes { override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { pos.isQualifier() and - any(ObjectOrCollectionInitializerConfiguration x) - .hasExprPath(_, cfn, _, call.getControlFlowNode()) + exists(ObjectOrCollectionInitializer init | init = oc.getInitializer() | + // E.g. `new Dictionary{ {0, "a"}, {1, "b"} }` + call.getExpr() = init.(CollectionInitializer).getAnElementInitializer() + or + // E.g. `new Dictionary() { [0] = "a", [1] = "b" }` + call.getExpr() = init.(ObjectInitializer).getAMemberInitializer().getLValue() + ) } override DataFlowCallable getEnclosingCallableImpl() { From 7124cd4e6edc1bfff46ca502090625a163d8c47d Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 13:59:22 +0100 Subject: [PATCH 55/72] C#: Remove splitting-awareness for source-to-def steps. --- .../dataflow/internal/DataFlowPrivate.qll | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 232b765c68a..830aab3eef5 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -286,7 +286,7 @@ module VariableCapture { e1 = LocalFlow::getALastEvalNode(e2) or exists(Ssa::Definition def, AssignableDefinition adef | - LocalFlow::defAssigns(adef, _, e1) and + LocalFlow::defAssigns(adef, _, _, e1) and def.getAnUltimateDefinition().(Ssa::ExplicitDefinition).getADefinition() = adef and exists(def.getAReadAtNode(e2)) ) @@ -379,7 +379,7 @@ module VariableCapture { this = def.getExpr().getAControlFlowNode() } - ControlFlow::Node getRhs() { LocalFlow::defAssigns(def, this, result) } + ControlFlow::Node getRhs() { LocalFlow::defAssigns(def, this, _, result) } CapturedVariable getVariable() { result = v } } @@ -620,35 +620,22 @@ module LocalFlow { ) ) } - - override predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - // Flow from source to definition - exactScope = false and - def.getSource() = e and - ( - scope = def.getExpr() and - isSuccessor = true - or - scope = def.(AssignableDefinitions::PatternDefinition).getMatch().(IsExpr) and - isSuccessor = false - or - exists(Switch s | - s.getACase() = def.(AssignableDefinitions::PatternDefinition).getMatch() and - isSuccessor = true - | - scope = s.getExpr() - or - scope = s.getACase() - ) - ) - } } - predicate defAssigns(AssignableDefinition def, ControlFlow::Node cfnDef, ControlFlow::Node value) { - any(LocalExprStepConfiguration x).hasDefPath(_, value, def, cfnDef) + predicate defAssigns( + AssignableDefinition def, ControlFlow::Node cfnDef, Expr value, ControlFlow::Node valueCfn + ) { + def.getSource() = value and + valueCfn = value.getControlFlowNode() and + cfnDef = def.getExpr().getAControlFlowNode() + } + + private predicate defAssigns(ExprNode value, AssignableDefinitionNode defNode) { + exists(ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef | + defAssigns(def, cfnDef, value.getExpr(), _) and + cfn = value.getControlFlowNode() and + defNode = TAssignableDefinitionNode(def, cfnDef) + ) } /** @@ -661,6 +648,8 @@ module LocalFlow { predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { hasNodePath(any(LocalExprStepConfiguration x), nodeFrom, nodeTo) or + defAssigns(nodeFrom, nodeTo) + or ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) and nodeFrom != nodeTo or @@ -729,9 +718,10 @@ module LocalFlow { e instanceof ThisAccess or e instanceof BaseAccess ) or + defAssigns(node1, node2) + or hasNodePath(any(LocalExprStepConfiguration x), node1, node2) and ( - node2 instanceof AssignableDefinitionNode or node2.asExpr() instanceof Cast or node2.asExpr() instanceof AssignExpr ) From 4c77e0f3150b906e00f559ec875f82a97a0a5e74 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 14:16:10 +0100 Subject: [PATCH 56/72] C#: Remove splitting-awareness for local expression steps. --- .../DataFlowConsistency.ql | 4 +- .../dataflow/internal/DataFlowPrivate.qll | 177 +++++++----------- 2 files changed, 67 insertions(+), 114 deletions(-) diff --git a/csharp/ql/consistency-queries/DataFlowConsistency.ql b/csharp/ql/consistency-queries/DataFlowConsistency.ql index 638bace3892..03e0f3f1b74 100644 --- a/csharp/ql/consistency-queries/DataFlowConsistency.ql +++ b/csharp/ql/consistency-queries/DataFlowConsistency.ql @@ -35,9 +35,7 @@ private module Input implements InputSig { or n.asExpr().(ObjectCreation).hasInitializer() or - exists( - n.(PostUpdateNode).getPreUpdateNode().asExprAtNode(LocalFlow::getPostUpdateReverseStep(_)) - ) + n.(PostUpdateNode).getPreUpdateNode().asExpr() = LocalFlow::getPostUpdateReverseStep(_) } predicate argHasPostUpdateExclude(ArgumentNode n) { diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 830aab3eef5..073a74e7890 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -283,7 +283,7 @@ module VariableCapture { private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks private predicate closureFlowStep(ControlFlow::Nodes::ExprNode e1, ControlFlow::Nodes::ExprNode e2) { - e1 = LocalFlow::getALastEvalNode(e2) + e1.getExpr() = LocalFlow::getALastEvalNode(e2.getExpr()) or exists(Ssa::Definition def, AssignableDefinition adef | LocalFlow::defAssigns(adef, _, _, e1) and @@ -528,98 +528,58 @@ module SsaFlow { /** Provides predicates related to local data flow. */ module LocalFlow { - class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration { - LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - exactScope = false and - ( - e1 = e2.(ParenthesizedExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(NullCoalescingExpr).getAnOperand() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(SuppressNullableWarningExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e2 = - any(ConditionalExpr ce | - e1 = ce.getThen() or - e1 = ce.getElse() - ) and - scope = e2 and - isSuccessor = true - or - e1 = e2.(Cast).getExpr() and - scope = e2 and - isSuccessor = true - or - // An `=` expression, where the result of the expression is used - e2 = - any(AssignExpr ae | - ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and - e1 = ae.getRValue() - ) and - scope = e2 and - isSuccessor = true - or - e1 = e2.(ObjectCreation).getInitializer() and - scope = e2 and - isSuccessor = false - or - e1 = e2.(ArrayCreation).getInitializer() and - scope = e2 and - isSuccessor = false - or - e1 = e2.(SwitchExpr).getACase().getBody() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(CheckedExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(UncheckedExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - e1 = e2.(CollectionExpression).getAnElement() and - e1 instanceof SpreadElementExpr and - scope = e2 and - isSuccessor = true - or - e1 = e2.(SpreadElementExpr).getExpr() and - scope = e2 and - isSuccessor = true - or - exists(WithExpr we | - scope = we and - isSuccessor = true - | - e1 = we.getExpr() and - e2 = we.getInitializer() - or - e1 = we.getInitializer() and - e2 = we - ) - or - scope = any(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1) and - isSuccessor = false - or - isSuccessor = true and - exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() | - cfe.(IsExpr).getExpr() = e1 and scope = cfe - or - exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1 and scope = sw) - ) + predicate localExprStep(Expr e1, Expr e2) { + e1 = e2.(ParenthesizedExpr).getExpr() + or + e1 = e2.(NullCoalescingExpr).getAnOperand() + or + e1 = e2.(SuppressNullableWarningExpr).getExpr() + or + e2 = + any(ConditionalExpr ce | + e1 = ce.getThen() or + e1 = ce.getElse() ) - } + or + e1 = e2.(Cast).getExpr() + or + // An `=` expression, where the result of the expression is used + e2 = + any(AssignExpr ae | + ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and + e1 = ae.getRValue() + ) + or + e1 = e2.(ObjectCreation).getInitializer() + or + e1 = e2.(ArrayCreation).getInitializer() + or + e1 = e2.(SwitchExpr).getACase().getBody() + or + e1 = e2.(CheckedExpr).getExpr() + or + e1 = e2.(UncheckedExpr).getExpr() + or + e1 = e2.(CollectionExpression).getAnElement() and + e1 instanceof SpreadElementExpr + or + e1 = e2.(SpreadElementExpr).getExpr() + or + exists(WithExpr we | + e1 = we.getExpr() and + e2 = we.getInitializer() + or + e1 = we.getInitializer() and + e2 = we + ) + or + exists(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1) + or + exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() | + cfe.(IsExpr).getExpr() = e1 + or + exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1) + ) } predicate defAssigns( @@ -646,7 +606,7 @@ module LocalFlow { } predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { - hasNodePath(any(LocalExprStepConfiguration x), nodeFrom, nodeTo) + localExprStep(nodeFrom.asExpr(), nodeTo.asExpr()) or defAssigns(nodeFrom, nodeTo) or @@ -674,11 +634,12 @@ module LocalFlow { } /** - * Gets a node that may execute last in `n`, and which, when it executes last, - * will be the value of `n`. + * Gets a node that may execute last in `e`, and which, when it executes last, + * will be the value of `e`. */ - ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) { - exists(Expr e | any(LocalExprStepConfiguration x).hasExprPath(_, result, e, cfn) | + Expr getALastEvalNode(Expr e) { + localExprStep(result, e) and + ( e instanceof ConditionalExpr or e instanceof Cast or e instanceof NullCoalescingExpr or @@ -702,9 +663,7 @@ module LocalFlow { * we add a reverse flow step from `[post] b ? x : y` to `[post] x` and to * `[post] y`, in order for the side-effect of `m` to reach both `x` and `y`. */ - ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) { - result = getALastEvalNode(e) - } + Expr getPostUpdateReverseStep(Expr e) { result = getALastEvalNode(e) } /** * Holds if the value of `node2` is given by `node1`. @@ -720,7 +679,7 @@ module LocalFlow { or defAssigns(node1, node2) or - hasNodePath(any(LocalExprStepConfiguration x), node1, node2) and + localExprStep(node1.asExpr(), node2.asExpr()) and ( node2.asExpr() instanceof Cast or node2.asExpr() instanceof AssignExpr @@ -765,12 +724,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) { or nodeTo = nodeFrom.(LocalFunctionCreationNode).getAnAccess(true) or - nodeTo.(PostUpdateNode).getPreUpdateNode().(ExprNode).getControlFlowNode() = - LocalFlow::getPostUpdateReverseStep(nodeFrom - .(PostUpdateNode) - .getPreUpdateNode() - .(ExprNode) - .getControlFlowNode()) + nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = + LocalFlow::getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()) ) and model = "" or @@ -1119,10 +1074,10 @@ private module Cached { ( cfn.getExpr() instanceof Argument or - cfn = - LocalFlow::getPostUpdateReverseStep(any(ControlFlow::Nodes::ExprNode e | - exists(any(SourcePostUpdateNode p).getPreUpdateNode().asExprAtNode(e)) - )) + cfn.getExpr() = + LocalFlow::getPostUpdateReverseStep(any(SourcePostUpdateNode p) + .getPreUpdateNode() + .asExpr()) ) and exprMayHavePostUpdateNode(cfn.getExpr()) or From e7edf15031b50cdca98ebf0c83e537084c083f8e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Mar 2026 14:21:21 +0100 Subject: [PATCH 57/72] C#: Clean up. --- config/identical-files.json | 4 - .../internal/ControlFlowReachability.qll | 246 ------------------ .../dataflow/internal/DataFlowPrivate.qll | 19 -- .../internal/TaintTrackingPrivate.qll | 1 - 4 files changed, 270 deletions(-) delete mode 100644 csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll diff --git a/config/identical-files.json b/config/identical-files.json index bdaf567ae17..8a5c00a49f8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -172,10 +172,6 @@ "cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll", "cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll" ], - "C# ControlFlowReachability": [ - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll" - ], "C++ ExternalAPIs": [ "cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll", "cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll" diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll deleted file mode 100644 index 706893c64ea..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll +++ /dev/null @@ -1,246 +0,0 @@ -import csharp - -private class ControlFlowScope extends ControlFlowElement { - private boolean exactScope; - - ControlFlowScope() { - exists(ControlFlowReachabilityConfiguration c | - c.candidate(_, _, this, exactScope, _) or - c.candidateDef(_, _, this, exactScope, _) - ) - } - - predicate isExact() { exactScope = true } - - predicate isNonExact() { exactScope = false } -} - -private newtype TControlFlowElementOrBasicBlock = - TControlFlowElement(ControlFlowElement cfe) or - TBasicBlock(ControlFlow::BasicBlock bb) - -class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock { - ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) } - - ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) } - - string toString() { - result = this.asControlFlowElement().toString() - or - result = this.asBasicBlock().toString() - } - - Location getLocation() { - result = this.asControlFlowElement().getLocation() - or - result = this.asBasicBlock().getLocation() - } -} - -private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock } - -private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) { - c.asControlFlowElement().(ControlFlowScope).isNonExact() -} - -private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) { - pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement() - or - pred.asControlFlowElement() = succ.asControlFlowElement().getAChild() -} - -private predicate basicBlockInNonExactScope( - ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope -) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope) - -pragma[noinline] -private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) { - basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and - exactScope = false - or - scope.isExact() and - result.getANode().getAstNode() = scope and - exactScope = true -} - -/** - * A helper class for determining control-flow reachability for pairs of - * elements. - * - * This is useful when defining for example expression-based data-flow steps in - * the presence of control-flow splitting, where a data-flow step should make - * sure to stay in the same split. - * - * For example, in - * - * ```csharp - * if (b) - * .... - * var x = "foo"; - * if (b) - * .... - * ``` - * - * there should only be steps from `[b = true] "foo"` to `[b = true] SSA def(x)` - * and `[b = false] "foo"` to `[b = false] SSA def(x)`, and for example not from - * `[b = true] "foo"` to `[b = false] SSA def(x)` - */ -abstract class ControlFlowReachabilityConfiguration extends string { - bindingset[this] - ControlFlowReachabilityConfiguration() { any() } - - /** - * Holds if `e1` and `e2` are expressions for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - none() - } - - /** - * Holds if `e` and `def` are elements for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - none() - } - - pragma[nomagic] - private predicate reachesBasicBlockExprBase( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i, - ControlFlow::BasicBlock bb - ) { - this.candidate(e1, e2, _, _, isSuccessor) and - cfn1 = e1.getAControlFlowNode() and - bb.getNode(i) = cfn1 - } - - pragma[nomagic] - private predicate reachesBasicBlockExprRec( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockExpr( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidate(e1, e2, scope, exactScope, isSuccessor) and - this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionBase( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - int i, ControlFlow::BasicBlock bb - ) { - this.candidateDef(e, def, _, _, isSuccessor) and - cfn = e.getAControlFlowNode() and - bb.getNode(i) = cfn - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionRec( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinition( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidateDef(e, def, scope, exactScope, isSuccessor) and - this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - /** - * Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a - * control-flow node for `e1` and `cfn2` is a control-flow node for `e2`. - */ - pragma[nomagic] - predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and - cfn2 = bb.getNode(j) and - cfn2 = e2.getAControlFlowNode() - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and - cfn2 = bb.getANode() and - cfn2 = e2.getAControlFlowNode() - ) - } - - /** - * Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a - * control-flow node for `e` and `cfnDef` is a control-flow node for `def`. - */ - pragma[nomagic] - predicate hasDefPath( - Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef - ) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and - cfnDef = bb.getNode(j) and - def.getExpr().getAControlFlowNode() = cfnDef - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and - def.getExpr().getAControlFlowNode() = cfnDef and - cfnDef = bb.getANode() - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 073a74e7890..03164960d41 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2,7 +2,6 @@ private import csharp private import DataFlowPublic private import DataFlowDispatch private import DataFlowImplCommon -private import ControlFlowReachability private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary private import semmle.code.csharp.dataflow.internal.ExternalFlow @@ -259,24 +258,6 @@ private module ThisFlow { } } -/** - * Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an - * expression node or an SSA definition node. - */ -pragma[nomagic] -predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, Node n2) { - exists(ControlFlow::Node cfn1, ControlFlow::Node cfn2 | conf.hasExprPath(_, cfn1, _, cfn2) | - cfn1 = n1.getControlFlowNode() and - cfn2 = n2.(ExprNode).getControlFlowNode() - ) - or - exists(ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef | - conf.hasDefPath(_, cfn, def, cfnDef) and - cfn = n1.getControlFlowNode() and - n2 = TAssignableDefinitionNode(def, cfnDef) - ) -} - /** Provides logic related to captured variables. */ module VariableCapture { private import codeql.dataflow.VariableCapture as Shared diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll index 78dc2f98d6b..99a50b36873 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll @@ -4,7 +4,6 @@ private import FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.Caching private import semmle.code.csharp.dataflow.internal.DataFlowDispatch private import semmle.code.csharp.dataflow.internal.DataFlowPrivate -private import semmle.code.csharp.dataflow.internal.ControlFlowReachability private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.commons.ComparisonTest // import `TaintedMember` definitions from other files to avoid potential reevaluation From db0a3e38e27770f64d72341804cdc377220d531c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 16 Mar 2026 09:09:54 +0100 Subject: [PATCH 58/72] C#: Accept a few irrelevant taint steps. --- csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index b2094817cfb..90ef19f62fe 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -26,6 +26,7 @@ | CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:16:31:20 | ... > ... | | CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:24:31:24 | access to parameter i | | CSharp7.cs:31:24:31:24 | access to parameter i | CSharp7.cs:31:16:31:59 | ... ? ... : ... | +| CSharp7.cs:31:28:31:59 | throw ... | CSharp7.cs:31:16:31:59 | ... ? ... : ... | | CSharp7.cs:35:7:35:18 | this | CSharp7.cs:35:7:35:18 | this access | | CSharp7.cs:39:9:39:9 | access to parameter x | CSharp7.cs:39:9:39:21 | SSA def(x) | | CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:9 | access to parameter x | @@ -253,6 +254,7 @@ | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) | | CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o | | CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... | +| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... | | CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... | | CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... | | CSharp7.cs:233:18:233:23 | Int32 i1 | CSharp7.cs:233:18:233:23 | SSA def(i1) | @@ -338,6 +340,8 @@ | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y | | CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:49:297:49 | access to local variable x | | CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | +| CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | +| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... | | CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... | | CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:297:40:297:44 | SSA def(y) | | CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y | From a929c0bf24e76c15759f096b09dea4c7056d5c4a Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 16 Mar 2026 09:05:00 +0100 Subject: [PATCH 59/72] C#: Remove splitting-awareness from Range Analysis. --- .../rangeanalysis/ControlFlowReachability.qll | 246 ------------------ .../internal/rangeanalysis/RangeUtils.qll | 18 +- 2 files changed, 3 insertions(+), 261 deletions(-) delete mode 100644 csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll deleted file mode 100644 index 706893c64ea..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll +++ /dev/null @@ -1,246 +0,0 @@ -import csharp - -private class ControlFlowScope extends ControlFlowElement { - private boolean exactScope; - - ControlFlowScope() { - exists(ControlFlowReachabilityConfiguration c | - c.candidate(_, _, this, exactScope, _) or - c.candidateDef(_, _, this, exactScope, _) - ) - } - - predicate isExact() { exactScope = true } - - predicate isNonExact() { exactScope = false } -} - -private newtype TControlFlowElementOrBasicBlock = - TControlFlowElement(ControlFlowElement cfe) or - TBasicBlock(ControlFlow::BasicBlock bb) - -class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock { - ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) } - - ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) } - - string toString() { - result = this.asControlFlowElement().toString() - or - result = this.asBasicBlock().toString() - } - - Location getLocation() { - result = this.asControlFlowElement().getLocation() - or - result = this.asBasicBlock().getLocation() - } -} - -private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock } - -private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) { - c.asControlFlowElement().(ControlFlowScope).isNonExact() -} - -private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) { - pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement() - or - pred.asControlFlowElement() = succ.asControlFlowElement().getAChild() -} - -private predicate basicBlockInNonExactScope( - ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope -) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope) - -pragma[noinline] -private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) { - basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and - exactScope = false - or - scope.isExact() and - result.getANode().getAstNode() = scope and - exactScope = true -} - -/** - * A helper class for determining control-flow reachability for pairs of - * elements. - * - * This is useful when defining for example expression-based data-flow steps in - * the presence of control-flow splitting, where a data-flow step should make - * sure to stay in the same split. - * - * For example, in - * - * ```csharp - * if (b) - * .... - * var x = "foo"; - * if (b) - * .... - * ``` - * - * there should only be steps from `[b = true] "foo"` to `[b = true] SSA def(x)` - * and `[b = false] "foo"` to `[b = false] SSA def(x)`, and for example not from - * `[b = true] "foo"` to `[b = false] SSA def(x)` - */ -abstract class ControlFlowReachabilityConfiguration extends string { - bindingset[this] - ControlFlowReachabilityConfiguration() { any() } - - /** - * Holds if `e1` and `e2` are expressions for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - none() - } - - /** - * Holds if `e` and `def` are elements for which we want to find a - * control-flow path that follows control flow successors (resp. - * predecessors, as specified by `isSuccessor`) inside the syntactic scope - * `scope`. The Boolean `exactScope` indicates whether a transitive child - * of `scope` is allowed (`exactScope = false`). - */ - predicate candidateDef( - Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, - boolean isSuccessor - ) { - none() - } - - pragma[nomagic] - private predicate reachesBasicBlockExprBase( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i, - ControlFlow::BasicBlock bb - ) { - this.candidate(e1, e2, _, _, isSuccessor) and - cfn1 = e1.getAControlFlowNode() and - bb.getNode(i) = cfn1 - } - - pragma[nomagic] - private predicate reachesBasicBlockExprRec( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockExpr( - Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidate(e1, e2, scope, exactScope, isSuccessor) and - this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionBase( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - int i, ControlFlow::BasicBlock bb - ) { - this.candidateDef(e, def, _, _, isSuccessor) and - cfn = e.getAControlFlowNode() and - bb.getNode(i) = cfn - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinitionRec( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - exists(ControlFlow::BasicBlock mid | - this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid) - | - isSuccessor = true and - bb = mid.getASuccessor() - or - isSuccessor = false and - bb = mid.getAPredecessor() - ) - } - - pragma[nomagic] - private predicate reachesBasicBlockDefinition( - Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, - ControlFlow::BasicBlock bb - ) { - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb) - or - exists(ControlFlowElement scope, boolean exactScope | - this.candidateDef(e, def, scope, exactScope, isSuccessor) and - this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and - bb = getABasicBlockInScope(scope, exactScope) - ) - } - - /** - * Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a - * control-flow node for `e1` and `cfn2` is a control-flow node for `e2`. - */ - pragma[nomagic] - predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and - cfn2 = bb.getNode(j) and - cfn2 = e2.getAControlFlowNode() - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and - cfn2 = bb.getANode() and - cfn2 = e2.getAControlFlowNode() - ) - } - - /** - * Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a - * control-flow node for `e` and `cfnDef` is a control-flow node for `def`. - */ - pragma[nomagic] - predicate hasDefPath( - Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef - ) { - exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j | - this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and - cfnDef = bb.getNode(j) and - def.getExpr().getAControlFlowNode() = cfnDef - | - isSuccessor = true and j >= i - or - isSuccessor = false and i >= j - ) - or - exists(ControlFlow::BasicBlock bb | - this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and - def.getExpr().getAControlFlowNode() = cfnDef and - cfnDef = bb.getANode() - ) - } -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll index 71d177a48bb..656bf9aae21 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll @@ -8,26 +8,14 @@ private module Impl { private import ConstantUtils private import SsaReadPositionCommon private import semmle.code.csharp.controlflow.Guards as G - private import ControlFlowReachability private class ExprNode = ControlFlow::Nodes::ExprNode; - private class ExprChildReachability extends ControlFlowReachabilityConfiguration { - ExprChildReachability() { this = "ExprChildReachability" } - - override predicate candidate( - Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor - ) { - e2 = e1.getAChild() and - scope = e1 and - exactScope = false and - isSuccessor in [false, true] - } - } - /** Holds if `parent` having child `child` implies `parentNode` having child `childNode`. */ predicate hasChild(Expr parent, Expr child, ExprNode parentNode, ExprNode childNode) { - any(ExprChildReachability x).hasExprPath(parent, parentNode, child, childNode) + parent.getAChild() = child and + parentNode = parent.getControlFlowNode() and + childNode = child.getControlFlowNode() } /** Holds if SSA definition `def` equals `e + delta`. */ From e70727524aa1d57d34211101d0b9bf9afe65c9c4 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 16 Mar 2026 12:37:00 +0000 Subject: [PATCH 60/72] Python: Rename `prints` tag to `flow` The former was a remnant of copying the setup over from `ql/test/experimental/import-resolution/importflow.ql`. --- .../import-resolution-namespace-relative/pkg/helper.py | 2 +- .../experimental/import-resolution-namespace-relative/test.ql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py index b9407161e08..760b239aa96 100644 --- a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py @@ -1,2 +1,2 @@ def process(value): - sink(value) #$ prints=source + sink(value) #$ flow=source diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/test.ql b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql index f826c02e423..4f5f09a527d 100644 --- a/python/ql/test/experimental/import-resolution-namespace-relative/test.ql +++ b/python/ql/test/experimental/import-resolution-namespace-relative/test.ql @@ -19,12 +19,12 @@ private module TestConfig implements DataFlow::ConfigSig { private module TestFlow = TaintTracking::Global; module FlowTest implements TestSig { - string getARelevantTag() { result = "prints" } + string getARelevantTag() { result = "flow" } predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node sink | TestFlow::flow(_, sink) and - tag = "prints" and + tag = "flow" and location = sink.getLocation() and value = "source" and element = sink.toString() From 92718a98d0c9cf389f60cc7c79f08e90a80112db Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 16 Mar 2026 12:41:09 +0000 Subject: [PATCH 61/72] Python: Add test for package inside namespace package --- .../import-resolution-namespace-relative/pkg/helper.py | 3 +++ .../import-resolution-namespace-relative/pkg/sub/__init__.py | 0 .../import-resolution-namespace-relative/pkg/sub/caller2.py | 5 +++++ 3 files changed, 8 insertions(+) create mode 100644 python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/__init__.py create mode 100644 python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py index 760b239aa96..f75e9957738 100644 --- a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/helper.py @@ -1,2 +1,5 @@ def process(value): sink(value) #$ flow=source + +def process2(value): + sink(value) #$ flow=source diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/__init__.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py new file mode 100644 index 00000000000..3afab28cd42 --- /dev/null +++ b/python/ql/test/experimental/import-resolution-namespace-relative/pkg/sub/caller2.py @@ -0,0 +1,5 @@ +from .. import helper + +def use_multi_level_relative(): + tainted = source() + helper.process2(tainted) From 2f7526d70bfd9498dda4868bb3b0311957bab13c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 16 Mar 2026 16:38:29 +0000 Subject: [PATCH 62/72] C++: Clarify doc comment and make build-mode: nonereferences more consistent. --- cpp/ql/lib/semmle/code/cpp/Function.qll | 4 ++-- .../2026-03-11-integer-multiplication-cast-to-long.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/Function.qll b/cpp/ql/lib/semmle/code/cpp/Function.qll index b5ea5b3cbc7..4ed678f90eb 100644 --- a/cpp/ql/lib/semmle/code/cpp/Function.qll +++ b/cpp/ql/lib/semmle/code/cpp/Function.qll @@ -526,8 +526,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { } /** - * Holds if this function has ambiguous return type (this occurs sometimes in - * Build Mode None). + * Holds if this function has an ambiguous return type, meaning that zero or multiple return + * types for this function are present in the database (this can occur in `build-mode: none`). */ predicate hasAmbiguousReturnType() { count(this.getType()) != 1 diff --git a/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md b/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md index a0efd8a8785..4d4a66c0a22 100644 --- a/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md +++ b/cpp/ql/src/change-notes/2026-03-11-integer-multiplication-cast-to-long.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* Fixed an issue with the "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query causing false positive results in Build Mode Node databases. +* Fixed an issue with the "Multiplication result converted to larger type" (`cpp/integer-multiplication-cast-to-long`) query causing false positive results in `build-mode: none` databases. From 8df4dfb585370d003261f646ead59e3d3f5cea1a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 16 Mar 2026 16:40:27 +0000 Subject: [PATCH 63/72] C++: Autoformat. --- cpp/ql/lib/semmle/code/cpp/Function.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/Function.qll b/cpp/ql/lib/semmle/code/cpp/Function.qll index 4ed678f90eb..8d93ac0f2a3 100644 --- a/cpp/ql/lib/semmle/code/cpp/Function.qll +++ b/cpp/ql/lib/semmle/code/cpp/Function.qll @@ -529,9 +529,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function { * Holds if this function has an ambiguous return type, meaning that zero or multiple return * types for this function are present in the database (this can occur in `build-mode: none`). */ - predicate hasAmbiguousReturnType() { - count(this.getType()) != 1 - } + predicate hasAmbiguousReturnType() { count(this.getType()) != 1 } } pragma[noinline] From 1ac9e5a2a4e40edba2ce3fb07245f5455b03d460 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 17 Mar 2026 09:51:15 +0100 Subject: [PATCH 64/72] Rust: Elaborate QL doc on `FunctionPosition` class --- .../lib/codeql/rust/internal/typeinference/FunctionType.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index 37df796a7be..26627450add 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -15,6 +15,12 @@ private newtype TFunctionPosition = * Either `return` or a positional parameter index, where `self` is translated * to position `0` and subsequent positional parameters at index `i` are * translated to position `i + 1`. + * + * Function-call adjusted positions are needed when resolving calls of the + * form `Foo::f(x_1, ..., x_n)`, where we do not know up front whether `f` is a + * method or a non-method, and hence we need to be able to match `x_1` against + * both a potential `self` parameter and a potential first positional parameter + * (and `x_2, ... x_n` against all subsequent positional parameters). */ class FunctionPosition extends TFunctionPosition { int asPosition() { result = this.asArgumentPosition().asPosition() } From 3aaee9d981233098f1216ea10a7edd51878e5080 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Mar 2026 12:01:05 +0000 Subject: [PATCH 65/72] Change @security-severity for rust/log-injection from 2.6 to 6.1 --- .../2026-03-13-adjust-xss-and-log-injection-severity.md | 1 + rust/ql/src/queries/security/CWE-117/LogInjection.ql | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md b/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md index 7c24d4147a5..8bfc5be1551 100644 --- a/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md +++ b/rust/ql/src/change-notes/2026-03-13-adjust-xss-and-log-injection-severity.md @@ -1,4 +1,5 @@ --- category: queryMetadata --- +* The `@security-severity` metadata of `rust/log-injection` has been increased from 2.6 (low) to 6.1 (medium). * The `@security-severity` metadata of `rust/xss` has been increased from 6.1 (medium) to 7.8 (high). diff --git a/rust/ql/src/queries/security/CWE-117/LogInjection.ql b/rust/ql/src/queries/security/CWE-117/LogInjection.ql index 64d9c47c790..c00ac310ef6 100644 --- a/rust/ql/src/queries/security/CWE-117/LogInjection.ql +++ b/rust/ql/src/queries/security/CWE-117/LogInjection.ql @@ -4,7 +4,7 @@ * insertion of forged log entries by a malicious user. * @kind path-problem * @problem.severity error - * @security-severity 2.6 + * @security-severity 6.1 * @precision medium * @id rust/log-injection * @tags security From 19faf8f30bda96f32d7b2eb286b9c0d74ae75de6 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 17 Mar 2026 13:29:36 +0100 Subject: [PATCH 66/72] C#: Add ObjectInitMethod as enclosing callable for the instance initializers. --- csharp/ql/lib/semmle/code/csharp/Callable.qll | 27 +++++++++++++++ .../semmle/code/csharp/ExprOrStmtParent.qll | 2 ++ .../internal/ControlFlowGraphImpl.qll | 33 ++----------------- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index f8346cfe01e..611b578b859 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -336,6 +336,22 @@ class ExtensionTypeExtensionMethod extends ExtensionMethodImpl { ExtensionTypeExtensionMethod() { this.isInExtension() } } +/** + * A non-static member with an initializer, for example a field `int Field = 0`. + */ +private class InitializedInstanceMember extends Member { + private AssignExpr ae; + + InitializedInstanceMember() { + not this.isStatic() and + expr_parent_top_level(ae, _, this) and + not ae = getExpressionBody(_) + } + + /** Gets the initializer expression. */ + AssignExpr getInitializer() { result = ae } +} + /** * An object initializer method. * @@ -347,6 +363,17 @@ class ExtensionTypeExtensionMethod extends ExtensionMethodImpl { */ class ObjectInitMethod extends Method { ObjectInitMethod() { this.getName() = "" } + + /** + * Holds if this object initializer method performs the initialization + * of a member via assignment `init`. + */ + predicate initializes(AssignExpr init) { + exists(InitializedInstanceMember m | + this.getDeclaringType().getAMember() = m and + init = m.getInitializer() + ) + } } /** diff --git a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll index aa834ef9103..5afacf608a8 100644 --- a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll @@ -214,6 +214,8 @@ private module Cached { parent*(enclosingStart(cfe), c.(Constructor).getInitializer()) or parent*(cfe, c.(Constructor).getObjectInitializerCall()) + or + parent*(cfe, any(AssignExpr init | c.(ObjectInitMethod).initializes(init))) } /** Holds if the enclosing statement of expression `e` is `s`. */ diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll index 1696869e591..0bdf1f795db 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll @@ -10,42 +10,15 @@ private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.commons.Compilation private module Initializers { - /** - * A non-static member with an initializer, for example a field `int Field = 0`. - */ - class InitializedInstanceMember extends Member { - private AssignExpr ae; - - InitializedInstanceMember() { - not this.isStatic() and - expr_parent_top_level(ae, _, this) and - not ae = any(Callable c).getExpressionBody() - } - - /** Gets the initializer expression. */ - AssignExpr getInitializer() { result = ae } - } - - /** - * Holds if `obinit` is an object initializer method that performs the initialization - * of a member via assignment `init`. - */ - predicate obinitInitializes(ObjectInitMethod obinit, AssignExpr init) { - exists(InitializedInstanceMember m | - obinit.getDeclaringType().getAMember() = m and - init = m.getInitializer() - ) - } - /** * Gets the `i`th member initializer expression for object initializer method `obinit` * in compilation `comp`. */ AssignExpr initializedInstanceMemberOrder(ObjectInitMethod obinit, CompilationExt comp, int i) { - obinitInitializes(obinit, result) and + obinit.initializes(result) and result = rank[i + 1](AssignExpr ae0, Location l | - obinitInitializes(obinit, ae0) and + obinit.initializes(ae0) and l = ae0.getLocation() and getCompilation(l.getFile()) = comp | @@ -74,7 +47,7 @@ class CfgScope extends Element, @top_level_exprorstmt_parent { any(Callable c | c.(Constructor).hasInitializer() or - Initializers::obinitInitializes(c, _) + c.(ObjectInitMethod).initializes(_) or c.hasBody() ) From af63e636861038f59cceded11c38b5ffb46c35fa Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 17 Mar 2026 14:12:18 +0100 Subject: [PATCH 67/72] C#: Accept test changes. --- csharp/ql/test/library-tests/dispatch/CallGraph.expected | 1 + .../structuralcomparison/structuralComparison.expected | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/library-tests/dispatch/CallGraph.expected b/csharp/ql/test/library-tests/dispatch/CallGraph.expected index 31e2a99ae24..e7ebca868ba 100644 --- a/csharp/ql/test/library-tests/dispatch/CallGraph.expected +++ b/csharp/ql/test/library-tests/dispatch/CallGraph.expected @@ -24,6 +24,7 @@ | ExactCallable.cs:15:25:15:35 | Run`2 | ExactCallable.cs:172:21:172:33 | MethodWithOut | | ExactCallable.cs:15:25:15:35 | Run`2 | ExactCallable.cs:177:21:177:34 | MethodWithOut2 | | ExactCallable.cs:182:21:182:22 | M1 | ExactCallable.cs:187:21:187:22 | M2 | +| TypeFlow.cs:3:7:3:14 | | TypeFlow.cs:22:20:22:22 | set_Prop | | TypeFlow.cs:5:5:5:12 | TypeFlow | TypeFlow.cs:24:10:24:12 | Run | | TypeFlow.cs:24:10:24:12 | Run | TypeFlow.cs:12:29:12:34 | Method | | TypeFlow.cs:24:10:24:12 | Run | TypeFlow.cs:17:30:17:35 | Method | diff --git a/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected b/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected index 0f131d8c25c..d9b6636469a 100644 --- a/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected +++ b/csharp/ql/test/library-tests/structuralcomparison/structuralComparison.expected @@ -56,11 +56,11 @@ gvn | StructuralComparison.cs:3:14:3:18 | this access | (kind:Expr(12),false,Class) | | StructuralComparison.cs:3:14:3:18 | {...} | (kind:Stmt(1)) | | StructuralComparison.cs:5:26:5:26 | access to field x | (kind:Expr(16),true,x) | -| StructuralComparison.cs:5:26:5:26 | this access | (kind:Expr(12)) | +| StructuralComparison.cs:5:26:5:26 | this access | (kind:Expr(12),false,Class) | | StructuralComparison.cs:5:26:5:30 | ... = ... | ((kind:Expr(16),true,x) :: (0 :: (kind:Expr(63)))) | | StructuralComparison.cs:5:30:5:30 | 0 | 0 | | StructuralComparison.cs:6:26:6:26 | access to field y | (kind:Expr(16),true,y) | -| StructuralComparison.cs:6:26:6:26 | this access | (kind:Expr(12)) | +| StructuralComparison.cs:6:26:6:26 | this access | (kind:Expr(12),false,Class) | | StructuralComparison.cs:6:26:6:30 | ... = ... | ((kind:Expr(16),true,y) :: (1 :: (kind:Expr(63)))) | | StructuralComparison.cs:6:30:6:30 | 1 | 1 | | StructuralComparison.cs:8:24:8:24 | 0 | 0 | From 97670b36743f35e105dba31e04cfbe7d9efe2404 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Mar 2026 16:32:04 +0100 Subject: [PATCH 68/72] Rust: Unify handling of struct and tuple constructors --- .../rust/elements/internal/StructExprImpl.qll | 5 + .../rust/elements/internal/StructImpl.qll | 6 + .../rust/elements/internal/StructPatImpl.qll | 7 + .../rust/elements/internal/VariantImpl.qll | 6 + .../internal/typeinference/TypeInference.qll | 427 ++++++------------ 5 files changed, 154 insertions(+), 297 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll index d7704894c49..897196b78cb 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructExprImpl.qll @@ -50,5 +50,10 @@ module Impl { or result = this.getVariant().getStructField(name) } + + /** Gets the `i`th struct field of the instantiated struct or variant. */ + StructField getNthStructField(int i) { + result = [this.getStruct().getNthStructField(i), this.getVariant().getNthStructField(i)] + } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll index cb4121b7224..23fa1e76d9a 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll @@ -35,6 +35,12 @@ module Impl { /** Gets a record field, if any. */ StructField getAStructField() { result = this.getStructField(_) } + /** Gets the `i`th struct field, if any. */ + pragma[nomagic] + StructField getNthStructField(int i) { + result = this.getFieldList().(StructFieldList).getField(i) + } + /** Gets the `i`th tuple field, if any. */ pragma[nomagic] TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) } diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll index 28afc2a5b0d..e649d2a5778 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructPatImpl.qll @@ -42,6 +42,13 @@ module Impl { ) } + /** Gets the `i`th struct field of the instantiated struct or variant. */ + StructField getNthStructField(int i) { + exists(PathResolution::ItemNode item | item = this.getResolvedPath(_) | + result = [item.(Struct).getNthStructField(i), item.(Variant).getNthStructField(i)] + ) + } + /** Gets the struct pattern for the field `name`. */ pragma[nomagic] StructPatField getPatField(string name) { diff --git a/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll index ed8b93f6c1d..58b061049bd 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll @@ -32,6 +32,12 @@ module Impl { result.getName().getText() = name } + /** Gets the `i`th struct field, if any. */ + pragma[nomagic] + StructField getNthStructField(int i) { + result = this.getFieldList().(StructFieldList).getField(i) + } + /** Gets the `i`th tuple field, if any. */ pragma[nomagic] TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index c194531a078..a4b338d7c69 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -872,188 +872,6 @@ private Type inferTypeEquality(AstNode n, TypePath path) { ) } -/** - * A matching configuration for resolving types of struct expressions - * like `Foo { bar = baz }`. - * - * This also includes nullary struct expressions like `None`. - */ -private module StructExprMatchingInput implements MatchingInputSig { - private newtype TPos = - TFieldPos(string name) { exists(any(Declaration decl).getField(name)) } or - TStructPos() - - class DeclarationPosition extends TPos { - string asFieldPos() { this = TFieldPos(result) } - - predicate isStructPos() { this = TStructPos() } - - string toString() { - result = this.asFieldPos() - or - this.isStructPos() and - result = "(struct)" - } - } - - abstract class Declaration extends AstNode { - final TypeParameter getTypeParameter(TypeParameterPosition ppos) { - typeParamMatchPosition(this.getTypeItem().getGenericParamList().getATypeParam(), result, ppos) - } - - abstract StructField getField(string name); - - abstract TypeItem getTypeItem(); - - Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - // type of a field - exists(TypeMention tp | - tp = this.getField(dpos.asFieldPos()).getTypeRepr() and - result = tp.getTypeAt(path) - ) - or - // type parameter of the struct itself - dpos.isStructPos() and - result = this.getTypeParameter(_) and - path = TypePath::singleton(result) - or - // type of the struct or enum itself - dpos.isStructPos() and - path.isEmpty() and - result = TDataType(this.getTypeItem()) - } - } - - private class StructDecl extends Declaration, Struct { - StructDecl() { this.isStruct() or this.isUnit() } - - override StructField getField(string name) { result = this.getStructField(name) } - - override TypeItem getTypeItem() { result = this } - } - - private class StructVariantDecl extends Declaration, Variant { - StructVariantDecl() { this.isStruct() or this.isUnit() } - - override StructField getField(string name) { result = this.getStructField(name) } - - override TypeItem getTypeItem() { result = this.getEnum() } - } - - class AccessPosition = DeclarationPosition; - - abstract class Access extends AstNode { - pragma[nomagic] - abstract AstNode getNodeAt(AccessPosition apos); - - pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) - } - - pragma[nomagic] - abstract Path getStructPath(); - - pragma[nomagic] - Declaration getTarget() { result = resolvePath(this.getStructPath()) } - - pragma[nomagic] - Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - // Handle constructions that use `Self {...}` syntax - exists(TypeMention tm, TypePath path0 | - tm = this.getStructPath() and - result = tm.getTypeAt(path0) and - path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) - ) - } - - /** - * Holds if the return type of this struct expression at `path` may have to - * be inferred from the context. - */ - pragma[nomagic] - predicate hasUnknownTypeAt(DeclarationPosition pos, TypePath path) { - exists(Declaration d, TypeParameter tp | - d = this.getTarget() and - pos.isStructPos() and - tp = d.getDeclaredType(pos, path) and - not exists(DeclarationPosition fieldPos | - not fieldPos.isStructPos() and - tp = d.getDeclaredType(fieldPos, _) - ) and - // check that no explicit type arguments have been supplied for `tp` - not exists(TypeArgumentPosition tapos | - exists(this.getTypeArgument(tapos, _)) and - TTypeParamTypeParameter(tapos.asTypeParam()) = tp - ) - ) - } - } - - private class StructExprAccess extends Access, StructExpr { - override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - result = super.getTypeArgument(apos, path) - or - exists(TypePath suffix | - suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and - result = CertainTypeInference::inferCertainType(this, suffix) - ) - } - - override AstNode getNodeAt(AccessPosition apos) { - result = this.getFieldExpr(apos.asFieldPos()).getExpr() - or - result = this and - apos.isStructPos() - } - - override Path getStructPath() { result = this.getPath() } - } - - /** - * A potential nullary struct/variant construction such as `None`. - */ - private class PathExprAccess extends Access, PathExpr { - PathExprAccess() { not exists(CallExpr ce | this = ce.getFunction()) } - - override AstNode getNodeAt(AccessPosition apos) { - result = this and - apos.isStructPos() - } - - override Path getStructPath() { result = this.getPath() } - } - - predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos = dpos - } -} - -private module StructExprMatching = Matching; - -pragma[nomagic] -private Type inferStructExprType0( - AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path -) { - exists(StructExprMatchingInput::Access a, StructExprMatchingInput::AccessPosition apos | - n = a.getNodeAt(apos) and - hasReceiver = false and - if apos.isStructPos() then pos.isReturn() else pos.asPosition() = 0 // the actual position doesn't matter, as long as it is positional - | - result = StructExprMatching::inferAccessType(a, apos, path) - or - a.hasUnknownTypeAt(apos, path) and - result = TUnknownType() - ) -} - -/** - * Gets the type of `n` at `path`, where `n` is either a struct expression or - * a field expression of a struct expression. - */ -private predicate inferStructExprType = - ContextTyping::CheckContextTyping::check/2; - pragma[nomagic] private TupleType inferTupleRootType(AstNode n) { // `typeEquality` handles the non-root cases @@ -3083,14 +2901,14 @@ private Type inferFunctionCallTypePreCheck( private predicate inferFunctionCallType = ContextTyping::CheckContextTyping::check/2; -abstract private class TupleLikeConstructor extends Addressable { +abstract private class Constructor extends Addressable { final TypeParameter getTypeParameter(TypeParameterPosition ppos) { typeParamMatchPosition(this.getTypeItem().getGenericParamList().getATypeParam(), result, ppos) } abstract TypeItem getTypeItem(); - abstract TupleField getTupleField(int i); + abstract TypeRepr getParameterTypeRepr(int pos); Type getReturnType(TypePath path) { result = TDataType(this.getTypeItem()) and @@ -3105,65 +2923,59 @@ abstract private class TupleLikeConstructor extends Addressable { or pos.isReturn() and result = this.getReturnType(path) - or - pos.isTypeQualifier() and - result = this.getReturnType(path) } Type getParameterType(int pos, TypePath path) { - result = this.getTupleField(pos).getTypeRepr().(TypeMention).getTypeAt(path) + result = this.getParameterTypeRepr(pos).(TypeMention).getTypeAt(path) } } -private class TupleLikeStruct extends TupleLikeConstructor instanceof Struct { - TupleLikeStruct() { this.isTuple() } - +private class StructConstructor extends Constructor instanceof Struct { override TypeItem getTypeItem() { result = this } - override TupleField getTupleField(int i) { result = Struct.super.getTupleField(i) } + override TypeRepr getParameterTypeRepr(int i) { + result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()] + } } -private class TupleLikeVariant extends TupleLikeConstructor instanceof Variant { - TupleLikeVariant() { this.isTuple() } - +private class VariantConstructor extends Constructor instanceof Variant { override TypeItem getTypeItem() { result = super.getEnum() } - override TupleField getTupleField(int i) { result = Variant.super.getTupleField(i) } + override TypeRepr getParameterTypeRepr(int i) { + result = [super.getTupleField(i).getTypeRepr(), super.getNthStructField(i).getTypeRepr()] + } } /** - * A matching configuration for resolving types of tuple-like variants and tuple - * structs such as `Result::Ok(42)`. + * A matching configuration for resolving types of constructors of enums and + * structs, such as `Result::Ok(42)`, `Foo { bar = 1 }` and `None`. */ -private module TupleLikeConstructionMatchingInput implements MatchingInputSig { +private module ConstructorMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput - class Declaration = TupleLikeConstructor; + class Declaration = Constructor; - class Access extends NonAssocCallExpr, ContextTyping::ContextTypedCallCand { - Access() { - this instanceof CallExprImpl::TupleStructExpr or - this instanceof CallExprImpl::TupleVariantExpr - } + abstract class Access extends AstNode { + abstract Type getInferredType(FunctionPosition pos, TypePath path); - override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { - result = NonAssocCallExpr.super.getTypeArgument(apos, path) - } + abstract Declaration getTarget(); - Declaration getTarget() { result = this.resolveCallTargetViaPathResolution() } + abstract AstNode getNodeAt(AccessPosition apos); + + abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path); /** - * Holds if the return type of this tuple-like construction at `path` may have to be inferred - * from the context, for example in `Result::Ok(42)` the error type has to be inferred from the - * context. + * Holds if the return type of this constructor expression at `path` may + * have to be inferred from the context. For example in `Result::Ok(42)` the + * error type has to be inferred from the context. */ pragma[nomagic] predicate hasUnknownTypeAt(FunctionPosition pos, TypePath path) { - exists(TupleLikeConstructor tc, TypeParameter tp | - tc = this.getTarget() and + exists(Declaration d, TypeParameter tp | + d = this.getTarget() and pos.isReturn() and - tp = tc.getReturnType(path) and - not tp = tc.getParameterType(_, _) and + tp = d.getDeclaredType(pos, path) and + not exists(FunctionPosition pos2 | not pos2.isReturn() and tp = d.getDeclaredType(pos2, _)) and // check that no explicit type arguments have been supplied for `tp` not exists(TypeArgumentPosition tapos | exists(this.getTypeArgument(tapos, _)) and @@ -3172,25 +2984,93 @@ private module TupleLikeConstructionMatchingInput implements MatchingInputSig { ) } } + + private class NonAssocCallAccess extends Access, NonAssocCallExpr, + ContextTyping::ContextTypedCallCand + { + NonAssocCallAccess() { + this instanceof CallExprImpl::TupleStructExpr or + this instanceof CallExprImpl::TupleVariantExpr + } + + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = NonAssocCallExpr.super.getTypeArgument(apos, path) + } + + override AstNode getNodeAt(AccessPosition apos) { + result = NonAssocCallExpr.super.getNodeAt(apos) + } + + override Type getInferredType(FunctionPosition pos, TypePath path) { + result = NonAssocCallExpr.super.getInferredType(pos, path) + } + + override Declaration getTarget() { result = this.resolveCallTargetViaPathResolution() } + } + + abstract private class StructAccess extends Access instanceof PathAstNode { + pragma[nomagic] + override Type getInferredType(AccessPosition apos, TypePath path) { + result = inferType(this.getNodeAt(apos), path) + } + + pragma[nomagic] + override Declaration getTarget() { result = resolvePath(super.getPath()) } + + pragma[nomagic] + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + // Handle constructions that use `Self {...}` syntax + exists(TypeMention tm, TypePath path0 | + tm = super.getPath() and + result = tm.getTypeAt(path0) and + path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) + ) + } + } + + private class StructExprAccess extends StructAccess, StructExpr { + override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { + result = super.getTypeArgument(apos, path) + or + exists(TypePath suffix | + suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and + result = CertainTypeInference::inferCertainType(this, suffix) + ) + } + + override AstNode getNodeAt(AccessPosition apos) { + result = + this.getFieldExpr(this.getNthStructField(apos.asPosition()).getName().getText()).getExpr() + or + result = this and apos.isReturn() + } + } + + /** A potential nullary struct/variant construction such as `None`. */ + private class PathExprAccess extends StructAccess, PathExpr { + PathExprAccess() { not exists(CallExpr ce | this = ce.getFunction()) } + + override AstNode getNodeAt(AccessPosition apos) { result = this and apos.isReturn() } + } } -private module TupleLikeConstructionMatching = Matching; +private module ConstructorMatching = Matching; pragma[nomagic] -private Type inferTupleLikeConstructionTypePreCheck( +private Type inferConstructorTypePreCheck( AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path ) { hasReceiver = false and - exists(TupleLikeConstructionMatchingInput::Access a | n = a.getNodeAt(pos) | - result = TupleLikeConstructionMatching::inferAccessType(a, pos, path) + exists(ConstructorMatchingInput::Access a | n = a.getNodeAt(pos) | + result = ConstructorMatching::inferAccessType(a, pos, path) or a.hasUnknownTypeAt(pos, path) and result = TUnknownType() ) } -private predicate inferTupleLikeConstructionType = - ContextTyping::CheckContextTyping::check/2; +private predicate inferConstructorType = + ContextTyping::CheckContextTyping::check/2; /** * A matching configuration for resolving types of operations like `a + b`. @@ -3676,71 +3556,27 @@ private Type inferDereferencedExprPtrType(AstNode n, TypePath path) { } /** - * A matching configuration for resolving types of struct patterns - * like `let Foo { bar } = ...`. + * A matching configuration for resolving types of constructor patterns like + * `let Foo { bar } = ...` or `let Some(x) = ...`. */ -private module StructPatMatchingInput implements MatchingInputSig { - class DeclarationPosition = StructExprMatchingInput::DeclarationPosition; - - class Declaration = StructExprMatchingInput::Declaration; - - class AccessPosition = DeclarationPosition; - - class Access extends StructPat { - Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } - - AstNode getNodeAt(AccessPosition apos) { - result = this.getPatField(apos.asFieldPos()).getPat() - or - result = this and - apos.isStructPos() - } - - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) - or - // The struct/enum type is supplied explicitly as a type qualifier, e.g. - // `let Foo::Variant { ... } = ...`. - apos.isStructPos() and - result = this.getPath().(TypeMention).getTypeAt(path) - } - - Declaration getTarget() { result = resolvePath(this.getPath()) } - } - - predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { - apos = dpos - } -} - -private module StructPatMatching = Matching; - -/** - * Gets the type of `n` at `path`, where `n` is either a struct pattern or - * a field pattern of a struct pattern. - */ -pragma[nomagic] -private Type inferStructPatType(AstNode n, TypePath path) { - exists(StructPatMatchingInput::Access a, StructPatMatchingInput::AccessPosition apos | - n = a.getNodeAt(apos) and - result = StructPatMatching::inferAccessType(a, apos, path) - ) -} - -/** - * A matching configuration for resolving types of tuple struct patterns - * like `let Some(x) = ...`. - */ -private module TupleStructPatMatchingInput implements MatchingInputSig { +private module ConstructorPatMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput - class Declaration = TupleLikeConstructor; + class Declaration = ConstructorMatchingInput::Declaration; + + class Access extends Pat instanceof PathAstNode { + Access() { this instanceof TupleStructPat or this instanceof StructPat } - class Access extends TupleStructPat { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } AstNode getNodeAt(AccessPosition apos) { - result = this.getField(apos.asPosition()) + this = + any(StructPat sp | + result = + sp.getPatField(sp.getNthStructField(apos.asPosition()).getName().getText()).getPat() + ) + or + result = this.(TupleStructPat).getField(apos.asPosition()) or result = this and apos.isReturn() @@ -3750,26 +3586,27 @@ private module TupleStructPatMatchingInput implements MatchingInputSig { result = inferType(this.getNodeAt(apos), path) or // The struct/enum type is supplied explicitly as a type qualifier, e.g. + // `let Foo::Variant { ... } = ...` or // `let Option::::Some(x) = ...`. - apos.isTypeQualifier() and - result = this.getPath().(TypeMention).getTypeAt(path) + apos.isReturn() and + result = super.getPath().(TypeMention).getTypeAt(path) } - Declaration getTarget() { result = resolvePath(this.getPath()) } + Declaration getTarget() { result = resolvePath(super.getPath()) } } } -private module TupleStructPatMatching = Matching; +private module ConstructorPatMatching = Matching; /** - * Gets the type of `n` at `path`, where `n` is either a tuple struct pattern or - * a positional pattern of a tuple struct pattern. + * Gets the type of `n` at `path`, where `n` is a pattern for a constructor, + * either a struct pattern or a tuple-struct pattern. */ pragma[nomagic] -private Type inferTupleStructPatType(AstNode n, TypePath path) { - exists(TupleStructPatMatchingInput::Access a, TupleStructPatMatchingInput::AccessPosition apos | +private Type inferConstructorPatType(AstNode n, TypePath path) { + exists(ConstructorPatMatchingInput::Access a, FunctionPosition apos | n = a.getNodeAt(apos) and - result = TupleStructPatMatching::inferAccessType(a, apos, path) + result = ConstructorPatMatching::inferAccessType(a, apos, path) ) } @@ -4080,11 +3917,9 @@ private module Cached { or result = inferTypeEquality(n, path) or - result = inferStructExprType(n, path) - or result = inferFunctionCallType(n, path) or - result = inferTupleLikeConstructionType(n, path) + result = inferConstructorType(n, path) or result = inferOperationType(n, path) or @@ -4106,9 +3941,7 @@ private module Cached { or result = inferClosureExprType(n, path) or - result = inferStructPatType(n, path) - or - result = inferTupleStructPatType(n, path) + result = inferConstructorPatType(n, path) ) } } @@ -4157,9 +3990,9 @@ private module Debug { t = inferFunctionCallType(n, path) } - predicate debugInferTupleLikeConstructionType(AstNode n, TypePath path, Type t) { + predicate debugInferConstructorType(AstNode n, TypePath path, Type t) { n = getRelevantLocatable() and - t = inferTupleLikeConstructionType(n, path) + t = inferConstructorType(n, path) } predicate debugTypeMention(TypeMention tm, TypePath path, Type type) { From d180900ab4d01a0d00dab29e7e9dea0a1ebbad94 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Mar 2026 19:01:22 +0100 Subject: [PATCH 69/72] Rust: Minor improvements to documentation comments Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../lib/codeql/rust/internal/typeinference/TypeInference.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index a4b338d7c69..41af0ec31f7 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -2948,7 +2948,7 @@ private class VariantConstructor extends Constructor instanceof Variant { /** * A matching configuration for resolving types of constructors of enums and - * structs, such as `Result::Ok(42)`, `Foo { bar = 1 }` and `None`. + * structs, such as `Result::Ok(42)`, `Foo { bar: 1 }` and `None`. */ private module ConstructorMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput @@ -3586,7 +3586,7 @@ private module ConstructorPatMatchingInput implements MatchingInputSig { result = inferType(this.getNodeAt(apos), path) or // The struct/enum type is supplied explicitly as a type qualifier, e.g. - // `let Foo::Variant { ... } = ...` or + // `let Foo::::Variant { ... } = ...` or // `let Option::::Some(x) = ...`. apos.isReturn() and result = super.getPath().(TypeMention).getTypeAt(path) From 6efd844180536df09573491df1cd63cf4c176c9a Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Mar 2026 14:04:49 +0100 Subject: [PATCH 70/72] Rust: Rename into "construction" and "deconstruction" --- .../internal/typeinference/TypeInference.qll | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 41af0ec31f7..e88a69e910f 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -2947,10 +2947,10 @@ private class VariantConstructor extends Constructor instanceof Variant { } /** - * A matching configuration for resolving types of constructors of enums and + * A matching configuration for resolving types of constructions of enums and * structs, such as `Result::Ok(42)`, `Foo { bar: 1 }` and `None`. */ -private module ConstructorMatchingInput implements MatchingInputSig { +private module ConstructionMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput class Declaration = Constructor; @@ -2965,7 +2965,7 @@ private module ConstructorMatchingInput implements MatchingInputSig { abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path); /** - * Holds if the return type of this constructor expression at `path` may + * Holds if the return type of this construction expression at `path` may * have to be inferred from the context. For example in `Result::Ok(42)` the * error type has to be inferred from the context. */ @@ -3054,23 +3054,23 @@ private module ConstructorMatchingInput implements MatchingInputSig { } } -private module ConstructorMatching = Matching; +private module ConstructionMatching = Matching; pragma[nomagic] -private Type inferConstructorTypePreCheck( +private Type inferConstructionTypePreCheck( AstNode n, FunctionPosition pos, boolean hasReceiver, TypePath path ) { hasReceiver = false and - exists(ConstructorMatchingInput::Access a | n = a.getNodeAt(pos) | - result = ConstructorMatching::inferAccessType(a, pos, path) + exists(ConstructionMatchingInput::Access a | n = a.getNodeAt(pos) | + result = ConstructionMatching::inferAccessType(a, pos, path) or a.hasUnknownTypeAt(pos, path) and result = TUnknownType() ) } -private predicate inferConstructorType = - ContextTyping::CheckContextTyping::check/2; +private predicate inferConstructionType = + ContextTyping::CheckContextTyping::check/2; /** * A matching configuration for resolving types of operations like `a + b`. @@ -3556,13 +3556,13 @@ private Type inferDereferencedExprPtrType(AstNode n, TypePath path) { } /** - * A matching configuration for resolving types of constructor patterns like + * A matching configuration for resolving types of deconstruction patterns like * `let Foo { bar } = ...` or `let Some(x) = ...`. */ -private module ConstructorPatMatchingInput implements MatchingInputSig { +private module DeconstructionPatMatchingInput implements MatchingInputSig { import FunctionPositionMatchingInput - class Declaration = ConstructorMatchingInput::Declaration; + class Declaration = ConstructionMatchingInput::Declaration; class Access extends Pat instanceof PathAstNode { Access() { this instanceof TupleStructPat or this instanceof StructPat } @@ -3596,17 +3596,17 @@ private module ConstructorPatMatchingInput implements MatchingInputSig { } } -private module ConstructorPatMatching = Matching; +private module DeconstructionPatMatching = Matching; /** * Gets the type of `n` at `path`, where `n` is a pattern for a constructor, * either a struct pattern or a tuple-struct pattern. */ pragma[nomagic] -private Type inferConstructorPatType(AstNode n, TypePath path) { - exists(ConstructorPatMatchingInput::Access a, FunctionPosition apos | +private Type inferDeconstructionPatType(AstNode n, TypePath path) { + exists(DeconstructionPatMatchingInput::Access a, FunctionPosition apos | n = a.getNodeAt(apos) and - result = ConstructorPatMatching::inferAccessType(a, apos, path) + result = DeconstructionPatMatching::inferAccessType(a, apos, path) ) } @@ -3919,7 +3919,7 @@ private module Cached { or result = inferFunctionCallType(n, path) or - result = inferConstructorType(n, path) + result = inferConstructionType(n, path) or result = inferOperationType(n, path) or @@ -3941,7 +3941,7 @@ private module Cached { or result = inferClosureExprType(n, path) or - result = inferConstructorPatType(n, path) + result = inferDeconstructionPatType(n, path) ) } } @@ -3990,9 +3990,9 @@ private module Debug { t = inferFunctionCallType(n, path) } - predicate debugInferConstructorType(AstNode n, TypePath path, Type t) { + predicate debugInferConstructionType(AstNode n, TypePath path, Type t) { n = getRelevantLocatable() and - t = inferConstructorType(n, path) + t = inferConstructionType(n, path) } predicate debugTypeMention(TypeMention tm, TypePath path, Type type) { From b8222167d2a74f55fd3466d15136d6269b62d9dc Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Mar 2026 15:02:54 +0100 Subject: [PATCH 71/72] Rust: Ensure that `TPositionalArgumentPosition` is large enough for struct expressions --- .../codeql/rust/elements/internal/InvocationExprImpl.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll index 685eee1e43a..9fad85e756f 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll @@ -9,7 +9,12 @@ module Impl { // For the type `FunctionPosition` used by type inference, we work with function-call syntax // adjusted positions, so a call like `x.m(a, b, c)` needs positions `0` through `3`; for this // reason, there is no `- 1` after `max(...)` below. - i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()])] + i in [0 .. max([ + any(ParamList l).getNumberOfParams(), + any(ArgList l).getNumberOfArgs(), + any(StructFieldList l).getNumberOfFields() // Positions are used for struct expressions in type inference + ] + )] } or TSelfArgumentPosition() or TTypeQualifierArgumentPosition() From f2a0724620371ebeb2043090f1cf0da256df2a8a Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Mar 2026 15:05:33 +0100 Subject: [PATCH 72/72] Rust: Use `getReturnType` --- .../ql/lib/codeql/rust/internal/typeinference/TypeInference.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index e88a69e910f..da150a3ef39 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -2974,7 +2974,7 @@ private module ConstructionMatchingInput implements MatchingInputSig { exists(Declaration d, TypeParameter tp | d = this.getTarget() and pos.isReturn() and - tp = d.getDeclaredType(pos, path) and + tp = d.getReturnType(path) and not exists(FunctionPosition pos2 | not pos2.isReturn() and tp = d.getDeclaredType(pos2, _)) and // check that no explicit type arguments have been supplied for `tp` not exists(TypeArgumentPosition tapos |