Skip to content

Commit b8eb19a

Browse files
committed
Rust: Address feedback from PR review
1 parent 12dcd75 commit b8eb19a

File tree

3 files changed

+55
-67
lines changed

3 files changed

+55
-67
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,19 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
648648

649649
override Visibility getVisibility() { result = Impl.super.getVisibility() }
650650

651+
TypeParamItemNode getBlanketImplementationTypeParam() {
652+
result = this.resolveSelfTy() and
653+
result = super.getGenericParamList().getAGenericParam() and
654+
// This impl block is not superseded by the expansion of an attribute macro.
655+
not exists(super.getAttributeMacroExpansion())
656+
}
657+
658+
/**
659+
* Holds if this impl block is a blanket implementation. That is, the
660+
* implementation targets a generic parameter of the impl block.
661+
*/
662+
predicate isBlanketImplementation() { exists(this.getBlanketImplementationTypeParam()) }
663+
651664
override predicate hasCanonicalPath(Crate c) { this.resolveSelfTy().hasCanonicalPathPrefix(c) }
652665

653666
/**

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

Lines changed: 40 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,29 +2158,26 @@ private predicate methodCallHasImplCandidate(MethodCall mc, Impl impl) {
21582158
}
21592159

21602160
private module BlanketImplementation {
2161-
/**
2162-
* Gets the type parameter for which `impl` is a blanket implementation, if
2163-
* any.
2164-
*/
2165-
private TypeParamItemNode getBlanketImplementationTypeParam(Impl impl) {
2166-
result = impl.(ImplItemNode).resolveSelfTy() and
2167-
result = impl.getGenericParamList().getAGenericParam() and
2168-
// This impl block is not superseded by the expansion of an attribute macro.
2169-
not exists(impl.getAttributeMacroExpansion())
2170-
}
2171-
2172-
predicate isBlanketImplementation(Impl impl) { exists(getBlanketImplementationTypeParam(impl)) }
2173-
2174-
private Impl getPotentialDuplicated(string fileName, string traitName, int arity, string tpName) {
2175-
tpName = getBlanketImplementationTypeParam(result).getName() and
2161+
private ImplItemNode getPotentialDuplicated(
2162+
string fileName, string traitName, int arity, string tpName
2163+
) {
2164+
tpName = result.getBlanketImplementationTypeParam().getName() and
21762165
fileName = result.getLocation().getFile().getBaseName() and
21772166
traitName = result.(ImplItemNode).resolveTraitTy().getName() and
21782167
arity = result.(ImplItemNode).resolveTraitTy().(Trait).getNumberOfGenericParams()
21792168
}
21802169

2170+
private predicate duplicatedImpl(Impl impl1, Impl impl2) {
2171+
exists(string fileName, string traitName, int arity, string tpName |
2172+
impl1 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
2173+
impl2 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
2174+
impl1.getLocation().getFile().getAbsolutePath() <
2175+
impl2.getLocation().getFile().getAbsolutePath()
2176+
)
2177+
}
2178+
21812179
/**
2182-
* Holds if `impl1` and `impl2` are duplicates and `impl2` is strictly more
2183-
* "canonical" than `impl1`.
2180+
* Holds if `impl` is a canonical blanket implementation.
21842181
*
21852182
* Libraries can often occur several times in the database for different
21862183
* library versions. This causes the same blanket implementations to exist
@@ -2189,40 +2186,18 @@ private module BlanketImplementation {
21892186
* We detect these duplicates based on some simple heuristics (same trait
21902187
* name, file name, etc.). For these duplicates we select the one with the
21912188
* greatest file name (which usually is also the one with the greatest library
2192-
* version in the path)
2189+
* version in the path) as the "canonical" implementation.
21932190
*/
2194-
predicate duplicatedImpl(Impl impl1, Impl impl2) {
2195-
exists(string fileName, string traitName, int arity, string tpName |
2196-
impl1 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
2197-
impl2 = getPotentialDuplicated(fileName, traitName, arity, tpName) and
2198-
impl1.getLocation().getFile().getAbsolutePath() <
2199-
impl2.getLocation().getFile().getAbsolutePath()
2200-
)
2191+
private predicate isCanonicalImpl(Impl impl) {
2192+
not duplicatedImpl(impl, _) and impl.(ImplItemNode).isBlanketImplementation()
22012193
}
22022194

2203-
predicate isCanonicalImpl(Impl impl) {
2204-
not duplicatedImpl(impl, _) and isBlanketImplementation(impl)
2205-
}
2206-
2207-
Impl getCanonicalImpl(Impl impl) {
2208-
result =
2209-
max(Impl impl0, Location l |
2210-
duplicatedImpl(impl, impl0) and l = impl0.getLocation()
2211-
|
2212-
impl0 order by l.getFile().getAbsolutePath(), l.getStartLine()
2213-
)
2214-
or
2215-
isCanonicalImpl(impl) and result = impl
2216-
}
2217-
2218-
predicate isCanonicalBlanketImplementation(Impl impl) { impl = getCanonicalImpl(impl) }
2219-
22202195
/**
2221-
* Holds if `impl` is a blanket implementation for a type parameter and the type
2222-
* parameter must implement `trait`.
2196+
* Holds if `impl` is a blanket implementation for a type parameter with trait
2197+
* bound `traitBound`.
22232198
*/
2224-
private predicate blanketImplementationTraitBound(Impl impl, Trait t) {
2225-
t =
2199+
private predicate blanketImplementationTraitBound(Impl impl, Trait traitBound) {
2200+
traitBound =
22262201
min(Trait trait, int i |
22272202
trait = getBlanketImplementationTypeParam(impl).resolveBound(i) and
22282203
// Exclude traits that are known to not narrow things down very much.
@@ -2243,10 +2218,10 @@ private module BlanketImplementation {
22432218
* `arity`.
22442219
*/
22452220
private predicate blanketImplementationMethod(
2246-
ImplItemNode impl, Trait trait, string name, int arity, Function f
2221+
ImplItemNode impl, Trait traitBound, string name, int arity, Function f
22472222
) {
2248-
isCanonicalBlanketImplementation(impl) and
2249-
blanketImplementationTraitBound(impl, trait) and
2223+
isCanonicalImpl(impl) and
2224+
blanketImplementationTraitBound(impl, traitBound) and
22502225
f.getParamList().hasSelfParam() and
22512226
arity = f.getParamList().getNumberOfParams() and
22522227
(
@@ -2258,48 +2233,48 @@ private module BlanketImplementation {
22582233
f = impl.resolveTraitTy().getAssocItem(name)
22592234
) and
22602235
// If the method is already available through one of the trait bounds on the
2261-
// type parameter (because they share a common ancestor trait) then ignore
2236+
// type parameter (because they share a common super trait) then ignore
22622237
// it.
22632238
not getBlanketImplementationTypeParam(impl).resolveABound().(TraitItemNode).getASuccessor(name) =
22642239
f
22652240
}
22662241

2267-
predicate methodCallMatchesBlanketImpl(MethodCall mc, Type t, Impl impl, Trait trait, Function f) {
2242+
pragma[nomagic]
2243+
predicate methodCallMatchesBlanketImpl(
2244+
MethodCall mc, Type t, ImplItemNode impl, Trait traitBound, Trait traitImpl, Function f
2245+
) {
22682246
// Only check method calls where we have ruled out inherent method targets.
22692247
// Ideally we would also check if non-blanket method targets have been ruled
22702248
// out.
22712249
methodCallHasNoInherentTarget(mc) and
22722250
exists(string name, int arity |
22732251
isMethodCall(mc, t, name, arity) and
2274-
blanketImplementationMethod(impl, trait, name, arity, f)
2275-
)
2252+
blanketImplementationMethod(impl, traitBound, name, arity, f)
2253+
) and
2254+
traitImpl = impl.resolveTraitTy()
22762255
}
22772256

22782257
private predicate relevantTraitVisible(Element mc, Trait trait) {
2279-
exists(ImplItemNode impl |
2280-
methodCallMatchesBlanketImpl(mc, _, impl, _, _) and
2281-
trait = impl.resolveTraitTy()
2282-
)
2258+
methodCallMatchesBlanketImpl(mc, _, _, _, trait, _)
22832259
}
22842260

22852261
module SatisfiesConstraintInput implements SatisfiesConstraintInputSig<MethodCall> {
22862262
pragma[nomagic]
22872263
predicate relevantConstraint(MethodCall mc, Type constraint) {
2288-
exists(Trait trait, Trait trait2, ImplItemNode impl |
2289-
methodCallMatchesBlanketImpl(mc, _, impl, trait, _) and
2290-
TraitIsVisible<relevantTraitVisible/2>::traitIsVisible(mc, pragma[only_bind_into](trait2)) and
2291-
trait2 = pragma[only_bind_into](impl.resolveTraitTy()) and
2292-
trait = constraint.(TraitType).getTrait()
2264+
exists(Trait traitBound, Trait traitImpl |
2265+
methodCallMatchesBlanketImpl(mc, _, _, traitBound, traitImpl, _) and
2266+
TraitIsVisible<relevantTraitVisible/2>::traitIsVisible(mc, traitImpl) and
2267+
traitBound = constraint.(TraitType).getTrait()
22932268
)
22942269
}
22952270

22962271
predicate useUniversalConditions() { none() }
22972272
}
22982273

2299-
predicate hasBlanketImpl(MethodCall mc, Type t, Impl impl, Trait trait, Function f) {
2274+
predicate hasBlanketImpl(MethodCall mc, Type t, Impl impl, Trait traitBound, Function f) {
23002275
SatisfiesConstraint<MethodCall, SatisfiesConstraintInput>::satisfiesConstraintType(mc,
2301-
TTrait(trait), _, _) and
2302-
methodCallMatchesBlanketImpl(mc, t, impl, trait, f)
2276+
TTrait(traitBound), _, _) and
2277+
methodCallMatchesBlanketImpl(mc, t, impl, traitBound, _, f)
23032278
}
23042279

23052280
pragma[nomagic]

rust/ql/test/library-tests/type-inference/blanket_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ mod extension_trait_blanket_impl {
112112
let result = my_try_flag.try_read_flag_twice(); // $ target=TryFlagExt::try_read_flag_twice
113113

114114
let my_flag = MyFlag { flag: true };
115-
// Here `TryFlagExt::try_read_flag_twice` is since there is a blanket
116-
// implementaton of `TryFlag` for `Flag`.
115+
// Here `TryFlagExt::try_read_flag_twice` is a target since there is a
116+
// blanket implementaton of `TryFlag` for `Flag`.
117117
let result = my_flag.try_read_flag_twice(); // $ MISSING: target=TryFlagExt::try_read_flag_twice
118118

119119
let my_other_flag = MyOtherFlag { flag: true };

0 commit comments

Comments
 (0)