diff --git a/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll index 298e07f4b3e9..3ff04276c638 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/ImplImpl.qll @@ -33,5 +33,11 @@ module Impl { result = "impl " + trait + this.getSelfTy().toAbbreviatedString() + " { ... }" ) } + + /** + * Holds if this is an inherent `impl` block, that is, one that does not implement a trait. + */ + pragma[nomagic] + predicate isInherent() { not this.hasTrait() } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll index e5dd4cdaee67..412a3b51ae82 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/InvocationExprImpl.qll @@ -6,7 +6,7 @@ module Impl { private newtype TArgumentPosition = TPositionalArgumentPosition(int i) { - i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] + i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()])] } or TSelfArgumentPosition() or TTypeQualifierArgumentPosition() 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/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index f8611ce2a3c0..92b537001154 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -29,18 +29,20 @@ class FunctionPosition extends TFunctionPosition { 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) { @@ -197,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()] ) @@ -209,7 +211,7 @@ class AssocFunctionType extends MkAssocFunctionType { } pragma[nomagic] -private Trait getALookupTrait(Type t) { +Trait getALookupTrait(Type t) { result = t.(TypeParamTypeParameter).getTypeParam().(TypeParamItemNode).resolveABound() or result = t.(SelfTypeParameter).getTrait() @@ -313,9 +315,9 @@ signature module ArgsAreInstantiationsOfInputSig { * If `i` is an inherent implementation, `tp` is a type parameter of the type being * implemented, otherwise `tp` is a type parameter of the trait (being implemented). * - * `pos` is one of the positions in `f` in which the relevant type occours. + * `posAdj` is one of the positions in `f` in which the relevant type occurs. */ - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos); + predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition posAdj); /** A call whose argument types are to be checked. */ class Call { @@ -323,7 +325,7 @@ signature module ArgsAreInstantiationsOfInputSig { Location getLocation(); - Type getArgType(FunctionPosition pos, TypePath path); + Type getArgType(FunctionPosition posAdj, TypePath path); predicate hasTargetCand(ImplOrTraitItemNode i, Function f); } @@ -337,9 +339,9 @@ signature module ArgsAreInstantiationsOfInputSig { module ArgsAreInstantiationsOf { pragma[nomagic] private predicate toCheckRanked( - ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, int rnk + ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition posAdj, int rnk ) { - Input::toCheck(i, f, tp, pos) and + Input::toCheck(i, f, tp, posAdj) and tp = rank[rnk + 1](TypeParameter tp0, int j | Input::toCheck(i, f, tp0, _) and @@ -351,41 +353,45 @@ module ArgsAreInstantiationsOf { pragma[nomagic] private predicate toCheck( - ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos, AssocFunctionType t + ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition posAdj, + AssocFunctionType t ) { - Input::toCheck(i, f, tp, pos) and - t.appliesTo(f, i, pos) + exists(FunctionPosition pos | + Input::toCheck(i, f, tp, posAdj) and + t.appliesTo(f, i, pos) and + posAdj = pos.getFunctionCallAdjusted(f) + ) } private newtype TCallAndPos = - MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) } + MkCallAndPos(Input::Call call, FunctionPosition posAdj) { exists(call.getArgType(posAdj, _)) } /** A call tagged with a position. */ private class CallAndPos extends MkCallAndPos { Input::Call call; - FunctionPosition pos; + FunctionPosition posAdj; - CallAndPos() { this = MkCallAndPos(call, pos) } + CallAndPos() { this = MkCallAndPos(call, posAdj) } Input::Call getCall() { result = call } - FunctionPosition getPos() { result = pos } + FunctionPosition getPosAdj() { result = posAdj } Location getLocation() { result = call.getLocation() } - Type getTypeAt(TypePath path) { result = call.getArgType(pos, path) } + Type getTypeAt(TypePath path) { result = call.getArgType(posAdj, path) } - string toString() { result = call.toString() + " [arg " + pos + "]" } + string toString() { result = call.toString() + " [arg " + posAdj + "]" } } pragma[nomagic] private predicate potentialInstantiationOf0( - CallAndPos cp, Input::Call call, TypeParameter tp, FunctionPosition pos, Function f, + CallAndPos cp, Input::Call call, TypeParameter tp, FunctionPosition posAdj, Function f, TypeAbstraction abs, AssocFunctionType constraint ) { - cp = MkCallAndPos(call, pragma[only_bind_into](pos)) and + cp = MkCallAndPos(call, pragma[only_bind_into](posAdj)) and call.hasTargetCand(abs, f) and - toCheck(abs, f, tp, pragma[only_bind_into](pos), constraint) + toCheck(abs, f, tp, pragma[only_bind_into](posAdj), constraint) } private module ArgIsInstantiationOfToIndexInput implements @@ -395,9 +401,9 @@ module ArgsAreInstantiationsOf { predicate potentialInstantiationOf( CallAndPos cp, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(Input::Call call, TypeParameter tp, FunctionPosition pos, int rnk, Function f | - potentialInstantiationOf0(cp, call, tp, pos, f, abs, constraint) and - toCheckRanked(abs, f, tp, pos, rnk) + exists(Input::Call call, TypeParameter tp, FunctionPosition posAdj, int rnk, Function f | + potentialInstantiationOf0(cp, call, tp, posAdj, f, abs, constraint) and + toCheckRanked(abs, f, tp, posAdj, rnk) | rnk = 0 or @@ -413,18 +419,18 @@ module ArgsAreInstantiationsOf { pragma[nomagic] private predicate argIsInstantiationOf( - Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i, Function f, int rnk + Input::Call call, FunctionPosition posAdj, ImplOrTraitItemNode i, Function f, int rnk ) { - ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and - toCheckRanked(i, f, _, pos, rnk) + ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, posAdj), i, _) and + toCheckRanked(i, f, _, posAdj, rnk) } pragma[nomagic] private predicate argsAreInstantiationsOfToIndex( Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - exists(FunctionPosition pos | - argIsInstantiationOf(call, pos, i, f, rnk) and + exists(FunctionPosition posAdj | + argIsInstantiationOf(call, posAdj, i, f, rnk) and call.hasTargetCand(i, f) | rnk = 0 @@ -465,9 +471,9 @@ module ArgsAreInstantiationsOf { pragma[nomagic] private predicate argsAreNotInstantiationsOf0( - Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i + Input::Call call, FunctionPosition posAdj, ImplOrTraitItemNode i ) { - ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _) + ArgsAreNotInstantiationOf::argIsNotInstantiationOf(MkCallAndPos(call, posAdj), i, _, _) } /** @@ -478,10 +484,10 @@ module ArgsAreInstantiationsOf { */ pragma[nomagic] predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) { - exists(FunctionPosition pos | - argsAreNotInstantiationsOf0(call, pos, i) and + exists(FunctionPosition posAdj | + argsAreNotInstantiationsOf0(call, posAdj, i) and call.hasTargetCand(i, f) and - Input::toCheck(i, f, _, pos) + Input::toCheck(i, f, _, posAdj) ) } } diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index 70dfe9e90056..0c6c19ab1306 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -343,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) | @@ -1236,42 +1240,6 @@ private module ContextTyping { } } -/** - * Holds if function `f` with the name `name` and the arity `arity` exists in - * `i`, and the type at position `pos` is `t`. - */ -pragma[nomagic] -private predicate assocFunctionInfo( - Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos, - AssocFunctionType t -) { - f = i.getASuccessor(name) and - arity = f.getParamList().getNumberOfParams() and - t.appliesTo(f, i, pos) -} - -/** - * Holds if function `f` with the name `name` and the arity `arity` exists in - * blanket (like) implementation `impl` of `trait`, and the type at position - * `pos` is `t`. - * - * `blanketPath` points to the type `blanketTypeParam` inside `t`, which - * is the type parameter used in the blanket implementation. - */ -pragma[nomagic] -private predicate functionInfoBlanketLike( - Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition pos, - AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam -) { - exists(TypePath blanketSelfPath | - assocFunctionInfo(f, name, arity, impl, pos, t) and - TTypeParamTypeParameter(blanketTypeParam) = t.getTypeAt(blanketPath) and - blanketPath = any(string s) + blanketSelfPath and - BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) and - trait = impl.resolveTraitTy() - ) -} - /** * Holds if the type path `path` pointing to `type` is stripped of any leading * complex root type allowed for `self` parameters, such as `&`, `Box`, `Rc`, @@ -1327,7 +1295,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 * @@ -1361,190 +1329,392 @@ 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 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 position `posAdj` is `t`. + */ + pragma[nomagic] + private predicate assocFunctionInfo( + Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition posAdj, + AssocFunctionType t + ) { + exists(FunctionPosition pos | + f = i.getASuccessor(name) and + arity = f.getNumberOfParamsInclSelf() and + t.appliesTo(f, i, pos) and + posAdj = pos.getFunctionCallAdjusted(f) + ) + } + + /** + * Holds if function `f` with the name `name` and the arity `arity` exists in + * blanket (like) implementation `impl` of `trait`, and the type at position + * `posAdj` is `t`. * - * `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()` - * and `strippedType` is the type inside the reference. + * `blanketPath` points to the type `blanketTypeParam` inside `t`, which + * is the type parameter used in the blanket implementation. */ pragma[nomagic] - private predicate methodInfo( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType + private predicate assocFunctionInfoBlanketLike( + Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition posAdj, + AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam ) { - assocFunctionInfo(m, name, arity, i, selfPos, selfType) and - strippedType = selfType.getTypeAt(strippedTypePath) and - isComplexRootStripped(strippedTypePath, strippedType) and - selfPos.isSelfOrTypeQualifier() + exists(TypePath blanketSelfPath | + assocFunctionInfo(f, name, arity, impl, posAdj, t) and + TTypeParamTypeParameter(blanketTypeParam) = t.getTypeAt(blanketPath) and + blanketPath = any(string s) + blanketSelfPath and + BlanketImplementation::isBlanketLike(impl, blanketSelfPath, blanketTypeParam) and + trait = impl.resolveTraitTy() + ) } + /** + * Holds if the non-method trait function `f` mentions the implicit `Self` type + * parameter at `pos`. + */ pragma[nomagic] - private predicate methodInfoTypeParam( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, TypeParam tp + private predicate traitSelfTypeParameterOccurrence( + TraitItemNode trait, NonMethodFunction f, FunctionPosition posAdj ) { - methodInfo(m, name, arity, selfPos, i, selfType, strippedTypePath, TTypeParamTypeParameter(tp)) + exists(FunctionPosition pos | + FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _, + TSelfTypeParameter(trait)) and + posAdj = pos.getFunctionCallAdjusted(f) + ) } /** - * Same as `methodInfo`, but restricted to non-blanket implementations, and - * allowing for any `strippedType` when the corresponding type inside `m` is - * a type parameter. + * Holds if the non-method function `f` implements a trait function that mentions + * the implicit `Self` type parameter at `pos`. */ - pragma[inline] - private predicate methodInfoNonBlanket( - Method m, string name, int arity, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType + pragma[nomagic] + private predicate traitImplSelfTypeParameterOccurrence( + ImplItemNode impl, NonMethodFunction f, FunctionPosition posAdj + ) { + exists(NonMethodFunction traitFunction | + f = impl.getAnAssocItem() and + f.implements(traitFunction) and + traitSelfTypeParameterOccurrence(_, traitFunction, posAdj) + ) + } + + private module TypeOption = Option; + + private class TypeOption = TypeOption::Option; + + /** + * 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 `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`. + * + * `implType` is the type being implemented by `i` (`None` when `i` is a trait). + * + * `trait` is the trait being implemented by `i` or `i` itself (`None` when `i` is inherent). + * + * `isMethod` indicates whether `f` is a method. + */ + pragma[nomagic] + private predicate assocFunctionInfo( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, TypeOption implType, + TypeOption trait, boolean isMethod ) { + assocFunctionInfo(f, name, arity, i, selfPosAdj, selfType) and + strippedType = selfType.getTypeAt(strippedTypePath) and + ( + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPosAdj.isTypeQualifier() and strippedTypePath.isEmpty() + ) and ( - methodInfo(m, name, arity, selfPos, i, selfType, strippedTypePath, strippedType) or - methodInfoTypeParam(m, name, arity, selfPos, i, selfType, strippedTypePath, _) + f instanceof Method and + selfPosAdj.asPosition() = 0 + or + selfPosAdj.isTypeQualifier() + or + traitSelfTypeParameterOccurrence(i, f, selfPosAdj) + or + traitImplSelfTypeParameterOccurrence(i, f, selfPosAdj) + ) and + ( + implType.asSome() = resolveImplSelfTypeAt(i, TypePath::nil()) + or + i instanceof Trait and + implType.isNone() + ) and + ( + trait.asSome() = + [ + TTrait(i).(Type), + TTrait(i.(ImplItemNode).resolveTraitTy()).(Type) + ] + or + i.(Impl).isInherent() and trait.isNone() ) and + if f instanceof Method then isMethod = true else isMethod = false + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLike( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, TypeOption implType, + TypeOption trait, boolean isMethod + ) { + assocFunctionInfo(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, strippedType, + implType, trait, isMethod) and not BlanketImplementation::isBlanketLike(i, _, _) } + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeTypeParam( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, TypeOption implType, TypeOption trait, + boolean isMethod + ) { + assocFunctionInfoNonBlanketLike(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, + TTypeParamTypeParameter(_), implType, trait, 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. + * + * `isMethod` indicates whether `f` is a method. */ pragma[nomagic] - private predicate methodInfoBlanketLike( - Method m, string name, int arity, FunctionPosition selfPos, ImplItemNode impl, Trait trait, - AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam + private predicate assocFunctionSelfInfoBlanketLike( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplItemNode impl, Trait trait, + AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam, boolean isMethod ) { - functionInfoBlanketLike(m, name, arity, impl, trait, selfPos, selfType, blanketPath, + assocFunctionInfoBlanketLike(f, name, arity, impl, trait, selfPosAdj, selfType, blanketPath, blanketTypeParam) and - selfPos.isSelfOrTypeQualifier() + ( + f instanceof Method and + selfPosAdj.asPosition() = 0 + or + selfPosAdj.isTypeQualifier() + or + traitImplSelfTypeParameterOccurrence(impl, f, selfPosAdj) + ) 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 + // we only need to check visibility of traits that are not mentioned explicitly + not afc0.hasATrait() ) ) } - private module MethodTraitIsVisible = TraitIsVisible; + private module AssocFunctionTraitIsVisible = TraitIsVisible; - private predicate methodCallVisibleTraitCandidate = MethodTraitIsVisible::traitIsVisible/2; - - 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) { + AssocFunctionTraitIsVisible::traitIsVisible(afc, impl.resolveTraitTy()) + } + + private Type getNonTypeParameterTypeQualifier(AssocFunctionCall afc) { + result = getCallExprTypeQualifier(afc, TypePath::nil(), _) and + not result instanceof TypeParameter + } + + pragma[nomagic] + private predicate callInfo( + AssocFunctionCall afc, string name, int arity, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + afc.hasNameAndArity(name, arity) and + (if afc.hasReceiver() then hasReceiver = true else hasReceiver = false) and + ( + typeQualifier.asSome() = getNonTypeParameterTypeQualifier(afc) + or + not exists(getNonTypeParameterTypeQualifier(afc)) and + typeQualifier.isNone() + ) and + ( + traitQualifier.asSome() = TTrait(afc.getATrait()) + or + not afc.hasATrait() and + traitQualifier.isNone() + ) + } + + bindingset[implType, trait, isMethod] + private predicate callMatching( + TypeOption implType, TypeOption trait, boolean isMethod, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + // when present, explicit type qualifier must match the type being implemented + typeQualifier = [implType, any(TypeOption non | non.isNone())] and + // when present, explicit trait qualifier must match the trait being implemented or the trait itself + traitQualifier = [trait, any(TypeOption non | non.isNone())] and + // when a receiver is present, the target must be a method + hasReceiver = [isMethod, false] + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeCand( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType, + TypeOption typeQualifier, TypeOption traitQualifier, boolean hasReceiver + ) { + exists(TypeOption implType, TypeOption trait, boolean isMethod | + assocFunctionInfoNonBlanketLike(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, + strippedType, implType, trait, isMethod) and + callMatching(implType, trait, isMethod, typeQualifier, traitQualifier, hasReceiver) + ) + } + + pragma[nomagic] + private predicate assocFunctionInfoNonBlanketLikeTypeParamCand( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, TypeOption typeQualifier, + TypeOption traitQualifier, boolean hasReceiver + ) { + exists(TypeOption implType, TypeOption trait, boolean isMethod | + assocFunctionInfoNonBlanketLikeTypeParam(f, name, arity, selfPosAdj, i, selfType, + strippedTypePath, implType, trait, isMethod) and + callMatching(implType, trait, isMethod, typeQualifier, traitQualifier, hasReceiver) + ) } /** - * 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, FunctionPosition selfPos, ImplOrTraitItemNode i, - AssocFunctionType self, TypePath strippedTypePath, Type strippedType + private predicate nonBlanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPosition selfPosAdj, ImplOrTraitItemNode i, + AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoNonBlanket(m, name, arity, selfPos, i, self, strippedTypePath, strippedType) + exists( + string name, int arity, TypeOption typeQualifier, TypeOption traitQualifier, + boolean hasReceiver | - i = - any(Impl impl | - not impl.hasTrait() - or - methodCallVisibleImplTraitCandidate(mc, impl) - ) - or - methodCallVisibleTraitCandidate(mc, i) + callInfo(afc, name, arity, typeQualifier, traitQualifier, hasReceiver) and + if not afc.hasATrait() and i.(Impl).hasTrait() + then callVisibleImplTraitCandidate(afc, i) + else any() + | + assocFunctionInfoNonBlanketLikeCand(f, name, arity, selfPosAdj, i, selfType, strippedTypePath, + strippedType, typeQualifier, traitQualifier, hasReceiver) or - i.(ImplItemNode).resolveTraitTy() = mc.getTrait() + assocFunctionInfoNonBlanketLikeTypeParamCand(f, name, arity, selfPosAdj, i, selfType, + strippedTypePath, typeQualifier, traitQualifier, hasReceiver) + ) + } + + pragma[nomagic] + private predicate assocFunctionSelfInfoBlanketLikeCand( + Function f, string name, int arity, FunctionPosition selfPosAdj, ImplItemNode impl, + AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam, + TypeOption traitQualifier, boolean hasReceiver + ) { + exists(Trait trait, boolean isMethod | + assocFunctionSelfInfoBlanketLike(f, name, arity, selfPosAdj, impl, trait, selfType, + blanketPath, blanketTypeParam, isMethod) and + traitQualifier = [TypeOption::some(TTrait(trait)), any(TypeOption non | non.isNone())] and + hasReceiver = [isMethod, false] ) } /** - * 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, FunctionPosition selfPos, ImplItemNode impl, AssocFunctionType self, - TypePath blanketPath, TypeParam blanketTypeParam + private predicate blanketLikeCandidate( + AssocFunctionCall afc, Function f, FunctionPosition selfPosAdj, ImplItemNode impl, + AssocFunctionType self, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(string name, int arity | - mc.hasNameAndArity(name, arity) and - methodInfoBlanketLike(m, name, arity, selfPos, impl, _, self, blanketPath, blanketTypeParam) + exists(string name, int arity, TypeOption traitQualifier, boolean hasReceiver | + callInfo(afc, name, arity, _, traitQualifier, hasReceiver) and + assocFunctionSelfInfoBlanketLikeCand(f, name, arity, selfPosAdj, impl, self, blanketPath, + blanketTypeParam, traitQualifier, hasReceiver) | - methodCallVisibleImplTraitCandidate(mc, impl) - or - impl.resolveTraitTy() = mc.getTrait() + if not afc.hasATrait() then callVisibleImplTraitCandidate(afc, impl) else any() ) } /** - * 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 class AssocFunctionCall extends Expr { abstract predicate hasNameAndArity(string name, int arity); - abstract Expr getArg(ArgumentPosition pos); + abstract Expr getNonReturnNodeAt(FunctionPosition pos); + + AstNode getNodeAt(FunctionPosition posAdj) { + exists(FunctionPosition pos | + (if this.hasReceiver() then posAdj = pos.getFunctionCallAdjusted() else posAdj = pos) and + result = this.getNonReturnNodeAt(pos) + ) + or + result = this and posAdj.isReturn() + } + + abstract predicate hasReceiver(); abstract predicate supportsAutoDerefAndBorrow(); @@ -1554,163 +1724,197 @@ private module MethodResolution { /** Holds if this call targets a trait. */ predicate hasTrait() { exists(this.getTrait()) } - AstNode getNodeAt(FunctionPosition apos) { - result = this.getArg(apos.asArgumentPosition()) + Trait getATrait() { + result = this.getTrait() or - result = this and apos.isReturn() + result = getALookupTrait(getCallExprTypeQualifier(this, TypePath::nil(), _)) } - Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = inferType(this.getArg(pos), path) + predicate hasATrait() { exists(this.getATrait()) } + + Type getTypeAt(FunctionPosition posAdj, TypePath path) { + result = inferType(this.getNodeAt(posAdj), path) } /** - * Same as `getACandidateReceiverTypeAt`, but without borrows. + * Holds if `selfPos` is a potentially relevant position for resolving this call. */ pragma[nomagic] - Type getACandidateReceiverTypeAtNoBorrow( - FunctionPosition selfPos, DerefChain derefChain, TypePath path - ) { - result = this.getArgumentTypeAt(selfPos.asArgumentPosition(), path) and - selfPos.isSelfOrTypeQualifier() and - derefChain.isEmpty() + private predicate isRelevantSelfPos(FunctionPosition selfPosAdj) { + not this.hasReceiver() and + exists(TypePath strippedTypePath, Type strippedType | + strippedType = substituteLookupTraits(this.getTypeAt(selfPosAdj, strippedTypePath)) and + strippedType != TNeverType() and + strippedType != TUnknownType() + | + nonBlanketLikeCandidate(this, _, selfPosAdj, _, _, strippedTypePath, strippedType) + or + blanketLikeCandidate(this, _, selfPosAdj, _, _, strippedTypePath, _) + ) + } + + predicate isReceiverPos(FunctionPosition posAdj) { + this.hasReceiver() and posAdj.asPosition() = 0 + } + + /** + * Same as `getSelfTypeAt`, but without borrows. + */ + pragma[nomagic] + Type getSelfTypeAtNoBorrow(FunctionPosition selfPosAdj, DerefChain derefChain, TypePath path) { + result = this.getTypeAt(selfPosAdj, path) and + derefChain.isEmpty() and + ( + this.isReceiverPos(selfPosAdj) + or + selfPosAdj.isTypeQualifier() + or + this.isRelevantSelfPos(selfPosAdj) + ) or exists(DerefImplItemNode impl, DerefChain suffix | result = - ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPos, impl, suffix, path) and + ImplicitDeref::getDereferencedCandidateReceiverType(this, selfPosAdj, 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, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, + ImplOrTraitItemNode i, FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, Type root ) { exists(TypePath path | - ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, selfPos, - derefChain, borrow), i, _, path) and + SelfArgIsInstantiationOf::argIsNotInstantiationOf(this, i, selfPosAdj, derefChain, borrow, + path) and path.isCons(root.getATypeParameter(), _) ) + or + exists(AssocFunctionType selfType | + SelfArgIsInstantiationOf::argIsInstantiationOf(this, i, selfPosAdj, derefChain, borrow, + selfType) and + OverloadedCallArgsAreInstantiationsOf::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, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + ImplItemNode impl, FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow ) { - ReceiverIsNotInstantiationOfBlanketLikeSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, - selfPos, derefChain, borrow), impl, _, _) + SelfArgIsNotInstantiationOfBlanketLike::argIsNotInstantiationOf(MkAssocFunctionCallCand(this, + selfPosAdj, derefChain, borrow), impl, _, _) or - ReceiverSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkMethodCallCand(this, - selfPos, derefChain, borrow), impl) + ArgSatisfiesBlanketLikeConstraint::dissatisfiesBlanketConstraint(MkAssocFunctionCallCand(this, + selfPosAdj, 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( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path + Type getANonPseudoSelfTypeAt( + FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAt(selfPos, derefChain, borrow, path) and + result = this.getSelfTypeAt(selfPosAdj, derefChain, borrow, path) and result != TNeverType() and result != TUnknownType() } pragma[nomagic] - private Type getComplexStrippedType( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath + private Type getComplexStrippedSelfType( + FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath ) { - result = - this.getANonPseudoCandidateReceiverTypeAt(selfPos, derefChain, borrow, strippedTypePath) and - isComplexRootStripped(strippedTypePath, result) + result = this.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, strippedTypePath) and + ( + isComplexRootStripped(strippedTypePath, result) + or + selfPosAdj.isTypeQualifier() and strippedTypePath.isEmpty() + ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketLikeTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType + FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType ) { forall(ImplOrTraitItemNode i | - methodCallNonBlanketCandidate(this, _, selfPos, i, _, strippedTypePath, strippedType) + nonBlanketLikeCandidate(this, _, selfPosAdj, i, _, strippedTypePath, strippedType) | - this.hasIncompatibleTarget(i, selfPos, derefChain, borrow, strippedType) + this.hasIncompatibleTarget(i, selfPosAdj, derefChain, borrow, strippedType) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType + FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, - strippedType) and - forall(ImplItemNode i | methodCallBlanketLikeCandidate(this, _, selfPos, i, _, _, _) | - this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, borrow, + strippedTypePath, strippedType) and + forall(ImplItemNode i | blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) | + this.hasIncompatibleBlanketLikeTarget(i, selfPosAdj, derefChain, borrow) ) } bindingset[derefChain, borrow, strippedTypePath, strippedType] private predicate hasNoCompatibleNonBlanketTargetCheck( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath strippedTypePath, - Type strippedType + FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, + TypePath strippedTypePath, Type strippedType ) { - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, borrow, strippedTypePath, - strippedType) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, borrow, + strippedTypePath, strippedType) and forall(ImplItemNode i | - methodCallBlanketLikeCandidate(this, _, selfPos, i, _, _, _) and + blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) and not i.isBlanketImplementation() | - this.hasIncompatibleBlanketLikeTarget(i, selfPos, derefChain, borrow) + this.hasIncompatibleBlanketLikeTarget(i, selfPosAdj, derefChain, borrow) ) } // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetNoBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPosition selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - ( - this.supportsAutoDerefAndBorrow() - or - // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - derefChain.isEmpty() - ) and + this.supportsAutoDerefAndBorrow() and + this.isReceiverPos(selfPosAdj) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, strippedType, - n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleTargetCheck(selfPos, derefChain, TNoBorrowKind(), strippedTypePath, t) + this.hasNoCompatibleTargetNoBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, + strippedType, n - 1) and + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleTargetCheck(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * 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(FunctionPosition selfPos, DerefChain derefChain) { + predicate hasNoCompatibleTargetNoBorrow(FunctionPosition selfPosAdj, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleTargetNoBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1718,38 +1922,44 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetNoBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPosition selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { ( - this.supportsAutoDerefAndBorrow() + this.supportsAutoDerefAndBorrow() and + this.isReceiverPos(selfPosAdj) or - // needed for the `hasNoCompatibleTarget` check in - // `ReceiverSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` - derefChain.isEmpty() + // needed for the `hasNoCompatibleNonBlanketTarget` check in + // `ArgSatisfiesBlanketLikeConstraintInput::hasBlanketCandidate` + exists(ImplItemNode i | + derefChain.isEmpty() and + blanketLikeCandidate(this, _, selfPosAdj, i, _, _, _) and + i.isBlanketImplementation() + ) ) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TNoBorrowKind(), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TNoBorrowKind(), + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TNoBorrowKind(), strippedTypePath, t) ) } /** * 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( - FunctionPosition selfPos, DerefChain derefChain + FunctionPosition selfPosAdj, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleNonBlanketTargetNoBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1757,30 +1967,32 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetSharedBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPosition selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), - strippedTypePath, t) + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, + TSomeBorrowKind(false), strippedTypePath, t) ) } /** * 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(FunctionPosition selfPos, DerefChain derefChain) { + predicate hasNoCompatibleTargetSharedBorrow(FunctionPosition selfPosAdj, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetSharedBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleTargetSharedBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1788,30 +2000,32 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleTargetMutBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPosition selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(true), + strippedTypePath) and n = -1 or - this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketLikeTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } /** * 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(FunctionPosition selfPos, DerefChain derefChain) { + predicate hasNoCompatibleTargetMutBorrow(FunctionPosition selfPosAdj, DerefChain derefChain) { exists(Type strippedType | - this.hasNoCompatibleTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, + this.hasNoCompatibleTargetMutBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1819,32 +2033,34 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetSharedBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPosition selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(false), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(false), + strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, strippedTypePath, - strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(false), + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPosAdj, derefChain, + strippedTypePath, strippedType, n - 1) and + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(false), strippedTypePath, t) ) } /** * 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( - FunctionPosition selfPos, DerefChain derefChain + FunctionPosition selfPosAdj, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPos, derefChain, _, + this.hasNoCompatibleNonBlanketTargetSharedBorrowToIndex(selfPosAdj, derefChain, _, strippedType, getLastLookupTypeIndex(strippedType)) ) } @@ -1852,38 +2068,43 @@ private module MethodResolution { // forex using recursion pragma[nomagic] private predicate hasNoCompatibleNonBlanketTargetMutBorrowToIndex( - FunctionPosition selfPos, DerefChain derefChain, TypePath strippedTypePath, Type strippedType, - int n + FunctionPosition selfPosAdj, DerefChain derefChain, TypePath strippedTypePath, + Type strippedType, int n ) { - this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and + this.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPosAdj, derefChain) and strippedType = - this.getComplexStrippedType(selfPos, derefChain, TSomeBorrowKind(true), strippedTypePath) and + this.getComplexStrippedSelfType(selfPosAdj, derefChain, TSomeBorrowKind(true), + strippedTypePath) and n = -1 or - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, strippedTypePath, + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPosAdj, derefChain, strippedTypePath, strippedType, n - 1) and - exists(Type t | t = getNthLookupType(strippedType, n) | - this.hasNoCompatibleNonBlanketTargetCheck(selfPos, derefChain, TSomeBorrowKind(true), + exists(Type t | + t = getNthLookupType(strippedType, n) and + this.hasNoCompatibleNonBlanketTargetCheck(selfPosAdj, derefChain, TSomeBorrowKind(true), strippedTypePath, t) ) } /** * 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( - FunctionPosition selfPos, DerefChain derefChain + FunctionPosition selfPosAdj, DerefChain derefChain ) { exists(Type strippedType | - this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPos, derefChain, _, strippedType, - getLastLookupTypeIndex(strippedType)) + this.hasNoCompatibleNonBlanketTargetMutBorrowToIndex(selfPosAdj, 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 @@ -1895,20 +2116,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( - FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow, TypePath path + Type getSelfTypeAt( + FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow, TypePath path ) { - result = this.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, path) and + result = this.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, path) and borrow.isNoBorrow() or exists(RefType rt | // first try shared borrow this.supportsAutoDerefAndBorrow() and - this.hasNoCompatibleTargetNoBorrow(selfPos, derefChain) and + this.isReceiverPos(selfPosAdj) and + this.hasNoCompatibleTargetNoBorrow(selfPosAdj, derefChain) and borrow.isSharedBorrow() or // then try mutable borrow - this.hasNoCompatibleTargetSharedBorrow(selfPos, derefChain) and + this.hasNoCompatibleTargetSharedBorrow(selfPosAdj, derefChain) and borrow.isMutableBorrow() | rt = borrow.getRefType() and @@ -1917,7 +2139,7 @@ private module MethodResolution { result = rt or exists(TypePath suffix | - result = this.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, suffix) and + result = this.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, suffix) and path = TypePath::cons(rt.getPositionalTypeParameter(0), suffix) ) ) @@ -1925,15 +2147,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) ) } @@ -1943,21 +2165,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 apos | apos.isSelf())) and - not (derefChain.isEmpty() and borrow.isNoBorrow()) + exists(FunctionPosition selfAdj | + this.isReceiverPos(selfAdj) and + exists(this.resolveCallTarget(_, derefChain, borrow)) and + arg = this.getNodeAt(selfAdj) 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) { name = super.getIdentifier().getText() and - arity = super.getArgList().getNumberOfArgs() + arity = super.getArgList().getNumberOfArgs() + 1 } - override Expr getArg(ArgumentPosition pos) { - result = MethodCallExpr.super.getSyntacticArgument(pos) + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = MethodCallExpr.super.getSyntacticArgument(pos.asArgumentPosition()) } override predicate supportsAutoDerefAndBorrow() { any() } @@ -1965,7 +2192,7 @@ 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) @@ -1974,10 +2201,12 @@ private module MethodResolution { pragma[nomagic] override predicate hasNameAndArity(string name, int arity) { (if this.isInMutableContext() then name = "index_mut" else name = "index") and - arity = 1 + arity = 2 } - override Expr getArg(ArgumentPosition pos) { + override predicate hasReceiver() { any() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { pos.isSelf() and result = super.getBase() or @@ -1994,95 +2223,90 @@ 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) + forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof AssocFunction) } pragma[nomagic] override predicate hasNameAndArity(string name, int arity) { name = CallExprImpl::getFunctionPath(this).getText() and - arity = super.getArgList().getNumberOfArgs() - 1 + arity = super.getArgList().getNumberOfArgs() } - override Expr getArg(ArgumentPosition pos) { - pos.isSelf() and - result = super.getSyntacticPositionalArgument(0) - or - result = super.getSyntacticPositionalArgument(pos.asPosition() + 1) + override predicate hasReceiver() { none() } + + override Expr getNonReturnNodeAt(FunctionPosition pos) { + result = super.getSyntacticPositionalArgument(pos.asPosition()) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { - result = super.getArgumentTypeAt(pos, path) + override Type getTypeAt(FunctionPosition posAdj, TypePath path) { + result = super.getTypeAt(posAdj, path) or - pos.isTypeQualifier() and + posAdj.isTypeQualifier() and result = getCallExprTypeQualifier(this, path, _) } - pragma[nomagic] - predicate hasNoInherentTarget() { - // `_` is fine below, because auto-deref/borrow is not supported - MkMethodCallCand(this, _, _, _).(MethodCallCand).hasNoInherentTarget() - } - override predicate supportsAutoDerefAndBorrow() { none() } 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) { super.isOverloaded(_, name, _) and - arity = super.getNumberOfOperands() - 1 + arity = super.getNumberOfOperands() } - override Expr getArg(ArgumentPosition pos) { + override predicate hasReceiver() { any() } + + 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 posAdj, boolean isMutable) { exists(int borrows | super.isOverloaded(_, _, borrows) | - pos.isSelf() and + posAdj.asPosition() = 0 and borrows >= 1 and if this instanceof CompoundAssignmentExpr then isMutable = true else isMutable = false or - pos.asPosition() = 0 and + posAdj.asPosition() = 1 and borrows = 2 and isMutable = false ) } - override Type getArgumentTypeAt(ArgumentPosition pos, TypePath path) { + override Type getTypeAt(FunctionPosition posAdj, TypePath path) { exists(boolean isMutable, RefType rt | - this.implicitBorrowAt(pos, isMutable) and + this.implicitBorrowAt(posAdj, isMutable) and rt = getRefType(isMutable) | result = rt and path.isEmpty() or exists(TypePath path0 | - result = inferType(this.getArg(pos), path0) and + result = inferType(this.getNodeAt(posAdj), path0) and path = TypePath::cons(rt.getPositionalTypeParameter(0), path0) ) ) or - not this.implicitBorrowAt(pos, _) and - result = inferType(this.getArg(pos), path) + not this.implicitBorrowAt(posAdj, _) and + result = inferType(this.getNodeAt(posAdj), path) } override predicate argumentHasImplicitDerefChainBorrow( Expr arg, DerefChain derefChain, BorrowKind borrow ) { - exists(ArgumentPosition apos, boolean isMutable | - this.implicitBorrowAt(apos, isMutable) and - arg = this.getArg(apos) and + exists(FunctionPosition posAdj, boolean isMutable | + this.implicitBorrowAt(posAdj, isMutable) and + arg = this.getNodeAt(posAdj) and derefChain = DerefChain::nil() and borrow = TSomeBorrowKind(isMutable) ) @@ -2094,81 +2318,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, FunctionPosition selfPos, DerefChain derefChain, BorrowKind borrow + private newtype TAssocFunctionCallCand = + MkAssocFunctionCallCand( + AssocFunctionCall afc, FunctionPosition selfPosAdj, DerefChain derefChain, BorrowKind borrow ) { - exists(mc.getACandidateReceiverTypeAt(selfPos, derefChain, borrow, _)) + exists(afc.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, _)) } - /** A method call with a dereference chain and a potential borrow. */ - private class MethodCallCand extends MkMethodCallCand { - MethodCall mc_; - FunctionPosition selfPos; + /** A call with a dereference chain and a potential borrow. */ + final private class AssocFunctionCallCand extends MkAssocFunctionCallCand { + AssocFunctionCall afc_; + FunctionPosition selfPosAdj; DerefChain derefChain; BorrowKind borrow; - MethodCallCand() { this = MkMethodCallCand(mc_, selfPos, derefChain, borrow) } + AssocFunctionCallCand() { this = MkAssocFunctionCallCand(afc_, selfPosAdj, derefChain, borrow) } - MethodCall getMethodCall() { result = mc_ } + AssocFunctionCall getAssocFunctionCall() { result = afc_ } Type getTypeAt(TypePath path) { result = - substituteLookupTraits(mc_.getANonPseudoCandidateReceiverTypeAt(selfPos, derefChain, borrow, - path)) + substituteLookupTraits(afc_.getANonPseudoSelfTypeAt(selfPosAdj, derefChain, borrow, path)) } pragma[nomagic] predicate hasNoCompatibleNonBlanketTarget() { - mc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetSharedBorrow(selfPosAdj, derefChain) and borrow.isSharedBorrow() or - mc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetMutBorrow(selfPosAdj, derefChain) and borrow.isMutableBorrow() or - mc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPos, derefChain) and + afc_.hasNoCompatibleNonBlanketTargetNoBorrow(selfPosAdj, derefChain) and borrow.isNoBorrow() } pragma[nomagic] predicate hasSignature( - MethodCall mc, FunctionPosition selfPos_, TypePath strippedTypePath, Type strippedType, + 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) and - selfPos = selfPos_ + ( + isComplexRootStripped(strippedTypePath, strippedType) + or + selfPosAdj.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, _, _) + SelfArgIsNotInstantiationOfInherent::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(_, selfPos, strippedTypePath, strippedType, name, arity) and + selfPosAdj.isTypeQualifier() or + afc_.isReceiverPos(selfPosAdj) or // todo? + selfPosAdj.asPosition() = 0 + | + this.hasSignature(_, selfPosAdj, strippedTypePath, strippedType, name, arity) and forall(Impl i | - methodInfoNonBlanket(_, name, arity, selfPos, i, _, strippedTypePath, strippedType) and - not i.hasTrait() + ( + assocFunctionInfoNonBlanketLike(_, name, arity, selfPosAdj, i, _, strippedTypePath, + strippedType, _, _, _) or + assocFunctionInfoNonBlanketLikeTypeParam(_, name, arity, selfPosAdj, i, _, + strippedTypePath, _, _, _) + ) and + i.isInherent() | this.hasIncompatibleInherentTarget(i) ) @@ -2177,32 +2413,32 @@ private module MethodResolution { pragma[nomagic] private predicate argIsInstantiationOf(ImplOrTraitItemNode i, string name, int arity) { - ReceiverIsInstantiationOfSelfParam::argIsInstantiationOf(this, i, _) and - mc_.hasNameAndArity(name, arity) + SelfArgIsInstantiationOf::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) + OverloadedCallArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result) } string toString() { - result = mc_.toString() + " [" + derefChain.toString() + "; " + borrow + "]" + result = afc_ + " at " + selfPosAdj + " [" + derefChain.toString() + "; " + borrow + "]" } - Location getLocation() { result = mc_.getLocation() } + Location getLocation() { result = afc_.getLocation() } } /** @@ -2210,23 +2446,23 @@ private module MethodResolution { */ private module ImplicitDeref { private newtype TMethodCallDerefCand = - MkMethodCallDerefCand(MethodCall mc, FunctionPosition selfPos, DerefChain derefChain) { + MkMethodCallDerefCand(AssocFunctionCall mc, FunctionPosition selfPosAdj, DerefChain derefChain) { mc.supportsAutoDerefAndBorrow() and - mc.hasNoCompatibleTargetMutBorrow(selfPos, derefChain) and - exists(mc.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, TypePath::nil())) + mc.isReceiverPos(selfPosAdj) and + mc.hasNoCompatibleTargetMutBorrow(selfPosAdj, derefChain) and + exists(mc.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, TypePath::nil())) } /** A method call with a dereference chain. */ private class MethodCallDerefCand extends MkMethodCallDerefCand { - MethodCall mc; - FunctionPosition selfPos; + AssocFunctionCall mc; + FunctionPosition selfPosAdj; DerefChain derefChain; - MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, selfPos, derefChain) } + MethodCallDerefCand() { this = MkMethodCallDerefCand(mc, selfPosAdj, derefChain) } Type getTypeAt(TypePath path) { - result = - substituteLookupTraits(mc.getACandidateReceiverTypeAtNoBorrow(selfPos, derefChain, path)) and + result = substituteLookupTraits(mc.getSelfTypeAtNoBorrow(selfPosAdj, derefChain, path)) and result != TNeverType() and result != TUnknownType() } @@ -2255,16 +2491,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, FunctionPosition selfPos, DerefImplItemNode impl, DerefChain derefChain, - TypePath path + AssocFunctionCall afc, FunctionPosition selfPosAdj, DerefImplItemNode impl, + DerefChain derefChain, TypePath path ) { exists(MethodCallDerefCand mcc, TypePath exprPath | - mcc = MkMethodCallDerefCand(mc, selfPos, derefChain) and + mcc = MkMethodCallDerefCand(afc, selfPosAdj, derefChain) and MethodCallSatisfiesDerefConstraint::satisfiesConstraintTypeThrough(mcc, impl, _, exprPath, result) and exprPath.isCons(getDerefTargetTypeParameter(), path) @@ -2272,21 +2508,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, FunctionPosition selfPos, BorrowKind borrow | - mcc = MkMethodCallCand(mc, selfPos, _, borrow) and - methodCallBlanketLikeCandidate(mc, _, selfPos, 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()) + if impl.isBlanketImplementation() then afcc.hasNoCompatibleNonBlanketTarget() else any() | borrow.isNoBorrow() or @@ -2295,116 +2532,146 @@ 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 SelfArgIsInstantiationOfInput implements + IsInstantiationOfInputSig { pragma[nomagic] additional predicate potentialInstantiationOf0( - MethodCallCand mcc, ImplOrTraitItemNode i, AssocFunctionType selfType + AssocFunctionCallCand afcc, ImplOrTraitItemNode i, AssocFunctionType selfType ) { exists( - MethodCall mc, FunctionPosition selfPos, Method m, TypePath strippedTypePath, + AssocFunctionCall afc, FunctionPosition selfPosAdj, Function f, TypePath strippedTypePath, Type strippedType | - mcc.hasSignature(mc, selfPos, strippedTypePath, strippedType, _, _) + afcc.hasSignature(afc, selfPosAdj, strippedTypePath, strippedType, _, _) | - methodCallNonBlanketCandidate(mc, m, selfPos, i, selfType, strippedTypePath, strippedType) + nonBlanketLikeCandidate(afc, f, selfPosAdj, i, selfType, strippedTypePath, strippedType) or - methodCallBlanketLikeCandidate(mc, m, selfPos, i, selfType, _, _) and - ReceiverSatisfiesBlanketLikeConstraint::satisfiesBlanketConstraint(mcc, i) + blanketLikeCandidate(afc, f, selfPosAdj, 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 SelfArgIsInstantiationOf { + import ArgIsInstantiationOf + + pragma[nomagic] + predicate argIsNotInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPosAdj, + DerefChain derefChain, BorrowKind borrow, TypePath path + ) { + argIsNotInstantiationOf(MkAssocFunctionCallCand(afc, selfPosAdj, derefChain, borrow), i, _, + path) + } + + pragma[nomagic] + predicate argIsInstantiationOf( + AssocFunctionCall afc, ImplOrTraitItemNode i, FunctionPosition selfPosAdj, + DerefChain derefChain, BorrowKind borrow, AssocFunctionType selfType + ) { + argIsInstantiationOf(MkAssocFunctionCallCand(afc, selfPosAdj, derefChain, borrow), i, selfType) + } + } /** - * 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 belonging to a blanket (like) implementation. */ - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParamInput implements - IsInstantiationOfInputSig + private module SelfArgIsNotInstantiationOfBlanketLikeInput implements + IsInstantiationOfInputSig { pragma[nomagic] predicate potentialInstantiationOf( - MethodCallCand mcc, TypeAbstraction abs, AssocFunctionType constraint + AssocFunctionCallCand afcc, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(MethodCall mc, FunctionPosition selfPos | - mcc = MkMethodCallCand(mc, selfPos, _, _) and - methodCallBlanketLikeCandidate(mc, _, selfPos, abs, constraint, _, _) and + exists(AssocFunctionCall afc, FunctionPosition selfPosAdj | + afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, _) and + blanketLikeCandidate(afc, _, selfPosAdj, 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() ) } } - private module ReceiverIsNotInstantiationOfBlanketLikeSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsNotInstantiationOfBlanketLike = + 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 SelfArgIsNotInstantiationOfInherentInput 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()) + SelfArgIsInstantiationOfInput::potentialInstantiationOf0(afcc, abs, constraint) and + abs.(Impl).isInherent() and + // todo: comment + exists(AssocFunctionCall afc, FunctionPosition selfPosAdj | + afcc = MkAssocFunctionCallCand(afc, selfPosAdj, _, _) + | + selfPosAdj.isTypeQualifier() or + afc.isReceiverPos(selfPosAdj) or + selfPosAdj.asPosition() = 0 // todo + ) } } - private module ReceiverIsNotInstantiationOfInherentSelfParam = - ArgIsInstantiationOf; + private module SelfArgIsNotInstantiationOfInherent = + 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 { - predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) { - FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) + private module OverloadedCallArgsAreInstantiationsOfInput implements + ArgsAreInstantiationsOfInputSig + { + predicate toCheck( + ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition posAdj + ) { + exists(FunctionPosition pos | + FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos) and + posAdj = pos.getFunctionCallAdjusted(f) + ) } - class Call extends MethodCallCand { - Type getArgType(FunctionPosition pos, TypePath path) { - result = mc_.getArgumentTypeAt(pos.asArgumentPosition(), path) - or - pos.isReturn() and - result = inferType(mc_.getNodeAt(pos), path) + class Call extends AssocFunctionCallCand { + Type getArgType(FunctionPosition posAdj, TypePath path) { + result = this.getAssocFunctionCall().getTypeAt(posAdj, path) } predicate hasTargetCand(ImplOrTraitItemNode i, Function f) { @@ -2413,8 +2680,14 @@ private module MethodResolution { } } - private module MethodArgsAreInstantiationsOf = - ArgsAreInstantiationsOf; + private module OverloadedCallArgsAreInstantiationsOf { + import ArgsAreInstantiationsOf + + pragma[nomagic] + predicate argsAreNotInstantiationsOf(AssocFunctionCall afc, ImplOrTraitItemNode i) { + argsAreNotInstantiationsOf(MkAssocFunctionCallCand(afc, _, _, _), i, _) + } + } } /** @@ -2477,9 +2750,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 @@ -2498,39 +2771,25 @@ 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(apos, derefChain, borrow, path) and - derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) + result = this.getSelfTypeAt(pos.getFunctionCallAdjusted(), derefChain, borrow, path) and + derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and + 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(FunctionPosition pos, TypePath path) { + result = this.getTypeAt(pos.getFunctionCallAdjusted(), path) and + not pos.isSelf() } bindingset[derefChainBorrow] - Type getInferredType(string derefChainBorrow, AccessPosition apos, TypePath path) { - result = this.getInferredSelfType(apos, derefChainBorrow, path) + Type getInferredType(string derefChainBorrow, FunctionPosition pos, TypePath path) { + result = this.getInferredSelfType(pos, derefChainBorrow, path) or - result = this.getInferredNonSelfType(apos, path) + result = this.getInferredNonSelfType(pos, path) } Method getTarget(ImplOrTraitItemNode i, string derefChainBorrow) { @@ -2557,6 +2816,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) + ) + } } } @@ -2565,15 +2838,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() - } - - /** - * 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() + forall(Function f | f = CallExprImpl::getResolvedFunction(this) | not f instanceof Method) } - /** - * 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.isTypeQualifier() - } - - 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 { @@ -3233,7 +3119,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) @@ -3255,12 +3141,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 @@ -3336,12 +3216,12 @@ private module OperationMatchingInput implements MatchingInputSig { } } - class Access extends MethodResolution::MethodCallOperation { + class Access extends AssocFunctionResolution::AssocFunctionCallOperation { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } pragma[nomagic] - Type getInferredType(AccessPosition apos, TypePath path) { - result = inferType(this.getNodeAt(apos), path) + Type getInferredType(FunctionPosition pos, TypePath path) { + result = inferType(this.getNodeAt(pos.getFunctionCallAdjusted()), path) } Declaration getTarget() { @@ -3356,8 +3236,9 @@ private module OperationMatching = Matching; pragma[nomagic] private Type inferOperationType0(AstNode n, FunctionPosition pos, TypePath path) { - exists(OperationMatchingInput::Access a | - n = a.getNodeAt(pos) and + exists(OperationMatchingInput::Access a, FunctionPosition posAdj | + n = a.getNodeAt(posAdj) and + posAdj = pos.getFunctionCallAdjusted() and result = OperationMatching::inferAccessType(a, pos, path) ) } @@ -4057,7 +3938,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 @@ -4089,8 +3971,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, _, _) ) } @@ -4223,7 +4104,7 @@ private module Debug { exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and filepath.matches("%/main.rs") and - startline = 103 + startline = 1309 ) } diff --git a/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql b/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql index 2f2991678930..28a22c899cfa 100644 --- a/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql +++ b/rust/ql/src/queries/security/CWE-825/AccessAfterLifetime.ql @@ -18,90 +18,130 @@ import codeql.rust.dataflow.TaintTracking import codeql.rust.security.AccessAfterLifetimeExtensions::AccessAfterLifetime import AccessAfterLifetimeFlow::PathGraph -/** - * A data flow configuration for detecting accesses to a pointer after its - * lifetime has ended. - */ -module AccessAfterLifetimeConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node node) { - node instanceof Source and - // exclude cases with sources in macros, since these results are difficult to interpret - not node.asExpr().isFromMacroExpansion() and - sourceValueScope(node, _, _) - } +signature predicate sourceSinkPairSig(DataFlow::Node source, DataFlow::Node sink); - predicate isSink(DataFlow::Node node) { - node instanceof Sink and - // Exclude cases with sinks in macros, since these results are difficult to interpret - not node.asExpr().isFromMacroExpansion() and - // TODO: Remove this condition if it can be done without negatively - // impacting performance. This condition only include nodes with - // corresponding to an expression. This excludes sinks from models-as-data. - exists(node.asExpr()) - } +module Config { + /** + * A data flow configuration for detecting accesses to a pointer after its + * lifetime has ended. + */ + module AccessAfterLifetimeConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + node instanceof Source and + sourceSinkPair(node, _) and + // exclude cases with sources in macros, since these results are difficult to interpret + not node.asExpr().isFromMacroExpansion() and + sourceValueScope(node, _, _) + } - predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } + predicate isSink(DataFlow::Node node) { + node instanceof Sink and + sourceSinkPair(_, node) and + // Exclude cases with sinks in macros, since these results are difficult to interpret + not node.asExpr().isFromMacroExpansion() and + // TODO: Remove this condition if it can be done without negatively + // impacting performance. This condition only include nodes with + // corresponding to an expression. This excludes sinks from models-as-data. + exists(node.asExpr()) + } - predicate observeDiffInformedIncrementalMode() { any() } + predicate isBarrier(DataFlow::Node barrier) { barrier instanceof Barrier } - Location getASelectedSourceLocation(DataFlow::Node source) { - exists(Variable target | - sourceValueScope(source, target, _) and - result = [target.getLocation(), source.getLocation()] - ) + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { + exists(Variable target | + sourceValueScope(source, target, _) and + result = [target.getLocation(), source.getLocation()] + ) + } } } -module AccessAfterLifetimeFlow = TaintTracking::Global; +pragma[inline] +predicate anySourceSinkPair(DataFlow::Node source, DataFlow::Node sink) { any() } + +module AccessAfterLifetimeConfig1 = Config::AccessAfterLifetimeConfig; + +module AccessAfterLifetimeFlow1 = TaintTracking::Global; -predicate sourceBlock(Source s, Variable target, BlockExpr be) { - AccessAfterLifetimeFlow::flow(s, _) and - sourceValueScope(s, target, be.getEnclosingBlock*()) +predicate relevantSourceSinkPairStage3(DataFlow::Node source, DataFlow::Node sink) { + exists( + AccessAfterLifetimeFlow1::Stages::Stage3::Graph::Public::PathNode sourceNode, + AccessAfterLifetimeFlow1::Stages::Stage3::Graph::Public::PathNode sinkNode + | + AccessAfterLifetimeFlow1::Stages::Stage3::Graph::Public::flowPath(sourceNode, sinkNode) and + sourceNode.getNode() = source and + sinkNode.getNode() = sink + ) } -predicate sinkBlock(Sink s, BlockExpr be) { - AccessAfterLifetimeFlow::flow(_, s) and - be = s.asExpr().getEnclosingBlock() +predicate relevantSourceSinkPair(DataFlow::Node source, DataFlow::Node sink) { + Restrict::dereferenceAfterLifetime(source, sink, _) } -private predicate tcStep(BlockExpr a, BlockExpr b) { - // propagate through function calls - exists(Call call | - a = call.getEnclosingBlock() and - call.getARuntimeTarget() = b.getEnclosingCallable() - ) +module AccessAfterLifetimeConfig2 = Config::AccessAfterLifetimeConfig; + +module AccessAfterLifetimeFlow2 = TaintTracking::Global; + +predicate relevantSourceSinkPair2(DataFlow::Node source, DataFlow::Node sink) { + Restrict::dereferenceAfterLifetime(source, sink, _) } -private predicate isTcSource(BlockExpr be) { sourceBlock(_, _, be) } +module AccessAfterLifetimeConfig3 = Config::AccessAfterLifetimeConfig; -private predicate isTcSink(BlockExpr be) { sinkBlock(_, be) } +module AccessAfterLifetimeFlow = TaintTracking::Global; -/** - * Holds if block `a` contains block `b`, in the sense that a stack allocated variable in - * `a` may still be on the stack during execution of `b`. This is interprocedural, - * but is an overapproximation that doesn't accurately track call contexts - * (for example if `f` and `g` both call `b`, then depending on the - * caller a variable in `f` or `g` may or may-not be on the stack during `b`). - */ -private predicate mayEncloseOnStack(BlockExpr a, BlockExpr b) = - doublyBoundedFastTC(tcStep/2, isTcSource/1, isTcSink/1)(a, b) +module Restrict { + predicate sourceBlock(Source s, Variable target, BlockExpr be) { + sourceSinkPair(s, _) and + sourceValueScope(s, target, be.getEnclosingBlock*()) + } -/** - * Holds if the pair `(source, sink)`, that represents a flow from a - * pointer or reference to a dereference, has its dereference outside the - * lifetime of the target variable `target`. - */ -predicate dereferenceAfterLifetime(Source source, Sink sink, Variable target) { - AccessAfterLifetimeFlow::flow(source, sink) and - sourceValueScope(source, target, _) and - not exists(BlockExpr beSource, BlockExpr beSink | - sourceBlock(source, target, beSource) and - sinkBlock(sink, beSink) - | - beSource = beSink - or - mayEncloseOnStack(beSource, beSink) - ) + predicate sinkBlock(Sink s, BlockExpr be) { + sourceSinkPair(_, s) and + be = s.asExpr().getEnclosingBlock() + } + + private predicate tcStep(BlockExpr a, BlockExpr b) { + // propagate through function calls + exists(Call call | + a = call.getEnclosingBlock() and + call.getARuntimeTarget() = b.getEnclosingCallable() + ) + } + + private predicate isTcSource(BlockExpr be) { sourceBlock(_, _, be) } + + private predicate isTcSink(BlockExpr be) { sinkBlock(_, be) } + + /** + * Holds if block `a` contains block `b`, in the sense that a stack allocated variable in + * `a` may still be on the stack during execution of `b`. This is interprocedural, + * but is an overapproximation that doesn't accurately track call contexts + * (for example if `f` and `g` both call `b`, then depending on the + * caller a variable in `f` or `g` may or may-not be on the stack during `b`). + */ + private predicate mayEncloseOnStack(BlockExpr a, BlockExpr b) = + doublyBoundedFastTC(tcStep/2, isTcSource/1, isTcSink/1)(a, b) + + /** + * Holds if the pair `(source, sink)`, that represents a flow from a + * pointer or reference to a dereference, has its dereference outside the + * lifetime of the target variable `target`. + */ + predicate dereferenceAfterLifetime(Source source, Sink sink, Variable target) { + sourceSinkPair(source, sink) and + sourceValueScope(source, target, _) and + not exists(BlockExpr beSource, BlockExpr beSink | + sourceBlock(source, target, beSource) and + sinkBlock(sink, beSink) + | + beSource = beSink + or + mayEncloseOnStack(beSource, beSink) + ) + } } from @@ -111,6 +151,7 @@ where // flow from a pointer or reference to the dereference AccessAfterLifetimeFlow::flowPath(sourceNode, sinkNode) and // check that the dereference is outside the lifetime of the target - dereferenceAfterLifetime(sourceNode.getNode(), sinkNode.getNode(), target) + Restrict::dereferenceAfterLifetime(sourceNode.getNode(), + sinkNode.getNode(), target) select sinkNode.getNode(), sourceNode, sinkNode, "Access of a pointer to $@ after its lifetime has ended.", target, target.toString() 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 5d0b167074ae..c2b34b38d987 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,15 +11194,12 @@ 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 | @@ -11275,25 +11289,18 @@ 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} | () | @@ -14510,9 +14517,7 @@ 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 | @@ -14526,7 +14531,6 @@ 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 | @@ -14789,4 +14793,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..22b5cdb7d152 100644 --- a/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected +++ b/rust/ql/test/query-tests/security/CWE-825/AccessAfterLifetime.expected @@ -24,9 +24,6 @@ | lifetime.rs:808:23:808:25 | ptr | lifetime.rs:798:9:798:12 | &val | lifetime.rs:808:23:808:25 | ptr | Access of a pointer to $@ after its lifetime has ended. | lifetime.rs:796:6:796:8 | val | val | | main.rs:64:23:64:24 | p2 | main.rs:44:26:44:28 | &b2 | main.rs:64:23:64:24 | p2 | Access of a pointer to $@ after its lifetime has ended. | main.rs:43:13:43:14 | b2 | b2 | edges -| deallocation.rs:242:6:242:7 | p1 | deallocation.rs:245:14:245:15 | p1 | provenance | | -| deallocation.rs:242:6:242:7 | p1 | deallocation.rs:252:14:252:15 | p1 | provenance | | -| deallocation.rs:242:30:242:38 | &raw const my_buffer | deallocation.rs:242:6:242:7 | p1 | provenance | | | lifetime.rs:21:2:21:18 | return ... | lifetime.rs:54:11:54:30 | get_local_dangling(...) | provenance | | | lifetime.rs:21:9:21:18 | &my_local1 | lifetime.rs:21:2:21:18 | return ... | provenance | | | lifetime.rs:27:2:27:22 | return ... | lifetime.rs:55:11:55:34 | get_local_dangling_mut(...) | provenance | | @@ -55,43 +52,13 @@ edges | lifetime.rs:59:11:59:36 | get_local_field_dangling(...) | lifetime.rs:59:6:59:7 | p6 | provenance | | | lifetime.rs:63:3:63:4 | p7 | lifetime.rs:75:13:75:14 | p7 | provenance | | | lifetime.rs:63:8:63:27 | &raw const my_local7 | lifetime.rs:63:3:63:4 | p7 | provenance | | -| lifetime.rs:91:17:91:30 | ...: ... | lifetime.rs:101:14:101:15 | p1 | provenance | | -| lifetime.rs:91:33:91:44 | ...: ... | lifetime.rs:102:14:102:15 | p2 | provenance | | -| lifetime.rs:91:33:91:44 | ...: ... | lifetime.rs:110:5:110:6 | p2 | provenance | | -| lifetime.rs:94:2:94:3 | p3 | lifetime.rs:103:14:103:15 | p3 | provenance | | -| lifetime.rs:94:7:94:16 | &my_local1 | lifetime.rs:94:2:94:3 | p3 | provenance | | -| lifetime.rs:119:15:119:24 | &my_local3 | lifetime.rs:91:17:91:30 | ...: ... | provenance | | -| lifetime.rs:119:27:119:44 | &mut my_local_mut4 | lifetime.rs:91:33:91:44 | ...: ... | provenance | | -| lifetime.rs:161:17:161:31 | ...: ... | lifetime.rs:164:13:164:15 | ptr | provenance | | | lifetime.rs:169:17:169:31 | ...: ... | lifetime.rs:172:13:172:15 | ptr | provenance | | -| lifetime.rs:177:17:177:31 | ...: ... | lifetime.rs:180:13:180:15 | ptr | provenance | | -| lifetime.rs:187:6:187:8 | ptr | lifetime.rs:189:15:189:17 | ptr | provenance | | -| lifetime.rs:187:6:187:8 | ptr | lifetime.rs:190:15:190:17 | ptr | provenance | | | lifetime.rs:187:6:187:8 | ptr | lifetime.rs:192:2:192:11 | return ptr | provenance | | | lifetime.rs:187:12:187:21 | &my_local1 | lifetime.rs:187:6:187:8 | ptr | provenance | | -| lifetime.rs:189:15:189:17 | ptr | lifetime.rs:161:17:161:31 | ...: ... | provenance | | -| lifetime.rs:190:15:190:17 | ptr | lifetime.rs:177:17:177:31 | ...: ... | provenance | | | lifetime.rs:192:2:192:11 | return ptr | lifetime.rs:196:12:196:36 | access_and_get_dangling(...) | provenance | | | lifetime.rs:196:6:196:8 | ptr | lifetime.rs:200:15:200:17 | ptr | provenance | | -| lifetime.rs:196:6:196:8 | ptr | lifetime.rs:201:15:201:17 | ptr | provenance | | | lifetime.rs:196:12:196:36 | access_and_get_dangling(...) | lifetime.rs:196:6:196:8 | ptr | provenance | | | lifetime.rs:200:15:200:17 | ptr | lifetime.rs:169:17:169:31 | ...: ... | provenance | | -| lifetime.rs:201:15:201:17 | ptr | lifetime.rs:177:17:177:31 | ...: ... | provenance | | -| lifetime.rs:206:19:206:36 | ...: ... | lifetime.rs:216:16:216:21 | ptr_up | provenance | | -| lifetime.rs:208:6:208:13 | ptr_ours | lifetime.rs:211:33:211:40 | ptr_ours | provenance | | -| lifetime.rs:208:6:208:13 | ptr_ours | lifetime.rs:225:2:225:16 | return ptr_ours | provenance | | -| lifetime.rs:208:17:208:29 | &my_local_rec | lifetime.rs:208:6:208:13 | ptr_ours | provenance | | -| lifetime.rs:211:7:211:14 | ptr_down | lifetime.rs:218:18:218:25 | ptr_down | provenance | | -| lifetime.rs:211:18:211:52 | access_ptr_rec(...) | lifetime.rs:211:7:211:14 | ptr_down | provenance | | -| lifetime.rs:211:33:211:40 | ptr_ours | lifetime.rs:206:19:206:36 | ...: ... | provenance | | -| lifetime.rs:225:2:225:16 | return ptr_ours | lifetime.rs:211:18:211:52 | access_ptr_rec(...) | provenance | | -| lifetime.rs:230:6:230:14 | ptr_start | lifetime.rs:232:21:232:29 | ptr_start | provenance | | -| lifetime.rs:230:18:230:31 | &my_local_rec2 | lifetime.rs:230:6:230:14 | ptr_start | provenance | | -| lifetime.rs:232:21:232:29 | ptr_start | lifetime.rs:206:19:206:36 | ...: ... | provenance | | -| lifetime.rs:239:6:239:13 | mut prev | lifetime.rs:247:15:247:18 | prev | provenance | | -| lifetime.rs:239:6:239:13 | mut prev | lifetime.rs:255:14:255:17 | prev | provenance | | -| lifetime.rs:239:34:239:43 | &my_local1 | lifetime.rs:239:6:239:13 | mut prev | provenance | | -| lifetime.rs:251:3:251:6 | prev | lifetime.rs:247:15:247:18 | prev | provenance | | | lifetime.rs:251:3:251:6 | prev | lifetime.rs:255:14:255:17 | prev | provenance | | | lifetime.rs:251:10:251:19 | &my_local2 | lifetime.rs:251:3:251:6 | prev | provenance | | | lifetime.rs:270:47:275:1 | { ... } | lifetime.rs:303:11:303:31 | get_pointer_to_enum(...) | provenance | | @@ -103,7 +70,6 @@ edges | lifetime.rs:279:28:279:30 | &v2 | lifetime.rs:279:11:279:31 | ...::Pointer(...) [Pointer] | provenance | | | lifetime.rs:284:46:300:1 | { ... } | lifetime.rs:305:15:305:37 | get_pointer_from_enum(...) | provenance | | | lifetime.rs:288:2:288:7 | result | lifetime.rs:284:46:300:1 | { ... } | provenance | | -| lifetime.rs:288:2:288:7 | result | lifetime.rs:295:13:295:18 | result | provenance | | | lifetime.rs:289:25:289:26 | &x | lifetime.rs:288:2:288:7 | result | provenance | | | lifetime.rs:303:6:303:7 | e1 | lifetime.rs:310:31:310:32 | e1 | provenance | | | lifetime.rs:303:11:303:31 | get_pointer_to_enum(...) | lifetime.rs:303:6:303:7 | e1 | provenance | | @@ -113,20 +79,6 @@ edges | lifetime.rs:305:15:305:37 | get_pointer_from_enum(...) | lifetime.rs:305:6:305:11 | result | provenance | | | lifetime.rs:313:10:313:29 | ...::Pointer(...) [Pointer] | lifetime.rs:313:27:313:28 | p2 | provenance | | | lifetime.rs:313:27:313:28 | p2 | lifetime.rs:314:23:314:24 | p2 | provenance | | -| lifetime.rs:332:6:332:13 | mut ref1 | lifetime.rs:338:9:338:35 | ...::Pointer(...) | provenance | | -| lifetime.rs:332:17:332:22 | &enum1 | lifetime.rs:332:6:332:13 | mut ref1 | provenance | | -| lifetime.rs:336:3:336:6 | ref1 | lifetime.rs:338:9:338:35 | ...::Pointer(...) | provenance | | -| lifetime.rs:336:10:336:15 | &inner | lifetime.rs:336:3:336:6 | ref1 | provenance | | -| lifetime.rs:338:9:338:35 | ...::Pointer(...) | lifetime.rs:339:28:339:30 | ptr | provenance | | -| lifetime.rs:348:6:348:13 | mut ref1 | lifetime.rs:354:9:354:35 | ...::Pointer(...) | provenance | | -| lifetime.rs:348:17:348:22 | &enum1 | lifetime.rs:348:6:348:13 | mut ref1 | provenance | | -| lifetime.rs:352:3:352:6 | ref1 | lifetime.rs:354:9:354:35 | ...::Pointer(...) | provenance | | -| lifetime.rs:352:10:352:15 | &inner | lifetime.rs:352:3:352:6 | ref1 | provenance | | -| lifetime.rs:354:9:354:35 | ...::Pointer(...) | lifetime.rs:355:28:355:30 | ptr | provenance | | -| lifetime.rs:383:3:383:4 | p1 | lifetime.rs:388:15:388:16 | p1 | provenance | | -| lifetime.rs:383:3:383:4 | p1 | lifetime.rs:391:15:391:16 | p1 | provenance | | -| lifetime.rs:383:3:383:4 | p1 | lifetime.rs:399:6:399:7 | p1 | provenance | | -| lifetime.rs:383:3:383:4 | p1 | lifetime.rs:401:6:401:7 | p1 | provenance | | | lifetime.rs:383:3:383:4 | p1 | lifetime.rs:411:16:411:17 | p1 | provenance | | | lifetime.rs:383:3:383:4 | p1 | lifetime.rs:416:16:416:17 | p1 | provenance | | | lifetime.rs:383:3:383:4 | p1 | lifetime.rs:428:7:428:8 | p1 | provenance | | @@ -134,17 +86,13 @@ edges | lifetime.rs:383:31:383:37 | &raw mut my_pair | lifetime.rs:383:3:383:4 | p1 | provenance | | | lifetime.rs:442:6:442:7 | r1 | lifetime.rs:443:42:443:43 | r1 | provenance | | | lifetime.rs:442:17:442:23 | &my_val | lifetime.rs:442:6:442:7 | r1 | provenance | | -| lifetime.rs:443:6:443:7 | p1 | lifetime.rs:446:13:446:14 | p1 | provenance | | | lifetime.rs:443:6:443:7 | p1 | lifetime.rs:450:2:450:10 | return p1 | provenance | | | lifetime.rs:443:23:443:44 | ...::from_ref(...) | lifetime.rs:443:6:443:7 | p1 | provenance | | -| lifetime.rs:443:42:443:43 | r1 | lifetime.rs:443:23:443:44 | ...::from_ref(...) | provenance | MaD:5 | +| lifetime.rs:443:42:443:43 | r1 | lifetime.rs:443:23:443:44 | ...::from_ref(...) | provenance | MaD:3 | | lifetime.rs:450:2:450:10 | return p1 | lifetime.rs:454:11:454:29 | get_ptr_from_ref(...) | provenance | | | lifetime.rs:450:2:450:10 | return p1 | lifetime.rs:460:13:460:31 | get_ptr_from_ref(...) | provenance | | | lifetime.rs:454:6:454:7 | p1 | lifetime.rs:459:13:459:14 | p1 | provenance | | | lifetime.rs:454:11:454:29 | get_ptr_from_ref(...) | lifetime.rs:454:6:454:7 | p1 | provenance | | -| lifetime.rs:568:7:568:8 | p2 | lifetime.rs:572:14:572:15 | p2 | provenance | | -| lifetime.rs:568:24:568:33 | &my_local2 | lifetime.rs:568:7:568:8 | p2 | provenance | | -| lifetime.rs:655:4:655:7 | ref1 | lifetime.rs:659:15:659:18 | ref1 | provenance | | | lifetime.rs:655:4:655:7 | ref1 | lifetime.rs:667:14:667:17 | ref1 | provenance | | | lifetime.rs:655:11:655:25 | &raw const str2 | lifetime.rs:655:4:655:7 | ref1 | provenance | | | lifetime.rs:781:2:781:19 | return ... | lifetime.rs:785:11:785:41 | get_local_for_unsafe_function(...) | provenance | | @@ -155,31 +103,15 @@ 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 | | -| 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 | | -| main.rs:18:26:18:28 | &b1 | main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | provenance | MaD:3 | -| main.rs:18:26:18:28 | &b1 | main.rs:18:14:18:29 | ...::as_ptr(...) [&ref] | provenance | MaD:4 | -| main.rs:44:9:44:10 | p2 [&ref] | main.rs:51:23:51:24 | p2 | provenance | | | main.rs:44:9:44:10 | p2 [&ref] | main.rs:64:23:64:24 | p2 | provenance | | | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | main.rs:44:9:44:10 | p2 [&ref] | provenance | | -| main.rs:44:26:44:28 | &b2 | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | provenance | MaD:3 | -| main.rs:44:26:44:28 | &b2 | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | provenance | MaD:4 | -| main.rs:47:9:47:10 | p3 [&ref] | main.rs:52:23:52:24 | p3 | provenance | | -| main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | main.rs:47:9:47:10 | p3 [&ref] | provenance | | -| main.rs:47:30:47:36 | &mut b3 | main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | provenance | MaD:1 | -| main.rs:47:30:47:36 | &mut b3 | main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | provenance | MaD:2 | +| main.rs:44:26:44:28 | &b2 | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | provenance | MaD:1 | +| main.rs:44:26:44:28 | &b2 | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | provenance | MaD:2 | models -| 1 | Summary: ::as_mut_ptr; Argument[0].Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value | -| 2 | Summary: ::as_mut_ptr; Argument[0].Reference.Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value | -| 3 | Summary: ::as_ptr; Argument[0].Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value | -| 4 | Summary: ::as_ptr; Argument[0].Reference.Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value | -| 5 | Summary: core::ptr::from_ref; Argument[0]; ReturnValue; value | +| 1 | Summary: ::as_ptr; Argument[0].Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value | +| 2 | Summary: ::as_ptr; Argument[0].Reference.Field[alloc::boxed::Box(0)]; ReturnValue.Reference; value | +| 3 | Summary: core::ptr::from_ref; Argument[0]; ReturnValue; value | nodes -| deallocation.rs:242:6:242:7 | p1 | semmle.label | p1 | -| deallocation.rs:242:30:242:38 | &raw const my_buffer | semmle.label | &raw const my_buffer | -| deallocation.rs:245:14:245:15 | p1 | semmle.label | p1 | -| deallocation.rs:252:14:252:15 | p1 | semmle.label | p1 | | lifetime.rs:21:2:21:18 | return ... | semmle.label | return ... | | lifetime.rs:21:9:21:18 | &my_local1 | semmle.label | &my_local1 | | lifetime.rs:27:2:27:22 | return ... | semmle.label | return ... | @@ -215,46 +147,14 @@ nodes | lifetime.rs:75:13:75:14 | p7 | semmle.label | p7 | | lifetime.rs:76:4:76:5 | p2 | semmle.label | p2 | | lifetime.rs:77:4:77:5 | p4 | semmle.label | p4 | -| lifetime.rs:91:17:91:30 | ...: ... | semmle.label | ...: ... | -| lifetime.rs:91:33:91:44 | ...: ... | semmle.label | ...: ... | -| lifetime.rs:94:2:94:3 | p3 | semmle.label | p3 | -| lifetime.rs:94:7:94:16 | &my_local1 | semmle.label | &my_local1 | -| lifetime.rs:101:14:101:15 | p1 | semmle.label | p1 | -| lifetime.rs:102:14:102:15 | p2 | semmle.label | p2 | -| lifetime.rs:103:14:103:15 | p3 | semmle.label | p3 | -| lifetime.rs:110:5:110:6 | p2 | semmle.label | p2 | -| lifetime.rs:119:15:119:24 | &my_local3 | semmle.label | &my_local3 | -| lifetime.rs:119:27:119:44 | &mut my_local_mut4 | semmle.label | &mut my_local_mut4 | -| lifetime.rs:161:17:161:31 | ...: ... | semmle.label | ...: ... | -| lifetime.rs:164:13:164:15 | ptr | semmle.label | ptr | | lifetime.rs:169:17:169:31 | ...: ... | semmle.label | ...: ... | | lifetime.rs:172:13:172:15 | ptr | semmle.label | ptr | -| lifetime.rs:177:17:177:31 | ...: ... | semmle.label | ...: ... | -| lifetime.rs:180:13:180:15 | ptr | semmle.label | ptr | | lifetime.rs:187:6:187:8 | ptr | semmle.label | ptr | | lifetime.rs:187:12:187:21 | &my_local1 | semmle.label | &my_local1 | -| lifetime.rs:189:15:189:17 | ptr | semmle.label | ptr | -| lifetime.rs:190:15:190:17 | ptr | semmle.label | ptr | | lifetime.rs:192:2:192:11 | return ptr | semmle.label | return ptr | | lifetime.rs:196:6:196:8 | ptr | semmle.label | ptr | | lifetime.rs:196:12:196:36 | access_and_get_dangling(...) | semmle.label | access_and_get_dangling(...) | | lifetime.rs:200:15:200:17 | ptr | semmle.label | ptr | -| lifetime.rs:201:15:201:17 | ptr | semmle.label | ptr | -| lifetime.rs:206:19:206:36 | ...: ... | semmle.label | ...: ... | -| lifetime.rs:208:6:208:13 | ptr_ours | semmle.label | ptr_ours | -| lifetime.rs:208:17:208:29 | &my_local_rec | semmle.label | &my_local_rec | -| lifetime.rs:211:7:211:14 | ptr_down | semmle.label | ptr_down | -| lifetime.rs:211:18:211:52 | access_ptr_rec(...) | semmle.label | access_ptr_rec(...) | -| lifetime.rs:211:33:211:40 | ptr_ours | semmle.label | ptr_ours | -| lifetime.rs:216:16:216:21 | ptr_up | semmle.label | ptr_up | -| lifetime.rs:218:18:218:25 | ptr_down | semmle.label | ptr_down | -| lifetime.rs:225:2:225:16 | return ptr_ours | semmle.label | return ptr_ours | -| lifetime.rs:230:6:230:14 | ptr_start | semmle.label | ptr_start | -| lifetime.rs:230:18:230:31 | &my_local_rec2 | semmle.label | &my_local_rec2 | -| lifetime.rs:232:21:232:29 | ptr_start | semmle.label | ptr_start | -| lifetime.rs:239:6:239:13 | mut prev | semmle.label | mut prev | -| lifetime.rs:239:34:239:43 | &my_local1 | semmle.label | &my_local1 | -| lifetime.rs:247:15:247:18 | prev | semmle.label | prev | | lifetime.rs:251:3:251:6 | prev | semmle.label | prev | | lifetime.rs:251:10:251:19 | &my_local2 | semmle.label | &my_local2 | | lifetime.rs:255:14:255:17 | prev | semmle.label | prev | @@ -268,7 +168,6 @@ nodes | lifetime.rs:284:46:300:1 | { ... } | semmle.label | { ... } | | lifetime.rs:288:2:288:7 | result | semmle.label | result | | lifetime.rs:289:25:289:26 | &x | semmle.label | &x | -| lifetime.rs:295:13:295:18 | result | semmle.label | result | | lifetime.rs:303:6:303:7 | e1 | semmle.label | e1 | | lifetime.rs:303:11:303:31 | get_pointer_to_enum(...) | semmle.label | get_pointer_to_enum(...) | | lifetime.rs:304:6:304:7 | e2 [Pointer] | semmle.label | e2 [Pointer] | @@ -280,24 +179,8 @@ nodes | lifetime.rs:313:27:313:28 | p2 | semmle.label | p2 | | lifetime.rs:314:23:314:24 | p2 | semmle.label | p2 | | lifetime.rs:317:13:317:18 | result | semmle.label | result | -| lifetime.rs:332:6:332:13 | mut ref1 | semmle.label | mut ref1 | -| lifetime.rs:332:17:332:22 | &enum1 | semmle.label | &enum1 | -| lifetime.rs:336:3:336:6 | ref1 | semmle.label | ref1 | -| lifetime.rs:336:10:336:15 | &inner | semmle.label | &inner | -| lifetime.rs:338:9:338:35 | ...::Pointer(...) | semmle.label | ...::Pointer(...) | -| lifetime.rs:339:28:339:30 | ptr | semmle.label | ptr | -| lifetime.rs:348:6:348:13 | mut ref1 | semmle.label | mut ref1 | -| lifetime.rs:348:17:348:22 | &enum1 | semmle.label | &enum1 | -| lifetime.rs:352:3:352:6 | ref1 | semmle.label | ref1 | -| lifetime.rs:352:10:352:15 | &inner | semmle.label | &inner | -| lifetime.rs:354:9:354:35 | ...::Pointer(...) | semmle.label | ...::Pointer(...) | -| lifetime.rs:355:28:355:30 | ptr | semmle.label | ptr | | lifetime.rs:383:3:383:4 | p1 | semmle.label | p1 | | lifetime.rs:383:31:383:37 | &raw mut my_pair | semmle.label | &raw mut my_pair | -| lifetime.rs:388:15:388:16 | p1 | semmle.label | p1 | -| lifetime.rs:391:15:391:16 | p1 | semmle.label | p1 | -| lifetime.rs:399:6:399:7 | p1 | semmle.label | p1 | -| lifetime.rs:401:6:401:7 | p1 | semmle.label | p1 | | lifetime.rs:411:16:411:17 | p1 | semmle.label | p1 | | lifetime.rs:416:16:416:17 | p1 | semmle.label | p1 | | lifetime.rs:428:7:428:8 | p1 | semmle.label | p1 | @@ -307,18 +190,13 @@ nodes | lifetime.rs:443:6:443:7 | p1 | semmle.label | p1 | | lifetime.rs:443:23:443:44 | ...::from_ref(...) | semmle.label | ...::from_ref(...) | | lifetime.rs:443:42:443:43 | r1 | semmle.label | r1 | -| lifetime.rs:446:13:446:14 | p1 | semmle.label | p1 | | lifetime.rs:450:2:450:10 | return p1 | semmle.label | return p1 | | lifetime.rs:454:6:454:7 | p1 | semmle.label | p1 | | lifetime.rs:454:11:454:29 | get_ptr_from_ref(...) | semmle.label | get_ptr_from_ref(...) | | lifetime.rs:459:13:459:14 | p1 | semmle.label | p1 | | lifetime.rs:460:13:460:31 | get_ptr_from_ref(...) | semmle.label | get_ptr_from_ref(...) | -| lifetime.rs:568:7:568:8 | p2 | semmle.label | p2 | -| lifetime.rs:568:24:568:33 | &my_local2 | semmle.label | &my_local2 | -| lifetime.rs:572:14:572:15 | p2 | semmle.label | p2 | | lifetime.rs:655:4:655:7 | ref1 | semmle.label | ref1 | | lifetime.rs:655:11:655:25 | &raw const str2 | semmle.label | &raw const str2 | -| lifetime.rs:659:15:659:18 | ref1 | semmle.label | ref1 | | lifetime.rs:667:14:667:17 | ref1 | semmle.label | ref1 | | lifetime.rs:781:2:781:19 | return ... | semmle.label | return ... | | lifetime.rs:781:9:781:19 | &my_local10 | semmle.label | &my_local10 | @@ -330,18 +208,8 @@ 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 | -| 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 | -| main.rs:21:19:21:20 | p1 | semmle.label | p1 | -| main.rs:29:19:29:20 | p1 | semmle.label | p1 | | main.rs:44:9:44:10 | p2 [&ref] | semmle.label | p2 [&ref] | | main.rs:44:14:44:29 | ...::as_ptr(...) [&ref] | semmle.label | ...::as_ptr(...) [&ref] | | main.rs:44:26:44:28 | &b2 | semmle.label | &b2 | -| main.rs:47:9:47:10 | p3 [&ref] | semmle.label | p3 [&ref] | -| main.rs:47:14:47:37 | ...::as_mut_ptr(...) [&ref] | semmle.label | ...::as_mut_ptr(...) [&ref] | -| main.rs:47:30:47:36 | &mut b3 | semmle.label | &mut b3 | -| main.rs:51:23:51:24 | p2 | semmle.label | p2 | -| main.rs:52:23:52:24 | p3 | semmle.label | p3 | | main.rs:64:23:64:24 | p2 | semmle.label | p2 | subpaths