mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
Merge remote-tracking branch 'upstream/main' into addsub
This commit is contained in:
@@ -99,10 +99,11 @@ module Impl {
|
||||
*/
|
||||
cached
|
||||
predicate isFromMacroExpansion(AstNode n) {
|
||||
exists(AstNode macro |
|
||||
exists(AstNode macro, Location l |
|
||||
macro = getImmediatelyEnclosingMacroInvocation(n) and
|
||||
not n = getATokenTreeNode(macro) and
|
||||
not isAttributeMacroExpansionSourceLocation(macro, n.getLocation())
|
||||
l = n.getLocation() and
|
||||
not isAttributeMacroExpansionSourceLocation(macro, l)
|
||||
)
|
||||
or
|
||||
isFromMacroExpansion(pragma[only_bind_into](getImmediatelyEnclosingMacroInvocation(n)))
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Trait
|
||||
private import codeql.rust.internal.PathResolution as PathResolution
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `Trait` and should not
|
||||
@@ -67,5 +68,11 @@ module Impl {
|
||||
* `where` clauses for `Self`.
|
||||
*/
|
||||
TypeBound getATypeBound() { result = this.getTypeBound(_) }
|
||||
|
||||
/** Gets a direct supertrait of this trait, if any. */
|
||||
Trait getSupertrait() {
|
||||
result =
|
||||
PathResolution::resolvePath(this.getATypeBound().getTypeRepr().(PathTypeRepr).getPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
private import rust
|
||||
private import codeql.rust.Concepts
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import codeql.rust.internal.typeinference.Type
|
||||
private import codeql.rust.internal.typeinference.TypeMention
|
||||
|
||||
/**
|
||||
* A call to the `starts_with` method on a `Path`.
|
||||
@@ -19,6 +22,34 @@ private class StartswithCall extends Path::SafeAccessCheck::Range, MethodCall {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow summary for the [reflexive implementation of the `From` trait][1].
|
||||
*
|
||||
* Blanket implementations currently don't have a canonical path, so we cannot
|
||||
* use models-as-data for this model.
|
||||
*
|
||||
* [1]: https://doc.rust-lang.org/std/convert/trait.From.html#impl-From%3CT%3E-for-T
|
||||
*/
|
||||
private class ReflexiveFrom extends SummarizedCallable::Range {
|
||||
ReflexiveFrom() {
|
||||
exists(ImplItemNode impl |
|
||||
impl.resolveTraitTy().(Trait).getCanonicalPath() = "core::convert::From" and
|
||||
this = impl.getAssocItem("from") and
|
||||
resolvePath(this.getParam(0).getTypeRepr().(PathTypeRepr).getPath()) =
|
||||
impl.getBlanketImplementationTypeParam()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
) {
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true and
|
||||
model = "ReflexiveFrom"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The [`Option` enum][1].
|
||||
*
|
||||
@@ -143,23 +174,48 @@ class FutureTrait extends Trait {
|
||||
TypeAlias getOutputType() { result = this.(TraitItemNode).getAssocItem("Output") }
|
||||
}
|
||||
|
||||
/** A function trait `FnOnce`, `FnMut`, or `Fn`. */
|
||||
abstract private class AnyFnTraitImpl extends Trait {
|
||||
/** Gets the `Args` type parameter of this trait. */
|
||||
TypeParam getTypeParam() { result = this.getGenericParamList().getGenericParam(0) }
|
||||
}
|
||||
|
||||
final class AnyFnTrait = AnyFnTraitImpl;
|
||||
|
||||
/**
|
||||
* The [`FnOnce` trait][1].
|
||||
*
|
||||
* [1]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
|
||||
*/
|
||||
class FnOnceTrait extends Trait {
|
||||
class FnOnceTrait extends AnyFnTraitImpl {
|
||||
pragma[nomagic]
|
||||
FnOnceTrait() { this.getCanonicalPath() = "core::ops::function::FnOnce" }
|
||||
|
||||
/** Gets the type parameter of this trait. */
|
||||
TypeParam getTypeParam() { result = this.getGenericParamList().getGenericParam(0) }
|
||||
|
||||
/** Gets the `Output` associated type. */
|
||||
pragma[nomagic]
|
||||
TypeAlias getOutputType() { result = this.(TraitItemNode).getAssocItem("Output") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The [`FnMut` trait][1].
|
||||
*
|
||||
* [1]: https://doc.rust-lang.org/std/ops/trait.FnMut.html
|
||||
*/
|
||||
class FnMutTrait extends AnyFnTraitImpl {
|
||||
pragma[nomagic]
|
||||
FnMutTrait() { this.getCanonicalPath() = "core::ops::function::FnMut" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The [`Fn` trait][1].
|
||||
*
|
||||
* [1]: https://doc.rust-lang.org/std/ops/trait.Fn.html
|
||||
*/
|
||||
class FnTrait extends AnyFnTraitImpl {
|
||||
pragma[nomagic]
|
||||
FnTrait() { this.getCanonicalPath() = "core::ops::function::Fn" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The [`Iterator` trait][1].
|
||||
*
|
||||
|
||||
@@ -117,8 +117,6 @@ module SatisfiesBlanketConstraint<
|
||||
predicate relevantConstraint(ArgumentTypeAndBlanketOffset ato, Type constraint) {
|
||||
relevantConstraint(ato, _, constraint.(TraitType).getTrait())
|
||||
}
|
||||
|
||||
predicate useUniversalConditions() { none() }
|
||||
}
|
||||
|
||||
private module SatisfiesBlanketConstraint =
|
||||
@@ -126,7 +124,7 @@ module SatisfiesBlanketConstraint<
|
||||
|
||||
/**
|
||||
* Holds if the argument type `at` satisfies the first non-trivial blanket
|
||||
* constraint of `impl`.
|
||||
* constraint of `impl`, or if there are no non-trivial constraints of `impl`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate satisfiesBlanketConstraint(ArgumentType at, ImplItemNode impl) {
|
||||
@@ -135,6 +133,11 @@ module SatisfiesBlanketConstraint<
|
||||
SatisfiesBlanketConstraintInput::relevantConstraint(ato, impl, traitBound) and
|
||||
SatisfiesBlanketConstraint::satisfiesConstraintType(ato, TTrait(traitBound), _, _)
|
||||
)
|
||||
or
|
||||
exists(TypeParam blanketTypeParam |
|
||||
hasBlanketCandidate(at, impl, _, blanketTypeParam) and
|
||||
not hasFirstNonTrivialTraitBound(blanketTypeParam, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
private import rust
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import Type
|
||||
private import TypeAbstraction
|
||||
private import TypeMention
|
||||
private import TypeInference
|
||||
private import FunctionType
|
||||
@@ -34,6 +35,12 @@ private predicate implSiblingCandidate(
|
||||
rootType = selfTy.resolveType()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate blanketImplSiblingCandidate(ImplItemNode impl, Trait trait) {
|
||||
impl.isBlanketImplementation() and
|
||||
trait = impl.resolveTraitTy()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `impl1` and `impl2` are a sibling implementations of `trait`. We
|
||||
* consider implementations to be siblings if they implement the same trait for
|
||||
@@ -43,17 +50,22 @@ private predicate implSiblingCandidate(
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
|
||||
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
|
||||
impl1 != impl2 and
|
||||
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
|
||||
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
|
||||
// In principle the second conjunct below should be superflous, but we still
|
||||
// have ill-formed type mentions for types that we don't understand. For
|
||||
// those checking both directions restricts further. Note also that we check
|
||||
// syntactic equality, whereas equality up to renaming would be more
|
||||
// correct.
|
||||
typeMentionEqual(selfTy1, selfTy2) and
|
||||
typeMentionEqual(selfTy2, selfTy1)
|
||||
impl1 != impl2 and
|
||||
(
|
||||
exists(Type rootType, TypeMention selfTy1, TypeMention selfTy2 |
|
||||
implSiblingCandidate(impl1, trait, rootType, selfTy1) and
|
||||
implSiblingCandidate(impl2, trait, rootType, selfTy2) and
|
||||
// In principle the second conjunct below should be superflous, but we still
|
||||
// have ill-formed type mentions for types that we don't understand. For
|
||||
// those checking both directions restricts further. Note also that we check
|
||||
// syntactic equality, whereas equality up to renaming would be more
|
||||
// correct.
|
||||
typeMentionEqual(selfTy1, selfTy2) and
|
||||
typeMentionEqual(selfTy2, selfTy1)
|
||||
)
|
||||
or
|
||||
blanketImplSiblingCandidate(impl1, trait) and
|
||||
blanketImplSiblingCandidate(impl2, trait)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -62,7 +74,7 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
|
||||
* exists for the same type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, impl, _) }
|
||||
private predicate implHasSibling(ImplItemNode impl, Trait trait) { implSiblings(trait, impl, _) }
|
||||
|
||||
/**
|
||||
* Holds if type parameter `tp` of `trait` occurs in the function `f` with the name
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
private import rust
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import TypeInference
|
||||
private import Type
|
||||
private import TypeAbstraction
|
||||
private import TypeMention
|
||||
private import TypeInference
|
||||
|
||||
private newtype TFunctionPosition =
|
||||
TArgumentFunctionPosition(ArgumentPosition pos) or
|
||||
@@ -355,7 +356,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
|
||||
string toString() { result = call.toString() + " [arg " + pos + "]" }
|
||||
}
|
||||
|
||||
private module ArgIsInstantiationOfInput implements
|
||||
private module ArgIsInstantiationOfToIndexInput implements
|
||||
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
|
||||
{
|
||||
pragma[nomagic]
|
||||
@@ -388,7 +389,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
|
||||
}
|
||||
|
||||
private module ArgIsInstantiationOfToIndex =
|
||||
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>;
|
||||
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfToIndexInput>;
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argsAreInstantiationsOfToIndex(
|
||||
@@ -412,4 +413,24 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
|
||||
rnk = max(int r | toCheckRanked(i, f, _, r))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argsAreNotInstantiationsOf0(
|
||||
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i
|
||||
) {
|
||||
ArgIsInstantiationOfToIndex::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if _some_ argument of `call` has a type that is not an instantiation of the
|
||||
* type of the corresponding parameter of `f` inside `i`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
|
||||
exists(FunctionPosition pos |
|
||||
argsAreNotInstantiationsOf0(call, pos, i) and
|
||||
call.hasTargetCand(i, f) and
|
||||
Input::toCheck(i, f, pos, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,17 @@ private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
|
||||
/** Gets a type alias of `trait` or of a supertrait of `trait`. */
|
||||
private TypeAlias getTraitTypeAlias(Trait trait) {
|
||||
result = trait.getSupertrait*().getAssocItemList().getAnAssocItem()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a dyn trait type should have a type parameter associated with `n`. A
|
||||
* dyn trait type inherits the type parameters of the trait it implements. That
|
||||
* includes the type parameters corresponding to associated types.
|
||||
* Holds if a dyn trait type for the trait `trait` should have a type parameter
|
||||
* associated with `n`.
|
||||
*
|
||||
* A dyn trait type inherits the type parameters of the trait it implements.
|
||||
* That includes the type parameters corresponding to associated types.
|
||||
*
|
||||
* For instance in
|
||||
* ```rust
|
||||
@@ -24,10 +31,7 @@ private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
*/
|
||||
private predicate dynTraitTypeParameter(Trait trait, AstNode n) {
|
||||
trait = any(DynTraitTypeRepr dt).getTrait() and
|
||||
(
|
||||
n = trait.getGenericParamList().getATypeParam() or
|
||||
n = trait.(TraitItemNode).getAnAssocItem().(TypeAlias)
|
||||
)
|
||||
n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitTypeAlias(trait)]
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -39,8 +43,10 @@ newtype TType =
|
||||
TNeverType() or
|
||||
TUnknownType() or
|
||||
TTypeParamTypeParameter(TypeParam t) or
|
||||
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
|
||||
TDynTraitTypeParameter(AstNode n) { dynTraitTypeParameter(_, n) } or
|
||||
TAssociatedTypeTypeParameter(Trait trait, TypeAlias typeAlias) {
|
||||
getTraitTypeAlias(trait) = typeAlias
|
||||
} or
|
||||
TDynTraitTypeParameter(Trait trait, AstNode n) { dynTraitTypeParameter(trait, n) } or
|
||||
TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) {
|
||||
implTraitTypeParam(implTrait, _, tp)
|
||||
} or
|
||||
@@ -90,6 +96,7 @@ abstract class Type extends TType {
|
||||
class TupleType extends StructType {
|
||||
private int arity;
|
||||
|
||||
pragma[nomagic]
|
||||
TupleType() { arity = this.getTypeItem().(Builtins::TupleType).getArity() }
|
||||
|
||||
/** Gets the arity of this tuple type. */
|
||||
@@ -197,6 +204,7 @@ class TraitType extends Type, TTrait {
|
||||
* Array types like `[i64; 5]` are modeled as normal generic types.
|
||||
*/
|
||||
class ArrayType extends StructType {
|
||||
pragma[nomagic]
|
||||
ArrayType() { this.getTypeItem() instanceof Builtins::ArrayType }
|
||||
|
||||
override string toString() { result = "[;]" }
|
||||
@@ -210,12 +218,14 @@ TypeParamTypeParameter getArrayTypeParameter() {
|
||||
abstract class RefType extends StructType { }
|
||||
|
||||
class RefMutType extends RefType {
|
||||
pragma[nomagic]
|
||||
RefMutType() { this.getTypeItem() instanceof Builtins::RefMutType }
|
||||
|
||||
override string toString() { result = "&mut" }
|
||||
}
|
||||
|
||||
class RefSharedType extends RefType {
|
||||
pragma[nomagic]
|
||||
RefSharedType() { this.getTypeItem() instanceof Builtins::RefSharedType }
|
||||
|
||||
override string toString() { result = "&" }
|
||||
@@ -270,17 +280,10 @@ class DynTraitType extends Type, TDynTraitType {
|
||||
DynTraitType() { this = TDynTraitType(trait) }
|
||||
|
||||
override DynTraitTypeParameter getPositionalTypeParameter(int i) {
|
||||
result = TDynTraitTypeParameter(trait.getGenericParamList().getTypeParam(i))
|
||||
result.getTypeParam() = trait.getGenericParamList().getTypeParam(i)
|
||||
}
|
||||
|
||||
override TypeParameter getATypeParameter() {
|
||||
result = super.getATypeParameter()
|
||||
or
|
||||
exists(AstNode n |
|
||||
dynTraitTypeParameter(trait, n) and
|
||||
result = TDynTraitTypeParameter(n)
|
||||
)
|
||||
}
|
||||
override DynTraitTypeParameter getATypeParameter() { result.getTrait() = trait }
|
||||
|
||||
Trait getTrait() { result = trait }
|
||||
|
||||
@@ -313,6 +316,7 @@ class ImplTraitReturnType extends ImplTraitType {
|
||||
* with a single type argument.
|
||||
*/
|
||||
class SliceType extends StructType {
|
||||
pragma[nomagic]
|
||||
SliceType() { this.getTypeItem() instanceof Builtins::SliceType }
|
||||
|
||||
override string toString() { result = "[]" }
|
||||
@@ -339,12 +343,14 @@ TypeParamTypeParameter getPtrTypeParameter() {
|
||||
}
|
||||
|
||||
class PtrMutType extends PtrType {
|
||||
pragma[nomagic]
|
||||
PtrMutType() { this.getTypeItem() instanceof Builtins::PtrMutType }
|
||||
|
||||
override string toString() { result = "*mut" }
|
||||
}
|
||||
|
||||
class PtrConstType extends PtrType {
|
||||
pragma[nomagic]
|
||||
PtrConstType() { this.getTypeItem() instanceof Builtins::PtrConstType }
|
||||
|
||||
override string toString() { result = "*const" }
|
||||
@@ -427,30 +433,54 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
* Furthermore, associated types of a supertrait induce a corresponding type
|
||||
* parameter in any subtraits. E.g., if we have a trait `SubTrait: ATrait` then
|
||||
* `SubTrait` also has a type parameter for the associated type
|
||||
* `AssociatedType`.
|
||||
*/
|
||||
class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypeParameter {
|
||||
private Trait trait;
|
||||
private TypeAlias typeAlias;
|
||||
|
||||
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(typeAlias) }
|
||||
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(trait, typeAlias) }
|
||||
|
||||
TypeAlias getTypeAlias() { result = typeAlias }
|
||||
|
||||
/** Gets the trait that contains this associated type declaration. */
|
||||
TraitItemNode getTrait() { result.getAnAssocItem() = typeAlias }
|
||||
TraitItemNode getTrait() { result = trait }
|
||||
|
||||
override ItemNode getDeclaringItem() { result = this.getTrait() }
|
||||
/**
|
||||
* Holds if this associated type type parameter corresponds directly its
|
||||
* trait, that is, it is not inherited from a supertrait.
|
||||
*/
|
||||
predicate isDirect() { trait.(TraitItemNode).getAnAssocItem() = typeAlias }
|
||||
|
||||
override string toString() { result = typeAlias.getName().getText() }
|
||||
override ItemNode getDeclaringItem() { result = trait }
|
||||
|
||||
override string toString() {
|
||||
result = typeAlias.getName().getText() + "[" + trait.getName().toString() + "]"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = typeAlias.getLocation() }
|
||||
}
|
||||
|
||||
/** Gets the associated type type-parameter corresponding directly to `typeAlias`. */
|
||||
AssociatedTypeTypeParameter getAssociatedTypeTypeParameter(TypeAlias typeAlias) {
|
||||
result.isDirect() and result.getTypeAlias() = typeAlias
|
||||
}
|
||||
|
||||
/** Gets the dyn type type-parameter corresponding directly to `typeAlias`. */
|
||||
DynTraitTypeParameter getDynTraitTypeParameter(TypeAlias typeAlias) {
|
||||
result.getTraitTypeParameter() = getAssociatedTypeTypeParameter(typeAlias)
|
||||
}
|
||||
|
||||
class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
|
||||
private Trait trait;
|
||||
private AstNode n;
|
||||
|
||||
DynTraitTypeParameter() { this = TDynTraitTypeParameter(n) }
|
||||
DynTraitTypeParameter() { this = TDynTraitTypeParameter(trait, n) }
|
||||
|
||||
Trait getTrait() { dynTraitTypeParameter(result, n) }
|
||||
Trait getTrait() { result = trait }
|
||||
|
||||
/** Gets the dyn trait type that this type parameter belongs to. */
|
||||
DynTraitType getDynTraitType() { result.getTrait() = this.getTrait() }
|
||||
@@ -465,7 +495,7 @@ class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
|
||||
TypeParameter getTraitTypeParameter() {
|
||||
result.(TypeParamTypeParameter).getTypeParam() = n
|
||||
or
|
||||
result.(AssociatedTypeTypeParameter).getTypeAlias() = n
|
||||
result = TAssociatedTypeTypeParameter(trait, n)
|
||||
}
|
||||
|
||||
private string toStringInner() {
|
||||
@@ -546,58 +576,6 @@ class ImplTraitTypeTypeParameter extends ImplTraitType, TypeParameter {
|
||||
override TypeParameter getPositionalTypeParameter(int i) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type abstraction. I.e., a place in the program where type variables are
|
||||
* introduced.
|
||||
*
|
||||
* Example:
|
||||
* ```rust
|
||||
* impl<A, B> Foo<A, B> { }
|
||||
* // ^^^^^^ a type abstraction
|
||||
* ```
|
||||
*/
|
||||
abstract class TypeAbstraction extends AstNode {
|
||||
abstract TypeParameter getATypeParameter();
|
||||
}
|
||||
|
||||
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
|
||||
override TypeParamTypeParameter getATypeParameter() {
|
||||
result.getTypeParam() = this.getGenericParamList().getATypeParam()
|
||||
}
|
||||
}
|
||||
|
||||
final class DynTypeAbstraction extends TypeAbstraction, DynTraitTypeRepr {
|
||||
override TypeParameter getATypeParameter() {
|
||||
result = any(DynTraitTypeParameter tp | tp.getTrait() = this.getTrait()).getTraitTypeParameter()
|
||||
}
|
||||
}
|
||||
|
||||
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
|
||||
override TypeParameter getATypeParameter() {
|
||||
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
|
||||
or
|
||||
result.(AssociatedTypeTypeParameter).getTrait() = this
|
||||
or
|
||||
result.(SelfTypeParameter).getTrait() = this
|
||||
}
|
||||
}
|
||||
|
||||
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
|
||||
override TypeParameter getATypeParameter() { none() }
|
||||
}
|
||||
|
||||
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
|
||||
SelfTypeBoundTypeAbstraction() { any(TraitTypeAbstraction trait).getName() = this }
|
||||
|
||||
override TypeParameter getATypeParameter() { none() }
|
||||
}
|
||||
|
||||
final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr {
|
||||
override TypeParameter getATypeParameter() {
|
||||
implTraitTypeParam(this, _, result.(TypeParamTypeParameter).getTypeParam())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t` is a valid complex [`self` root type][1].
|
||||
*
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
private import rust
|
||||
private import codeql.rust.elements.internal.generated.Raw
|
||||
private import codeql.rust.elements.internal.generated.Synth
|
||||
private import Type
|
||||
|
||||
/**
|
||||
* A type abstraction. I.e., a place in the program where type variables are
|
||||
* introduced.
|
||||
*
|
||||
* Example:
|
||||
* ```rust
|
||||
* impl<A, B> Foo<A, B> { }
|
||||
* // ^^^^^^ a type abstraction
|
||||
* ```
|
||||
*/
|
||||
abstract class TypeAbstraction extends AstNode {
|
||||
abstract TypeParameter getATypeParameter();
|
||||
}
|
||||
|
||||
final class ImplTypeAbstraction extends TypeAbstraction, Impl {
|
||||
override TypeParamTypeParameter getATypeParameter() {
|
||||
result.getTypeParam() = this.getGenericParamList().getATypeParam()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate idDynTraitTypeRepr(Raw::DynTraitTypeRepr x, Raw::DynTraitTypeRepr y) { x = y }
|
||||
|
||||
private predicate idOfDynTraitTypeRepr(Raw::DynTraitTypeRepr x, int y) =
|
||||
equivalenceRelation(idDynTraitTypeRepr/2)(x, y)
|
||||
|
||||
private int idOfDynTraitTypeRepr(DynTraitTypeRepr node) {
|
||||
idOfDynTraitTypeRepr(Synth::convertAstNodeToRaw(node), result)
|
||||
}
|
||||
|
||||
/** Holds if `dt` is the (arbitrarily chosen) canonical dyn trait type abstraction for `trait`. */
|
||||
private predicate canonicalDynTraitTypeAbstraction(DynTraitTypeRepr dt) {
|
||||
exists(Trait trait |
|
||||
dt = min(DynTraitTypeRepr d | d.getTrait() = trait | d order by idOfDynTraitTypeRepr(d))
|
||||
)
|
||||
}
|
||||
|
||||
final class DynTypeAbstraction extends TypeAbstraction, DynTraitTypeRepr {
|
||||
DynTypeAbstraction() {
|
||||
// We pick a "canonical" `dyn Trait` in order to avoid including multiple
|
||||
// entries in `conditionSatisfiesConstraint` with the exact same effect when
|
||||
// `dyn Trait` occurs multiple times for the same trait.
|
||||
canonicalDynTraitTypeAbstraction(this)
|
||||
}
|
||||
|
||||
override TypeParameter getATypeParameter() {
|
||||
result = any(DynTraitTypeParameter tp | tp.getTrait() = this.getTrait()).getTraitTypeParameter()
|
||||
}
|
||||
}
|
||||
|
||||
final class TraitTypeAbstraction extends TypeAbstraction, Trait {
|
||||
override TypeParameter getATypeParameter() {
|
||||
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
|
||||
or
|
||||
result.(AssociatedTypeTypeParameter).getTrait() = this
|
||||
or
|
||||
result.(SelfTypeParameter).getTrait() = this
|
||||
}
|
||||
}
|
||||
|
||||
final class TypeBoundTypeAbstraction extends TypeAbstraction, TypeBound {
|
||||
override TypeParameter getATypeParameter() { none() }
|
||||
}
|
||||
|
||||
final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name {
|
||||
SelfTypeBoundTypeAbstraction() { any(TraitTypeAbstraction trait).getName() = this }
|
||||
|
||||
override TypeParameter getATypeParameter() { none() }
|
||||
}
|
||||
|
||||
final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr {
|
||||
override TypeParamTypeParameter getATypeParameter() {
|
||||
exists(TImplTraitTypeParameter(this, result.getTypeParam()))
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ private import codeql.util.Option
|
||||
private import rust
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import Type
|
||||
private import TypeAbstraction
|
||||
private import TypeAbstraction as TA
|
||||
private import Type as T
|
||||
private import TypeMention
|
||||
private import codeql.rust.internal.typeinference.DerefChain
|
||||
@@ -37,7 +39,7 @@ private module Input1 implements InputSig1<Location> {
|
||||
|
||||
class TypeParameter = T::TypeParameter;
|
||||
|
||||
class TypeAbstraction = T::TypeAbstraction;
|
||||
class TypeAbstraction = TA::TypeAbstraction;
|
||||
|
||||
class TypeArgumentPosition extends TTypeArgumentPosition {
|
||||
int asMethodTypeArgumentPosition() { this = TMethodTypeArgumentPosition(result) }
|
||||
@@ -90,7 +92,7 @@ private module Input1 implements InputSig1<Location> {
|
||||
tp =
|
||||
rank[result](TypeParameter tp0, int kind, int id1, int id2 |
|
||||
kind = 1 and
|
||||
id1 = 0 and
|
||||
id1 = idOfTypeParameterAstNode(tp0.(DynTraitTypeParameter).getTrait()) and
|
||||
id2 =
|
||||
idOfTypeParameterAstNode([
|
||||
tp0.(DynTraitTypeParameter).getTypeParam().(AstNode),
|
||||
@@ -102,10 +104,13 @@ private module Input1 implements InputSig1<Location> {
|
||||
id2 = idOfTypeParameterAstNode(tp0.(ImplTraitTypeParameter).getTypeParam())
|
||||
or
|
||||
kind = 3 and
|
||||
id1 = idOfTypeParameterAstNode(tp0.(AssociatedTypeTypeParameter).getTrait()) and
|
||||
id2 = idOfTypeParameterAstNode(tp0.(AssociatedTypeTypeParameter).getTypeAlias())
|
||||
or
|
||||
kind = 4 and
|
||||
id1 = 0 and
|
||||
exists(AstNode node | id2 = idOfTypeParameterAstNode(node) |
|
||||
node = tp0.(TypeParamTypeParameter).getTypeParam() or
|
||||
node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or
|
||||
node = tp0.(SelfTypeParameter).getTrait() or
|
||||
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
|
||||
)
|
||||
@@ -1284,6 +1289,13 @@ private class BorrowKind extends TBorrowKind {
|
||||
}
|
||||
}
|
||||
|
||||
// for now, we do not handle ambiguous targets when one of the types is itself
|
||||
// a constrained type parameter; we should be checking the constraints in this case
|
||||
private predicate typeCanBeUsedForDisambiguation(Type t) {
|
||||
not t instanceof TypeParameter or
|
||||
t.(TypeParamTypeParameter).getTypeParam() = any(TypeParam tp | not tp.hasTypeBound())
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides logic for resolving calls to methods.
|
||||
*
|
||||
@@ -2188,8 +2200,6 @@ private module MethodResolution {
|
||||
exists(mc) and
|
||||
constraint.(TraitType).getTrait() instanceof DerefTrait
|
||||
}
|
||||
|
||||
predicate useUniversalConditions() { none() }
|
||||
}
|
||||
|
||||
private module MethodCallSatisfiesDerefConstraint =
|
||||
@@ -2229,7 +2239,8 @@ private module MethodResolution {
|
||||
methodCallBlanketLikeCandidate(mc, _, 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)
|
||||
// (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())
|
||||
|
|
||||
borrow.isNoBorrow()
|
||||
@@ -2379,10 +2390,7 @@ private module MethodResolution {
|
||||
exists(TypePath path, Type t0 |
|
||||
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) and
|
||||
t.appliesTo(f, i, pos) and
|
||||
// for now, we do not handle ambiguous targets when one of the types it iself
|
||||
// a type parameter; we should be checking the constraints on that type parameter
|
||||
// in this case
|
||||
not t0 instanceof TypeParameter
|
||||
typeCanBeUsedForDisambiguation(t0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2741,7 +2749,7 @@ private module NonMethodResolution {
|
||||
* Gets the blanket function that this call may resolve to, if any.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
|
||||
NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
|
||||
exists(string name |
|
||||
this.hasNameAndArity(pragma[only_bind_into](name), _) and
|
||||
ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and
|
||||
@@ -2756,12 +2764,11 @@ private module NonMethodResolution {
|
||||
predicate hasTrait() { exists(this.getTrait()) }
|
||||
|
||||
pragma[nomagic]
|
||||
NonMethodFunction resolveAssocCallTargetCand(ImplItemNode i) {
|
||||
NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) {
|
||||
not this.hasTrait() and
|
||||
result = this.getPathResolutionResolved() and
|
||||
result = i.getASuccessor(_)
|
||||
or
|
||||
result = this.resolveCallTargetBlanketCand(i)
|
||||
result = i.getASuccessor(_) and
|
||||
FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
|
||||
}
|
||||
|
||||
AstNode getNodeAt(FunctionPosition pos) {
|
||||
@@ -2793,6 +2800,21 @@ private module NonMethodResolution {
|
||||
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.resolveCallTargetBlanketLikeCandidate(_, _, _, _) and
|
||||
not exists(this.resolveCallTargetViaPathResolution()) and
|
||||
forall(ImplOrTraitItemNode i, Function f |
|
||||
this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
|
||||
|
|
||||
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of this call, which can be resolved using only path resolution.
|
||||
*/
|
||||
@@ -2811,7 +2833,9 @@ private module NonMethodResolution {
|
||||
result = this.resolveCallTargetBlanketCand(i) and
|
||||
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
|
||||
or
|
||||
NonMethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result)
|
||||
NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result)
|
||||
or
|
||||
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2850,7 +2874,12 @@ private module NonMethodResolution {
|
||||
) {
|
||||
exists(NonMethodCall fc, FunctionPosition pos |
|
||||
fcp = MkCallAndBlanketPos(fc, pos) and
|
||||
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam)
|
||||
fc.resolveCallTargetBlanketLikeCandidate(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())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2885,37 +2914,24 @@ private module NonMethodResolution {
|
||||
private module ArgIsInstantiationOfBlanketParam =
|
||||
ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>;
|
||||
|
||||
private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig {
|
||||
private module NonMethodArgsAreInstantiationsOfBlanketInput implements
|
||||
ArgsAreInstantiationsOfInputSig
|
||||
{
|
||||
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
|
||||
t.appliesTo(f, i, pos) and
|
||||
(
|
||||
exists(Type t0 |
|
||||
// for now, we do not handle ambiguous targets when one of the types it iself
|
||||
// a type parameter; we should be checking the constraints on that type parameter
|
||||
// in this case
|
||||
not t0 instanceof TypeParameter
|
||||
|
|
||||
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
|
||||
or
|
||||
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
|
||||
)
|
||||
exists(Type t0 | typeCanBeUsedForDisambiguation(t0) |
|
||||
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
|
||||
or
|
||||
// match against the trait function itself
|
||||
exists(Trait trait |
|
||||
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
|
||||
TSelfTypeParameter(trait))
|
||||
)
|
||||
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
|
||||
)
|
||||
}
|
||||
|
||||
class Call extends NonMethodCall {
|
||||
final class Call extends NonMethodCall {
|
||||
Type getArgType(FunctionPosition pos, TypePath path) {
|
||||
result = inferType(this.getNodeAt(pos), path)
|
||||
}
|
||||
|
||||
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
|
||||
f = this.resolveAssocCallTargetCand(i)
|
||||
or
|
||||
predicate hasTraitResolvedCand(ImplOrTraitItemNode i, Function f) {
|
||||
exists(TraitItemNode trait, NonMethodFunction resolved, ImplItemNode i1, Function f1 |
|
||||
this.hasTraitResolved(trait, resolved) and
|
||||
traitFunctionDependsOnPos(trait, resolved, _, _, i1, f1)
|
||||
@@ -2927,11 +2943,45 @@ private module NonMethodResolution {
|
||||
i = trait
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
|
||||
f = this.resolveCallTargetBlanketCand(i)
|
||||
or
|
||||
this.hasTraitResolvedCand(i, f) and
|
||||
BlanketImplementation::isBlanketLike(i, _, _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module NonMethodArgsAreInstantiationsOf =
|
||||
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfInput>;
|
||||
private module NonMethodArgsAreInstantiationsOfBlanket =
|
||||
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfBlanketInput>;
|
||||
|
||||
private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements
|
||||
ArgsAreInstantiationsOfInputSig
|
||||
{
|
||||
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
|
||||
NonMethodArgsAreInstantiationsOfBlanketInput::toCheck(i, f, pos, t)
|
||||
or
|
||||
// match against the trait function itself
|
||||
t.appliesTo(f, i, pos) and
|
||||
exists(Trait trait |
|
||||
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
|
||||
TSelfTypeParameter(trait))
|
||||
)
|
||||
}
|
||||
|
||||
class Call extends NonMethodArgsAreInstantiationsOfBlanketInput::Call {
|
||||
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
|
||||
f = this.resolveCallTargetNonBlanketCand(i)
|
||||
or
|
||||
this.hasTraitResolvedCand(i, f) and
|
||||
not BlanketImplementation::isBlanketLike(i, _, _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module NonMethodArgsAreInstantiationsOfNonBlanket =
|
||||
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfNonBlanketInput>;
|
||||
}
|
||||
|
||||
abstract private class TupleLikeConstructor extends Addressable {
|
||||
@@ -3507,12 +3557,12 @@ private DynTraitType getFutureTraitType() { result.getTrait() instanceof FutureT
|
||||
|
||||
pragma[nomagic]
|
||||
private AssociatedTypeTypeParameter getFutureOutputTypeParameter() {
|
||||
result.getTypeAlias() = any(FutureTrait ft).getOutputType()
|
||||
result = getAssociatedTypeTypeParameter(any(FutureTrait ft).getOutputType())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DynTraitTypeParameter getDynFutureOutputTypeParameter() {
|
||||
result = TDynTraitTypeParameter(any(FutureTrait ft).getOutputType())
|
||||
result.getTraitTypeParameter() = getFutureOutputTypeParameter()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -3561,8 +3611,6 @@ private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintInput
|
||||
exists(term) and
|
||||
constraint.(TraitType).getTrait() instanceof FutureTrait
|
||||
}
|
||||
|
||||
predicate useUniversalConditions() { none() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -3759,18 +3807,16 @@ private module ForIterableSatisfiesConstraintInput implements
|
||||
t instanceof IntoIteratorTrait
|
||||
)
|
||||
}
|
||||
|
||||
predicate useUniversalConditions() { none() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private AssociatedTypeTypeParameter getIteratorItemTypeParameter() {
|
||||
result.getTypeAlias() = any(IteratorTrait t).getItemType()
|
||||
result = getAssociatedTypeTypeParameter(any(IteratorTrait t).getItemType())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private AssociatedTypeTypeParameter getIntoIteratorItemTypeParameter() {
|
||||
result.getTypeAlias() = any(IntoIteratorTrait t).getItemType()
|
||||
result = getAssociatedTypeTypeParameter(any(IntoIteratorTrait t).getItemType())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -3812,8 +3858,6 @@ private module InvokedClosureSatisfiesConstraintInput implements
|
||||
exists(term) and
|
||||
constraint.(TraitType).getTrait() instanceof FnOnceTrait
|
||||
}
|
||||
|
||||
predicate useUniversalConditions() { none() }
|
||||
}
|
||||
|
||||
/** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */
|
||||
@@ -3822,22 +3866,35 @@ private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) {
|
||||
_, path, result)
|
||||
}
|
||||
|
||||
/** Gets the path to a closure's return type. */
|
||||
private TypePath closureReturnPath() {
|
||||
result = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
/**
|
||||
* Gets the root type of a closure.
|
||||
*
|
||||
* We model closures as `dyn Fn` trait object types. A closure might implement
|
||||
* only `Fn`, `FnMut`, or `FnOnce`. But since `Fn` is a subtrait of the others,
|
||||
* giving closures the type `dyn Fn` works well in practice -- even if not
|
||||
* entirely accurate.
|
||||
*/
|
||||
private DynTraitType closureRootType() {
|
||||
result = TDynTraitType(any(FnTrait t)) // always exists because of the mention in `builtins/mentions.rs`
|
||||
}
|
||||
|
||||
/** Gets the path to a closure with arity `arity`s `index`th parameter type. */
|
||||
/** Gets the path to a closure's return type. */
|
||||
private TypePath closureReturnPath() {
|
||||
result =
|
||||
TypePath::singleton(TDynTraitTypeParameter(any(FnTrait t), any(FnOnceTrait t).getOutputType()))
|
||||
}
|
||||
|
||||
/** Gets the path to a closure with arity `arity`'s `index`th parameter type. */
|
||||
pragma[nomagic]
|
||||
private TypePath closureParameterPath(int arity, int index) {
|
||||
result =
|
||||
TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()),
|
||||
TypePath::cons(TDynTraitTypeParameter(_, any(FnTrait t).getTypeParam()),
|
||||
TypePath::singleton(getTupleTypeParameter(arity, index)))
|
||||
}
|
||||
|
||||
/** Gets the path to the return type of the `FnOnce` trait. */
|
||||
private TypePath fnReturnPath() {
|
||||
result = TypePath::singleton(TAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
result = TypePath::singleton(getAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3869,9 +3926,7 @@ private Type inferDynamicCallExprType(Expr n, TypePath path) {
|
||||
or
|
||||
// _If_ the invoked expression has the type of a closure, then we propagate
|
||||
// the surrounding types into the closure.
|
||||
exists(int arity, TypePath path0 |
|
||||
ce.getTypeAt(TypePath::nil()).(DynTraitType).getTrait() instanceof FnOnceTrait
|
||||
|
|
||||
exists(int arity, TypePath path0 | ce.getTypeAt(TypePath::nil()) = closureRootType() |
|
||||
// Propagate the type of arguments to the parameter types of closure
|
||||
exists(int index, ArgList args |
|
||||
n = ce and
|
||||
@@ -3895,10 +3950,10 @@ private Type inferClosureExprType(AstNode n, TypePath path) {
|
||||
exists(ClosureExpr ce |
|
||||
n = ce and
|
||||
path.isEmpty() and
|
||||
result = TDynTraitType(any(FnOnceTrait t)) // always exists because of the mention in `builtins/mentions.rs`
|
||||
result = closureRootType()
|
||||
or
|
||||
n = ce and
|
||||
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
|
||||
path = TypePath::singleton(TDynTraitTypeParameter(_, any(FnTrait t).getTypeParam())) and
|
||||
result.(TupleType).getArity() = ce.getNumberOfParams()
|
||||
or
|
||||
// Propagate return type annotation to body
|
||||
|
||||
@@ -18,6 +18,8 @@ query predicate illFormedTypeMention(TypeMention tm) {
|
||||
any(PathTypeMention ptm |
|
||||
exists(ptm.resolvePathTypeAt(TypePath::nil())) and
|
||||
not exists(ptm.resolveType())
|
||||
or
|
||||
ptm.(NonAliasPathTypeMention).getResolved() instanceof TypeAlias
|
||||
) and
|
||||
// Only include inconsistencies in the source, as we otherwise get
|
||||
// inconsistencies from library code in every project.
|
||||
|
||||
@@ -4,6 +4,7 @@ private import rust
|
||||
private import codeql.rust.internal.PathResolution
|
||||
private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import Type
|
||||
private import TypeAbstraction
|
||||
private import TypeInference
|
||||
|
||||
/** An AST node that may mention a type. */
|
||||
@@ -148,30 +149,11 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
|
||||
TypeItemNode getResolved() { result = resolved }
|
||||
|
||||
/**
|
||||
* Gets a type alias with the name `name` of the trait that this path resolves
|
||||
* to, if any.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private TypeAlias getResolvedTraitAlias(string name) {
|
||||
result = resolved.(TraitItemNode).getAnAssocItem() and
|
||||
name = result.getName().getText()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TypeRepr getAssocTypeArg(string name) {
|
||||
private TypeMention getAssocTypeArg(string name) {
|
||||
result = this.getSegment().getGenericArgList().getAssocTypeArg(name)
|
||||
}
|
||||
|
||||
/** Gets the type argument for the associated type `alias`, if any. */
|
||||
pragma[nomagic]
|
||||
private TypeRepr getAnAssocTypeArgument(TypeAlias alias) {
|
||||
exists(string name |
|
||||
alias = this.getResolvedTraitAlias(name) and
|
||||
result = this.getAssocTypeArg(name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type mention that instantiates the implicit `Self` type parameter
|
||||
* for this path, if it occurs in the position of a trait bound.
|
||||
@@ -231,7 +213,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
// associated types of `Fn` and `FnMut` yet.
|
||||
//
|
||||
// [1]: https://doc.rust-lang.org/reference/paths.html#grammar-TypePathFn
|
||||
exists(FnOnceTrait t, PathSegment s |
|
||||
exists(AnyFnTrait t, PathSegment s |
|
||||
t = resolved and
|
||||
s = this.getSegment() and
|
||||
s.hasParenthesizedArgList()
|
||||
@@ -239,7 +221,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
tp = TTypeParamTypeParameter(t.getTypeParam()) and
|
||||
result = s.getParenthesizedArgList().(TypeMention).resolveTypeAt(path)
|
||||
or
|
||||
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
|
||||
tp = TAssociatedTypeTypeParameter(t, any(FnOnceTrait tr).getOutputType()) and
|
||||
(
|
||||
result = s.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
|
||||
or
|
||||
@@ -249,19 +231,47 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
path.isEmpty()
|
||||
)
|
||||
)
|
||||
or
|
||||
// If `path` is the supertrait of a trait block then any associated types
|
||||
// of the supertrait should be instantiated with the subtrait's
|
||||
// corresponding copies.
|
||||
//
|
||||
// As an example, for
|
||||
// ```rust
|
||||
// trait Sub: Super {
|
||||
// // ^^^^^ this
|
||||
// ```
|
||||
// we do something to the effect of:
|
||||
// ```rust
|
||||
// trait Sub: Super<Assoc=Assoc[Sub]>
|
||||
// ```
|
||||
// Where `Assoc` is an associated type of `Super` and `Assoc[Sub]` denotes
|
||||
// the copy of the type parameter inherited by `Sub`.
|
||||
exists(Trait subtrait, TypeAlias alias |
|
||||
subtrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() = this and
|
||||
result = TAssociatedTypeTypeParameter(subtrait, alias) and
|
||||
tp = TAssociatedTypeTypeParameter(resolved, alias) and
|
||||
path.isEmpty()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
bindingset[name]
|
||||
private TypeAlias getResolvedAlias(string name) {
|
||||
result = resolved.(TraitItemNode).getAssocItem(name)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
private TypeAlias getResolvedTraitAssocType(string name) {
|
||||
result = resolved.(TraitItemNode).getASuccessor(name)
|
||||
}
|
||||
|
||||
/** Gets the type mention in this path for the type parameter `tp`, if any. */
|
||||
pragma[nomagic]
|
||||
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
|
||||
exists(TypeAlias alias |
|
||||
result = this.getAnAssocTypeArgument(alias) and
|
||||
tp = TAssociatedTypeTypeParameter(alias)
|
||||
exists(TypeAlias alias, string name |
|
||||
result = this.getAssocTypeArg(name) and
|
||||
tp = TAssociatedTypeTypeParameter(resolved, alias) and
|
||||
alias = this.getResolvedTraitAssocType(name)
|
||||
)
|
||||
or
|
||||
// If `path` is the trait of an `impl` block then any associated types
|
||||
@@ -279,9 +289,9 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
// the rhs. of the type alias is a type argument to the trait.
|
||||
exists(ImplItemNode impl, TypeAlias alias, string name |
|
||||
this = impl.getTraitPath() and
|
||||
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
|
||||
alias = impl.getASuccessor(name) and
|
||||
result = alias.getTypeRepr() and
|
||||
tp = TAssociatedTypeTypeParameter(this.getResolvedAlias(pragma[only_bind_into](name)))
|
||||
tp = TAssociatedTypeTypeParameter(resolved, this.getResolvedAlias(name))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -299,7 +309,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
or
|
||||
result = TTypeParamTypeParameter(resolved)
|
||||
or
|
||||
result = TAssociatedTypeTypeParameter(resolved)
|
||||
result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved)
|
||||
}
|
||||
|
||||
override Type resolvePathTypeAt(TypePath typePath) {
|
||||
@@ -384,9 +394,8 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
|
||||
result = TSelfTypeParameter(this)
|
||||
or
|
||||
exists(TypeAlias alias |
|
||||
alias = super.getAnAssocItem() and
|
||||
typePath = TypePath::singleton(result) and
|
||||
result = TAssociatedTypeTypeParameter(alias)
|
||||
result = TAssociatedTypeTypeParameter(this, alias)
|
||||
)
|
||||
or
|
||||
exists(TypeParam tp |
|
||||
@@ -540,7 +549,7 @@ class DynTraitTypeReprMention extends TypeMention instanceof DynTraitTypeRepr {
|
||||
// impl<A, B, ..> Trait<A, B, ..> for (dyn Trait)<A, B, ..>
|
||||
// ```
|
||||
// To achieve this:
|
||||
// - `DynTypeAbstraction` is an abstraction over type parameters of the trait.
|
||||
// - `DynTypeAbstraction` is an abstraction over the type parameters of the trait.
|
||||
// - `DynTypeBoundListMention` (this class) is a type mention which has `dyn
|
||||
// Trait` at the root and which for every type parameter of `dyn Trait` has the
|
||||
// corresponding type parameter of the trait.
|
||||
@@ -555,7 +564,14 @@ class DynTypeBoundListMention extends TypeMention instanceof TypeBoundList {
|
||||
private Trait trait;
|
||||
|
||||
DynTypeBoundListMention() {
|
||||
exists(DynTraitTypeRepr dyn | this = dyn.getTypeBoundList() and trait = dyn.getTrait())
|
||||
exists(DynTraitTypeRepr dyn |
|
||||
// We only need this type mention when the `dyn Trait` is a type
|
||||
// abstraction, that is, when it's "canonical" and used in
|
||||
// `conditionSatisfiesConstraint`.
|
||||
dyn instanceof DynTypeAbstraction and
|
||||
this = dyn.getTypeBoundList() and
|
||||
trait = dyn.getTrait()
|
||||
)
|
||||
}
|
||||
|
||||
override Type resolveTypeAt(TypePath path) {
|
||||
|
||||
Reference in New Issue
Block a user