diff --git a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll index d4f68329de94..acf82066f128 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll @@ -8,7 +8,8 @@ module Impl { TPositionalArgumentPosition(int i) { i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] } or - TSelfArgumentPosition() + TSelfArgumentPosition() or + TTypeQualifierArgumentPosition() /** An argument position in a call. */ class ArgumentPosition extends TArgumentPosition { @@ -16,13 +17,22 @@ module Impl { int asPosition() { this = TPositionalArgumentPosition(result) } /** Holds if this call position is a self argument. */ - predicate isSelf() { this instanceof TSelfArgumentPosition } + predicate isSelf() { this = TSelfArgumentPosition() } + + /** + * Holds if this call position is a type qualifier, that is, not an actual + * argument, but rather an annotation that is needed to resolve the call target, + * just like actual arguments may be need to resolve the call target. + */ + predicate isTypeQualifier() { this = TTypeQualifierArgumentPosition() } /** Gets a string representation of this argument position. */ string toString() { result = this.asPosition().toString() or this.isSelf() and result = "self" + or + this.isTypeQualifier() and result = "type qualifier" } } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll b/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll index 51781a473057..db1402280d4d 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll @@ -41,16 +41,19 @@ private predicate hasFirstNonTrivialTraitBound(TypeParamItemNode tp, Trait trait */ pragma[nomagic] predicate isBlanketLike(ImplItemNode i, TypePath blanketSelfPath, TypeParam blanketTypeParam) { - blanketTypeParam = i.getBlanketImplementationTypeParam() and - blanketSelfPath.isEmpty() - or - exists(TypeMention tm, Type root, TypeParameter tp | - tm = i.(Impl).getSelfTy() and - complexSelfRoot(root, tp) and - tm.getType() = root and - tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and - blanketSelfPath = TypePath::singleton(tp) and - hasFirstNonTrivialTraitBound(blanketTypeParam, _) + i.(Impl).hasTrait() and + ( + blanketTypeParam = i.getBlanketImplementationTypeParam() and + blanketSelfPath.isEmpty() + or + exists(TypeMention tm, Type root, TypeParameter tp | + tm = i.(Impl).getSelfTy() and + complexSelfRoot(root, tp) and + tm.getType() = root and + tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and + blanketSelfPath = TypePath::singleton(tp) and + hasFirstNonTrivialTraitBound(blanketTypeParam, _) + ) ) } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll index d96fd892c73e..0f65d21dcf71 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll @@ -86,7 +86,7 @@ predicate traitTypeParameterOccurrence( TypeParameter traitTp ) { f = trait.getAssocItem(functionName) and - traitTp = getAssocFunctionTypeInclNonMethodSelfAt(f, trait, pos, path) and + traitTp = getAssocFunctionTypeAt(f, trait, pos, path) and traitTp = trait.(TraitTypeAbstraction).getATypeParameter() } @@ -124,7 +124,7 @@ private predicate functionResolutionDependsOnArgumentCand( implHasSibling(impl, trait) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, traitTp) and f = impl.getASuccessor(functionName) and - not pos.isSelf() + not pos.isSelfOrTypeQualifier() ) } @@ -141,7 +141,7 @@ pragma[nomagic] private Type getAssocFunctionNonTypeParameterTypeAt( ImplItemNode impl, Function f, FunctionPosition pos, TypePath path ) { - result = getAssocFunctionTypeInclNonMethodSelfAt(f, impl, pos, path) and + result = getAssocFunctionTypeAt(f, impl, pos, path) and not result instanceof TypeParameter } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index 74d8385bdf20..d31dd407df68 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -23,20 +23,26 @@ class FunctionPosition extends TFunctionPosition { ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) } + predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() } + + predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() } + predicate isReturn() { this = TReturnFunctionPosition() } + /** Gets the corresponding position when function call syntax is used. */ + FunctionPosition getFunctionCallAdjusted() { + (this.isReturn() or this.isTypeQualifier()) and + result = this + or + this.isSelf() and result.asPosition() = 0 + or + result.asPosition() = this.asPosition() + 1 + } + /** Gets the corresponding position when `f` is invoked via a function call. */ bindingset[f] FunctionPosition getFunctionCallAdjusted(Function f) { - this.isReturn() and - result = this - or - if f.hasSelfParam() - then - this.isSelf() and result.asPosition() = 0 - or - result.asPosition() = this.asPosition() + 1 - else result = this + if f.hasSelfParam() then result = this.getFunctionCallAdjusted() else result = this } TypeMention getTypeMention(Function f) { @@ -82,9 +88,9 @@ private newtype TAssocFunctionType = // through `i`. This ensures that `parent` is either a supertrait of `i` or // `i` in an `impl` block implementing `parent`. (parent = i or BaseTypes::rootTypesSatisfaction(_, TTrait(parent), i, _, _)) and - // We always include the `self` position, even for non-methods, where it is used + // We always include the type qualifer position, even for non-methods, where it is used // to match type qualifiers against the `impl` or trait type, such as in `Vec::new`. - (exists(pos.getTypeMention(f)) or pos.isSelf()) + (exists(pos.getTypeMention(f)) or pos.isTypeQualifier()) } bindingset[abs, constraint, tp] @@ -116,21 +122,9 @@ Type getAssocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition else result = getTraitConstraintTypeAt(i, constraint, tp, suffix) ) ) -} - -/** - * Same as `getAssocFunctionTypeAt`, but also includes types at the `self` position - * for non-methods. - */ -pragma[nomagic] -Type getAssocFunctionTypeInclNonMethodSelfAt( - Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path -) { - result = getAssocFunctionTypeAt(f, i, pos, path) or f = i.getASuccessor(_) and - not f.hasSelfParam() and - pos.isSelf() and + pos.isTypeQualifier() and result = resolveImplOrTraitType(i, path) } @@ -192,7 +186,7 @@ class AssocFunctionType extends MkAssocFunctionType { Type getTypeAt(TypePath path) { exists(Function f, FunctionPosition pos, ImplOrTraitItemNode i, Type t | this.appliesTo(f, i, pos) and - t = getAssocFunctionTypeInclNonMethodSelfAt(f, i, pos, path) + t = getAssocFunctionTypeAt(f, i, pos, path) | not t instanceof SelfTypeParameter and result = t @@ -205,7 +199,7 @@ class AssocFunctionType extends MkAssocFunctionType { exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) | result = pos.getTypeMention(f) or - pos.isSelf() and + pos.isSelfOrTypeQualifier() and not f.hasSelfParam() and result = [i.(Impl).getSelfTy().(AstNode), i.(Trait).getName()] ) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 50431c6775b6..22ba23ec5d88 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -298,13 +298,11 @@ private class FunctionDeclaration extends Function { } pragma[nomagic] - Type getParameterTypeInclNonMethodSelf( - ImplOrTraitItemNodeOption i, FunctionPosition pos, TypePath path - ) { + Type getParameterType(ImplOrTraitItemNodeOption i, FunctionPosition pos, TypePath path) { i = parent and ( not pos.isReturn() and - result = getAssocFunctionTypeInclNonMethodSelfAt(this, i.asSome(), pos, path) + result = getAssocFunctionTypeAt(this, i.asSome(), pos, path) or i.isNone() and result = this.getParam(pos.asPosition()).getTypeRepr().(TypeMention).getTypeAt(path) @@ -315,7 +313,7 @@ private class FunctionDeclaration extends Function { i = parent and ( result = - getAssocFunctionTypeAt(this, i.asSome(), any(FunctionPosition pos | pos.isReturn()), path) + getAssocFunctionTypeAt(this, i.asSome(), any(FunctionPosition ret | ret.isReturn()), path) or i.isNone() and result = getReturnTypeMention(this).getTypeAt(path) @@ -345,6 +343,10 @@ private class FunctionDeclaration extends Function { } } +private class AssocFunction extends FunctionDeclaration { + AssocFunction() { this.isAssoc(_) } +} + pragma[nomagic] private TypeMention getCallExprTypeMentionArgument(CallExpr ce, TypeArgumentPosition apos) { exists(Path p, int i | p = CallExprImpl::getFunctionPath(ce) | @@ -1122,6 +1124,7 @@ private module ContextTyping { ) { exists(FunctionPosition nonRetPos | not nonRetPos.isReturn() and + not nonRetPos.isTypeQualifier() and tp = getAssocFunctionTypeAt(f, i, nonRetPos, _) ) or @@ -1247,7 +1250,7 @@ private predicate assocFunctionInfo( AssocFunctionType t ) { f = i.getASuccessor(name) and - arity = f.getParamList().getNumberOfParams() and + arity = f.getNumberOfParamsInclSelf() and t.appliesTo(f, i, pos) } @@ -1260,7 +1263,7 @@ private predicate assocFunctionInfo( * is the type parameter used in the blanket implementation. */ pragma[nomagic] -private predicate functionInfoBlanketLike( +private predicate assocFunctionInfoBlanketLike( Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam ) { @@ -1328,7 +1331,7 @@ private class BorrowKind extends TBorrowKind { } /** - * Provides logic for resolving calls to methods. + * Provides logic for resolving calls to associated functions. * * When resolving a method call, a list of [candidate receiver types][1] is constructed * @@ -1362,194 +1365,270 @@ private class BorrowKind extends TBorrowKind { * * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ -private module MethodResolution { +private module AssocFunctionResolution { + /** + * Holds if the non-method trait function `f` mentions the implicit `Self` type + * parameter at `pos`. + */ + pragma[nomagic] + private predicate traitSelfTypeParameterOccurrence( + TraitItemNode trait, NonMethodFunction f, FunctionPosition pos + ) { + FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _, TSelfTypeParameter(trait)) + } + + /** + * Holds if the non-method function `f` implements a trait function that mentions + * the implicit `Self` type parameter at `pos`. + */ + pragma[nomagic] + private predicate traitImplSelfTypeParameterOccurrence( + ImplItemNode impl, NonMethodFunction f, FunctionPosition pos + ) { + exists(NonMethodFunction traitFunction | + f = impl.getAnAssocItem() and + f.implements(traitFunction) and + traitSelfTypeParameterOccurrence(_, traitFunction, pos) + ) + } + /** - * Holds if method `m` with the name `name` and the arity `arity` exists in - * `i`, and the type of the `self` parameter is `selfType`. + * Holds if function `f` with the name `name` and the arity `arity` exists in + * `i`, and the type at `selfPos` is `selfType`. * * `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 `getRefSharedTypeParameter()` + * if `f` has a `&self` parameter, then `strippedTypePath` is `getRefSharedTypeParameter()` * and `strippedType` is the type inside the reference. + * + * `selfPosAdj` is the function-call adjusted version of `selfPos`. */ pragma[nomagic] - private predicate methodInfo( - Method m, string name, int arity, ImplOrTraitItemNode i, AssocFunctionType selfType, - TypePath strippedTypePath, Type strippedType + private predicate assocFunctionInfo( + Function f, string name, int arity, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, + TypeOption implType, boolean isMethod ) { - exists(FunctionPosition pos | - assocFunctionInfo(m, name, arity, i, pos, selfType) and - strippedType = selfType.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - pos.isSelf() - ) + assocFunctionInfo(f, name, arity, i, selfPos, selfType) and + strippedType = selfType.getTypeAt(strippedTypePath) and + ( + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() + ) and + selfPosAdj = selfPos.getFunctionCallAdjusted(f) and + ( + selfPos.isSelfOrTypeQualifier() + or + traitSelfTypeParameterOccurrence(i, f, selfPos) + or + traitImplSelfTypeParameterOccurrence(i, f, selfPos) + ) and + ( + not i instanceof Impl and + implType.isNone() + or + implType.asSome() = resolveImplSelfTypeAt(i, TypePath::nil()) + ) and + if f instanceof Method then isMethod = true else isMethod = false } pragma[nomagic] - private predicate methodInfoTypeParam( - Method m, string name, int arity, ImplOrTraitItemNode i, AssocFunctionType selfType, - TypePath strippedTypePath, TypeParam tp + private predicate assocFunctionInfoNonBlanketLike0( + Function f, string name, int arity, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, + TypeOption implType, boolean isMethod ) { - methodInfo(m, name, arity, i, selfType, strippedTypePath, TTypeParamTypeParameter(tp)) + assocFunctionInfo(f, name, arity, selfPos, selfPosAdj, i, selfType, strippedTypePath, + strippedType, implType, isMethod) and + not BlanketImplementation::isBlanketLike(i, _, _) + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeTypeParam( + Function f, string name, int arity, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, TypeParam tp, + TypeOption implType, boolean isMethod + ) { + assocFunctionInfo(f, name, arity, selfPos, selfPosAdj, i, selfType, strippedTypePath, + TTypeParamTypeParameter(tp), implType, isMethod) and + not BlanketImplementation::isBlanketLike(i, _, _) } /** - * Same as `methodInfo`, but restricted to non-blanket implementations, and - * allowing for any `strippedType` when the corresponding type inside `m` is + * Same as `assocFunctionInfo`, but restricted to non-blanket-like implementations, and + * allowing for any `strippedType` when the corresponding type inside `f` is * a type parameter. */ pragma[inline] - private predicate methodInfoNonBlanket( - Method m, string name, int arity, ImplOrTraitItemNode i, AssocFunctionType selfType, - TypePath strippedTypePath, Type strippedType + private predicate assocFunctionInfoNonBlanketLike( + Function f, string name, int arity, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, + TypeOption implType, boolean isMethod ) { - ( - methodInfo(m, name, arity, i, selfType, strippedTypePath, strippedType) or - methodInfoTypeParam(m, name, arity, i, selfType, strippedTypePath, _) - ) and - not BlanketImplementation::isBlanketLike(i, _, _) + assocFunctionInfoNonBlanketLike0(f, name, arity, selfPos, selfPosAdj, i, selfType, + strippedTypePath, strippedType, implType, isMethod) or + assocFunctionInfoNonBlanketLikeTypeParam(f, name, arity, selfPos, selfPosAdj, i, selfType, + strippedTypePath, _, implType, isMethod) } /** - * Holds if method `m` with the name `name` and the arity `arity` exists in - * blanket (like) implementation `impl` of `trait`, and the type of the `self` - * parameter is `selfType`. + * Holds if associated function `f` with the name `name` and the arity `arity` exists + * in blanket (like) implementation `impl` of `trait`, and the type at `selfPos` is + * `selfType`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. */ pragma[nomagic] - private predicate methodInfoBlanketLike( - Method m, string name, int arity, ImplItemNode impl, Trait trait, AssocFunctionType selfType, - TypePath blanketPath, TypeParam blanketTypeParam + private predicate assocFunctionSelfInfoBlanketLike( + Function f, string name, int arity, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplItemNode impl, Trait trait, AssocFunctionType selfType, TypePath blanketPath, + TypeParam blanketTypeParam, boolean isMethod ) { - exists(FunctionPosition pos | - functionInfoBlanketLike(m, name, arity, impl, trait, pos, selfType, blanketPath, - blanketTypeParam) and - pos.isSelf() - ) + assocFunctionInfoBlanketLike(f, name, arity, impl, trait, selfPos, selfType, blanketPath, + blanketTypeParam) and + selfPosAdj = selfPos.getFunctionCallAdjusted(f) and + ( + selfPos.isSelfOrTypeQualifier() + or + traitImplSelfTypeParameterOccurrence(impl, f, selfPos) + ) and + if f instanceof Method then isMethod = true else isMethod = false } pragma[nomagic] - private predicate methodTraitInfo(string name, int arity, Trait trait) { + private predicate assocFunctionTraitInfo(string name, int arity, Trait trait) { exists(ImplItemNode i | - methodInfo(_, name, arity, i, _, _, _) and + assocFunctionInfo(_, name, arity, _, _, i, _, _, _, _, _) and trait = i.resolveTraitTy() ) or - methodInfo(_, name, arity, trait, _, _, _) + assocFunctionInfo(_, name, arity, _, _, trait, _, _, _, _, _) } pragma[nomagic] - private predicate methodCallTraitCandidate(Element mc, Trait trait) { - mc = - any(MethodCall mc0 | + private predicate assocFunctionCallTraitCandidate(Element afc, Trait trait) { + afc = + any(AssocFunctionCall afc0 | exists(string name, int arity | - mc0.hasNameAndArity(name, arity) and - methodTraitInfo(name, arity, trait) - | - not mc0.hasTrait() - or - trait = mc0.getTrait() + afc0.hasNameAndArity(name, arity, _, _) and + assocFunctionTraitInfo(name, arity, trait) and + not afc0.hasTrait() ) ) } - private module MethodTraitIsVisible = TraitIsVisible; + private module AssocFunctionTraitIsVisible = TraitIsVisible; - private predicate methodCallVisibleTraitCandidate = MethodTraitIsVisible::traitIsVisible/2; + pragma[nomagic] + predicate callVisibleTraitCandidate(AssocFunctionCall afc, Trait trait) { + AssocFunctionTraitIsVisible::traitIsVisible(afc, trait) + or + // if the call has a trait qualifier then that trait must be visible + trait = afc.getTrait() + } - bindingset[mc, impl] + bindingset[afc, impl] pragma[inline_late] - private predicate methodCallVisibleImplTraitCandidate(MethodCall mc, ImplItemNode impl) { - methodCallVisibleTraitCandidate(mc, impl.resolveTraitTy()) + private predicate callVisibleImplTraitCandidate(AssocFunctionCall afc, ImplItemNode impl) { + callVisibleTraitCandidate(afc, impl.resolveTraitTy()) } + pragma[nomagic] + private predicate implHasNoTrait(Impl i) { not i.hasTrait() } + /** - * Holds if method call `mc` may target a method in `i` with `self` parameter having - * type `selfType`. + * Holds if call `afc` may target function `f` in `i` with type `selfType` at + * `selfPos`. * * `strippedTypePath` points to the type `strippedType` inside `selfType`, * which is the (possibly complex-stripped) root type of `selfType`. * - * This predicate only checks for matching method names and arities, and whether + * This predicate only checks for matching function names and arities, and whether * the trait being implemented by `i` (when `i` is not a trait itself) is visible - * at `mc`. + * at `afc`. */ - bindingset[mc, strippedTypePath, strippedType] + bindingset[afc, strippedTypePath, strippedType] pragma[inline_late] - private predicate methodCallNonBlanketCandidate( - MethodCall mc, Method m, ImplOrTraitItemNode i, AssocFunctionType self, - TypePath strippedTypePath, Type strippedType + private predicate nonBlanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoNonBlanket(m, name, arity, i, self, strippedTypePath, strippedType) + exists(string name, int arity, TypeOption implType, boolean isMethod | + afc.hasNameAndArity(name, arity, [implType, any(TypeOption non | non.isNone())], isMethod) and + assocFunctionInfoNonBlanketLike(f, name, arity, selfPos, selfPosAdj, i, selfType, + strippedTypePath, strippedType, implType, isMethod) | - i = - any(Impl impl | - not impl.hasTrait() - or - methodCallVisibleImplTraitCandidate(mc, impl) - ) + implHasNoTrait(i) or - methodCallVisibleTraitCandidate(mc, i) + callVisibleImplTraitCandidate(afc, i) or - i.(ImplItemNode).resolveTraitTy() = mc.getTrait() + callVisibleTraitCandidate(afc, i) ) } /** - * Holds if method call `mc` may target a method in blanket (like) implementation - * `impl` with `self` parameter having type `selfType`. + * Holds if call `afc` may target function `f` in blanket (like) implementation + * `impl` with type `selfType` at `selfPos`. * * `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which * is the type parameter used in the blanket implementation. * - * This predicate only checks for matching method names and arities, and whether + * This predicate only checks for matching function names and arities, and whether * the trait being implemented by `i` (when `i` is not a trait itself) is visible - * at `mc`. + * at `afc`. */ - bindingset[mc] + bindingset[afc] pragma[inline_late] - private predicate methodCallBlanketLikeCandidate( - MethodCall mc, Method m, ImplItemNode impl, AssocFunctionType self, TypePath blanketPath, - TypeParam blanketTypeParam + private predicate blanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPosition selfPos, FunctionPosition selfPosAdj, + ImplItemNode impl, AssocFunctionType self, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoBlanketLike(m, name, arity, impl, _, self, blanketPath, blanketTypeParam) - | - methodCallVisibleImplTraitCandidate(mc, impl) - or - impl.resolveTraitTy() = mc.getTrait() + exists(string name, int arity, boolean isMethod | + afc.hasNameAndArity(name, arity, _, isMethod) and + assocFunctionSelfInfoBlanketLike(f, name, arity, selfPos, selfPosAdj, impl, _, self, + blanketPath, blanketTypeParam, isMethod) and + callVisibleImplTraitCandidate(afc, impl) ) } + private module TypeOption = Option; + + private class TypeOption = TypeOption::Option; + /** - * A (potential) method call. + * A (potential) call to an associated function. * * This is either: * - * 1. `MethodCallMethodCallExpr`: an actual method call, `x.m()`; - * 2. `MethodCallIndexExpr`: an index expression, `x[i]`, which is [syntactic sugar][1] + * 1. `AssocFunctionCallMethodCallExpr`: a method call, `x.m()`; + * 2. `AssocFunctionCallIndexExpr`: an index expression, `x[i]`, which is [syntactic sugar][1] * for `*x.index(i)`; - * 3. `MethodCallCallExpr`: a qualified function call, `Q::m(x)`, where `m` is a method; - * or - * 4. `MethodCallOperation`: an operation expression, `x + y`, which is syntactic sugar + * 3. `AssocFunctionCallCallExpr`: a qualified function call, `Q::f(x)`, where `f` is an associated + * function; or + * 4. `AssocFunctionCallOperation`: an operation expression, `x + y`, which is syntactic sugar * for `Add::add(x, y)`. * * Note that only in case 1 and 2 is auto-dereferencing and borrowing allowed. * - * Note also that only case 4 is a _potential_ method call; in all other cases, we are - * guaranteed that the target is a method. + * Note also that only case 3 is a _potential_ call; in all other cases, we are guaranteed that + * the target is an associated function. * * [1]: https://doc.rust-lang.org/std/ops/trait.Index.html */ - abstract class MethodCall extends Expr { - abstract predicate hasNameAndArity(string name, int arity); + abstract class AssocFunctionCall extends Expr { + abstract predicate hasNameAndArity(string name, int arity, TypeOption implType, boolean isMethod); - abstract Expr getArg(ArgumentPosition pos); + abstract Expr getNonReturnNodeAt(FunctionPosition apos); + + AstNode getNodeAt(FunctionPosition pos) { + result = this.getNonReturnNodeAt(pos) + or + result = this and pos.isReturn() + } + + predicate hasReceiver() { exists(this.getNodeAt(any(FunctionPosition self | self.isSelf()))) } abstract predicate supportsAutoDerefAndBorrow(); @@ -1559,154 +1638,195 @@ private module MethodResolution { /** Holds if this call targets a trait. */ predicate hasTrait() { exists(this.getTrait()) } - AstNode getNodeAt(FunctionPosition apos) { - result = this.getArg(apos.asArgumentPosition()) - or - result = this and apos.isReturn() - } - - Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = inferType(this.getArg(pos), path) + Type getTypeAt(FunctionPosition pos, TypePath path) { + result = inferType(this.getNodeAt(pos), path) } - private Type getReceiverTypeAt(TypePath path) { - result = this.getArgumentTypeAt(any(ArgumentPosition pos | pos.isSelf()), path) + /** + * Holds if `selfPos` is a potentially relevant position for resolving this call. + */ + pragma[nomagic] + private predicate isRelevantSelfPos(FunctionPosition selfPos) { + exists(TypePath strippedTypePath, Type strippedType | + strippedType = substituteLookupTraits(this.getTypeAt(selfPos, strippedTypePath)) + | + selfPos.isSelfOrTypeQualifier() + or + not this.hasReceiver() and + ( + blanketLikeCandidate(this, _, _, selfPos, _, _, _, _) + or + nonBlanketLikeCandidate(this, _, _, selfPos, _, _, strippedTypePath, strippedType) + ) + ) } /** - * Same as `getACandidateReceiverTypeAt`, but without borrows. + * Same as `getSelfTypeAt`, but without borrows. */ pragma[nomagic] - Type getACandidateReceiverTypeAtNoBorrow(DerefChain derefChain, TypePath path) { - result = this.getReceiverTypeAt(path) and - derefChain.isEmpty() + Type getSelfTypeAtNoBorrow(FunctionPosition selfPos, DerefChain derefChain, TypePath path) { + result = this.getTypeAt(selfPos, path) and + derefChain.isEmpty() and + this.isRelevantSelfPos(selfPos) or exists(DerefImplItemNode impl, DerefChain suffix | - result = ImplicitDeref::getDereferencedCandidateReceiverType(this, impl, suffix, path) and + result = + ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPos, impl, suffix, path) and derefChain = DerefChain::cons(impl, suffix) ) } /** - * Holds if the method inside `i` with matching name and arity can be ruled + * Holds if the function inside `i` with matching name and arity can be ruled * out as a target of this call, because the candidate receiver type represented - * by `derefChain` and `borrow` is incompatible with the `self` parameter type. + * by `derefChain` and `borrow` is incompatible with the type at `selfPos`. * * The types are incompatible because they disagree on a concrete type somewhere * inside `root`. */ pragma[nomagic] private predicate hasIncompatibleTarget( - ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow, Type root + ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + Type root ) { exists(TypePath path | - ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, - derefChain, borrow), i, _, path) and + ArgIsInstantiationOfSelfParam::argIsNotInstantiationOf(this, i, selfPos, derefChain, borrow, + path) and path.isCons(root.getATypeParameter(), _) ) + or + exists(AssocFunctionType selfType | + ArgIsInstantiationOfSelfParam::argIsInstantiationOf(this, i, selfPos, derefChain, borrow, + selfType) and + CallArgsAreInstantiationsOf::argsAreNotInstantiationsOf(this, i) and + root = selfType.getTypeAt(TypePath::nil()) + ) } /** - * Holds if the method inside blanket-like implementation `impl` with matching name + * Holds if the function inside blanket-like implementation `impl` with matching name * and arity can be ruled out as a target of this call, either because the candidate - * receiver type represented by `derefChain` and `borrow` is incompatible with the `self` - * parameter type, or because the blanket constraint is not satisfied. + * receiver type represented by `derefChain` and `borrow` is incompatible with the type + * at `selfPos`, or because the blanket constraint is not satisfied. */ pragma[nomagic] private predicate hasIncompatibleBlanketLikeTarget( - ImplItemNode impl, DerefChain derefChain, BorrowKind borrow + ImplItemNode impl, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow ) { - ReceiverIsNotInstantiationOfBlanketLikeSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, - derefChain, borrow), impl, _, _) + ArgIsNotInstantiationOfBlanketLikeSelfParam::argIsNotInstantiationOf(MkAssocFunctionCallCand(this, + selfPos, _, derefChain, borrow), impl, _, _) or - ReceiverSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkMethodCallCand(this, - derefChain, borrow), impl) + ArgSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkAssocFunctionCallCand(this, + selfPos, _, derefChain, borrow), impl) } /** - * Same as `getACandidateReceiverTypeAt`, but excludes pseudo types `!` and `unknown`. + * Same as `getTypeAt`, but excludes pseudo types `!` and `unknown`. */ pragma[nomagic] - Type getANonPseudoCandidateReceiverTypeAt( - DerefChain derefChain, BorrowKind borrow, TypePath path + Type getANonPseudoSelfTypeAt( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAt(derefChain, borrow, path) and + result = this.getSelfTypeAt(selfPos, derefChain, borrow, path) and result != TNeverType() and result != TUnknownType() } pragma[nomagic] - private Type getComplexStrippedType( - DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath + private Type getComplexStrippedSelfType( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath ) { - result = this.getANonPseudoCandidateReceiverTypeAt(derefChain, borrow, strippedTypePath) and - isComplexRootStripped(strippedTypePath, result) + result = this.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, strippedTypePath) and + ( + isComplexRootStripped(strippedTypePath, result) + or + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() + ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketLikeTargetCheck( - DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, + Type strippedType ) { forall(ImplOrTraitItemNode i | - methodCallNonBlanketCandidate(this, _, i, _, strippedTypePath, strippedType) + nonBlanketLikeCandidate(this, _, selfPos, _, i, _, strippedTypePath, strippedType) | - this.hasIncompatibleTarget(i, derefChain, borrow, strippedType) + this.hasIncompatibleTarget(i, selfPos, derefChain, borrow, strippedType) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleTargetCheck( - DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, + Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(derefChain, borrow, strippedTypePath, + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, strippedType) and - forall(ImplItemNode i | methodCallBlanketLikeCandidate(this, _, i, _, _, _) | - this.hasIncompatibleBlanketLikeTarget(i, derefChain, borrow) + forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPos, _, i, _, _, _) | + this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketTargetCheck( - DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, Type strippedType + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, + Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(derefChain, borrow, strippedTypePath, + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, strippedType) and forall(ImplItemNode i | - methodCallBlanketLikeCandidate(this, _, i, _, _, _) and not i.isBlanketImplementation() + blanketLikeCandidate(this, _, selfPos, _, i, _, _, _) and + not i.isBlanketImplementation() | - this.hasIncompatibleBlanketLikeTarget(i, derefChain, borrow) + this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) ) } // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetNoBorrowToIndex( - DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { ( - this.supportsAutoDerefAndBorrow() + this.supportsAutoDerefAndBorrow() and + selfPos.isSelf() or // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` + // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` derefChain.isEmpty() ) and - strippedType = this.getComplexStrippedType(derefChain, TNoBorrowKind(), strippedTypePath) and + strippedType = + this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetNoBorrowToIndex(derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleTargetCheck(derefChain, TNoBorrowKind(), strippedTypePath, t) + exists(Type t | + this.hasNoCompatibleTargetNoBorrowToIndexRec(selfPos, derefChain, strippedTypePath, + strippedType, n, t) and + this.hasNoCompatibleTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } + pragma[nomagic] + private predicate hasNoCompatibleTargetNoBorrowToIndexRec( + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n, Type t + ) { + this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, + n - 1) and + t = getNthLookupType(strippedType, n) + } + /** * Holds if the candidate receiver type represented by `derefChain` does not - * have a matching method target. + * have a matching call target at `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleTargetNoBorrow(DerefChain derefChain) { + predicate hasNoCompatibleTargetNoBorrow(FunctionPosition selfPos, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetNoBorrowToIndex(derefChain, _, strippedType, + this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1714,33 +1834,49 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndex( - DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { ( - this.supportsAutoDerefAndBorrow() + this.supportsAutoDerefAndBorrow() and + selfPos.isSelf() or // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` + // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` derefChain.isEmpty() ) and - strippedType = this.getComplexStrippedType(derefChain, TNoBorrowKind(), strippedTypePath) and + strippedType = + this.getComplexStrippedSelfType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(derefChain, TNoBorrowKind(), strippedTypePath, t) + exists(Type t | + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndexRec(selfPos, derefChain, + strippedTypePath, strippedType, n, t) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TNoBorrowKind(), + strippedTypePath, t) ) } + pragma[nomagic] + private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndexRec( + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n, Type t + ) { + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, + strippedType, n - 1) and + t = getNthLookupType(strippedType, n) + } + /** * Holds if the candidate receiver type represented by `derefChain` does not have - * a matching non-blanket method target. + * a matching non-blanket call target at `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetNoBorrow(DerefChain derefChain) { + predicate hasNoCompatibleNonBlanketTargetNoBorrow( + FunctionPosition selfPos, DerefChain derefChain + ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(derefChain, _, strippedType, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1748,29 +1884,41 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetSharedBorrowToIndex( - DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleTargetNoBorrow(derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetSharedBorrowToIndex(derefChain, strippedTypePath, strippedType, - n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketLikeTargetCheck(derefChain, TSomeBorrowKind(false), + exists(Type t | + this.hasNoCompatibleTargetSharedBorrowToIndexRec(selfPos, derefChain, strippedTypePath, + strippedType, n, t) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) } + pragma[nomagic] + private predicate hasNoCompatibleTargetSharedBorrowToIndexRec( + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n, Type t + ) { + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, + strippedType, n - 1) and + t = getNthLookupType(strippedType, n) + } + /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching method target. + * by a shared borrow, does not have a matching call target at `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleTargetSharedBorrow(DerefChain derefChain) { + predicate hasNoCompatibleTargetSharedBorrow(FunctionPosition selfPos, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetSharedBorrowToIndex(derefChain, _, strippedType, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1778,28 +1926,40 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetMutBorrowToIndex( - DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleTargetSharedBorrow(derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetMutBorrowToIndex(derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketLikeTargetCheck(derefChain, TSomeBorrowKind(true), + exists(Type t | + this.hasNoCompatibleTargetMutBorrowToIndexRec(selfPos, derefChain, strippedTypePath, + strippedType, n, t) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } + pragma[nomagic] + private predicate hasNoCompatibleTargetMutBorrowToIndexRec( + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n, Type t + ) { + this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, + strippedType, n - 1) and + t = getNthLookupType(strippedType, n) + } + /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching method target. + * by a `mut` borrow, does not have a matching call target at `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleTargetMutBorrow(DerefChain derefChain) { + predicate hasNoCompatibleTargetMutBorrow(FunctionPosition selfPos, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetMutBorrowToIndex(derefChain, _, strippedType, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1807,65 +1967,95 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndex( - DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleTargetNoBorrow(derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(derefChain, TSomeBorrowKind(false), + exists(Type t | + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndexRec(selfPos, derefChain, + strippedTypePath, strippedType, n, t) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) } + pragma[nomagic] + private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndexRec( + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n, Type t + ) { + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, + strippedType, n - 1) and + t = getNthLookupType(strippedType, n) + } + /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a shared borrow, does not have a matching non-blanket method target. + * by a shared borrow, does not have a matching non-blanket call target at `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetSharedBorrow(DerefChain derefChain) { + predicate hasNoCompatibleNonBlanketTargetSharedBorrow( + FunctionPosition selfPos, DerefChain derefChain + ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(derefChain, _, strippedType, - getLastLookupTypeIndex(strippedType)) + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, _, + strippedType, getLastLookupTypeIndex(strippedType)) ) } // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndex( - DerefChain derefChain, TypePath strippedTypePath, Type strippedType, int n + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n ) { - this.hasNoCompatibleNonBlanketTargetSharedBorrow(derefChain) and + this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and strippedType = - this.getComplexStrippedType(derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(derefChain, TSomeBorrowKind(true), + exists(Type t | + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndexRec(selfPos, derefChain, + strippedTypePath, strippedType, n, t) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } + pragma[nomagic] + private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndexRec( + FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, + int n, Type t + ) { + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, + strippedType, n - 1) and + t = getNthLookupType(strippedType, n) + } + /** * Holds if the candidate receiver type represented by `derefChain`, followed - * by a `mut` borrow, does not have a matching non-blanket method target. + * by a `mut` borrow, does not have a matching non-blanket call target at `selfPos`. */ pragma[nomagic] - predicate hasNoCompatibleNonBlanketTargetMutBorrow(DerefChain derefChain) { + predicate hasNoCompatibleNonBlanketTargetMutBorrow( + FunctionPosition selfPos, DerefChain derefChain + ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(derefChain, _, strippedType, + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } /** - * Gets a [candidate receiver type][1] of this method call at `path`. + * Gets the type of this call at `selfPos` and `path`. + * + * In case this call supports auto-dereferencing and borrowing and `selfPos` is the + * `self` parameter position, the result is a [candidate receiver type][1]: * * The type is obtained by repeatedly dereferencing the receiver expression's type, * as long as the method cannot be resolved in an earlier candidate type, and possibly @@ -1877,18 +2067,21 @@ private module MethodResolution { * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ pragma[nomagic] - Type getACandidateReceiverTypeAt(DerefChain derefChain, BorrowKind borrow, TypePath path) { - result = this.getACandidateReceiverTypeAtNoBorrow(derefChain, path) and + Type getSelfTypeAt( + FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path + ) { + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, path) and borrow.isNoBorrow() or exists(RefType rt | // first try shared borrow this.supportsAutoDerefAndBorrow() and - this.hasNoCompatibleTargetNoBorrow(derefChain) and + selfPos.isSelf() and + this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and borrow.isSharedBorrow() or // then try mutable borrow - this.hasNoCompatibleTargetSharedBorrow(derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and borrow.isMutableBorrow() | rt = borrow.getRefType() and @@ -1897,7 +2090,7 @@ private module MethodResolution { result = rt or exists(TypePath suffix | - result = this.getACandidateReceiverTypeAtNoBorrow(derefChain, suffix) and + result = this.getSelfTypeAtNoBorrow(selfPos, derefChain, suffix) and path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) ) ) @@ -1905,15 +2098,15 @@ private module MethodResolution { } /** - * Gets a method that this call resolves to after having applied a sequence of + * Gets a function that this call resolves to after having applied a sequence of * dereferences and possibly a borrow on the receiver type, encoded in `derefChain` * and `borrow`. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow) { - exists(MethodCallCand mcc | - mcc = MkMethodCallCand(this, derefChain, borrow) and - result = mcc.resolveCallTarget(i) + AssocFunction resolveCallTarget(ImplOrTraitItemNode i, DerefChain derefChain, BorrowKind borrow) { + exists(AssocFunctionCallCand afcc | + afcc = MkAssocFunctionCallCand(this, _, _, derefChain, borrow) and + result = afcc.resolveCallTarget(i) ) } @@ -1923,21 +2116,26 @@ private module MethodResolution { * resolve the call target. */ predicate argumentHasImplicitDerefChainBorrow(Expr arg, DerefChain derefChain, BorrowKind borrow) { - exists(this.resolveCallTarget(_, derefChain, borrow)) and - arg = this.getArg(any(ArgumentPosition pos | pos.isSelf())) and - not (derefChain.isEmpty() and borrow.isNoBorrow()) + exists(FunctionPosition self | + self.isSelf() and + exists(this.resolveCallTarget(_, derefChain, borrow)) and + arg = this.getNodeAt(self) and + not (derefChain.isEmpty() and borrow.isNoBorrow()) + ) } } - private class MethodCallMethodCallExpr extends MethodCall instanceof MethodCallExpr { + private class AssocFunctionCallMethodCallExpr extends AssocFunctionCall instanceof MethodCallExpr { pragma[nomagic] - override predicate hasNameAndArity(string name, int arity) { + override predicate hasNameAndArity(string name, int arity, TypeOption implType, boolean isMethod) { name = super.getIdentifier().getText() and - arity = super.getArgList().getNumberOfArgs() + arity = super.getArgList().getNumberOfArgs() + 1 and + implType.isNone() and + isMethod = true } - override Expr getArg(ArgumentPosition pos) { - result = MethodCallExpr.super.getSyntacticArgument(pos) + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = MethodCallExpr.super.getSyntacticArgument(pos.asArgumentPosition()) } override predicate supportsAutoDerefAndBorrow() { any() } @@ -1945,19 +2143,21 @@ private module MethodResolution { override Trait getTrait() { none() } } - private class MethodCallIndexExpr extends MethodCall instanceof IndexExpr { + private class AssocFunctionCallIndexExpr extends AssocFunctionCall instanceof IndexExpr { private predicate isInMutableContext() { // todo: does not handle all cases yet VariableImpl::assignmentOperationDescendant(_, this) } pragma[nomagic] - override predicate hasNameAndArity(string name, int arity) { + override predicate hasNameAndArity(string name, int arity, TypeOption implType, boolean isMethod) { (if this.isInMutableContext() then name = "index_mut" else name = "index") and - arity = 1 + arity = 2 and + implType.isNone() and + isMethod = true } - override Expr getArg(ArgumentPosition pos) { + override Expr getNonReturnNodeAt(FunctionPosition pos) { pos.isSelf() and result = super.getBase() or @@ -1974,67 +2174,42 @@ private module MethodResolution { } } - private class MethodCallCallExpr extends MethodCall instanceof CallExpr { - MethodCallCallExpr() { + class AssocFunctionCallCallExpr extends AssocFunctionCall instanceof CallExpr { + AssocFunctionCallCallExpr() { exists(getCallExprPathQualifier(this)) and - // even if a method cannot be resolved by path resolution, it may still + // even if a target cannot be resolved by path resolution, it may still // be possible to resolve a blanket implementation (so not `forex`) - forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof Method) - } - - bindingset[this, f] - pragma[inline_late] - private predicate hasTypeQualifiedCandidateFilter(Function f, ImplItemNode impl) { - f = impl.getAnAssocItem() - or - exists(TraitItemNode trait | - f = trait.getAnAssocItem() and - methodCallVisibleTraitCandidate(this, trait) and - impl.resolveTraitTy() = trait - ) + forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof AssocFunction) } - /** - * Holds if this call has a type qualifier, and we are able to resolve, - * using path resolution, the method to a member of `impl` or the trait - * being implemented by `impl` (when this call os of the kind - * `::f()`). - * - * When this is the case, we still want to check that the type qualifier - * is an instance of the type being implemented, which is done in - * `TypeQualifierIsInstantiationOfImplSelfInput`. - */ pragma[nomagic] - predicate hasTypeQualifiedCandidate(ImplItemNode impl) { - exists(Function f | - exists(getCallExprTypeQualifier(this, _, _)) and - f = CallExprImpl::getResolvedFunction(this) and - this.hasTypeQualifiedCandidateFilter(f, impl) - ) + private Type getNonTypeParameterTypeQualifier() { + result = getCallExprTypeQualifier(this, TypePath::nil(), _) and + not result instanceof TypeParameter } pragma[nomagic] - override predicate hasNameAndArity(string name, int arity) { + override predicate hasNameAndArity(string name, int arity, TypeOption implType, boolean isMethod) { name = CallExprImpl::getFunctionPath(this).getText() and - arity = super.getArgList().getNumberOfArgs() - 1 - } - - override Expr getArg(ArgumentPosition pos) { - pos.isSelf() and - result = super.getSyntacticPositionalArgument(0) - or - result = super.getSyntacticPositionalArgument(pos.asPosition() + 1) + arity = super.getArgList().getNumberOfArgs() and + ( + not exists(this.getNonTypeParameterTypeQualifier()) and + implType.isNone() + or + implType.asSome() = this.getNonTypeParameterTypeQualifier() + ) and + isMethod = [false, true] } - // needed for `TypeQualifierIsInstantiationOfImplSelfInput` - Type getTypeAt(TypePath path) { - result = substituteLookupTraits(getCallExprTypeQualifier(this, path, _)) + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = super.getSyntacticPositionalArgument(pos.asPosition()) } - pragma[nomagic] - predicate hasNoInherentTarget() { - // `_` is fine below, because auto-deref/borrow is not supported - MkMethodCallCand(this, _, _).(MethodCallCand).hasNoInherentTarget() + override Type getTypeAt(FunctionPosition pos, TypePath path) { + result = super.getTypeAt(pos, path) + or + pos.isTypeQualifier() and + result = getCallExprTypeQualifier(this, path, _) } override predicate supportsAutoDerefAndBorrow() { none() } @@ -2042,21 +2217,23 @@ private module MethodResolution { override Trait getTrait() { result = getCallExprTraitQualifier(this) } } - final class MethodCallOperation extends MethodCall instanceof Operation { + final class AssocFunctionCallOperation extends AssocFunctionCall instanceof Operation { pragma[nomagic] - override predicate hasNameAndArity(string name, int arity) { + override predicate hasNameAndArity(string name, int arity, TypeOption implType, boolean isMethod) { super.isOverloaded(_, name, _) and - arity = super.getNumberOfOperands() - 1 + arity = super.getNumberOfOperands() and + implType.isNone() and + isMethod = true } - override Expr getArg(ArgumentPosition pos) { + override Expr getNonReturnNodeAt(FunctionPosition pos) { pos.isSelf() and result = super.getOperand(0) or result = super.getOperand(pos.asPosition() + 1) } - private predicate implicitBorrowAt(ArgumentPosition pos, boolean isMutable) { + private predicate implicitBorrowAt(FunctionPosition pos, boolean isMutable) { exists(int borrows | super.isOverloaded(_, _, borrows) | pos.isSelf() and borrows >= 1 and @@ -2068,7 +2245,7 @@ private module MethodResolution { ) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { + override Type getTypeAt(FunctionPosition pos, TypePath path) { exists(boolean isMutable, RefType rt | this.implicitBorrowAt(pos, isMutable) and rt = getRefType(isMutable) @@ -2077,21 +2254,21 @@ private module MethodResolution { path.isEmpty() or exists(TypePath path0 | - result = inferType(this.getArg(pos), path0) and + result = inferType(this.getNodeAt(pos), path0) and path = TypePath::cons(rt.getPositionalTypeParameter(0), path0) ) ) or not this.implicitBorrowAt(pos, _) and - result = inferType(this.getArg(pos), path) + result = inferType(this.getNodeAt(pos), path) } override predicate argumentHasImplicitDerefChainBorrow( Expr arg, DerefChain derefChain, BorrowKind borrow ) { - exists(ArgumentPosition pos, boolean isMutable | + exists(FunctionPosition pos, boolean isMutable | this.implicitBorrowAt(pos, isMutable) and - arg = this.getArg(pos) and + arg = this.getNodeAt(pos) and derefChain = DerefChain::nil() and borrow = TSomeBorrowKind(isMutable) ) @@ -2103,74 +2280,93 @@ private module MethodResolution { } pragma[nomagic] - private Method getMethodSuccessor(ImplOrTraitItemNode i, string name, int arity) { + private AssocFunction getFunctionSuccessor(ImplOrTraitItemNode i, string name, int arity) { result = i.getASuccessor(name) and - arity = result.getParamList().getNumberOfParams() + arity = result.getNumberOfParamsInclSelf() } - private newtype TMethodCallCand = - MkMethodCallCand(MethodCall mc, DerefChain derefChain, BorrowKind borrow) { - exists(mc.getACandidateReceiverTypeAt(derefChain, borrow, _)) + private newtype TAssocFunctionCallCand = + MkAssocFunctionCallCand( + AssocFunctionCall afc, FunctionPosition selfPos, FunctionPosition selfPosAdj, + DerefChain derefChain, BorrowKind borrow + ) { + exists(afc.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, _)) and + if afc.hasReceiver() + then selfPosAdj = selfPos.getFunctionCallAdjusted() + else selfPosAdj = selfPos } - /** A method call with a dereference chain and a potential borrow. */ - private class MethodCallCand extends MkMethodCallCand { - MethodCall mc_; + /** A call with a dereference chain and a potential borrow. */ + final private class AssocFunctionCallCand extends MkAssocFunctionCallCand { + AssocFunctionCall afc_; + FunctionPosition selfPos; + FunctionPosition selfPosAdj; DerefChain derefChain; BorrowKind borrow; - MethodCallCand() { this = MkMethodCallCand(mc_, derefChain, borrow) } + AssocFunctionCallCand() { + this = MkAssocFunctionCallCand(afc_, selfPos, selfPosAdj, derefChain, borrow) + } - MethodCall getMethodCall() { result = mc_ } + AssocFunctionCall getAssocFunctionCall() { result = afc_ } Type getTypeAt(TypePath path) { result = - substituteLookupTraits(mc_.getANonPseudoCandidateReceiverTypeAt(derefChain, borrow, path)) + substituteLookupTraits(afc_.getANonPseudoSelfTypeAt(selfPos, derefChain, borrow, path)) } pragma[nomagic] predicate hasNoCompatibleNonBlanketTarget() { - mc_.hasNoCompatibleNonBlanketTargetSharedBorrow(derefChain) and + afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and borrow.isSharedBorrow() or - mc_.hasNoCompatibleNonBlanketTargetMutBorrow(derefChain) and + afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos, derefChain) and borrow.isMutableBorrow() or - mc_.hasNoCompatibleNonBlanketTargetNoBorrow(derefChain) and + afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos, derefChain) and borrow.isNoBorrow() } pragma[nomagic] predicate hasSignature( - MethodCall mc, TypePath strippedTypePath, Type strippedType, string name, int arity + AssocFunctionCall afc, FunctionPosition pos, TypePath strippedTypePath, Type strippedType, + string name, int arity ) { strippedType = this.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - mc = mc_ and - mc.hasNameAndArity(name, arity) + ( + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPos.isTypeQualifier() and strippedTypePath.isEmpty() + ) and + afc = afc_ and + afc.hasNameAndArity(name, arity, _, _) and + pos = selfPosAdj } /** - * Holds if the inherent method inside `impl` with matching name and arity can be + * Holds if the inherent function inside `impl` with matching name and arity can be * ruled out as a candidate for this call. */ pragma[nomagic] private predicate hasIncompatibleInherentTarget(Impl impl) { - ReceiverIsNotInstantiationOfInherentSelfParam::argIsNotInstantiationOf(this, impl, _, _) + ArgIsNotInstantiationOfInherentSelfParam::argIsNotInstantiationOf(this, impl, _, _) } /** - * Holds if this method call has no inherent target, i.e., it does not - * resolve to a method in an `impl` block for the type of the receiver. + * Holds if this function call has no inherent target, i.e., it does not + * resolve to a function in an `impl` block for the type of the receiver. */ pragma[nomagic] predicate hasNoInherentTarget() { - mc_.hasTrait() + afc_.hasTrait() or exists(TypePath strippedTypePath, Type strippedType, string name, int arity | - this.hasSignature(_, strippedTypePath, strippedType, name, arity) and + selfPosAdj.isTypeQualifier() or selfPosAdj.asPosition() = 0 + | + this.hasSignature(_, selfPosAdj, strippedTypePath, strippedType, name, arity) and forall(Impl i | - methodInfoNonBlanket(_, name, arity, i, _, strippedTypePath, strippedType) and + assocFunctionInfoNonBlanketLike(_, name, arity, _, selfPosAdj, i, _, strippedTypePath, + strippedType, _, _) and not i.hasTrait() | this.hasIncompatibleInherentTarget(i) @@ -2178,43 +2374,34 @@ private module MethodResolution { ) } - pragma[nomagic] - private predicate typeQualifierIsInstantiationOf(ImplItemNode i) { - TypeQualifierIsInstantiationOfImplSelf::isInstantiationOf(mc_, i, _) - } - pragma[nomagic] private predicate argIsInstantiationOf(ImplOrTraitItemNode i, string name, int arity) { - ( - ReceiverIsInstantiationOfSelfParam::argIsInstantiationOf(this, i, _) - or - this.typeQualifierIsInstantiationOf(i) - ) and - mc_.hasNameAndArity(name, arity) + ArgIsInstantiationOfSelfParam::argIsInstantiationOf(this, i, _) and + afc_.hasNameAndArity(name, arity, _, _) } pragma[nomagic] - Method resolveCallTargetCand(ImplOrTraitItemNode i) { + AssocFunction resolveCallTargetCand(ImplOrTraitItemNode i) { exists(string name, int arity | this.argIsInstantiationOf(i, name, arity) and - result = getMethodSuccessor(i, name, arity) + result = getFunctionSuccessor(i, name, arity) ) } - /** Gets a method that matches this method call. */ + /** Gets a function that matches this call. */ pragma[nomagic] - Method resolveCallTarget(ImplOrTraitItemNode i) { + AssocFunction resolveCallTarget(ImplOrTraitItemNode i) { result = this.resolveCallTargetCand(i) and not FunctionOverloading::functionResolutionDependsOnArgument(i, result, _, _) or - MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) + CallArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) } string toString() { - result = mc_.toString() + " [" + derefChain.toString() + "; " + borrow + "]" + result = afc_ + " at " + selfPos + " [" + derefChain.toString() + "; " + borrow + "]" } - Location getLocation() { result = mc_.getLocation() } + Location getLocation() { result = afc_.getLocation() } } /** @@ -2222,21 +2409,23 @@ private module MethodResolution { */ private module ImplicitDeref { private newtype TMethodCallDerefCand = - MkMethodCallDerefCand(MethodCall mc, DerefChain derefChain) { + MkMethodCallDerefCand(AssocFunctionCall mc, FunctionPosition selfPos, DerefChain derefChain) { mc.supportsAutoDerefAndBorrow() and - mc.hasNoCompatibleTargetMutBorrow(derefChain) and - exists(mc.getACandidateReceiverTypeAtNoBorrow(derefChain, TypePath::nil())) + selfPos.isSelf() and + mc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and + exists(mc.getSelfTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) } /** A method call with a dereference chain. */ private class MethodCallDerefCand extends MkMethodCallDerefCand { - MethodCall mc; + AssocFunctionCall mc; + FunctionPosition selfPos; DerefChain derefChain; - MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, derefChain) } + MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, selfPos, derefChain) } Type getTypeAt(TypePath path) { - result = substituteLookupTraits(mc.getACandidateReceiverTypeAtNoBorrow(derefChain, path)) and + result = substituteLookupTraits(mc.getSelfTypeAtNoBorrow(selfPos, derefChain, path)) and result != TNeverType() and result != TUnknownType() } @@ -2265,15 +2454,16 @@ private module MethodResolution { } /** - * Gets the type of the receiver of `mc` at `path` after applying the implicit + * Gets the type of the receiver of `afc` at `path` after applying the implicit * dereference inside `impl`, following the existing dereference chain `derefChain`. */ pragma[nomagic] Type getDereferencedCandidateReceiverType( - MethodCall mc, DerefImplItemNode impl, DerefChain derefChain, TypePath path + AssocFunctionCall afc, FunctionPosition selfPos, DerefImplItemNode impl, + DerefChain derefChain, TypePath path ) { exists(MethodCallDerefCand mcc, TypePath exprPath | - mcc = MkMethodCallDerefCand(mc, derefChain) and + mcc = MkMethodCallDerefCand(afc, selfPos, derefChain) and MethodCallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(mcc, impl, _, exprPath, result) and exprPath.isCons(getDerefTargetTypeParameter(), path) @@ -2281,21 +2471,22 @@ private module MethodResolution { } } - private module ReceiverSatisfiesBlanketLikeConstraintInput implements - BlanketImplementation::SatisfiesBlanketConstraintInputSig + private module ArgSatisfiesBlanketLikeConstraintInput implements + BlanketImplementation::SatisfiesBlanketConstraintInputSig { pragma[nomagic] predicate hasBlanketCandidate( - MethodCallCand mcc, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam + AssocFunctionCallCand afcc, ImplItemNode impl, TypePath blanketPath, + TypeParam blanketTypeParam ) { - exists(MethodCall mc, BorrowKind borrow | - mcc = MkMethodCallCand(mc, _, borrow) and - methodCallBlanketLikeCandidate(mc, _, impl, _, blanketPath, blanketTypeParam) and + exists(AssocFunctionCall afc, FunctionPosition selfPosAdj, BorrowKind borrow | + afcc = MkAssocFunctionCallCand(afc, _, selfPosAdj, _, borrow) and + blanketLikeCandidate(afc, _, _, selfPosAdj, 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), as well as // cases where our blanket implementation filtering is not precise enough. - (mcc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation()) + (afcc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation()) | borrow.isNoBorrow() or @@ -2304,151 +2495,135 @@ private module MethodResolution { } } - private module ReceiverSatisfiesBlanketLikeConstraint = - BlanketImplementation::SatisfiesBlanketConstraint; + private module ArgSatisfiesBlanketLikeConstraint = + BlanketImplementation::SatisfiesBlanketConstraint; /** - * A configuration for matching the type of a receiver against the type of - * a `self` parameter. + * A configuration for matching the type of an argument against the type of + * a `self` parameter or similar parameter used to determine dispatch. */ - private module ReceiverIsInstantiationOfSelfParamInput implements - IsInstantiationOfInputSig + private module ArgIsInstantiationOfSelfParamInput implements + IsInstantiationOfInputSig { pragma[nomagic] additional predicate potentialInstantiationOf0( - MethodCallCand mcc, ImplOrTraitItemNode i, AssocFunctionType selfType + AssocFunctionCallCand afcc, ImplOrTraitItemNode i, AssocFunctionType selfType ) { exists( - MethodCall mc, Method m, string name, int arity, TypePath strippedTypePath, + AssocFunctionCall afc, FunctionPosition pos, Function f, TypePath strippedTypePath, Type strippedType | - mcc.hasSignature(mc, strippedTypePath, strippedType, name, arity) + afcc.hasSignature(afc, pos, strippedTypePath, strippedType, _, _) | - methodCallNonBlanketCandidate(mc, m, i, selfType, strippedTypePath, strippedType) + nonBlanketLikeCandidate(afc, f, _, pos, i, selfType, strippedTypePath, strippedType) or - methodCallBlanketLikeCandidate(mc, m, i, selfType, _, _) and - ReceiverSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(mcc, i) + blanketLikeCandidate(afc, f, _, pos, i, selfType, _, _) and + ArgSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(afcc, i) ) } pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - potentialInstantiationOf0(mcc, abs, constraint) and + potentialInstantiationOf0(afcc, abs, constraint) and if abs.(Impl).hasTrait() then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - mcc.hasNoInherentTarget() + // inherent functions take precedence over trait functions, so only allow + // trait functions when there are no matching inherent functions + afcc.hasNoInherentTarget() else any() } predicate relevantConstraint(AssocFunctionType constraint) { - methodInfo(_, _, _, _, constraint, _, _) + assocFunctionInfo(_, _, _, _, _, _, constraint, _, _, _, _) } } - private module ReceiverIsInstantiationOfSelfParam = - ArgIsInstantiationOf; + private module ArgIsInstantiationOfSelfParam { + import ArgIsInstantiationOf - /** - * A configuration for anti-matching the type of a receiver against the type of - * a `self` parameter belonging to a blanket (like) implementation. - */ - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements - IsInstantiationOfInputSig - { pragma[nomagic] - predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + predicate argIsNotInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, + BorrowKind borrow, TypePath path ) { - methodCallBlanketLikeCandidate(mcc.getMethodCall(), _, abs, constraint, _, _) and - if abs.(Impl).hasTrait() - then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - mcc.hasNoInherentTarget() - else any() + argIsNotInstantiationOf(MkAssocFunctionCallCand(afc, selfPos, _, derefChain, borrow), i, _, + path) } - } - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam = - ArgIsInstantiationOf; - - /** - * A configuration for matching the type qualifier of a method call - * against the type being implemented in an `impl` block. For example, - * in `Foo::::m(x)`, we check that the type `Foo` is an - * instance of the type being implemented. - */ - private module TypeQualifierIsInstantiationOfImplSelfInput implements - IsInstantiationOfInputSig - { pragma[nomagic] - private predicate potentialInstantiationOf0( - MethodCallCallExpr ce, ImplItemNode impl, TypeMention constraint + predicate argIsInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPos, DerefChain derefChain, + BorrowKind borrow, AssocFunctionType selfType ) { - ce.hasTypeQualifiedCandidate(impl) and - constraint = impl.getSelfPath() + argIsInstantiationOf(MkAssocFunctionCallCand(afc, selfPos, _, derefChain, borrow), i, selfType) } + } + /** + * A configuration for anti-matching the type of an argument against the type of + * a `self` parameter belonging to a blanket (like) implementation. + */ + private module ArgIsNotInstantiationOfBlanketLikeSelfParamInput implements + IsInstantiationOfInputSig + { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCallExpr ce, TypeAbstraction abs, TypeMention constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - potentialInstantiationOf0(ce, abs, constraint) and - if abs.(Impl).hasTrait() - then - // inherent methods take precedence over trait methods, so only allow - // trait methods when there are no matching inherent methods - ce.hasNoInherentTarget() - else any() - } - - predicate relevantConstraint(TypeMention constraint) { - potentialInstantiationOf0(_, _, constraint) + exists(AssocFunctionCall afc, FunctionPosition selfPosAdj | + afcc = MkAssocFunctionCallCand(afc, _, selfPosAdj, _, _) and + blanketLikeCandidate(afc, _, _, selfPosAdj, abs, constraint, _, _) and + if abs.(Impl).hasTrait() + then + // inherent functions take precedence over trait functions, so only allow + // trait functions when there are no matching inherent functions + afcc.hasNoInherentTarget() + else any() + ) } } - private module TypeQualifierIsInstantiationOfImplSelf = - IsInstantiationOf; + private module ArgIsNotInstantiationOfBlanketLikeSelfParam = + ArgIsInstantiationOf; /** - * A configuration for anti-matching the type of a receiver against the type of + * A configuration for anti-matching the type of an argument against the type of * a `self` parameter in an inherent method. */ - private module ReceiverIsNotInstantiationOfInherentSelfParamInput implements - IsInstantiationOfInputSig + private module ArgIsNotInstantiationOfInherentSelfParamInput implements + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - ReceiverIsInstantiationOfSelfParamInput::potentialInstantiationOf0(mcc, abs, constraint) and - abs = any(Impl i | not i.hasTrait()) + ArgIsInstantiationOfSelfParamInput::potentialInstantiationOf0(afcc, abs, constraint) and + abs = any(Impl i | not i.hasTrait()) and + // todo: comment + exists(FunctionPosition selfPosAdj | afcc = MkAssocFunctionCallCand(_, _, selfPosAdj, _, _) | + selfPosAdj.isTypeQualifier() or selfPosAdj.asPosition() = 0 + ) } } - private module ReceiverIsNotInstantiationOfInherentSelfParam = - ArgIsInstantiationOf; + private module ArgIsNotInstantiationOfInherentSelfParam = + ArgIsInstantiationOf; /** * A configuration for matching the types of positional arguments against the * types of parameters, when needed to disambiguate the call. */ - private module MethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { + private module CallArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) } - class Call extends MethodCallCand { + class Call extends AssocFunctionCallCand { Type getArgType(FunctionPosition pos, TypePath path) { - result = mc_.getArgumentTypeAt(pos.asArgumentPosition(), path) - or - pos.isReturn() and - result = inferType(mc_.getNodeAt(pos), path) + result = this.getAssocFunctionCall().getTypeAt(pos, path) } predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { @@ -2457,8 +2632,14 @@ private module MethodResolution { } } - private module MethodArgsAreInstantiationsOf = - ArgsAreInstantiationsOf; + private module CallArgsAreInstantiationsOf { + import ArgsAreInstantiationsOf + + pragma[nomagic] + predicate argsAreNotInstantiationsOf(AssocFunctionCall afc, ImplOrTraitItemNode i) { + argsAreNotInstantiationsOf(MkAssocFunctionCallCand(afc, _, _, _, _), i, _) + } + } } /** @@ -2492,7 +2673,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi } Type getDeclaredType(DeclarationPosition dpos, TypePath path) { - result = m.getParameterTypeInclNonMethodSelf(someParent, dpos, path) + result = m.getParameterType(someParent, dpos, path) or dpos.isReturn() and result = m.getReturnType(someParent, path) @@ -2521,9 +2702,9 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi ) } - final private class MethodCallFinal = MethodResolution::MethodCall; + final private class AssocFunctionCallFinal = AssocFunctionResolution::AssocFunctionCall; - class Access extends MethodCallFinal, ContextTyping::ContextTypedCallCand { + class Access extends AssocFunctionCallFinal, ContextTyping::ContextTypedCallCand { Access() { // handled in the `OperationMatchingInput` module not this instanceof Operation @@ -2542,32 +2723,20 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi } pragma[nomagic] - private Type getInferredSelfType(AccessPosition apos, string derefChainBorrow, TypePath path) { + private Type getInferredSelfType(FunctionPosition pos, string derefChainBorrow, TypePath path) { exists(DerefChain derefChain, BorrowKind borrow | - result = this.getACandidateReceiverTypeAt(derefChain, borrow, path) and + result = this.getSelfTypeAt(pos, derefChain, borrow, path) and derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and - apos.isSelf() + pos.isSelf() ) } pragma[nomagic] - Type getInferredNonSelfType(AccessPosition apos, TypePath path) { - if - // index expression `x[i]` desugars to `*x.index(i)`, so we must account for - // the implicit deref - apos.isReturn() and - this instanceof IndexExpr - then - path.isEmpty() and - result instanceof RefType - or - exists(TypePath suffix | - result = inferType(this.getNodeAt(apos), suffix) and - path = TypePath::cons(getRefTypeParameter(_), suffix) - ) - else ( - not apos.isSelf() and - result = inferType(this.getNodeAt(apos), path) + private Type getInferredNonSelfType(AccessPosition apos, TypePath path) { + exists(FunctionPosition pos | + result = this.getTypeAt(pos, path) and + not pos.isSelf() and + if this.hasReceiver() then apos = pos else pos = apos.getFunctionCallAdjusted() ) } @@ -2602,6 +2771,20 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi this.hasUnknownTypeAt(i, this.getTarget(i, derefChainBorrow), pos, path) ) } + + /** + * 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) { + forex(ImplOrTraitItemNode i, Function f | + f = CallExprImpl::getResolvedFunction(this) and + f = i.getAnAssocItem() + | + this.hasUnknownTypeAt(i, f, pos, path) + ) + } } } @@ -2610,15 +2793,26 @@ private module MethodCallMatching = MatchingWithEnvironment; - /** A (potential) non-method call, `f(x)`. */ final class NonMethodCall extends CallExpr { NonMethodCall() { // even if a function cannot be resolved by path resolution, it may still // be possible to resolve a blanket implementation (so not `forex`) - forall(Function f | f = CallExprImpl::getResolvedFunction(this) | - f instanceof NonMethodFunction - ) - } - - pragma[nomagic] - predicate hasNameAndArity(string name, int arity) { - name = CallExprImpl::getFunctionPath(this).getText() and - arity = this.getArgList().getNumberOfArgs() - } - - /** - * Gets the item that this function call resolves to using path resolution, - * if any. - */ - private ItemNode getPathResolutionResolved() { - result = CallExprImpl::getResolvedFunction(this) and - not result.(Function).hasSelfParam() + forall(Function f | f = CallExprImpl::getResolvedFunction(this) | not f instanceof Method) } - /** - * Gets the associated function that this function call resolves to using path - * resolution, if any. - */ - pragma[nomagic] - NonMethodFunction getPathResolutionResolved(ImplOrTraitItemNode i) { - result = this.getPathResolutionResolved() and - result = i.getAnAssocItem() - } - - /** - * Gets the blanket function that this call may resolve to, if any. - */ - pragma[nomagic] - NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) { - exists(string name | - this.hasNameAndArity(pragma[only_bind_into](name), _) and - ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and - result = impl.getASuccessor(pragma[only_bind_into](name)) - ) - } - - /** Gets the trait targeted by this call, if any. */ - Trait getTrait() { result = getCallExprTraitQualifier(this) } - - /** Holds if this call targets a trait. */ - predicate hasTrait() { exists(this.getTrait()) } - AstNode getNodeAt(FunctionPosition pos) { result = this.getSyntacticArgument(pos.asArgumentPosition()) or result = this and pos.isReturn() } - Type getTypeAt(FunctionPosition pos, TypePath path) { - result = inferType(this.getNodeAt(pos), path) - } - - pragma[nomagic] - NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) { - not this.hasTrait() and - result = this.getPathResolutionResolved(i) and - not exists(this.resolveCallTargetViaPathResolution()) and - functionResolutionDependsOnArgument(i, result, _, _) - } - - pragma[nomagic] - predicate resolveCallTargetBlanketLikeCand( - ImplItemNode impl, FunctionPosition pos, TypePath blanketPath, TypeParam blanketTypeParam - ) { - exists(string name, int arity, Trait trait, AssocFunctionType t | - this.hasNameAndArity(name, arity) and - exists(this.getTypeAt(pos, blanketPath)) and - functionInfoBlanketLikeRelevantPos(_, name, arity, impl, trait, pos, t, blanketPath, - blanketTypeParam) and - BlanketTraitIsVisible::traitIsVisible(this, trait) - | - not this.hasTrait() - or - trait = this.getTrait() - ) - } - - pragma[nomagic] - predicate hasTraitResolved(TraitItemNode trait, NonMethodFunction resolved) { - resolved = this.getPathResolutionResolved() and - 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.resolveCallTargetBlanketLikeCand(_, _, _, _) and - not exists(this.resolveCallTargetViaPathResolution()) and - forall(ImplOrTraitItemNode i, Function f | f = this.resolveCallTargetNonBlanketCand(i) | - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f) - ) and - ( - not this.hasTraitResolved(_, _) - or - exists( - TraitItemNode trait, NonMethodFunction resolved, FunctionPosition pos, TypePath path, - Type t - | - this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call) - .hasTraitResolvedSelfType(trait, resolved, pos, path, t) - | - forall(ImplOrTraitItemNode i, Function f | - traitFunctionHasSelfType(trait, resolved, pos, path, t, i, f) - | - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f) - ) - ) - ) - } - /** * Gets the target of this call, which can be resolved using only path resolution. */ pragma[nomagic] ItemNode resolveCallTargetViaPathResolution() { - not this.hasTrait() and - result = this.getPathResolutionResolved() and - not 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 - NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result) - or - NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result) - } - } - - private newtype TCallAndBlanketPos = - MkCallAndBlanketPos(NonMethodCall fc, FunctionPosition pos) { - fc.resolveCallTargetBlanketLikeCand(_, pos, _, _) - } - - /** A call tagged with a position. */ - private class CallAndBlanketPos extends MkCallAndBlanketPos { - NonMethodCall fc; - FunctionPosition pos; - - CallAndBlanketPos() { this = MkCallAndBlanketPos(fc, pos) } - - Location getLocation() { result = fc.getLocation() } - - Type getTypeAt(TypePath path) { result = fc.getTypeAt(pos, path) } - - string toString() { result = fc.toString() + " [arg " + pos + "]" } - } - - private module ArgSatisfiesBlanketConstraintInput implements - BlanketImplementation::SatisfiesBlanketConstraintInputSig - { - pragma[nomagic] - predicate hasBlanketCandidate( - CallAndBlanketPos fcp, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam - ) { - exists(NonMethodCall fc, FunctionPosition pos | - fcp = MkCallAndBlanketPos(fc, pos) and - fc.resolveCallTargetBlanketLikeCand(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()) - ) - } - } - - private module ArgSatisfiesBlanketConstraint = - BlanketImplementation::SatisfiesBlanketConstraint; - - /** - * A configuration for matching the type of an argument against the type of - * a parameter that mentions a satisfied blanket type parameter. - */ - private module ArgIsInstantiationOfBlanketParamInput implements - IsInstantiationOfInputSig - { - pragma[nomagic] - predicate potentialInstantiationOf( - CallAndBlanketPos fcp, TypeAbstraction abs, AssocFunctionType constraint - ) { - exists(FunctionPosition pos | - ArgSatisfiesBlanketConstraint::satisfiesBlanketConstraint(fcp, abs) and - fcp = MkCallAndBlanketPos(_, pos) and - functionInfoBlanketLikeRelevantPos(_, _, _, abs, _, pos, constraint, _, _) - ) - } - - predicate relevantConstraint(AssocFunctionType constraint) { - functionInfoBlanketLikeRelevantPos(_, _, _, _, _, _, constraint, _, _) - } - } - - private module ArgIsInstantiationOfBlanketParam = - ArgIsInstantiationOf; - - private Type getArgType( - NonMethodCall call, FunctionPosition pos, TypePath path, boolean isDefaultTypeArg - ) { - result = inferType(call.getNodeAt(pos), path) and - isDefaultTypeArg = false - or - result = getCallExprTypeQualifier(call, path, isDefaultTypeArg) and - pos.isSelf() - } - - private module NonMethodArgsAreInstantiationsOfBlanketInput implements - ArgsAreInstantiationsOfInputSig - { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos) { - functionResolutionDependsOnArgument(i, f, pos, tp) - } - - final class Call extends NonMethodCall { - Type getArgType(FunctionPosition pos, TypePath path) { - result = getArgType(this, pos, path, false) - } - - predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { - f = this.resolveCallTargetBlanketCand(i) - } - } - } - - private module NonMethodArgsAreInstantiationsOfBlanket = - ArgsAreInstantiationsOf; - - private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements - ArgsAreInstantiationsOfInputSig - { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { - functionResolutionDependsOnArgument(i, f, pos, traitTp) - or - // Also match against the trait function itself - FunctionOverloading::traitTypeParameterOccurrence(i, f, _, pos, _, traitTp) and - traitTp = TSelfTypeParameter(i) - } - - class Call extends NonMethodCall { - Type getArgType(FunctionPosition pos, TypePath path) { - result = getArgType(this, pos, path, _) - } - - /** - * Holds if this call is of the form `Trait::function(args)`, and the type at `pos` and - * `path` matches the `Self` type parameter of `Trait`. - */ - pragma[nomagic] - predicate hasTraitResolvedSelfType( - TraitItemNode trait, NonMethodFunction function, FunctionPosition pos, TypePath path, Type t - ) { - this.hasTraitResolved(trait, function) and - FunctionOverloading::traitTypeParameterOccurrence(trait, function, _, pos, path, - TSelfTypeParameter(trait)) and - t = substituteLookupTraits(this.getArgType(pos, path)) and - t != TUnknownType() - } - - predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { - f = this.resolveCallTargetNonBlanketCand(i) - or - exists( - TraitItemNode trait, NonMethodFunction resolved, FunctionPosition pos, TypePath path, - Type t - | - this.hasTraitResolvedSelfType(trait, resolved, pos, path, t) and - traitFunctionHasSelfType(trait, resolved, pos, path, t, i, f) - ) - } + result = CallExprImpl::getResolvedFunction(this) and + not result instanceof AssocFunction } } - - private module NonMethodArgsAreInstantiationsOfNonBlanket = - ArgsAreInstantiationsOf; } abstract private class TupleLikeConstructor extends Addressable { @@ -3223,7 +3019,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { } override Type getParameterType(DeclarationPosition dpos, TypePath path) { - result = f.getParameterTypeInclNonMethodSelf(i, dpos, path) + result = f.getParameterType(i, dpos, path) } override Type getReturnType(TypePath path) { result = f.getReturnType(i, path) } @@ -3267,7 +3063,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { pragma[nomagic] Type getInferredType(AccessPosition apos, TypePath path) { - apos.isSelf() and + apos.isTypeQualifier() and result = getCallExprTypeQualifier(this, path, false) or result = inferType(this.getNodeAt(apos), path) @@ -3278,7 +3074,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { exists(ImplOrTraitItemNodeOption i, NonMethodFunctionDeclaration f | result = TNonMethodFunctionDeclaration(i, f) | - f = this.resolveCallTargetViaTypeInference(i.asSome()) // mutual recursion; resolving some associated function calls requires resolving types + f = this.(AssocFunctionResolution::AssocFunctionCall).resolveCallTarget(i.asSome(), _, _) // mutual recursion; resolving some associated function calls requires resolving types or f = this.resolveCallTargetViaPathResolution() and f.isDirectlyFor(i) @@ -3300,12 +3096,6 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { this.hasUnknownTypeAt(i.asSome(), f, pos, path) ) or - forex(ImplOrTraitItemNode i, NonMethodFunctionDeclaration f | - f = this.getPathResolutionResolved(i) - | - this.hasUnknownTypeAt(i, f, pos, path) - ) - or // Tuple declarations, such as `Result::Ok(...)`, may also be context typed exists(TupleLikeConstructor tc, TypeParameter tp | tc = this.resolveCallTargetViaPathResolution() and @@ -3381,7 +3171,7 @@ private module OperationMatchingInput implements MatchingInputSig { } } - class Access extends MethodResolution::MethodCallOperation { + class Access extends AssocFunctionResolution::AssocFunctionCallOperation { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } pragma[nomagic] @@ -4102,7 +3892,8 @@ private module Cached { cached predicate implicitDerefChainBorrow(Expr e, DerefChain derefChain, boolean borrow) { exists(BorrowKind bk | - any(MethodResolution::MethodCall mc).argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and + any(AssocFunctionResolution::AssocFunctionCall afc) + .argumentHasImplicitDerefChainBorrow(e, derefChain, bk) and if bk.isNoBorrow() then borrow = false else borrow = true ) or @@ -4134,8 +3925,7 @@ private module Cached { or i instanceof ImplItemNode and dispatch = false | - result = call.(MethodResolution::MethodCall).resolveCallTarget(i, _, _) or - result = call.(NonMethodResolution::NonMethodCall).resolveCallTargetViaTypeInference(i) + result = call.(AssocFunctionResolution::AssocFunctionCall).resolveCallTarget(i, _, _) ) } @@ -4267,8 +4057,8 @@ private module Debug { Locatable getRelevantLocatable() { exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and - filepath.matches("%/sqlx.rs") and - startline = [56 .. 60] + filepath.matches("%/main.rs") and + startline = 50 ) } diff --git a/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected index 8ca58acd1d06..e69de29bb2d1 100644 --- a/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/library-tests/dataflow/sources/net/CONSISTENCY/PathResolutionConsistency.expected @@ -1,6 +0,0 @@ -multipleResolvedTargets -| test.rs:389:30:389:67 | pinned.poll_read(...) | -| test.rs:416:26:416:54 | pinned.poll_fill_buf(...) | -| test.rs:423:27:423:71 | ... .poll_fill_buf(...) | -| test.rs:447:30:447:67 | pinned.poll_read(...) | -| test.rs:470:26:470:54 | pinned.poll_fill_buf(...) | diff --git a/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected b/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected index 255af4cc86ed..763bff966d3f 100644 --- a/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected +++ b/rust/ql/test/library-tests/dataflow/taint/inline-taint-flow.expected @@ -100,7 +100,9 @@ edges | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | provenance | MaD:30 | | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | provenance | MaD:30 | | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | provenance | MaD:19 | +| main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | provenance | MaD:19 | | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | provenance | MaD:19 | +| main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | provenance | MaD:19 | | main.rs:170:5:170:5 | [post] a | main.rs:171:5:171:5 | a | provenance | | | main.rs:170:5:170:5 | [post] a | main.rs:172:5:172:5 | a | provenance | | | main.rs:170:5:170:5 | [post] a | main.rs:173:5:173:5 | a | provenance | | @@ -351,8 +353,12 @@ nodes | main.rs:162:19:162:27 | source(...) | semmle.label | source(...) | | main.rs:164:10:164:18 | source(...) | semmle.label | source(...) | | main.rs:164:10:164:30 | ... .bitor(...) | semmle.label | ... .bitor(...) | +| main.rs:165:10:165:18 | source(...) | semmle.label | source(...) | +| main.rs:165:10:165:27 | ... .bitor(...) | semmle.label | ... .bitor(...) | | main.rs:166:10:166:30 | 1i64.bitor(...) | semmle.label | 1i64.bitor(...) | | main.rs:166:21:166:29 | source(...) | semmle.label | source(...) | +| main.rs:167:10:167:27 | 1.bitor(...) | semmle.label | 1.bitor(...) | +| main.rs:167:18:167:26 | source(...) | semmle.label | source(...) | | main.rs:170:5:170:5 | [post] a | semmle.label | [post] a | | main.rs:170:18:170:26 | source(...) | semmle.label | source(...) | | main.rs:171:5:171:5 | [post] a | semmle.label | [post] a | @@ -516,7 +522,9 @@ testFailures | main.rs:161:10:161:25 | ... .shr(...) | main.rs:161:10:161:18 | source(...) | main.rs:161:10:161:25 | ... .shr(...) | $@ | main.rs:161:10:161:18 | source(...) | source(...) | | main.rs:162:10:162:28 | 1i64.shr(...) | main.rs:162:19:162:27 | source(...) | main.rs:162:10:162:28 | 1i64.shr(...) | $@ | main.rs:162:19:162:27 | source(...) | source(...) | | main.rs:164:10:164:30 | ... .bitor(...) | main.rs:164:10:164:18 | source(...) | main.rs:164:10:164:30 | ... .bitor(...) | $@ | main.rs:164:10:164:18 | source(...) | source(...) | +| main.rs:165:10:165:27 | ... .bitor(...) | main.rs:165:10:165:18 | source(...) | main.rs:165:10:165:27 | ... .bitor(...) | $@ | main.rs:165:10:165:18 | source(...) | source(...) | | main.rs:166:10:166:30 | 1i64.bitor(...) | main.rs:166:21:166:29 | source(...) | main.rs:166:10:166:30 | 1i64.bitor(...) | $@ | main.rs:166:21:166:29 | source(...) | source(...) | +| main.rs:167:10:167:27 | 1.bitor(...) | main.rs:167:18:167:26 | source(...) | main.rs:167:10:167:27 | 1.bitor(...) | $@ | main.rs:167:18:167:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:170:18:170:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:170:18:170:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:171:18:171:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:171:18:171:26 | source(...) | source(...) | | main.rs:176:10:176:10 | a | main.rs:172:18:172:26 | source(...) | main.rs:176:10:176:10 | a | $@ | main.rs:172:18:172:26 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/taint/main.rs b/rust/ql/test/library-tests/dataflow/taint/main.rs index 07770cc71189..05dbd1eb702f 100644 --- a/rust/ql/test/library-tests/dataflow/taint/main.rs +++ b/rust/ql/test/library-tests/dataflow/taint/main.rs @@ -162,9 +162,9 @@ fn std_ops() { sink(1i64.shr(source(2))); // $ hasTaintFlow=2 sink(source(1).bitor(2i64)); // $ hasTaintFlow=1 - sink(source(1).bitor(2)); // $ MISSING: hasTaintFlow=1 + sink(source(1).bitor(2)); // $ hasTaintFlow=1 sink(1i64.bitor(source(2))); // $ hasTaintFlow=2 - sink(1.bitor(source(2))); // $ MISSING: hasTaintFlow=2 + sink(1.bitor(source(2))); // $ hasTaintFlow=2 let mut a: i64 = 1; a.add_assign(source(2)); diff --git a/rust/ql/test/library-tests/type-inference/regressions.rs b/rust/ql/test/library-tests/type-inference/regressions.rs index 17475d50166b..2830ca5aa2be 100644 --- a/rust/ql/test/library-tests/type-inference/regressions.rs +++ b/rust/ql/test/library-tests/type-inference/regressions.rs @@ -32,3 +32,41 @@ mod regression1 { opt_e.unwrap() // $ target=unwrap } } + +mod regression2 { + trait SomeTrait {} + + trait MyFrom { + fn my_from(value: T) -> Self; + } + + impl MyFrom for T { + fn my_from(s: T) -> Self { + s + } + } + + impl MyFrom for Option { + fn my_from(val: T) -> Option { + Some(val) + } + } + + pub struct S(T); + + impl MyFrom> for Option { + fn my_from(s: S) -> Self { + Some(s.0) // $ fieldof=S + } + } + + pub fn f(x: T2) -> T2 + where + T2: SomeTrait + MyFrom>, + Option: MyFrom, + { + let y = MyFrom::my_from(x); // $ target=my_from + let z = MyFrom::my_from(y); // $ target=my_from + z + } +} diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index fa0f9eaa0c28..78358a8adab8 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -4947,6 +4947,23 @@ inferCertainType | regressions.rs:27:37:27:41 | vec_e | | {EXTERNAL LOCATION} | Vec | | regressions.rs:27:37:27:41 | vec_e | A | {EXTERNAL LOCATION} | Global | | regressions.rs:28:9:30:9 | { ... } | | {EXTERNAL LOCATION} | () | +| regressions.rs:40:20:40:24 | value | | regressions.rs:39:18:39:18 | T | +| regressions.rs:44:20:44:20 | s | | regressions.rs:43:10:43:10 | T | +| regressions.rs:44:34:46:9 | { ... } | | regressions.rs:43:10:43:10 | T | +| regressions.rs:45:13:45:13 | s | | regressions.rs:43:10:43:10 | T | +| regressions.rs:50:20:50:22 | val | | regressions.rs:49:10:49:10 | T | +| regressions.rs:50:41:52:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:50:41:52:9 | { ... } | T | regressions.rs:49:10:49:10 | T | +| regressions.rs:51:18:51:20 | val | | regressions.rs:49:10:49:10 | T | +| regressions.rs:58:20:58:20 | s | | regressions.rs:55:5:55:23 | S | +| regressions.rs:58:20:58:20 | s | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:58:37:60:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:58:37:60:9 | { ... } | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:59:18:59:18 | s | | regressions.rs:55:5:55:23 | S | +| regressions.rs:59:18:59:18 | s | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:63:22:63:22 | x | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:67:5:71:5 | { ... } | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:68:33:68:33 | x | | regressions.rs:63:18:63:19 | T2 | inferType | associated_types.rs:5:15:5:18 | SelfParam | | associated_types.rs:1:1:2:21 | Wrapper | | associated_types.rs:5:15:5:18 | SelfParam | A | associated_types.rs:4:6:4:6 | A | @@ -11177,12 +11194,15 @@ inferType | main.rs:2319:18:2319:23 | range1 | Idx | {EXTERNAL LOCATION} | u16 | | main.rs:2319:25:2319:26 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2323:13:2323:17 | vals3 | | {EXTERNAL LOCATION} | Vec | +| main.rs:2323:13:2323:17 | vals3 | A | {EXTERNAL LOCATION} | Global | | main.rs:2323:21:2323:33 | MacroExpr | | {EXTERNAL LOCATION} | Vec | +| main.rs:2323:21:2323:33 | MacroExpr | A | {EXTERNAL LOCATION} | Global | | main.rs:2323:26:2323:26 | 1 | | {EXTERNAL LOCATION} | i32 | | main.rs:2323:29:2323:29 | 2 | | {EXTERNAL LOCATION} | i32 | | main.rs:2323:32:2323:32 | 3 | | {EXTERNAL LOCATION} | i32 | | main.rs:2324:9:2324:25 | for ... in ... { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2324:18:2324:22 | vals3 | | {EXTERNAL LOCATION} | Vec | +| main.rs:2324:18:2324:22 | vals3 | A | {EXTERNAL LOCATION} | Global | | main.rs:2324:24:2324:25 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2326:13:2326:18 | vals4a | | {EXTERNAL LOCATION} | Vec | | main.rs:2326:13:2326:18 | vals4a | A | {EXTERNAL LOCATION} | Global | @@ -11272,18 +11292,25 @@ inferType | main.rs:2340:18:2340:22 | vals7 | T | {EXTERNAL LOCATION} | u8 | | main.rs:2340:24:2340:25 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2342:13:2342:19 | matrix1 | | {EXTERNAL LOCATION} | Vec | +| main.rs:2342:13:2342:19 | matrix1 | A | {EXTERNAL LOCATION} | Global | | main.rs:2342:23:2342:50 | MacroExpr | | {EXTERNAL LOCATION} | Vec | +| main.rs:2342:23:2342:50 | MacroExpr | A | {EXTERNAL LOCATION} | Global | | main.rs:2342:28:2342:37 | (...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2342:28:2342:37 | (...) | A | {EXTERNAL LOCATION} | Global | | main.rs:2342:28:2342:37 | MacroExpr | | {EXTERNAL LOCATION} | Vec | +| main.rs:2342:28:2342:37 | MacroExpr | A | {EXTERNAL LOCATION} | Global | | main.rs:2342:33:2342:33 | 1 | | {EXTERNAL LOCATION} | i32 | | main.rs:2342:36:2342:36 | 2 | | {EXTERNAL LOCATION} | i32 | | main.rs:2342:40:2342:49 | (...) | | {EXTERNAL LOCATION} | Vec | +| main.rs:2342:40:2342:49 | (...) | A | {EXTERNAL LOCATION} | Global | | main.rs:2342:40:2342:49 | MacroExpr | | {EXTERNAL LOCATION} | Vec | +| main.rs:2342:40:2342:49 | MacroExpr | A | {EXTERNAL LOCATION} | Global | | main.rs:2342:45:2342:45 | 3 | | {EXTERNAL LOCATION} | i32 | | main.rs:2342:48:2342:48 | 4 | | {EXTERNAL LOCATION} | i32 | | main.rs:2344:13:2344:13 | _ | | {EXTERNAL LOCATION} | () | | main.rs:2344:17:2347:9 | for ... in ... { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2344:28:2344:34 | matrix1 | | {EXTERNAL LOCATION} | Vec | +| main.rs:2344:28:2344:34 | matrix1 | A | {EXTERNAL LOCATION} | Global | | main.rs:2344:36:2347:9 | { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2345:13:2346:13 | for ... in ... { ... } | | {EXTERNAL LOCATION} | () | | main.rs:2345:29:2346:13 | { ... } | | {EXTERNAL LOCATION} | () | @@ -14500,7 +14527,9 @@ inferType | pattern_matching.rs:788:41:788:45 | tuple | T2 | {EXTERNAL LOCATION} | bool | | pattern_matching.rs:792:35:824:1 | { ... } | | {EXTERNAL LOCATION} | () | | pattern_matching.rs:794:9:794:14 | points | | {EXTERNAL LOCATION} | Vec | +| pattern_matching.rs:794:9:794:14 | points | A | {EXTERNAL LOCATION} | Global | | pattern_matching.rs:794:18:794:65 | MacroExpr | | {EXTERNAL LOCATION} | Vec | +| pattern_matching.rs:794:18:794:65 | MacroExpr | A | {EXTERNAL LOCATION} | Global | | pattern_matching.rs:794:23:794:42 | (...) | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:794:23:794:42 | Point {...} | | pattern_matching.rs:135:1:140:1 | Point | | pattern_matching.rs:794:34:794:34 | 1 | | {EXTERNAL LOCATION} | i32 | @@ -14514,6 +14543,7 @@ inferType | pattern_matching.rs:795:17:795:17 | x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:795:20:795:20 | y | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:795:27:795:32 | points | | {EXTERNAL LOCATION} | Vec | +| pattern_matching.rs:795:27:795:32 | points | A | {EXTERNAL LOCATION} | Global | | pattern_matching.rs:795:34:799:5 | { ... } | | {EXTERNAL LOCATION} | () | | pattern_matching.rs:796:13:796:18 | loop_x | | {EXTERNAL LOCATION} | i32 | | pattern_matching.rs:796:22:796:22 | x | | {EXTERNAL LOCATION} | i32 | @@ -14776,4 +14806,38 @@ inferType | regressions.rs:32:9:32:13 | opt_e | | {EXTERNAL LOCATION} | Option | | regressions.rs:32:9:32:13 | opt_e | T | regressions.rs:5:5:7:5 | E | | regressions.rs:32:9:32:22 | opt_e.unwrap() | | regressions.rs:5:5:7:5 | E | +| regressions.rs:40:20:40:24 | value | | regressions.rs:39:18:39:18 | T | +| regressions.rs:44:20:44:20 | s | | regressions.rs:43:10:43:10 | T | +| regressions.rs:44:34:46:9 | { ... } | | regressions.rs:43:10:43:10 | T | +| regressions.rs:45:13:45:13 | s | | regressions.rs:43:10:43:10 | T | +| regressions.rs:50:20:50:22 | val | | regressions.rs:49:10:49:10 | T | +| regressions.rs:50:41:52:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:50:41:52:9 | { ... } | T | regressions.rs:49:10:49:10 | T | +| regressions.rs:51:13:51:21 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:51:13:51:21 | Some(...) | T | regressions.rs:49:10:49:10 | T | +| regressions.rs:51:18:51:20 | val | | regressions.rs:49:10:49:10 | T | +| regressions.rs:58:20:58:20 | s | | regressions.rs:55:5:55:23 | S | +| regressions.rs:58:20:58:20 | s | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:58:37:60:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:58:37:60:9 | { ... } | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:59:13:59:21 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:59:13:59:21 | Some(...) | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:59:18:59:18 | s | | regressions.rs:55:5:55:23 | S | +| regressions.rs:59:18:59:18 | s | T | regressions.rs:57:10:57:10 | T | +| regressions.rs:59:18:59:20 | s.0 | | regressions.rs:57:10:57:10 | T | +| regressions.rs:63:22:63:22 | x | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:67:5:71:5 | { ... } | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:68:13:68:13 | y | | {EXTERNAL LOCATION} | Option | +| regressions.rs:68:13:68:13 | y | T | regressions.rs:63:14:63:15 | T1 | +| regressions.rs:68:13:68:13 | y | T | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:68:17:68:34 | ...::my_from(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:68:17:68:34 | ...::my_from(...) | T | regressions.rs:63:14:63:15 | T1 | +| regressions.rs:68:17:68:34 | ...::my_from(...) | T | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:68:33:68:33 | x | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:69:13:69:13 | z | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:69:17:69:34 | ...::my_from(...) | | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:69:33:69:33 | y | | {EXTERNAL LOCATION} | Option | +| regressions.rs:69:33:69:33 | y | T | regressions.rs:63:14:63:15 | T1 | +| regressions.rs:69:33:69:33 | y | T | regressions.rs:63:18:63:19 | T2 | +| regressions.rs:70:9:70:9 | z | | regressions.rs:63:18:63:19 | T2 | testFailures diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected index ef0a9e0d8063..a04fd96739cd 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/BrokenCryptoAlgorithm.expected @@ -21,3 +21,9 @@ | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:109:23:109:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 | | test_cipher.rs:114:23:114:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:50 | ...::new(...) | The cryptographic algorithm RC5 | | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:118:23:118:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:136:23:136:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:136:23:136:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:139:23:139:64 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:139:23:139:64 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:142:23:142:76 | ...::new_from_slices(...) | The cryptographic algorithm DES | +| test_cipher.rs:145:23:145:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:145:23:145:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:171:23:171:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:171:23:171:65 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:175:23:175:65 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:175:23:175:65 | ...::new(...) | The cryptographic algorithm RC2 | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected deleted file mode 100644 index 18400b7ab59b..000000000000 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/CONSISTENCY/PathResolutionConsistency.expected +++ /dev/null @@ -1,2 +0,0 @@ -multipleResolvedTargets -| test_cipher.rs:114:23:114:50 | ...::new(...) | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs index 17db0f9ceb19..81964436720d 100644 --- a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm/test_cipher.rs @@ -133,16 +133,16 @@ fn test_cbc( _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // des (broken) - let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); - let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); } @@ -168,10 +168,10 @@ fn test_ecb( _ = aes_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); // des with ECB (broken cipher + weak block mode) - let des_cipher1 = ecb::Encryptor::::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let des_cipher1 = ecb::Encryptor::::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); // rc2 with ECB (broken cipher + weak block mode) - let rc2_cipher1 = ecb::Encryptor::::new(key.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + let rc2_cipher1 = ecb::Encryptor::::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] _ = rc2_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); } diff --git a/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected b/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected index 92e11e895cdc..40da53dca45b 100644 --- a/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected +++ b/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected @@ -155,6 +155,10 @@ edges | lifetime.rs:798:9:798:12 | &val | lifetime.rs:798:2:798:12 | return ... | provenance | | | lifetime.rs:802:6:802:8 | ptr | lifetime.rs:808:23:808:25 | ptr | provenance | | | lifetime.rs:802:12:802:24 | get_pointer(...) | lifetime.rs:802:6:802:8 | ptr | provenance | | +| lifetime.rs:841:13:841:27 | ...: ... | lifetime.rs:843:12:843:14 | ptr | provenance | | +| lifetime.rs:851:6:851:8 | ptr | lifetime.rs:853:20:853:22 | ptr | provenance | | +| lifetime.rs:851:12:851:23 | &local_value | lifetime.rs:851:6:851:8 | ptr | provenance | | +| lifetime.rs:853:20:853:22 | ptr | lifetime.rs:841:13:841:27 | ...: ... | provenance | | | main.rs:18:9:18:10 | p1 [&ref] | main.rs:21:19:21:20 | p1 | provenance | | | main.rs:18:9:18:10 | p1 [&ref] | main.rs:29:19:29:20 | p1 | provenance | | | main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | main.rs:18:9:18:10 | p1 [&ref] | provenance | | @@ -330,6 +334,11 @@ nodes | lifetime.rs:802:6:802:8 | ptr | semmle.label | ptr | | lifetime.rs:802:12:802:24 | get_pointer(...) | semmle.label | get_pointer(...) | | lifetime.rs:808:23:808:25 | ptr | semmle.label | ptr | +| lifetime.rs:841:13:841:27 | ...: ... | semmle.label | ...: ... | +| lifetime.rs:843:12:843:14 | ptr | semmle.label | ptr | +| lifetime.rs:851:6:851:8 | ptr | semmle.label | ptr | +| lifetime.rs:851:12:851:23 | &local_value | semmle.label | &local_value | +| lifetime.rs:853:20:853:22 | ptr | semmle.label | ptr | | main.rs:18:9:18:10 | p1 [&ref] | semmle.label | p1 [&ref] | | main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | semmle.label | ...::as_ptr(...) [&ref] | | main.rs:18:26:18:28 | &b1 | semmle.label | &b1 |