Rust: Handle builtin types in path resolution

This commit is contained in:
Tom Hvitved
2025-11-13 13:01:53 +01:00
parent 39720a17ef
commit 46f5d89674
14 changed files with 2618 additions and 2478 deletions

View File

@@ -4,6 +4,7 @@
private import rust
private import codeql.rust.controlflow.CfgNodes
private import codeql.rust.frameworks.stdlib.Builtins
private import DataFlowImpl
/**
@@ -36,7 +37,11 @@ class TupleFieldContent extends FieldContent, TTupleFieldContent {
/** Holds if this field belongs to a struct. */
predicate isStructField(Struct s, int pos) { field.isStructField(s, pos) }
override FieldExprCfgNode getAnAccess() { field = result.getFieldExpr().getTupleField() }
override FieldExprCfgNode getAnAccess() {
field = result.getFieldExpr().getTupleField() and
// tuples are handled using the special `TupleContent` type
not field = any(TupleType tt).getATupleField()
}
final override string toString() {
exists(Variant v, int pos, string vname |

View File

@@ -32,10 +32,16 @@ module Impl {
result.getName().getText() = name
}
/** Gets a record field, if any. */
StructField getAStructField() { result = this.getStructField(_) }
/** Gets the `i`th tuple field, if any. */
pragma[nomagic]
TupleField getTupleField(int i) { result = this.getFieldList().(TupleFieldList).getField(i) }
/** Gets a tuple field, if any. */
TupleField getATupleField() { result = this.getTupleField(_) }
/** Holds if this struct uses tuple fields. */
pragma[nomagic]
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }

View File

@@ -136,3 +136,36 @@ class F32 extends FloatingPointTypeImpl {
class F64 extends FloatingPointTypeImpl {
F64() { this.getName() = "f64" }
}
/** The builtin slice type `[T]`. */
class SliceType extends BuiltinType {
SliceType() { this.getName() = "Slice" }
}
/** The builtin array type `[T; N]`. */
class ArrayType extends BuiltinType {
ArrayType() { this.getName() = "Array" }
}
/** The builtin reference type `&T` or `&mut T`. */
class RefType extends BuiltinType {
RefType() { this.getName() = "Ref" }
}
/** The builtin pointer type `*const T` or `*mut T`. */
class PtrType extends BuiltinType {
PtrType() { this.getName() = "Ptr" }
}
/** A builtin tuple type `(T1, T2, ...)`. */
class TupleType extends BuiltinType {
TupleType() { this.getName().matches("Tuple%") }
/** Gets the arity of this tuple type. */
int getArity() {
not this.hasGenericParamList() and
result = 0
or
result = this.getGenericParamList().getNumberOfGenericParams()
}
}

View File

@@ -713,12 +713,34 @@ abstract class ImplOrTraitItemNode extends ItemNode {
predicate hasAssocItem(string name) { name = this.getAnAssocItem().getName() }
}
private TypeItemNode resolveBuiltin(TypeRepr tr) {
tr instanceof SliceTypeRepr and
result instanceof Builtins::SliceType
or
tr instanceof ArrayTypeRepr and
result instanceof Builtins::ArrayType
or
tr instanceof RefTypeRepr and
result instanceof Builtins::RefType
or
tr instanceof PtrTypeRepr and
result instanceof Builtins::PtrType
or
result.(Builtins::TupleType).getArity() = tr.(TupleTypeRepr).getNumberOfFields()
}
final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
Path getSelfPath() { result = super.getSelfTy().(PathTypeRepr).getPath() }
Path getTraitPath() { result = super.getTrait().(PathTypeRepr).getPath() }
TypeItemNode resolveSelfTy() { result = resolvePath(this.getSelfPath()) }
TypeItemNode resolveSelfTyBuiltin() { result = resolveBuiltin(this.(Impl).getSelfTy()) }
TypeItemNode resolveSelfTy() {
result = resolvePath(this.getSelfPath())
or
result = this.resolveSelfTyBuiltin()
}
TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) }
@@ -893,7 +915,11 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
}
private class ImplItemNodeImpl extends ImplItemNode {
TypeItemNode resolveSelfTyCand() { result = resolvePathCand(this.getSelfPath()) }
TypeItemNode resolveSelfTyCand() {
result = resolvePathCand(this.getSelfPath())
or
result = this.resolveSelfTyBuiltin()
}
TraitItemNode resolveTraitTyCand() { result = resolvePathCand(this.getTraitPath()) }
}
@@ -1764,6 +1790,10 @@ private ItemNode resolvePathCand0(RelevantPath path, Namespace ns) {
or
result = resolveUseTreeListItem(_, _, path, _) and
ns = result.getNamespace()
or
result = resolveBuiltin(path.getSegment().getTypeRepr()) and
not path.getSegment().hasTraitTypeRepr() and
ns.isType()
}
pragma[nomagic]
@@ -2141,7 +2171,9 @@ pragma[nomagic]
private predicate builtin(string name, ItemNode i) {
exists(BuiltinSourceFile builtins |
builtins.getFile().getBaseName() = "types.rs" and
i = builtins.getASuccessor(name)
i = builtins.getASuccessor(name) and
not name = ["Slice", "Array", "Ref", "Ptr"] and
not name.matches("Tuple%")
)
}

View File

@@ -7,6 +7,7 @@ private import codeql.rust.internal.CachedStages
private import codeql.rust.elements.internal.generated.Raw
private import codeql.rust.elements.internal.generated.Synth
private import codeql.rust.frameworks.stdlib.Stdlib
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
/**
* Holds if a dyn trait type should have a type parameter associated with `n`. A
@@ -31,39 +32,21 @@ private predicate dynTraitTypeParameter(Trait trait, AstNode n) {
cached
newtype TType =
TTuple(int arity) {
arity =
[
any(TupleTypeRepr t).getNumberOfFields(),
any(TupleExpr e).getNumberOfFields(),
any(TuplePat p).getNumberOfFields()
] and
Stages::TypeInferenceStage::ref()
} or
TStruct(Struct s) or
TStruct(Struct s) { Stages::TypeInferenceStage::ref() } or
TEnum(Enum e) or
TTrait(Trait t) or
TUnion(Union u) or
TArrayType() or // todo: add size?
TRefType() or // todo: add mut?
TImplTraitType(ImplTraitTypeRepr impl) or
TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or
TSliceType() or
TNeverType() or
TPtrType() or
TUnknownType() or
TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or
TTypeParamTypeParameter(TypeParam t) or
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
TArrayTypeParameter() or
TDynTraitTypeParameter(AstNode n) { dynTraitTypeParameter(_, n) } or
TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) {
implTraitTypeParam(implTrait, _, tp)
} or
TRefTypeParameter() or
TSelfTypeParameter(Trait t) or
TSliceTypeParameter() or
TPtrTypeParameter()
TSelfTypeParameter(Trait t)
private predicate implTraitTypeParam(ImplTraitTypeRepr implTrait, int i, TypeParam tp) {
implTrait.isInReturnPos() and
@@ -106,26 +89,25 @@ abstract class Type extends TType {
}
/** A tuple type `(T, ...)`. */
class TupleType extends Type, TTuple {
class TupleType extends StructType {
private int arity;
TupleType() { this = TTuple(arity) }
override TypeParameter getPositionalTypeParameter(int i) {
result = TTupleTypeParameter(arity, i)
}
TupleType() { arity = this.getStruct().(Builtins::TupleType).getArity() }
/** Gets the arity of this tuple type. */
int getArity() { result = arity }
override string toString() { result = "(T_" + arity + ")" }
}
override Location getLocation() { result instanceof EmptyLocation }
pragma[nomagic]
TypeParamTypeParameter getTupleTypeParameter(int arity, int i) {
result = any(TupleType t | t.getArity() = arity).getPositionalTypeParameter(i)
}
/** The unit type `()`. */
class UnitType extends TupleType {
UnitType() { this = TTuple(0) }
UnitType() { this.getArity() = 0 }
override string toString() { result = "()" }
}
@@ -229,17 +211,15 @@ class UnionType extends Type, TUnion {
* Array types like `[i64; 5]` are modeled as normal generic types
* with a single type argument.
*/
class ArrayType extends Type, TArrayType {
ArrayType() { this = TArrayType() }
class ArrayType extends StructType {
ArrayType() { this.getStruct() instanceof Builtins::ArrayType }
override TypeParameter getPositionalTypeParameter(int i) {
result = TArrayTypeParameter() and
i = 0
}
override string toString() { result = "[;]" }
}
override string toString() { result = "[]" }
override Location getLocation() { result instanceof EmptyLocation }
pragma[nomagic]
TypeParamTypeParameter getArrayTypeParameter() {
result = any(ArrayType t).getPositionalTypeParameter(0)
}
/**
@@ -248,17 +228,15 @@ class ArrayType extends Type, TArrayType {
* Reference types like `& i64` are modeled as normal generic types
* with a single type argument.
*/
class RefType extends Type, TRefType {
RefType() { this = TRefType() }
override TypeParameter getPositionalTypeParameter(int i) {
result = TRefTypeParameter() and
i = 0
}
class RefType extends StructType {
RefType() { this.getStruct() instanceof Builtins::RefType }
override string toString() { result = "&" }
}
override Location getLocation() { result instanceof EmptyLocation }
pragma[nomagic]
TypeParamTypeParameter getRefTypeParameter() {
result = any(RefType t).getPositionalTypeParameter(0)
}
/**
@@ -340,17 +318,15 @@ class ImplTraitReturnType extends ImplTraitType {
* Slice types like `[i64]` are modeled as normal generic types
* with a single type argument.
*/
class SliceType extends Type, TSliceType {
SliceType() { this = TSliceType() }
override TypeParameter getPositionalTypeParameter(int i) {
result = TSliceTypeParameter() and
i = 0
}
class SliceType extends StructType {
SliceType() { this.getStruct() instanceof Builtins::SliceType }
override string toString() { result = "[]" }
}
override Location getLocation() { result instanceof EmptyLocation }
pragma[nomagic]
TypeParamTypeParameter getSliceTypeParameter() {
result = any(SliceType t).getPositionalTypeParameter(0)
}
class NeverType extends Type, TNeverType {
@@ -361,11 +337,8 @@ class NeverType extends Type, TNeverType {
override Location getLocation() { result instanceof EmptyLocation }
}
class PtrType extends Type, TPtrType {
override TypeParameter getPositionalTypeParameter(int i) {
i = 0 and
result = TPtrTypeParameter()
}
class PtrType extends StructType {
PtrType() { this.getStruct() instanceof Builtins::PtrType }
override string toString() { result = "*" }
@@ -402,6 +375,11 @@ class UnknownType extends Type, TUnknownType {
override Location getLocation() { result instanceof EmptyLocation }
}
pragma[nomagic]
TypeParamTypeParameter getPtrTypeParameter() {
result = any(PtrType t).getPositionalTypeParameter(0)
}
/** A type parameter. */
abstract class TypeParameter extends Type {
override TypeParameter getPositionalTypeParameter(int i) { none() }
@@ -423,7 +401,32 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
TypeParam getTypeParam() { result = typeParam }
override string toString() { result = typeParam.toString() }
override string toString() {
this = any(SliceType st).getATypeParameter() and
result = "[T]"
or
this = any(ArrayType at).getATypeParameter() and
result = "[T;...]"
or
this = any(RefType rt).getATypeParameter() and
result = "&T"
or
this = any(PtrType pt).getATypeParameter() and
result = "*T"
or
exists(TupleType tt, int arity, int i |
this = tt.getPositionalTypeParameter(i) and
arity = tt.getArity() and
result = i + "(" + arity + ")"
)
or
not this = any(SliceType st).getATypeParameter() and
not this = any(ArrayType at).getATypeParameter() and
not this = any(RefType rt).getATypeParameter() and
not this = any(PtrType pt).getATypeParameter() and
not this = any(TupleType tt).getATypeParameter() and
result = typeParam.toString()
}
override Location getLocation() { result = typeParam.getLocation() }
}
@@ -461,37 +464,6 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
override Location getLocation() { result = typeAlias.getLocation() }
}
/**
* A tuple type parameter. For instance the `T` in `(T, U)`.
*
* Since tuples are structural their type parameters can be represented as their
* positional index. The type inference library requires that type parameters
* belong to a single type, so we also include the arity of the tuple type.
*/
class TupleTypeParameter extends TypeParameter, TTupleTypeParameter {
private int arity;
private int index;
TupleTypeParameter() { this = TTupleTypeParameter(arity, index) }
override string toString() { result = index.toString() + "(" + arity + ")" }
override Location getLocation() { result instanceof EmptyLocation }
/** Gets the index of this tuple type parameter. */
int getIndex() { result = index }
/** Gets the tuple type that corresponds to this tuple type parameter. */
TupleType getTupleType() { result = TTuple(arity) }
}
/** An implicit array type parameter. */
class ArrayTypeParameter extends TypeParameter, TArrayTypeParameter {
override string toString() { result = "[T;...]" }
override Location getLocation() { result instanceof EmptyLocation }
}
class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
private AstNode n;
@@ -539,26 +511,6 @@ class ImplTraitTypeParameter extends TypeParameter, TImplTraitTypeParameter {
override Location getLocation() { result = typeParam.getLocation() }
}
/** An implicit reference type parameter. */
class RefTypeParameter extends TypeParameter, TRefTypeParameter {
override string toString() { result = "&T" }
override Location getLocation() { result instanceof EmptyLocation }
}
/** An implicit slice type parameter. */
class SliceTypeParameter extends TypeParameter, TSliceTypeParameter {
override string toString() { result = "[T]" }
override Location getLocation() { result instanceof EmptyLocation }
}
class PtrTypeParameter extends TypeParameter, TPtrTypeParameter {
override string toString() { result = "*T" }
override Location getLocation() { result instanceof EmptyLocation }
}
/**
* The implicit `Self` type parameter of a trait, that refers to the
* implementing type of the trait.

View File

@@ -87,26 +87,6 @@ private module Input1 implements InputSig1<Location> {
int getTypeParameterId(TypeParameter tp) {
tp =
rank[result](TypeParameter tp0, int kind, int id1, int id2 |
tp0 instanceof ArrayTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 0
or
tp0 instanceof RefTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 1
or
tp0 instanceof SliceTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 2
or
tp0 instanceof PtrTypeParameter and
kind = 0 and
id1 = 0 and
id2 = 3
or
kind = 1 and
id1 = 0 and
id2 =
@@ -127,10 +107,6 @@ private module Input1 implements InputSig1<Location> {
node = tp0.(SelfTypeParameter).getTrait() or
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
)
or
kind = 4 and
id1 = tp0.(TupleTypeParameter).getTupleType().getArity() and
id2 = tp0.(TupleTypeParameter).getIndex()
|
tp0 order by kind, id1, id2
)
@@ -421,7 +397,9 @@ module CertainTypeInference {
any(IdentPat ip |
n2 = ip.getName() and
prefix1.isEmpty() and
if ip.isRef() then prefix2 = TypePath::singleton(TRefTypeParameter()) else prefix2.isEmpty()
if ip.isRef()
then prefix2 = TypePath::singleton(getRefTypeParameter())
else prefix2.isEmpty()
)
}
@@ -631,11 +609,11 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
n1 = n2.(RefPat).getPat()
) and
prefix1.isEmpty() and
prefix2 = TypePath::singleton(TRefTypeParameter())
prefix2 = TypePath::singleton(getRefTypeParameter())
or
exists(int i, int arity |
prefix1.isEmpty() and
prefix2 = TypePath::singleton(TTupleTypeParameter(arity, i))
prefix2 = TypePath::singleton(getTupleTypeParameter(arity, i))
|
arity = n2.(TupleExpr).getNumberOfFields() and
n1 = n2.(TupleExpr).getField(i)
@@ -663,12 +641,12 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
ale.getAnExpr() = n2 and
ale.getNumberOfExprs() = 1
) and
prefix1 = TypePath::singleton(TArrayTypeParameter()) and
prefix1 = TypePath::singleton(getArrayTypeParameter()) and
prefix2.isEmpty()
or
// an array repeat expression (`[1; 3]`) has the type of the repeat operand
n1.(ArrayRepeatExpr).getRepeatOperand() = n2 and
prefix1 = TypePath::singleton(TArrayTypeParameter()) and
prefix1 = TypePath::singleton(getArrayTypeParameter()) and
prefix2.isEmpty()
or
exists(Struct s |
@@ -717,7 +695,7 @@ private predicate lubCoercion(AstNode parent, AstNode child, TypePath prefix) {
child = ale.getAnExpr() and
ale.getNumberOfExprs() > 1
) and
prefix = TypePath::singleton(TArrayTypeParameter())
prefix = TypePath::singleton(getArrayTypeParameter())
or
bodyReturns(parent, child) and
strictcount(Expr e | bodyReturns(parent, e)) > 1 and
@@ -956,9 +934,9 @@ private predicate inferStructExprType =
ContextTyping::CheckContextTyping<inferStructExprType0/3>::check/2;
pragma[nomagic]
private Type inferTupleRootType(AstNode n) {
private TupleType inferTupleRootType(AstNode n) {
// `typeEquality` handles the non-root cases
result = TTuple([n.(TupleExpr).getNumberOfFields(), n.(TuplePat).getTupleArity()])
result.getArity() = [n.(TupleExpr).getNumberOfFields(), n.(TuplePat).getTupleArity()]
}
pragma[nomagic]
@@ -1191,7 +1169,7 @@ private module MethodResolution {
*
* `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 `TRefTypeParameter()`
* if `m` has a `&self` parameter, then `strippedTypePath` is `getRefTypeParameter()`
* and `strippedType` is the type inside the reference.
*/
pragma[nomagic]
@@ -1401,7 +1379,7 @@ private module MethodResolution {
this.hasNoCompatibleTargetBorrow(derefChain0) and
t0 = this.getACandidateReceiverTypeAtNoBorrow(derefChain0, path0)
|
path0.isCons(TRefTypeParameter(), path) and
path0.isCons(getRefTypeParameter(), path) and
result = t0 and
derefChain = derefChain0 + ".ref"
or
@@ -1583,11 +1561,11 @@ private module MethodResolution {
borrow = true and
(
path.isEmpty() and
result = TRefType()
result instanceof RefType
or
exists(TypePath suffix |
result = this.getACandidateReceiverTypeAtNoBorrow(derefChain, suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix)
path = TypePath::cons(getRefTypeParameter(), suffix)
)
)
}
@@ -1706,12 +1684,12 @@ private module MethodResolution {
override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) {
if this.(Call).implicitBorrowAt(pos, true)
then
result = TRefType() and
result instanceof RefType and
path.isEmpty()
or
exists(TypePath path0 |
result = inferType(this.getArgument(pos), path0) and
path = TypePath::cons(TRefTypeParameter(), path0)
path = TypePath::cons(getRefTypeParameter(), path0)
)
else result = inferType(this.getArgument(pos), path)
}
@@ -1854,7 +1832,7 @@ private module MethodResolution {
|
mcc.hasNoBorrow()
or
blanketPath.getHead() = TRefTypeParameter()
blanketPath.getHead() = getRefTypeParameter()
)
}
}
@@ -2133,11 +2111,11 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
this instanceof IndexExpr
then
path.isEmpty() and
result = TRefType()
result instanceof RefType
or
exists(TypePath suffix |
result = inferType(this.getNodeAt(apos), suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix)
path = TypePath::cons(getRefTypeParameter(), suffix)
)
else (
not apos.isSelf() and
@@ -2195,7 +2173,7 @@ private Type inferMethodCallType0(
// the implicit deref
apos.isReturn() and
a instanceof IndexExpr
then path0.isCons(TRefTypeParameter(), path)
then path0.isCons(getRefTypeParameter(), path)
else path = path0
)
}
@@ -2219,12 +2197,12 @@ private Type inferMethodCallType1(AstNode n, boolean isReturn, TypePath path) {
// adjust for implicit deref
apos.isSelf() and
derefChainBorrow = ".ref;" and
path = TypePath::cons(TRefTypeParameter(), path0)
path = TypePath::cons(getRefTypeParameter(), path0)
or
// adjust for implicit borrow
apos.isSelf() and
derefChainBorrow = ";borrow" and
path0.isCons(TRefTypeParameter(), path)
path0.isCons(getRefTypeParameter(), path)
)
}
@@ -2751,7 +2729,7 @@ private module OperationMatchingInput implements MatchingInputSig {
private Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(TypePath path0 |
result = super.getParameterType(dpos, path0) and
if this.borrowsAt(dpos) then path0.isCons(TRefTypeParameter(), path) else path0 = path
if this.borrowsAt(dpos) then path0.isCons(getRefTypeParameter(), path) else path0 = path
)
}
@@ -2762,7 +2740,7 @@ private module OperationMatchingInput implements MatchingInputSig {
private Type getReturnType(TypePath path) {
exists(TypePath path0 |
result = super.getReturnType(path0) and
if this.derefsReturn() then path0.isCons(TRefTypeParameter(), path) else path0 = path
if this.derefsReturn() then path0.isCons(getRefTypeParameter(), path) else path0 = path
)
}
@@ -2819,14 +2797,6 @@ private Type getTupleFieldExprLookupType(FieldExpr fe, int pos) {
)
}
pragma[nomagic]
private TupleTypeParameter resolveTupleTypeFieldExpr(FieldExpr fe) {
exists(int arity, int i |
TTuple(arity) = getTupleFieldExprLookupType(fe, i) and
result = TTupleTypeParameter(arity, i)
)
}
/**
* A matching configuration for resolving types of field expressions like `x.field`.
*/
@@ -2851,8 +2821,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
private newtype TDeclaration =
TStructFieldDecl(StructField sf) or
TTupleFieldDecl(TupleField tf) or
TTupleTypeParameterDecl(TupleTypeParameter ttp)
TTupleFieldDecl(TupleField tf)
abstract class Declaration extends TDeclaration {
TypeParameter getTypeParameter(TypeParameterPosition ppos) { none() }
@@ -2909,31 +2878,6 @@ private module FieldExprMatchingInput implements MatchingInputSig {
override TypeRepr getTypeRepr() { result = tf.getTypeRepr() }
}
private class TupleTypeParameterDecl extends Declaration, TTupleTypeParameterDecl {
private TupleTypeParameter ttp;
TupleTypeParameterDecl() { this = TTupleTypeParameterDecl(ttp) }
override Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
dpos.isSelf() and
(
result = ttp.getTupleType() and
path.isEmpty()
or
result = ttp and
path = TypePath::singleton(ttp)
)
or
dpos.isField() and
result = ttp and
path.isEmpty()
}
override string toString() { result = ttp.toString() }
override Location getLocation() { result = ttp.getLocation() }
}
class AccessPosition = DeclarationPosition;
class Access extends FieldExpr {
@@ -2952,10 +2896,10 @@ private module FieldExprMatchingInput implements MatchingInputSig {
if apos.isSelf()
then
// adjust for implicit deref
path0.isCons(TRefTypeParameter(), path)
path0.isCons(getRefTypeParameter(), path)
or
not path0.isCons(TRefTypeParameter(), _) and
not (result = TRefType() and path0.isEmpty()) and
not path0.isCons(getRefTypeParameter(), _) and
not (result instanceof RefType and path0.isEmpty()) and
path = path0
else path = path0
)
@@ -2966,8 +2910,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
result =
[
TStructFieldDecl(resolveStructFieldExpr(this)).(TDeclaration),
TTupleFieldDecl(resolveTupleFieldExpr(this)),
TTupleTypeParameterDecl(resolveTupleTypeFieldExpr(this))
TTupleFieldDecl(resolveTupleFieldExpr(this))
]
}
}
@@ -2994,12 +2937,12 @@ private Type inferFieldExprType(AstNode n, TypePath path) {
if apos.isSelf()
then
exists(Type receiverType | receiverType = inferType(n) |
if receiverType = TRefType()
if receiverType instanceof RefType
then
// adjust for implicit deref
not path0.isCons(TRefTypeParameter(), _) and
not (path0.isEmpty() and result = TRefType()) and
path = TypePath::cons(TRefTypeParameter(), path0)
not path0.isCons(getRefTypeParameter(), _) and
not (path0.isEmpty() and result instanceof RefType) and
path = TypePath::cons(getRefTypeParameter(), path0)
else path = path0
)
else path = path0
@@ -3016,7 +2959,7 @@ private Type inferRefNodeType(AstNode ref) {
or
ref instanceof RefPat
) and
result = TRefType()
result instanceof RefType
}
pragma[nomagic]
@@ -3070,9 +3013,9 @@ private Type inferLiteralType(LiteralExpr le, TypePath path, boolean certain) {
or
le instanceof StringLiteralExpr and
(
path.isEmpty() and result = TRefType()
path.isEmpty() and result instanceof RefType
or
path = TypePath::singleton(TRefTypeParameter()) and
path = TypePath::singleton(getRefTypeParameter()) and
result = getStrStruct()
) and
certain = true
@@ -3146,7 +3089,7 @@ private Type inferAwaitExprType(AstNode n, TypePath path) {
* Gets the root type of the array expression `ae`.
*/
pragma[nomagic]
private Type inferArrayExprType(ArrayExpr ae) { exists(ae) and result = TArrayType() }
private Type inferArrayExprType(ArrayExpr ae) { exists(ae) and result instanceof ArrayType }
/**
* Gets the root type of the range expression `re`.
@@ -3182,11 +3125,11 @@ private Type inferIndexExprType(IndexExpr ie, TypePath path) {
// todo: remove?
exprPath.isCons(TTypeParamTypeParameter(any(Vec v).getElementTypeParam()), path)
or
exprPath.isCons(any(ArrayTypeParameter tp), path)
exprPath.isCons(getArrayTypeParameter(), path)
or
exists(TypePath path0 |
exprPath.isCons(any(RefTypeParameter tp), path0) and
path0.isCons(any(SliceTypeParameter tp), path)
exprPath.isCons(getRefTypeParameter(), path0) and
path0.isCons(getSliceTypeParameter(), path)
)
)
}
@@ -3331,7 +3274,7 @@ private Type inferForLoopExprType(AstNode n, TypePath path) {
or
// TODO: Remove once we can handle the `impl<I: Iterator> IntoIterator for I` implementation
tp = getIteratorItemTypeParameter() and
inferType(fe.getIterable()) != TArrayType()
inferType(fe.getIterable()) != getArrayTypeParameter()
)
}
@@ -3378,7 +3321,7 @@ pragma[nomagic]
private TypePath closureParameterPath(int arity, int index) {
result =
TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(TTupleTypeParameter(arity, index)))
TypePath::singleton(getTupleTypeParameter(arity, index)))
}
/** Gets the path to the return type of the `FnOnce` trait. */
@@ -3394,7 +3337,7 @@ pragma[nomagic]
private TypePath fnParameterPath(int arity, int index) {
result =
TypePath::cons(TTypeParamTypeParameter(any(FnOnceTrait t).getTypeParam()),
TypePath::singleton(TTupleTypeParameter(arity, index)))
TypePath::singleton(getTupleTypeParameter(arity, index)))
}
pragma[nomagic]
@@ -3443,7 +3386,7 @@ private Type inferClosureExprType(AstNode n, TypePath path) {
or
n = ce and
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
result = TTuple(ce.getNumberOfParams())
result.(TupleType).getArity() = ce.getNumberOfParams()
or
// Propagate return type annotation to body
n = ce.getClosureBody() and

View File

@@ -20,11 +20,11 @@ abstract class TypeMention extends AstNode {
class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TTuple(super.getNumberOfFields())
result.(TupleType).getArity() = super.getNumberOfFields()
or
exists(TypePath suffix, int i |
result = super.getField(i).(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TTupleTypeParameter(super.getNumberOfFields(), i), suffix)
path = TypePath::cons(getTupleTypeParameter(super.getNumberOfFields(), i), suffix)
)
}
}
@@ -32,11 +32,11 @@ class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr {
class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedArgList {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TTuple(super.getNumberOfTypeArgs())
result.(TupleType).getArity() = super.getNumberOfTypeArgs()
or
exists(TypePath suffix, int index |
result = super.getTypeArg(index).getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix)
path = TypePath::cons(getTupleTypeParameter(super.getNumberOfTypeArgs(), index), suffix)
)
}
}
@@ -44,11 +44,11 @@ class ParenthesizedArgListMention extends TypeMention instanceof ParenthesizedAr
class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TArrayType()
result instanceof ArrayType
or
exists(TypePath suffix |
result = super.getElementTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TArrayTypeParameter(), suffix)
path = TypePath::cons(getArrayTypeParameter(), suffix)
)
}
}
@@ -56,11 +56,11 @@ class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TRefType()
result instanceof RefType
or
exists(TypePath suffix |
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TRefTypeParameter(), suffix)
path = TypePath::cons(getRefTypeParameter(), suffix)
)
}
}
@@ -68,11 +68,11 @@ class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TSliceType()
result instanceof SliceType
or
exists(TypePath suffix |
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TSliceTypeParameter(), suffix)
path = TypePath::cons(getSliceTypeParameter(), suffix)
)
}
}
@@ -291,6 +291,9 @@ class NonAliasPathTypeMention extends PathTypeMention {
result = this.getSelfTraitBoundArg().resolveTypeAt(suffix) and
typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix)
)
or
not this.getSegment().hasTraitTypeRepr() and
result = this.getSegment().getTypeRepr().(TypeMention).resolveTypeAt(typePath)
}
}
@@ -426,11 +429,11 @@ class ShorthandSelfParameterMention extends TypeMention instanceof SelfParam {
then
// `fn f(&self, ...)`
typePath.isEmpty() and
result = TRefType()
result instanceof RefType
or
exists(TypePath suffix |
result = this.resolveSelfType(suffix) and
typePath = TypePath::cons(TRefTypeParameter(), suffix)
typePath = TypePath::cons(getRefTypeParameter(), suffix)
)
else
// `fn f(self, ...)`
@@ -541,11 +544,11 @@ class NeverTypeReprMention extends TypeMention, NeverTypeRepr {
class PtrTypeReprMention extends TypeMention instanceof PtrTypeRepr {
override Type resolveTypeAt(TypePath path) {
path.isEmpty() and
result = TPtrType()
result instanceof PtrType
or
exists(TypePath suffix |
result = super.getTypeRepr().(TypeMention).resolveTypeAt(suffix) and
path = TypePath::cons(TPtrTypeParameter(), suffix)
path = TypePath::cons(getPtrTypeParameter(), suffix)
)
}
}

View File

@@ -7,7 +7,7 @@ import rust
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.internal.TypeInference as TypeInference
private import codeql.rust.internal.Type
private import codeql.rust.frameworks.stdlib.Builtins
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
/**
* A node whose type is a numeric or boolean type, which may be an appropriate
@@ -19,8 +19,8 @@ class NumericTypeBarrier extends DataFlow::Node {
t = TypeInference::inferType(this.asExpr().getExpr()) and
s = t.getStruct()
|
s instanceof NumericType or
s instanceof Bool
s instanceof Builtins::NumericType or
s instanceof Builtins::Bool
)
}
}
@@ -35,8 +35,8 @@ class IntegralOrBooleanTypeBarrier extends DataFlow::Node {
t = TypeInference::inferType(this.asExpr().getExpr()) and
s = t.getStruct()
|
s instanceof IntegralType or
s instanceof Bool
s instanceof Builtins::IntegralType or
s instanceof Builtins::Bool
)
}
}

View File

@@ -1,3 +1,24 @@
| struct Array | |
| struct Ptr | |
| struct Ref | |
| struct Slice | |
| struct Tuple0 | |
| struct Tuple1 | |
| struct Tuple2 | |
| struct Tuple3 | |
| struct Tuple4 | |
| struct Tuple5 | |
| struct Tuple6 | |
| struct Tuple7 | |
| struct Tuple8 | |
| struct Tuple9 | |
| struct Tuple10 | |
| struct Tuple11 | |
| struct Tuple12 | |
| struct Tuple13 | |
| struct Tuple14 | |
| struct Tuple15 | |
| struct Tuple16 | |
| struct bool | |
| struct char | |
| struct f32 | FloatingPointType, NumericType |

View File

@@ -1,6 +1,5 @@
import rust
import codeql.rust.frameworks.stdlib.Builtins
import codeql.rust.internal.Type
string describe(BuiltinType t) {
t instanceof NumericType and result = "NumericType"

View File

@@ -1755,7 +1755,7 @@ mod builtins {
let x = [1, 2, 3].my_method(); // $ target=my_method type=x:&T.i32
let x = <[_; 3]>::my_method(&[1, 2, 3]); // $ target=my_method type=x:&T.i32
let x = <[i32; 3]>::my_func(); // $ MISSING: target=my_func type=x:i32
let x = <[i32; 3]>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for [T] {
fn my_method(&self) -> &T {
@@ -1770,11 +1770,11 @@ mod builtins {
let s: &[i32] = &[1, 2, 3];
let x = s.my_method(); // $ target=my_method type=x:&T.i32
let x = <[_]>::my_method(s); // $ target=my_method type=x:&T.i32
let x = <[i32]>::my_func(); // $ MISSING: target=my_func type=x:i32
let x = <[i32]>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for (T, i32) {
fn my_method(&self) -> &T {
&self.0
&self.0 // $ fieldof=Tuple2
}
fn my_func() -> T {
@@ -1785,7 +1785,7 @@ mod builtins {
let p = (42, 7);
let x = p.my_method(); // $ target=my_method type=x:&T.i32
let x = <(_, _)>::my_method(&p); // $ target=my_method type=x:&T.i32
let x = <(i32, i32)>::my_func(); // $ MISSING: target=my_func type=x:i32
let x = <(i32, i32)>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for &T {
fn my_method(&self) -> &T {
@@ -1800,7 +1800,7 @@ mod builtins {
let r = &42;
let x = r.my_method(); // $ target=my_method type=x:&T.i32
let x = <&_>::my_method(&r); // $ target=my_method type=x:&T.i32
let x = <&i32>::my_func(); // $ MISSING: target=my_func type=x:i32
let x = <&i32>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for *mut T {
fn my_method(&self) -> &T {
@@ -1816,7 +1816,7 @@ mod builtins {
let p: *mut i32 = &mut v;
let x = unsafe { p.my_method() }; // $ target=my_method type=x:&T.i32
let x = unsafe { <*mut _>::my_method(&p) }; // $ target=my_method type=x:&T.i32
let x = <*mut i32>::my_func(); // $ MISSING: target=my_func type=x:i32
let x = <*mut i32>::my_func(); // $ target=my_func type=x:i32
}
}
@@ -2344,7 +2344,7 @@ mod impl_trait {
// For this function the `impl` type does not appear in the root of the return type
let f = get_a_my_trait3(S1).unwrap().get_a(); // $ target=get_a_my_trait3 target=unwrap target=MyTrait::get_a type=f:S1
let g = get_a_my_trait4(S1).0.get_a(); // $ target=get_a_my_trait4 target=MyTrait::get_a type=g:S1
let g = get_a_my_trait4(S1).0.get_a(); // $ target=get_a_my_trait4 target=MyTrait::get_a type=g:S1 fieldof=Tuple2
}
}
@@ -2670,7 +2670,7 @@ mod loops {
// for loops with containers
let vals3 = vec![1, 2, 3]; // $ MISSING: type=vals3:Vec type=vals3:T.i32
let vals3 = vec![1, 2, 3]; // $ type=vals3:Vec $ MISSING: type=vals3:T.i32
for i in vals3 {} // $ MISSING: type=i:i32
let vals4a: Vec<u16> = [1u16, 2, 3].to_vec(); // $ certainType=vals4a:Vec certainType=vals4a:T.u16
@@ -2689,7 +2689,7 @@ mod loops {
vals7.push(1u8); // $ target=push
for u in vals7 {} // $ type=u:u8
let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ MISSING: type=matrix1:Vec type=matrix1:T.Vec type=matrix1:T.T.i32
let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ type=matrix1:Vec $ MISSING: type=matrix1:T.Vec type=matrix1:T.T.i32
#[rustfmt::skip]
let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row:T.i32
for cell in row { // $ MISSING: type=cell:i32
@@ -2790,8 +2790,8 @@ mod tuples {
let (mut e, f) = S1::get_pair(); // $ target=get_pair type=e:S1 type=f:S1
let (mut g, mut h) = S1::get_pair(); // $ target=get_pair type=g:S1 type=h:S1
a.0.foo(); // $ target=foo
b.1.foo(); // $ target=foo
a.0.foo(); // $ target=foo fieldof=Tuple2
b.1.foo(); // $ target=foo fieldof=Tuple2
c.foo(); // $ target=foo
d.foo(); // $ target=foo
e.foo(); // $ target=foo
@@ -2805,18 +2805,18 @@ mod tuples {
let a = Default::default(); // $ target=default type=a:i64
let b = Default::default(); // $ target=default type=b:bool
let pair = (a, b); // $ type=pair:0(2).i64 type=pair:1(2).bool
let i: i64 = pair.0;
let j: bool = pair.1;
let i: i64 = pair.0; // $ fieldof=Tuple2
let j: bool = pair.1; // $ fieldof=Tuple2
let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:0(2).i32 type=pair:1(2).i32 MISSING: target=into
match pair {
(0, 0) => print!("unexpected"),
_ => print!("expected"),
}
let x = pair.0; // $ type=x:i32
let x = pair.0; // $ type=x:i32 fieldof=Tuple2
let y = &S1::get_pair(); // $ target=get_pair
y.0.foo(); // $ target=foo
y.0.foo(); // $ target=foo fieldof=Tuple2
}
}

View File

@@ -60,9 +60,10 @@ module TypeTest implements TestSig {
exists(AstNode n, TypePath path, Type t |
t = TypeInference::inferType(n, path) and
(
if t = TypeInference::CertainTypeInference::inferCertainType(n, path)
then tag = "certainType"
else tag = "type"
tag = "type"
or
t = TypeInference::CertainTypeInference::inferCertainType(n, path) and
tag = "certainType"
) and
location = n.getLocation() and
(

View File

@@ -23,3 +23,125 @@ pub struct isize;
// floating-point types
pub struct f32;
pub struct f64;
pub struct Slice<T>;
pub struct Array<T, const N: usize>;
pub struct Ref<T>; // todo: add mut variant
pub struct Ptr<T>; // todo: add mut variant
// tuples
pub struct Tuple0;
pub struct Tuple1<T>(T);
pub struct Tuple2<T1, T2>(T1, T2);
pub struct Tuple3<T1, T2, T3>(T1, T2, T3);
pub struct Tuple4<T1, T2, T3, T4>(T1, T2, T3, T4);
pub struct Tuple5<T1, T2, T3, T4, T5>(T1, T2, T3, T4, T5);
pub struct Tuple6<T1, T2, T3, T4, T5, T6>(T1, T2, T3, T4, T5, T6);
pub struct Tuple7<T1, T2, T3, T4, T5, T6, T7>(T1, T2, T3, T4, T5, T6, T7);
pub struct Tuple8<T1, T2, T3, T4, T5, T6, T7, T8>(T1, T2, T3, T4, T5, T6, T7, T8);
pub struct Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(T1, T2, T3, T4, T5, T6, T7, T8, T9);
pub struct Tuple10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
);
pub struct Tuple11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
);
pub struct Tuple12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
T12,
);
pub struct Tuple13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
T12,
T13,
);
pub struct Tuple14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
T12,
T13,
T14,
);
pub struct Tuple15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
T12,
T13,
T14,
T15,
);
pub struct Tuple16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(
T1,
T2,
T3,
T4,
T5,
T6,
T7,
T8,
T9,
T10,
T11,
T12,
T13,
T14,
T15,
T16,
);