mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #20683 from hvitved/rust/type-inference-arg-target-typed
Rust: Restrict type propagation into arguments
This commit is contained in:
@@ -51,6 +51,7 @@ newtype TType =
|
||||
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
|
||||
@@ -371,6 +372,36 @@ class PtrType extends Type, TPtrType {
|
||||
override Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
* A special pseudo type used to indicate that the actual type may have to be
|
||||
* inferred by propagating type information back into call arguments.
|
||||
*
|
||||
* For example, in
|
||||
*
|
||||
* ```rust
|
||||
* let x = Default::default();
|
||||
* foo(x);
|
||||
* ```
|
||||
*
|
||||
* `Default::default()` is assigned this type, which allows us to infer the actual
|
||||
* type from the type of `foo`'s first parameter.
|
||||
*
|
||||
* Unknown types are not restricted to root types, for example in a call like
|
||||
* `Vec::new()` we assign this type at the type path corresponding to the type
|
||||
* parameter of `Vec`.
|
||||
*
|
||||
* Unknown types are used to restrict when type information is allowed to flow
|
||||
* into call arguments (including method call receivers), in order to avoid
|
||||
* combinatorial explosions.
|
||||
*/
|
||||
class UnknownType extends Type, TUnknownType {
|
||||
override TypeParameter getPositionalTypeParameter(int i) { none() }
|
||||
|
||||
override string toString() { result = "(context typed)" }
|
||||
|
||||
override Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** A type parameter. */
|
||||
abstract class TypeParameter extends Type {
|
||||
override TypeParameter getPositionalTypeParameter(int i) { none() }
|
||||
|
||||
@@ -260,11 +260,22 @@ private class NonMethodFunction extends Function {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TypeMention getCallExprTypeArgument(CallExpr ce, TypeArgumentPosition apos) {
|
||||
exists(Path p, int i |
|
||||
private TypeMention getCallExprTypeMentionArgument(CallExpr ce, TypeArgumentPosition apos) {
|
||||
exists(Path p, int i | p = CallExprImpl::getFunctionPath(ce) |
|
||||
apos.asTypeParam() = resolvePath(p).getTypeParam(pragma[only_bind_into](i)) and
|
||||
result = getPathTypeArgument(p, pragma[only_bind_into](i))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Type getCallExprTypeArgument(CallExpr ce, TypeArgumentPosition apos, TypePath path) {
|
||||
result = getCallExprTypeMentionArgument(ce, apos).resolveTypeAt(path)
|
||||
or
|
||||
// Handle constructions that use `Self(...)` syntax
|
||||
exists(Path p, TypePath path0 |
|
||||
p = CallExprImpl::getFunctionPath(ce) and
|
||||
result = p.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
|
||||
apos.asTypeParam() = resolvePath(p).getTypeParam(pragma[only_bind_into](i))
|
||||
result = p.(TypeMention).resolveTypeAt(path0) and
|
||||
path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -356,8 +367,7 @@ module CertainTypeInference {
|
||||
// For type parameters of the function we must resolve their
|
||||
// instantiation from the path. For instance, for `fn bar<A>(a: A) -> A`
|
||||
// and the path `bar<i64>`, we must resolve `A` to `i64`.
|
||||
result =
|
||||
getCallExprTypeArgument(ce, TTypeParamTypeArgumentPosition(tp)).resolveTypeAt(suffix)
|
||||
result = getCallExprTypeArgument(ce, TTypeParamTypeArgumentPosition(tp), suffix)
|
||||
)
|
||||
or
|
||||
not ty instanceof TypeParameter and
|
||||
@@ -748,6 +758,8 @@ private Type inferTypeEquality(AstNode n, TypePath path) {
|
||||
/**
|
||||
* A matching configuration for resolving types of struct expressions
|
||||
* like `Foo { bar = baz }`.
|
||||
*
|
||||
* This also includes nullary struct expressions like `None`.
|
||||
*/
|
||||
private module StructExprMatchingInput implements MatchingInputSig {
|
||||
private newtype TPos =
|
||||
@@ -830,26 +842,86 @@ private module StructExprMatchingInput implements MatchingInputSig {
|
||||
|
||||
class AccessPosition = DeclarationPosition;
|
||||
|
||||
class Access extends StructExpr {
|
||||
abstract class Access extends AstNode {
|
||||
pragma[nomagic]
|
||||
abstract AstNode getNodeAt(AccessPosition apos);
|
||||
|
||||
pragma[nomagic]
|
||||
Type getInferredType(AccessPosition apos, TypePath path) {
|
||||
result = inferType(this.getNodeAt(apos), path)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
abstract Path getStructPath();
|
||||
|
||||
pragma[nomagic]
|
||||
Declaration getTarget() { result = resolvePath(this.getStructPath()) }
|
||||
|
||||
pragma[nomagic]
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
// Handle constructions that use `Self {...}` syntax
|
||||
exists(TypeMention tm, TypePath path0 |
|
||||
tm = this.getStructPath() and
|
||||
result = tm.resolveTypeAt(path0) and
|
||||
path0.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the return type of this struct expression at `path` may have to
|
||||
* be inferred from the context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate hasUnknownTypeAt(DeclarationPosition pos, TypePath path) {
|
||||
exists(Declaration d, TypeParameter tp |
|
||||
d = this.getTarget() and
|
||||
pos.isStructPos() and
|
||||
tp = d.getDeclaredType(pos, path) and
|
||||
not exists(DeclarationPosition fieldPos |
|
||||
not fieldPos.isStructPos() and
|
||||
tp = d.getDeclaredType(fieldPos, _)
|
||||
) and
|
||||
// check that no explicit type arguments have been supplied for `tp`
|
||||
not exists(TypeArgumentPosition tapos |
|
||||
exists(this.getTypeArgument(tapos, _)) and
|
||||
TTypeParamTypeParameter(tapos.asTypeParam()) = tp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class StructExprAccess extends Access, StructExpr {
|
||||
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
result = super.getTypeArgument(apos, path)
|
||||
or
|
||||
exists(TypePath suffix |
|
||||
suffix.isCons(TTypeParamTypeParameter(apos.asTypeParam()), path) and
|
||||
result = CertainTypeInference::inferCertainType(this, suffix)
|
||||
)
|
||||
}
|
||||
|
||||
AstNode getNodeAt(AccessPosition apos) {
|
||||
override AstNode getNodeAt(AccessPosition apos) {
|
||||
result = this.getFieldExpr(apos.asFieldPos()).getExpr()
|
||||
or
|
||||
result = this and
|
||||
apos.isStructPos()
|
||||
}
|
||||
|
||||
Type getInferredType(AccessPosition apos, TypePath path) {
|
||||
result = inferType(this.getNodeAt(apos), path)
|
||||
override Path getStructPath() { result = this.getPath() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A potential nullary struct/variant construction such as `None`.
|
||||
*/
|
||||
private class PathExprAccess extends Access, PathExpr {
|
||||
PathExprAccess() { not exists(CallExpr ce | this = ce.getFunction()) }
|
||||
|
||||
override AstNode getNodeAt(AccessPosition apos) {
|
||||
result = this and
|
||||
apos.isStructPos()
|
||||
}
|
||||
|
||||
Declaration getTarget() { result = resolvePath(this.getPath()) }
|
||||
override Path getStructPath() { result = this.getPath() }
|
||||
}
|
||||
|
||||
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) {
|
||||
@@ -859,17 +931,25 @@ private module StructExprMatchingInput implements MatchingInputSig {
|
||||
|
||||
private module StructExprMatching = Matching<StructExprMatchingInput>;
|
||||
|
||||
pragma[nomagic]
|
||||
private Type inferStructExprType0(AstNode n, boolean isReturn, TypePath path) {
|
||||
exists(StructExprMatchingInput::Access a, StructExprMatchingInput::AccessPosition apos |
|
||||
n = a.getNodeAt(apos) and
|
||||
if apos.isStructPos() then isReturn = true else isReturn = false
|
||||
|
|
||||
result = StructExprMatching::inferAccessType(a, apos, path)
|
||||
or
|
||||
a.hasUnknownTypeAt(apos, path) and
|
||||
result = TUnknownType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of `n` at `path`, where `n` is either a struct expression or
|
||||
* a field expression of a struct expression.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Type inferStructExprType(AstNode n, TypePath path) {
|
||||
exists(StructExprMatchingInput::Access a, StructExprMatchingInput::AccessPosition apos |
|
||||
n = a.getNodeAt(apos) and
|
||||
result = StructExprMatching::inferAccessType(a, apos, path)
|
||||
)
|
||||
}
|
||||
private predicate inferStructExprType =
|
||||
ContextTyping::CheckContextTyping<inferStructExprType0/3>::check/2;
|
||||
|
||||
pragma[nomagic]
|
||||
private Type inferTupleRootType(AstNode n) {
|
||||
@@ -877,18 +957,6 @@ private Type inferTupleRootType(AstNode n) {
|
||||
result = TTuple([n.(TupleExpr).getNumberOfFields(), n.(TuplePat).getTupleArity()])
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Type inferPathExprType(PathExpr pe, TypePath path) {
|
||||
// nullary struct/variant constructors
|
||||
not exists(CallExpr ce | pe = ce.getFunction()) and
|
||||
path.isEmpty() and
|
||||
exists(ItemNode i | i = resolvePath(pe.getPath()) |
|
||||
result = TEnum(i.(Variant).getEnum())
|
||||
or
|
||||
result = TStruct(i)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Path getCallExprPathQualifier(CallExpr ce) {
|
||||
result = CallExprImpl::getFunctionPath(ce).getQualifier()
|
||||
@@ -909,6 +977,114 @@ private Type getCallExprTypeQualifier(CallExpr ce, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides functionality related to context-based typing of calls.
|
||||
*/
|
||||
private module ContextTyping {
|
||||
/**
|
||||
* Holds if the return type of the function `f` inside `i` at `path` is type
|
||||
* parameter `tp`, and `tp` does not appear in the type of any parameter of
|
||||
* `f`.
|
||||
*
|
||||
* In this case, the context in which `f` is called may be needed to infer
|
||||
* the instantiation of `tp`.
|
||||
*
|
||||
* This covers functions like `Default::default` and `Vec::new`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate assocFunctionReturnContextTypedAt(
|
||||
ImplOrTraitItemNode i, Function f, FunctionPosition pos, TypePath path, TypeParameter tp
|
||||
) {
|
||||
pos.isReturn() and
|
||||
tp = getAssocFunctionTypeAt(f, i, pos, path) and
|
||||
not exists(FunctionPosition nonResPos | not nonResPos.isReturn() |
|
||||
tp = getAssocFunctionTypeAt(f, i, nonResPos, _)
|
||||
or
|
||||
// `Self` types in traits implicitly mention all type parameters of the trait
|
||||
getAssocFunctionTypeAt(f, i, nonResPos, _) = TSelfTypeParameter(i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A call where the type of the result may have to be inferred from the
|
||||
* context in which the call appears, for example a call like
|
||||
* `Default::default()`.
|
||||
*/
|
||||
abstract class ContextTypedCallCand extends AstNode {
|
||||
abstract Type getTypeArgument(TypeArgumentPosition apos, TypePath path);
|
||||
|
||||
private predicate hasTypeArgument(TypeArgumentPosition apos) {
|
||||
exists(this.getTypeArgument(apos, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this call resolves to `target` inside `i`, and the return type
|
||||
* at `pos` and `path` may have to be inferred from the context.
|
||||
*/
|
||||
bindingset[this, i, target]
|
||||
predicate hasUnknownTypeAt(
|
||||
ImplOrTraitItemNode i, Function target, FunctionPosition pos, TypePath path
|
||||
) {
|
||||
exists(TypeParameter tp |
|
||||
assocFunctionReturnContextTypedAt(i, target, pos, path, tp) and
|
||||
// check that no explicit type arguments have been supplied for `tp`
|
||||
not exists(TypeArgumentPosition tapos | this.hasTypeArgument(tapos) |
|
||||
exists(int j |
|
||||
j = tapos.asMethodTypeArgumentPosition() and
|
||||
tp = TTypeParamTypeParameter(target.getGenericParamList().getTypeParam(j))
|
||||
)
|
||||
or
|
||||
TTypeParamTypeParameter(tapos.asTypeParam()) = tp
|
||||
) and
|
||||
not (
|
||||
tp instanceof TSelfTypeParameter and
|
||||
exists(getCallExprTypeQualifier(this, _))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasUnknownTypeAt(AstNode n, TypePath path) {
|
||||
inferType(n, path) = TUnknownType()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasUnknownType(AstNode n) { hasUnknownTypeAt(n, _) }
|
||||
|
||||
signature Type inferCallTypeSig(AstNode n, boolean isReturn, TypePath path);
|
||||
|
||||
/**
|
||||
* Given a predicate `inferCallType` for inferring the type of a call at a given
|
||||
* position, this module exposes the predicate `check`, which wraps the input
|
||||
* predicate and checks that types are only propagated into arguments when they
|
||||
* are context-typed.
|
||||
*/
|
||||
module CheckContextTyping<inferCallTypeSig/3 inferCallType> {
|
||||
pragma[nomagic]
|
||||
private Type inferCallTypeFromContextCand(AstNode n, TypePath path, TypePath prefix) {
|
||||
result = inferCallType(n, false, path) and
|
||||
hasUnknownType(n) and
|
||||
prefix = path
|
||||
or
|
||||
exists(TypePath mid |
|
||||
result = inferCallTypeFromContextCand(n, path, mid) and
|
||||
mid.isSnoc(prefix, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
Type check(AstNode n, TypePath path) {
|
||||
result = inferCallType(n, true, path)
|
||||
or
|
||||
exists(TypePath prefix |
|
||||
result = inferCallTypeFromContextCand(n, path, prefix) and
|
||||
hasUnknownTypeAt(n, prefix)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if function `f` with the name `name` and the arity `arity` exists in
|
||||
* `i`, and the type at position `pos` is `t`.
|
||||
@@ -1418,20 +1594,20 @@ private module MethodResolution {
|
||||
* `derefChain` and the Boolean `borrow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Method resolveCallTarget(string derefChain, boolean borrow) {
|
||||
Method resolveCallTarget(ImplOrTraitItemNode i, string derefChain, boolean borrow) {
|
||||
exists(MethodCallCand mcc |
|
||||
mcc = MkMethodCallCand(this, derefChain, borrow) and
|
||||
result = mcc.resolveCallTarget()
|
||||
result = mcc.resolveCallTarget(i)
|
||||
)
|
||||
}
|
||||
|
||||
predicate receiverHasImplicitDeref(AstNode receiver) {
|
||||
exists(this.resolveCallTarget(".ref", false)) and
|
||||
exists(this.resolveCallTarget(_, ".ref", false)) and
|
||||
receiver = this.getArgument(CallImpl::TSelfArgumentPosition())
|
||||
}
|
||||
|
||||
predicate receiverHasImplicitBorrow(AstNode receiver) {
|
||||
exists(this.resolveCallTarget("", true)) and
|
||||
exists(this.resolveCallTarget(_, "", true)) and
|
||||
receiver = this.getArgument(CallImpl::TSelfArgumentPosition())
|
||||
}
|
||||
}
|
||||
@@ -1569,7 +1745,8 @@ private module MethodResolution {
|
||||
|
||||
Type getTypeAt(TypePath path) {
|
||||
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(derefChain, borrow, path) and
|
||||
not result = TNeverType()
|
||||
not result = TNeverType() and
|
||||
not result = TUnknownType()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1642,13 +1819,11 @@ private module MethodResolution {
|
||||
|
||||
/** Gets a method that matches this method call. */
|
||||
pragma[nomagic]
|
||||
Method resolveCallTarget() {
|
||||
exists(ImplOrTraitItemNode i |
|
||||
result = this.resolveCallTargetCand(i) and
|
||||
not FunctionOverloading::functionResolutionDependsOnArgument(i, _, _, _, _)
|
||||
)
|
||||
Method resolveCallTarget(ImplOrTraitItemNode i) {
|
||||
result = this.resolveCallTargetCand(i) and
|
||||
not FunctionOverloading::functionResolutionDependsOnArgument(i, _, _, _, _)
|
||||
or
|
||||
MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, _, result)
|
||||
MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result)
|
||||
}
|
||||
|
||||
predicate hasNoBorrow() { borrow = false }
|
||||
@@ -1918,20 +2093,22 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
|
||||
|
||||
final private class MethodCallFinal = MethodResolution::MethodCall;
|
||||
|
||||
class Access extends MethodCallFinal {
|
||||
class Access extends MethodCallFinal, ContextTyping::ContextTypedCallCand {
|
||||
Access() {
|
||||
// handled in the `OperationMatchingInput` module
|
||||
not this instanceof Operation
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
exists(TypeMention arg | result = arg.resolveTypeAt(path) |
|
||||
arg =
|
||||
this.(MethodCallExpr).getGenericArgList().getTypeArg(apos.asMethodTypeArgumentPosition())
|
||||
or
|
||||
arg = getCallExprTypeArgument(this, apos)
|
||||
)
|
||||
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
result =
|
||||
this.(MethodCallExpr)
|
||||
.getGenericArgList()
|
||||
.getTypeArg(apos.asMethodTypeArgumentPosition())
|
||||
.(TypeMention)
|
||||
.resolveTypeAt(path)
|
||||
or
|
||||
result = getCallExprTypeArgument(this, apos, path)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1971,10 +2148,23 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
|
||||
result = this.getInferredNonSelfType(apos, path)
|
||||
}
|
||||
|
||||
Declaration getTarget(string derefChainBorrow) {
|
||||
Declaration getTarget(ImplOrTraitItemNode i, string derefChainBorrow) {
|
||||
exists(string derefChain, boolean borrow |
|
||||
derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and
|
||||
result = this.resolveCallTarget(derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa
|
||||
result = this.resolveCallTarget(i, derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa
|
||||
)
|
||||
}
|
||||
|
||||
Declaration getTarget(string derefChainBorrow) { result = this.getTarget(_, derefChainBorrow) }
|
||||
|
||||
/**
|
||||
* Holds if the return type of this call at `path` may have to be inferred
|
||||
* from the context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate hasUnknownTypeAt(string derefChainBorrow, FunctionPosition pos, TypePath path) {
|
||||
exists(ImplOrTraitItemNode i |
|
||||
this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1989,7 +2179,12 @@ private Type inferMethodCallType0(
|
||||
) {
|
||||
exists(TypePath path0 |
|
||||
n = a.getNodeAt(apos) and
|
||||
result = MethodCallMatching::inferAccessType(a, derefChainBorrow, apos, path0)
|
||||
(
|
||||
result = MethodCallMatching::inferAccessType(a, derefChainBorrow, apos, path0)
|
||||
or
|
||||
a.hasUnknownTypeAt(derefChainBorrow, apos, path0) and
|
||||
result = TUnknownType()
|
||||
)
|
||||
|
|
||||
if
|
||||
// index expression `x[i]` desugars to `*x.index(i)`, so we must account for
|
||||
@@ -2001,17 +2196,14 @@ private Type inferMethodCallType0(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of `n` at `path`, where `n` is either a method call or an
|
||||
* argument/receiver of a method call.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Type inferMethodCallType(AstNode n, TypePath path) {
|
||||
private Type inferMethodCallType1(AstNode n, boolean isReturn, TypePath path) {
|
||||
exists(
|
||||
MethodCallMatchingInput::Access a, MethodCallMatchingInput::AccessPosition apos,
|
||||
string derefChainBorrow, TypePath path0
|
||||
|
|
||||
result = inferMethodCallType0(a, apos, n, derefChainBorrow, path0)
|
||||
result = inferMethodCallType0(a, apos, n, derefChainBorrow, path0) and
|
||||
if apos.isReturn() then isReturn = true else isReturn = false
|
||||
|
|
||||
(
|
||||
not apos.isSelf()
|
||||
@@ -2032,6 +2224,13 @@ private Type inferMethodCallType(AstNode n, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of `n` at `path`, where `n` is either a method call or an
|
||||
* argument/receiver of a method call.
|
||||
*/
|
||||
private predicate inferMethodCallType =
|
||||
ContextTyping::CheckContextTyping<inferMethodCallType1/3>::check/2;
|
||||
|
||||
/**
|
||||
* Provides logic for resolving calls to non-method items. This includes
|
||||
* "calls" to tuple variants and tuple structs.
|
||||
@@ -2178,26 +2377,39 @@ private module NonMethodResolution {
|
||||
trait = this.(Call).getTrait()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of this call, which can be resolved using only path resolution.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private NonMethodFunction resolveCallTargetRec() {
|
||||
result = this.resolveCallTargetBlanketCand(_) and
|
||||
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
|
||||
or
|
||||
NonMethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, _, result)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
ItemNode resolveCallTargetNonRec() {
|
||||
ItemNode resolveCallTargetViaPathResolution() {
|
||||
not this.(Call).hasTrait() and
|
||||
result = this.getPathResolutionResolved() and
|
||||
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of this call, which can be resolved using type inference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
NonMethodFunction resolveCallTargetViaTypeInference(ImplOrTraitItemNode i) {
|
||||
result = this.resolveCallTargetBlanketCand(i) and
|
||||
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
|
||||
or
|
||||
NonMethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
ItemNode resolveCallTarget() {
|
||||
result = this.resolveCallTargetNonRec()
|
||||
result = this.resolveCallTargetViaPathResolution()
|
||||
or
|
||||
result = this.resolveCallTargetRec()
|
||||
result = this.resolveCallTargetViaTypeInference(_)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
NonMethodFunction resolveTraitFunctionViaPathResolution(TraitItemNode trait) {
|
||||
this.(Call).hasTrait() and
|
||||
result = this.getPathResolutionResolved() and
|
||||
result = trait.getASuccessor(_)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2316,6 +2528,9 @@ private module NonMethodResolution {
|
||||
/**
|
||||
* A matching configuration for resolving types of calls like
|
||||
* `foo::bar(baz)` where the target is not a method.
|
||||
*
|
||||
* This also includes "calls" to tuple variants and tuple structs such
|
||||
* as `Result::Ok(42)`.
|
||||
*/
|
||||
private module NonMethodCallMatchingInput implements MatchingInputSig {
|
||||
import FunctionPositionMatchingInput
|
||||
@@ -2433,10 +2648,10 @@ private module NonMethodCallMatchingInput implements MatchingInputSig {
|
||||
}
|
||||
}
|
||||
|
||||
class Access extends NonMethodResolution::NonMethodCall {
|
||||
class Access extends NonMethodResolution::NonMethodCall, ContextTyping::ContextTypedCallCand {
|
||||
pragma[nomagic]
|
||||
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
result = getCallExprTypeArgument(this, apos).resolveTypeAt(path)
|
||||
override Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
|
||||
result = getCallExprTypeArgument(this, apos, path)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2450,19 +2665,56 @@ private module NonMethodCallMatchingInput implements MatchingInputSig {
|
||||
Declaration getTarget() {
|
||||
result = this.resolveCallTarget() // potential mutual recursion; resolving some associated function calls requires resolving types
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the return type of this call at `path` may have to be inferred
|
||||
* from the context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate hasUnknownTypeAt(FunctionPosition pos, TypePath path) {
|
||||
exists(ImplOrTraitItemNode i |
|
||||
this.hasUnknownTypeAt(i,
|
||||
[
|
||||
this.resolveCallTargetViaPathResolution().(NonMethodFunction),
|
||||
this.resolveCallTargetViaTypeInference(i),
|
||||
this.resolveTraitFunctionViaPathResolution(i)
|
||||
], pos, path)
|
||||
)
|
||||
or
|
||||
// Tuple declarations, such as `Result::Ok(...)`, may also be context typed
|
||||
exists(TupleDeclaration td, TypeParameter tp |
|
||||
td = this.resolveCallTargetViaPathResolution() and
|
||||
pos.isReturn() and
|
||||
tp = td.getReturnType(path) and
|
||||
not tp = td.getParameterType(_, _) and
|
||||
// check that no explicit type arguments have been supplied for `tp`
|
||||
not exists(TypeArgumentPosition tapos |
|
||||
exists(this.getTypeArgument(tapos, _)) and
|
||||
TTypeParamTypeParameter(tapos.asTypeParam()) = tp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module NonMethodCallMatching = Matching<NonMethodCallMatchingInput>;
|
||||
|
||||
pragma[nomagic]
|
||||
private Type inferNonMethodCallType(AstNode n, TypePath path) {
|
||||
private Type inferNonMethodCallType0(AstNode n, boolean isReturn, TypePath path) {
|
||||
exists(NonMethodCallMatchingInput::Access a, NonMethodCallMatchingInput::AccessPosition apos |
|
||||
n = a.getNodeAt(apos) and
|
||||
if apos.isReturn() then isReturn = true else isReturn = false
|
||||
|
|
||||
result = NonMethodCallMatching::inferAccessType(a, apos, path)
|
||||
or
|
||||
a.hasUnknownTypeAt(apos, path) and
|
||||
result = TUnknownType()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate inferNonMethodCallType =
|
||||
ContextTyping::CheckContextTyping<inferNonMethodCallType0/3>::check/2;
|
||||
|
||||
/**
|
||||
* A matching configuration for resolving types of operations like `a + b`.
|
||||
*/
|
||||
@@ -2527,7 +2779,7 @@ private module OperationMatchingInput implements MatchingInputSig {
|
||||
}
|
||||
|
||||
Declaration getTarget() {
|
||||
result = this.resolveCallTarget(_, _) // mutual recursion
|
||||
result = this.resolveCallTarget(_, _, _) // mutual recursion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2535,13 +2787,17 @@ private module OperationMatchingInput implements MatchingInputSig {
|
||||
private module OperationMatching = Matching<OperationMatchingInput>;
|
||||
|
||||
pragma[nomagic]
|
||||
private Type inferOperationType(AstNode n, TypePath path) {
|
||||
private Type inferOperationType0(AstNode n, boolean isReturn, TypePath path) {
|
||||
exists(OperationMatchingInput::Access a, OperationMatchingInput::AccessPosition apos |
|
||||
n = a.getNodeAt(apos) and
|
||||
result = OperationMatching::inferAccessType(a, apos, path)
|
||||
result = OperationMatching::inferAccessType(a, apos, path) and
|
||||
if apos.isReturn() then isReturn = true else isReturn = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate inferOperationType =
|
||||
ContextTyping::CheckContextTyping<inferOperationType0/3>::check/2;
|
||||
|
||||
pragma[nomagic]
|
||||
private Type getFieldExprLookupType(FieldExpr fe, string name) {
|
||||
exists(TypePath path |
|
||||
@@ -3215,7 +3471,7 @@ private module Cached {
|
||||
/** Gets an item (function or tuple struct/variant) that `call` resolves to, if any. */
|
||||
cached
|
||||
Addressable resolveCallTarget(Call call) {
|
||||
result = call.(MethodResolution::MethodCall).resolveCallTarget(_, _)
|
||||
result = call.(MethodResolution::MethodCall).resolveCallTarget(_, _, _)
|
||||
or
|
||||
result = call.(NonMethodResolution::NonMethodCall).resolveCallTarget()
|
||||
}
|
||||
@@ -3303,8 +3559,6 @@ private module Cached {
|
||||
or
|
||||
result = inferStructExprType(n, path)
|
||||
or
|
||||
result = inferPathExprType(n, path)
|
||||
or
|
||||
result = inferMethodCallType(n, path)
|
||||
or
|
||||
result = inferNonMethodCallType(n, path)
|
||||
|
||||
@@ -108,6 +108,20 @@ class AliasPathTypeMention extends PathTypeMention {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th type argument of `p`.
|
||||
*
|
||||
* Takes into account that variants can have type arguments applied to both the
|
||||
* enum and the variant itself, e.g. `Option::<i32>::Some` is valid in addition
|
||||
* to `Option::Some::<i32>`.
|
||||
*/
|
||||
TypeMention getPathTypeArgument(Path p, int i) {
|
||||
result = p.getSegment().getGenericArgList().getTypeArg(i)
|
||||
or
|
||||
resolvePath(p) instanceof Variant and
|
||||
result = p.getQualifier().getSegment().getGenericArgList().getTypeArg(i)
|
||||
}
|
||||
|
||||
class NonAliasPathTypeMention extends PathTypeMention {
|
||||
TypeItemNode resolved;
|
||||
|
||||
@@ -143,18 +157,6 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the positional type argument at index `i` that occurs in this path, if
|
||||
* any.
|
||||
*/
|
||||
private TypeMention getPathPositionalTypeArgument(int i) {
|
||||
result = this.getSegment().getGenericArgList().getTypeArg(i)
|
||||
or
|
||||
// `Option::<i32>::Some` is valid in addition to `Option::Some::<i32>`
|
||||
resolvePath(this) instanceof Variant and
|
||||
result = this.getQualifier().getSegment().getGenericArgList().getTypeArg(i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type mention that instantiates the implicit `Self` type parameter
|
||||
* for this path, if it occurs in the position of a trait bound.
|
||||
@@ -173,7 +175,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
private Type getDefaultPositionalTypeArgument(int i, TypePath path) {
|
||||
// If a type argument is not given in the path, then we use the default for
|
||||
// the type parameter if one exists for the type.
|
||||
not exists(this.getPathPositionalTypeArgument(i)) and
|
||||
not exists(getPathTypeArgument(this, i)) and
|
||||
// Defaults only apply to type mentions in type annotations
|
||||
this = any(PathTypeRepr ptp).getPath().getQualifier*() and
|
||||
exists(Type ty, TypePath prefix |
|
||||
@@ -191,7 +193,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
}
|
||||
|
||||
private Type getPositionalTypeArgument(int i, TypePath path) {
|
||||
result = this.getPathPositionalTypeArgument(i).resolveTypeAt(path)
|
||||
result = getPathTypeArgument(this, i).resolveTypeAt(path)
|
||||
or
|
||||
result = this.getDefaultPositionalTypeArgument(i, path)
|
||||
}
|
||||
|
||||
@@ -92,7 +92,8 @@ module SatisfiesBlanketConstraint<
|
||||
|
||||
Type getTypeAt(TypePath path) {
|
||||
result = at.getTypeAt(blanketPath.appendInverse(path)) and
|
||||
not result = TNeverType()
|
||||
not result = TNeverType() and
|
||||
not result = TUnknownType()
|
||||
}
|
||||
|
||||
string toString() { result = at.toString() + " [blanket at " + blanketPath.toString() + "]" }
|
||||
|
||||
@@ -229,7 +229,8 @@ module ArgIsInstantiationOf<
|
||||
private class ArgSubst extends ArgFinal {
|
||||
Type getTypeAt(TypePath path) {
|
||||
result = substituteLookupTraits(super.getTypeAt(path)) and
|
||||
not result = TNeverType()
|
||||
not result = TNeverType() and
|
||||
not result = TUnknownType()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
multipleCallTargets
|
||||
| test.rs:288:7:288:36 | ... .as_str() |
|
||||
@@ -9,9 +9,9 @@ multipleCallTargets
|
||||
| main.rs:590:9:590:18 | ...::m(...) |
|
||||
| main.rs:591:9:591:20 | ... .m() |
|
||||
| main.rs:592:9:592:24 | ...::m(...) |
|
||||
| main.rs:2524:13:2524:31 | ...::from(...) |
|
||||
| main.rs:2525:13:2525:31 | ...::from(...) |
|
||||
| main.rs:2526:13:2526:31 | ...::from(...) |
|
||||
| main.rs:2532:13:2532:31 | ...::from(...) |
|
||||
| main.rs:2533:13:2533:31 | ...::from(...) |
|
||||
| main.rs:2534:13:2534:31 | ...::from(...) |
|
||||
| main.rs:2553:13:2553:31 | ...::from(...) |
|
||||
| main.rs:2554:13:2554:31 | ...::from(...) |
|
||||
| main.rs:2555:13:2555:31 | ...::from(...) |
|
||||
| main.rs:2561:13:2561:31 | ...::from(...) |
|
||||
| main.rs:2562:13:2562:31 | ...::from(...) |
|
||||
| main.rs:2563:13:2563:31 | ...::from(...) |
|
||||
|
||||
@@ -758,6 +758,26 @@ mod function_trait_bounds {
|
||||
fn assoc(x: Self) -> A;
|
||||
}
|
||||
|
||||
impl<T: Default> MyTrait<T> for S2 {
|
||||
fn m1(self) -> T {
|
||||
Default::default() // $ target=default
|
||||
}
|
||||
|
||||
fn assoc(x: Self) -> T {
|
||||
Default::default() // $ target=default
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTrait<i32> for S1 {
|
||||
fn m1(self) -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn assoc(x: Self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// Type parameter with bound occurs in the root of a parameter type.
|
||||
|
||||
fn call_trait_m1<T1, T2: MyTrait<T1> + Copy>(x: T2) -> T1 {
|
||||
@@ -863,6 +883,8 @@ mod function_trait_bounds {
|
||||
println!("{:?}", b);
|
||||
let b = call_trait_thing_m1_3(y3); // $ type=b:S2 target=call_trait_thing_m1_3
|
||||
println!("{:?}", b);
|
||||
let x = S1::m2(S1); // $ target=m2 $ type=x:i32
|
||||
let y: i32 = S2::m2(S2); // $ target=m2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1576,11 +1598,18 @@ mod implicit_self_borrow {
|
||||
fn foo(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
|
||||
fn bar(&self, x: &Self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let x = MyStruct(S);
|
||||
x.foo(); // $ target=foo
|
||||
let x = MyStruct(S);
|
||||
// `&&x` below is Deref coerced to `&x` (see https://doc.rust-lang.org/std/ops/trait.Deref.html#deref-coercion)
|
||||
x.bar(&&x); // $ target=bar
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2875,6 +2904,57 @@ mod block_types {
|
||||
}
|
||||
}
|
||||
|
||||
mod context_typed {
|
||||
pub fn f() {
|
||||
let x = None; // $ type=x:T.i32
|
||||
let x: Option<i32> = x;
|
||||
let x = Option::<i32>::None; // $ type=x:T.i32
|
||||
let x = Option::None::<i32>; // $ type=x:T.i32
|
||||
|
||||
fn pin_option<T>(opt: Option<T>, x: T) {}
|
||||
|
||||
let x = None; // $ type=x:T.i32
|
||||
pin_option(x, 0); // $ target=pin_option
|
||||
|
||||
enum MyEither<T1, T2> {
|
||||
A { left: T1 },
|
||||
B { right: T2 },
|
||||
}
|
||||
|
||||
let x = MyEither::A { left: 0 }; // $ type=x:T1.i32 type=x:T2.String
|
||||
let x: MyEither<i32, String> = x;
|
||||
let x = MyEither::<_, String>::A { left: 0 }; // $ type=x:T1.i32 certainType=x:T2.String
|
||||
#[rustfmt::skip]
|
||||
let x = MyEither::B::<i32, _> { // $ certainType=x:T1.i32 type=x:T2.String
|
||||
right: String::new(), // $ target=new
|
||||
};
|
||||
|
||||
fn pin_my_either<T>(e: MyEither<T, String>, x: T) {}
|
||||
|
||||
#[rustfmt::skip]
|
||||
let x = MyEither::B { // $ type=x:T1.i32 type=x:T2.String
|
||||
right: String::new(), // $ target=new
|
||||
};
|
||||
pin_my_either(x, 0); // $ target=pin_my_either
|
||||
|
||||
let x = Result::Ok(0); // $ type=x:E.String
|
||||
let x: Result<i32, String> = x;
|
||||
let x = Result::<i32, String>::Ok(0); // $ type=x:E.String
|
||||
let x = Result::Ok::<i32, String>(0); // $ type=x:E.String
|
||||
|
||||
fn pin_result<T, E>(res: Result<T, E>, x: E) {}
|
||||
|
||||
let x = Result::Ok(0); // $ type=x:T.i32 type=x:E.bool
|
||||
pin_result(x, false); // $ target=pin_result
|
||||
|
||||
let mut x = Vec::new(); // $ type=x:T.i32 target=new
|
||||
x.push(0); // $ target=push
|
||||
|
||||
let y = Default::default(); // $ type=y:i32 target=default
|
||||
x.push(y); // $ target=push
|
||||
}
|
||||
}
|
||||
|
||||
mod blanket_impl;
|
||||
mod closure;
|
||||
mod dereference;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,12 @@
|
||||
import rust
|
||||
import utils.test.InlineExpectationsTest
|
||||
import codeql.rust.internal.Type
|
||||
import codeql.rust.internal.TypeInference as TypeInference
|
||||
import TypeInference
|
||||
|
||||
query predicate inferType(AstNode n, TypePath path, Type t) {
|
||||
t = TypeInference::inferType(n, path) and
|
||||
t != TUnknownType() and
|
||||
n.fromSource() and
|
||||
not n.isFromMacroExpansion() and
|
||||
not n instanceof IdentPat and // avoid overlap in the output with the underlying `Name` node
|
||||
|
||||
@@ -3,29 +3,10 @@ multipleCallTargets
|
||||
| mysql.rs:16:26:16:85 | ...::from(...) |
|
||||
| mysql.rs:18:13:18:66 | ...::from(...) |
|
||||
| mysql.rs:19:30:19:83 | ...::from(...) |
|
||||
| mysql.rs:46:45:46:66 | remote_string.as_str() |
|
||||
| mysql.rs:47:71:47:92 | remote_string.as_str() |
|
||||
| mysql.rs:48:46:48:67 | remote_string.as_str() |
|
||||
| mysql.rs:49:33:49:54 | remote_string.as_str() |
|
||||
| mysql.rs:50:46:50:67 | remote_string.as_str() |
|
||||
| mysql.rs:52:37:52:58 | remote_string.as_str() |
|
||||
| mysql.rs:56:14:56:35 | remote_string.as_str() |
|
||||
| mysql.rs:62:14:62:35 | remote_string.as_str() |
|
||||
| mysql.rs:66:40:66:61 | remote_string.as_str() |
|
||||
| mysql.rs:67:39:67:60 | remote_string.as_str() |
|
||||
| mysql.rs:70:14:70:35 | remote_string.as_str() |
|
||||
| mysql.rs:100:24:100:39 | ...::from(...) |
|
||||
| mysql.rs:101:26:101:85 | ...::from(...) |
|
||||
| mysql.rs:103:13:103:66 | ...::from(...) |
|
||||
| mysql.rs:104:30:104:83 | ...::from(...) |
|
||||
| mysql.rs:126:45:126:66 | remote_string.as_str() |
|
||||
| mysql.rs:128:38:128:59 | remote_string.as_str() |
|
||||
| mysql.rs:130:33:130:54 | remote_string.as_str() |
|
||||
| mysql.rs:131:54:131:75 | remote_string.as_str() |
|
||||
| mysql.rs:135:18:135:39 | remote_string.as_str() |
|
||||
| mysql.rs:140:40:140:61 | remote_string.as_str() |
|
||||
| mysql.rs:142:62:142:83 | remote_string.as_str() |
|
||||
| mysql.rs:145:31:145:52 | remote_string.as_str() |
|
||||
| sqlx.rs:46:24:46:44 | ...::from(...) |
|
||||
| sqlx.rs:47:56:47:76 | ...::from(...) |
|
||||
| sqlx.rs:48:97:48:117 | ...::from(...) |
|
||||
@@ -33,8 +14,6 @@ multipleCallTargets
|
||||
| sqlx.rs:51:24:51:77 | ...::from(...) |
|
||||
| sqlx.rs:55:26:55:79 | ...::from(...) |
|
||||
| sqlx.rs:61:28:61:81 | ...::from(...) |
|
||||
| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() |
|
||||
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() |
|
||||
| sqlx.rs:99:24:99:44 | ...::from(...) |
|
||||
| sqlx.rs:100:97:100:117 | ...::from(...) |
|
||||
| sqlx.rs:101:24:101:77 | ...::from(...) |
|
||||
|
||||
@@ -36,7 +36,7 @@ edges
|
||||
| mysql.rs:12:13:12:29 | mut remote_string | mysql.rs:18:71:18:83 | remote_string | provenance | |
|
||||
| mysql.rs:12:33:12:54 | ...::get | mysql.rs:12:33:12:77 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
|
||||
| mysql.rs:12:33:12:77 | ...::get(...) [Ok] | mysql.rs:12:33:13:21 | ... .unwrap() | provenance | MaD:31 |
|
||||
| mysql.rs:12:33:13:21 | ... .unwrap() | mysql.rs:12:33:14:19 | ... .text() [Ok] | provenance | MaD:34 |
|
||||
| mysql.rs:12:33:13:21 | ... .unwrap() | mysql.rs:12:33:14:19 | ... .text() [Ok] | provenance | MaD:33 |
|
||||
| mysql.rs:12:33:14:19 | ... .text() [Ok] | mysql.rs:12:33:15:40 | ... .unwrap_or(...) | provenance | MaD:32 |
|
||||
| mysql.rs:12:33:15:40 | ... .unwrap_or(...) | mysql.rs:12:13:12:29 | mut remote_string | provenance | |
|
||||
| mysql.rs:17:13:17:24 | unsafe_query | mysql.rs:25:38:25:49 | unsafe_query | provenance | |
|
||||
@@ -113,7 +113,7 @@ edges
|
||||
| mysql.rs:97:13:97:29 | mut remote_string | mysql.rs:103:71:103:83 | remote_string | provenance | |
|
||||
| mysql.rs:97:33:97:54 | ...::get | mysql.rs:97:33:97:77 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
|
||||
| mysql.rs:97:33:97:77 | ...::get(...) [Ok] | mysql.rs:97:33:98:21 | ... .unwrap() | provenance | MaD:31 |
|
||||
| mysql.rs:97:33:98:21 | ... .unwrap() | mysql.rs:97:33:99:19 | ... .text() [Ok] | provenance | MaD:34 |
|
||||
| mysql.rs:97:33:98:21 | ... .unwrap() | mysql.rs:97:33:99:19 | ... .text() [Ok] | provenance | MaD:33 |
|
||||
| mysql.rs:97:33:99:19 | ... .text() [Ok] | mysql.rs:97:33:100:40 | ... .unwrap_or(...) | provenance | MaD:32 |
|
||||
| mysql.rs:97:33:100:40 | ... .unwrap_or(...) | mysql.rs:97:13:97:29 | mut remote_string | provenance | |
|
||||
| mysql.rs:102:13:102:24 | unsafe_query | mysql.rs:110:38:110:49 | unsafe_query | provenance | |
|
||||
@@ -177,15 +177,13 @@ edges
|
||||
| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:59:17:59:72 | MacroExpr | provenance | |
|
||||
| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
|
||||
| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:31 |
|
||||
| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:34 |
|
||||
| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:33 |
|
||||
| sqlx.rs:48:25:48:85 | ... .text() [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:32 |
|
||||
| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | |
|
||||
| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:29 |
|
||||
| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | |
|
||||
| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | |
|
||||
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:29 |
|
||||
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:33 |
|
||||
| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:33 |
|
||||
| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | |
|
||||
| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | |
|
||||
| sqlx.rs:55:9:55:22 | unsafe_query_3 | sqlx.rs:81:29:81:42 | unsafe_query_3 | provenance | |
|
||||
@@ -200,8 +198,8 @@ edges
|
||||
| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:29 |
|
||||
| sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:17:59:72 | { ... } | provenance | |
|
||||
| sqlx.rs:59:17:59:72 | ...::must_use(...) | sqlx.rs:56:9:56:22 | unsafe_query_4 | provenance | |
|
||||
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:35 |
|
||||
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:36 |
|
||||
| sqlx.rs:59:17:59:72 | MacroExpr | sqlx.rs:59:17:59:72 | ...::format(...) | provenance | MaD:34 |
|
||||
| sqlx.rs:59:17:59:72 | { ... } | sqlx.rs:59:17:59:72 | ...::must_use(...) | provenance | MaD:35 |
|
||||
| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:20 Sink:MaD:20 |
|
||||
| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:20 Sink:MaD:20 |
|
||||
| sqlx.rs:81:29:81:42 | unsafe_query_3 | sqlx.rs:81:29:81:51 | unsafe_query_3.as_str() [&ref] | provenance | MaD:29 |
|
||||
@@ -213,7 +211,7 @@ edges
|
||||
| sqlx.rs:100:9:100:21 | remote_string | sqlx.rs:102:84:102:96 | remote_string | provenance | |
|
||||
| sqlx.rs:100:25:100:46 | ...::get | sqlx.rs:100:25:100:69 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
|
||||
| sqlx.rs:100:25:100:69 | ...::get(...) [Ok] | sqlx.rs:100:25:100:78 | ... .unwrap() | provenance | MaD:31 |
|
||||
| sqlx.rs:100:25:100:78 | ... .unwrap() | sqlx.rs:100:25:100:85 | ... .text() [Ok] | provenance | MaD:34 |
|
||||
| sqlx.rs:100:25:100:78 | ... .unwrap() | sqlx.rs:100:25:100:85 | ... .text() [Ok] | provenance | MaD:33 |
|
||||
| sqlx.rs:100:25:100:85 | ... .text() [Ok] | sqlx.rs:100:25:100:118 | ... .unwrap_or(...) | provenance | MaD:32 |
|
||||
| sqlx.rs:100:25:100:118 | ... .unwrap_or(...) | sqlx.rs:100:9:100:21 | remote_string | provenance | |
|
||||
| sqlx.rs:102:9:102:22 | unsafe_query_1 | sqlx.rs:113:31:113:44 | unsafe_query_1 | provenance | |
|
||||
@@ -255,7 +253,7 @@ edges
|
||||
| sqlx.rs:173:9:173:21 | remote_string | sqlx.rs:175:84:175:96 | remote_string | provenance | |
|
||||
| sqlx.rs:173:25:173:46 | ...::get | sqlx.rs:173:25:173:69 | ...::get(...) [Ok] | provenance | Src:MaD:23 |
|
||||
| sqlx.rs:173:25:173:69 | ...::get(...) [Ok] | sqlx.rs:173:25:173:78 | ... .unwrap() | provenance | MaD:31 |
|
||||
| sqlx.rs:173:25:173:78 | ... .unwrap() | sqlx.rs:173:25:173:85 | ... .text() [Ok] | provenance | MaD:34 |
|
||||
| sqlx.rs:173:25:173:78 | ... .unwrap() | sqlx.rs:173:25:173:85 | ... .text() [Ok] | provenance | MaD:33 |
|
||||
| sqlx.rs:173:25:173:85 | ... .text() [Ok] | sqlx.rs:173:25:173:118 | ... .unwrap_or(...) | provenance | MaD:32 |
|
||||
| sqlx.rs:173:25:173:118 | ... .unwrap_or(...) | sqlx.rs:173:9:173:21 | remote_string | provenance | |
|
||||
| sqlx.rs:175:9:175:22 | unsafe_query_1 | sqlx.rs:188:29:188:42 | unsafe_query_1 | provenance | |
|
||||
@@ -302,10 +300,9 @@ models
|
||||
| 30 | Summary: <core::option::Option>::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value |
|
||||
| 31 | Summary: <core::result::Result>::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
|
||||
| 32 | Summary: <core::result::Result>::unwrap_or; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value |
|
||||
| 33 | Summary: <core::str>::as_str; Argument[self]; ReturnValue; value |
|
||||
| 34 | Summary: <reqwest::blocking::response::Response>::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
|
||||
| 35 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
|
||||
| 36 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
|
||||
| 33 | Summary: <reqwest::blocking::response::Response>::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint |
|
||||
| 34 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint |
|
||||
| 35 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value |
|
||||
nodes
|
||||
| mysql.rs:12:13:12:29 | mut remote_string | semmle.label | mut remote_string |
|
||||
| mysql.rs:12:33:12:54 | ...::get | semmle.label | ...::get |
|
||||
|
||||
@@ -13,7 +13,6 @@ multipleCallTargets
|
||||
| test_storage.rs:73:25:73:67 | ...::from(...) |
|
||||
| test_storage.rs:75:25:75:65 | ...::from(...) |
|
||||
| test_storage.rs:76:25:76:65 | ...::from(...) |
|
||||
| test_storage.rs:77:14:77:24 | s1.as_str() |
|
||||
| test_storage.rs:78:25:78:65 | ...::from(...) |
|
||||
| test_storage.rs:79:25:79:65 | ...::from(...) |
|
||||
| test_storage.rs:80:25:80:70 | ...::from(...) |
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
multipleCallTargets
|
||||
| request_forgery_tests.rs:30:36:30:52 | user_url.as_str() |
|
||||
Reference in New Issue
Block a user