Skip to content

Commit 79cc731

Browse files
authored
Merge pull request #20096 from paldepind/rust/path-resolution-associated-type-fix
Rust: Path resolution associated type fix
2 parents 05572b4 + 2885046 commit 79cc731

File tree

6 files changed

+2861
-2705
lines changed

6 files changed

+2861
-2705
lines changed

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,18 @@ abstract class ItemNode extends Locatable {
112112
result = this.(SourceFileItemNode).getSuper()
113113
}
114114

115+
pragma[nomagic]
116+
private ItemNode getAChildSuccessor(string name) {
117+
this = result.getImmediateParent() and
118+
name = result.getName()
119+
}
120+
115121
cached
116122
ItemNode getASuccessorRec(string name) {
117123
Stages::PathResolutionStage::ref() and
118124
sourceFileEdge(this, name, result)
119125
or
120-
this = result.getImmediateParent() and
121-
name = result.getName()
126+
result = this.getAChildSuccessor(name)
122127
or
123128
fileImportEdge(this, name, result)
124129
or
@@ -224,6 +229,38 @@ abstract class ItemNode extends Locatable {
224229
result.(CrateItemNode).isPotentialDollarCrateTarget()
225230
}
226231

232+
/**
233+
* Holds if the successor `item` with the name `name` is not available locally
234+
* for unqualified paths.
235+
*
236+
* This has the effect that a path of the form `name` inside `this` will not
237+
* resolve to `item`.
238+
*/
239+
pragma[nomagic]
240+
predicate excludedLocally(string name, ItemNode item) {
241+
// Associated items in an impl or trait block are not directly available
242+
// inside the block, they require a qualified path with a `Self` prefix.
243+
item = this.getAChildSuccessor(name) and
244+
this instanceof ImplOrTraitItemNode and
245+
item instanceof AssocItemNode
246+
}
247+
248+
/**
249+
* Holds if the successor `item` with the name `name` is not available
250+
* externally for qualified paths that resolve to this item.
251+
*
252+
* This has the effect that a path of the form `Qualifier::name`, where
253+
* `Qualifier` resolves to this item, will not resolve to `item`.
254+
*/
255+
pragma[nomagic]
256+
predicate excludedExternally(string name, ItemNode item) {
257+
// Type parameters for an `impl` or trait block are not available outside of
258+
// the block.
259+
item = this.getAChildSuccessor(name) and
260+
this instanceof ImplOrTraitItemNode and
261+
item instanceof TypeParamItemNode
262+
}
263+
227264
pragma[nomagic]
228265
private predicate hasSourceFunction(string name) {
229266
this.getASuccessorFull(name).(Function).fromSource()
@@ -1145,7 +1182,9 @@ pragma[nomagic]
11451182
private predicate declares(ItemNode item, Namespace ns, string name) {
11461183
exists(ItemNode child | child.getImmediateParent() = item |
11471184
child.getName() = name and
1148-
child.getNamespace() = ns
1185+
child.getNamespace() = ns and
1186+
// If `item` is excluded locally then it does not declare `name`.
1187+
not item.excludedLocally(name, child)
11491188
or
11501189
useTreeDeclares(child.(Use).getUseTree(), name) and
11511190
exists(ns) // `use foo::bar` can refer to both a value and a type
@@ -1193,38 +1232,27 @@ private ItemNode getOuterScope(ItemNode i) {
11931232
result = i.getImmediateParent()
11941233
}
11951234

1196-
pragma[nomagic]
1197-
private ItemNode getAdjustedEnclosing(ItemNode encl0, Namespace ns) {
1198-
// functions in `impl` blocks need to use explicit `Self::` to access other
1199-
// functions in the `impl` block
1200-
if encl0 instanceof ImplOrTraitItemNode and ns.isValue()
1201-
then result = encl0.getImmediateParent()
1202-
else result = encl0
1203-
}
1204-
12051235
/**
12061236
* Holds if the unqualified path `p` references an item named `name`, and `name`
12071237
* may be looked up in the `ns` namespace inside enclosing item `encl`.
12081238
*/
12091239
pragma[nomagic]
12101240
private predicate unqualifiedPathLookup(ItemNode encl, string name, Namespace ns, RelevantPath p) {
1211-
exists(ItemNode encl0 | encl = getAdjustedEnclosing(encl0, ns) |
1212-
// lookup in the immediately enclosing item
1213-
p.isUnqualified(name) and
1214-
encl0.getADescendant() = p and
1215-
exists(ns) and
1216-
not name = ["crate", "$crate", "super", "self"]
1217-
or
1218-
// lookup in an outer scope, but only if the item is not declared in inner scope
1219-
exists(ItemNode mid |
1220-
unqualifiedPathLookup(mid, name, ns, p) and
1221-
not declares(mid, ns, name) and
1222-
not (
1223-
name = "Self" and
1224-
mid = any(ImplOrTraitItemNode i).getAnItemInSelfScope()
1225-
) and
1226-
encl0 = getOuterScope(mid)
1227-
)
1241+
// lookup in the immediately enclosing item
1242+
p.isUnqualified(name) and
1243+
encl.getADescendant() = p and
1244+
exists(ns) and
1245+
not name = ["crate", "$crate", "super", "self"]
1246+
or
1247+
// lookup in an outer scope, but only if the item is not declared in inner scope
1248+
exists(ItemNode mid |
1249+
unqualifiedPathLookup(mid, name, ns, p) and
1250+
not declares(mid, ns, name) and
1251+
not (
1252+
name = "Self" and
1253+
mid = any(ImplOrTraitItemNode i).getAnItemInSelfScope()
1254+
) and
1255+
encl = getOuterScope(mid)
12281256
)
12291257
}
12301258

@@ -1245,10 +1273,10 @@ private predicate sourceFileHasCratePathTc(ItemNode i1, ItemNode i2) =
12451273

12461274
/**
12471275
* Holds if the unqualified path `p` references a keyword item named `name`, and
1248-
* `name` may be looked up in the `ns` namespace inside enclosing item `encl`.
1276+
* `name` may be looked up inside enclosing item `encl`.
12491277
*/
12501278
pragma[nomagic]
1251-
private predicate keywordLookup(ItemNode encl, string name, Namespace ns, RelevantPath p) {
1279+
private predicate keywordLookup(ItemNode encl, string name, RelevantPath p) {
12521280
// For `($)crate`, jump directly to the root module
12531281
exists(ItemNode i | p.isCratePath(name, i) |
12541282
encl instanceof SourceFile and
@@ -1259,18 +1287,17 @@ private predicate keywordLookup(ItemNode encl, string name, Namespace ns, Releva
12591287
or
12601288
name = ["super", "self"] and
12611289
p.isUnqualified(name) and
1262-
exists(ItemNode encl0 |
1263-
encl0.getADescendant() = p and
1264-
encl = getAdjustedEnclosing(encl0, ns)
1265-
)
1290+
encl.getADescendant() = p
12661291
}
12671292

12681293
pragma[nomagic]
12691294
private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns) {
1270-
exists(ItemNode encl, string name | result = getASuccessorFull(encl, name, ns) |
1295+
exists(ItemNode encl, string name |
1296+
result = getASuccessorFull(encl, name, ns) and not encl.excludedLocally(name, result)
1297+
|
12711298
unqualifiedPathLookup(encl, name, ns, p)
12721299
or
1273-
keywordLookup(encl, name, ns, p)
1300+
keywordLookup(encl, name, p) and exists(ns)
12741301
)
12751302
}
12761303

@@ -1291,7 +1318,8 @@ private ItemNode resolvePath0(RelevantPath path, Namespace ns) {
12911318
or
12921319
exists(ItemNode q, string name |
12931320
q = resolvePathQualifier(path, name) and
1294-
result = getASuccessorFull(q, name, ns)
1321+
result = getASuccessorFull(q, name, ns) and
1322+
not q.excludedExternally(name, result)
12951323
)
12961324
or
12971325
result = resolveUseTreeListItem(_, _, path) and

rust/ql/test/library-tests/path-resolution/main.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,60 @@ impl AStruct // $ item=I123
636636
pub fn z(&self) {} // I125
637637
}
638638

639+
mod associated_types {
640+
use std::marker::PhantomData; // $ item=PhantomData
641+
use std::result::Result; // $ item=Result
642+
643+
trait Reduce {
644+
type Input; // ReduceInput
645+
type Error; // ReduceError
646+
type Output; // ReduceOutput
647+
fn feed(
648+
&mut self,
649+
item: Self::Input, // $ item=ReduceInput
650+
) -> Result<Self::Output, Self::Error>; // $ item=Result item=ReduceOutput item=ReduceError
651+
} // IReduce
652+
653+
struct MyImpl<Input, Error> {
654+
_input: PhantomData<Input>, // $ item=PhantomData item=Input
655+
_error: PhantomData<Error>, // $ item=PhantomData item=Error
656+
} // MyImpl
657+
658+
#[rustfmt::skip]
659+
impl<
660+
Input, // IInput
661+
Error, // IError
662+
> Reduce // $ item=IReduce
663+
for MyImpl<
664+
Input, // $ item=IInput
665+
Error, // $ item=IError
666+
> // $ item=MyImpl
667+
{
668+
type Input = Result<
669+
Input, // $ item=IInput
670+
Self::Error, // $ item=IErrorAssociated
671+
> // $ item=Result
672+
; // IInputAssociated
673+
type Error = Option<
674+
Error // $ item=IError
675+
> // $ item=Option
676+
; // IErrorAssociated
677+
type Output =
678+
Input // $ item=IInput
679+
; // IOutputAssociated
680+
681+
fn feed(
682+
&mut self,
683+
item: Self::Input // $ item=IInputAssociated
684+
) -> Result<
685+
Self::Output, // $ item=IOutputAssociated
686+
Self::Error // $ item=IErrorAssociated
687+
> { // $ item=Result
688+
item
689+
}
690+
}
691+
}
692+
639693
use std::{self as ztd}; // $ item=std
640694

641695
fn use_ztd(x: ztd::string::String) {} // $ item=String

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy