From 99b498b891bab893c2f542ea3de0d100fd7b48dd Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 2 Feb 2026 13:29:26 +0100 Subject: [PATCH] Rust: Resolve `Self` paths in type definitions --- .../codeql/rust/internal/PathResolution.qll | 34 ++++++------------- .../library-tests/path-resolution/main.rs | 6 ++-- .../path-resolution/path-resolution.expected | 3 ++ 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 7e77669cc4f..bfc2c4a0cc0 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -119,6 +119,15 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki if result.isPublic() then kind.isBoth() else kind.isInternal() + or + // `Self` has scoping rules similar to type parameters and can be considered + // an implicit type parameter child of the introducing item. + // - https://doc.rust-lang.org/stable/reference/paths.html#r-paths.qualifiers.type-self + // - https://doc.rust-lang.org/stable/reference/names/scopes.html#r-names.scopes.self + (item instanceof TypeItemTypeItemNode or item instanceof ImplOrTraitItemNode) and + name = "Self" and + kind.isInternal() and + result = item } private module UseOption = Option; @@ -405,9 +414,6 @@ abstract class ItemNode extends Locatable { this instanceof SourceFile and builtin(name, result) or - name = "Self" and - this = result.(ImplOrTraitItemNode).getAnItemInSelfScope() - or name = "crate" and this = result.(CrateItemNode).getASourceFile() ) @@ -718,26 +724,12 @@ class FunctionItemNode extends AssocItemNode, ParameterizableItemNode instanceof } abstract class ImplOrTraitItemNode extends ItemNode { - /** Gets an item that may refer to this node using `Self`. */ - pragma[nomagic] - ItemNode getAnItemInSelfScope() { - result = this - or - result.getImmediateParent() = this - or - exists(ItemNode mid | - mid = this.getAnItemInSelfScope() and - result.getImmediateParent() = mid and - not mid instanceof ImplOrTraitItemNode - ) - } - /** Gets a `Self` path that refers to this item. */ cached Path getASelfPath() { Stages::PathResolutionStage::ref() and isUnqualifiedSelfPath(result) and - result = this.getAnItemInSelfScope().getADescendant() + this = unqualifiedPathLookup(result, _, _) } /** Gets an associated item belonging to this trait or `impl` block. */ @@ -1610,11 +1602,7 @@ private predicate unqualifiedPathLookup(ItemNode ancestor, string name, Namespac // lookup in an outer scope, but only if the item is not declared in inner scope exists(ItemNode mid | unqualifiedPathLookup(mid, name, ns, encl) and - not declares(mid, ns, name) and - not ( - name = "Self" and - mid = any(ImplOrTraitItemNode i).getAnItemInSelfScope() - ) + not declares(mid, ns, name) | ancestor = getOuterScope(mid) or diff --git a/rust/ql/test/library-tests/path-resolution/main.rs b/rust/ql/test/library-tests/path-resolution/main.rs index b330822ecc8..4a3e4c82c20 100644 --- a/rust/ql/test/library-tests/path-resolution/main.rs +++ b/rust/ql/test/library-tests/path-resolution/main.rs @@ -1060,12 +1060,12 @@ mod self_constructors { mod self_types { struct NonEmptyListStruct { head: T, // $ item=T - tail: Option>, // $ item=Option item=Box MISSING: item=NonEmptyListStruct + tail: Option>, // $ item=Option item=Box item=NonEmptyListStruct } enum NonEmptyListEnum { Single(T), // $ item=T - Cons(T, Box), // $ item=T item=Box MISSING: item=NonEmptyListEnum + Cons(T, Box), // $ item=T item=Box item=NonEmptyListEnum } #[rustfmt::skip] @@ -1075,7 +1075,7 @@ mod self_types { : Copy // $ item=Copy > { single: T, // $ item=T - cons: (T, &'a Self), // $ item=T MISSING: item=NonEmptyListUnion + cons: (T, &'a Self), // $ item=T item=NonEmptyListUnion } } diff --git a/rust/ql/test/library-tests/path-resolution/path-resolution.expected b/rust/ql/test/library-tests/path-resolution/path-resolution.expected index e1f9f60b76a..fbb81bbf2ca 100644 --- a/rust/ql/test/library-tests/path-resolution/path-resolution.expected +++ b/rust/ql/test/library-tests/path-resolution/path-resolution.expected @@ -536,12 +536,15 @@ resolvePath | main.rs:1062:15:1062:15 | T | main.rs:1061:31:1061:31 | T | | main.rs:1063:15:1063:31 | Option::<...> | {EXTERNAL LOCATION} | enum Option | | main.rs:1063:22:1063:30 | Box::<...> | {EXTERNAL LOCATION} | struct Box | +| main.rs:1063:26:1063:29 | Self | main.rs:1061:5:1064:5 | struct NonEmptyListStruct | | main.rs:1067:16:1067:16 | T | main.rs:1066:27:1066:27 | T | | main.rs:1068:14:1068:14 | T | main.rs:1066:27:1066:27 | T | | main.rs:1068:17:1068:25 | Box::<...> | {EXTERNAL LOCATION} | struct Box | +| main.rs:1068:21:1068:24 | Self | main.rs:1066:5:1069:5 | enum NonEmptyListEnum | | main.rs:1075:13:1075:16 | Copy | {EXTERNAL LOCATION} | trait Copy | | main.rs:1077:17:1077:17 | T | main.rs:1074:9:1074:9 | T | | main.rs:1078:16:1078:16 | T | main.rs:1074:9:1074:9 | T | +| main.rs:1078:23:1078:26 | Self | main.rs:1071:5:1079:5 | union NonEmptyListUnion | | main.rs:1083:5:1083:6 | my | main.rs:1:1:1:7 | mod my | | main.rs:1083:5:1083:14 | ...::nested | my.rs:1:1:1:15 | mod nested | | main.rs:1083:5:1083:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |