diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index 15c3d13f9d8..4ce224ec610 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -626,6 +626,23 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR } } +/** + * Holds if `t` is a valid complex [`self` root type][1]. + * + * [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty + */ +pragma[nomagic] +predicate validSelfType(Type t) { + t instanceof RefType + or + exists(Struct s | t = TStruct(s) | + s instanceof BoxStruct or + s instanceof RcStruct or + s instanceof ArcStruct or + s instanceof PinStruct + ) +} + /** * Holds if `root` is a valid complex [`self` root type][1], with type * parameter `tp`. @@ -634,18 +651,6 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR */ pragma[nomagic] predicate complexSelfRoot(Type root, TypeParameter tp) { - tp = root.(RefType).getPositionalTypeParameter(_) - or - exists(Struct s | - root = TStruct(s) and - tp = root.getPositionalTypeParameter(0) - | - s instanceof BoxStruct - or - s instanceof RcStruct - or - s instanceof ArcStruct - or - s instanceof PinStruct - ) + validSelfType(root) and + tp = root.getPositionalTypeParameter(0) } diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index de7b4447236..b5e0dbe7df4 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -817,7 +817,7 @@ private Type getCallExprTypeQualifier(CallExpr ce, TypePath path) { */ pragma[nomagic] private predicate assocFunctionInfo( - Function f, string name, int arity, ImplOrTraitItemNode i, FunctionTypePosition pos, + Function f, string name, int arity, ImplOrTraitItemNode i, FunctionPosition pos, AssocFunctionType t ) { f = i.getASuccessor(name) and @@ -835,7 +835,7 @@ private predicate assocFunctionInfo( */ pragma[nomagic] private predicate functionInfoBlanket( - Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionTypePosition pos, + Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionPosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam ) { exists(TypePath blanketSelfPath | @@ -859,7 +859,7 @@ private predicate functionInfoBlanket( bindingset[path, type] private predicate isComplexRootStripped(TypePath path, Type type) { path.isEmpty() and - not complexSelfRoot(type, _) + not validSelfType(type) or exists(TypeParameter tp | complexSelfRoot(_, tp) and @@ -918,7 +918,7 @@ private module MethodResolution { Method m, string name, int arity, ImplOrTraitItemNode i, AssocFunctionType selfType, TypePath strippedTypePath, Type strippedType ) { - exists(FunctionTypePosition pos | + exists(FunctionPosition pos | assocFunctionInfo(m, name, arity, i, pos, selfType) and strippedType = selfType.getTypeAt(strippedTypePath) and isComplexRootStripped(strippedTypePath, strippedType) and @@ -964,7 +964,7 @@ private module MethodResolution { Method m, string name, int arity, ImplItemNode impl, Trait trait, AssocFunctionType selfType, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(FunctionTypePosition pos | + exists(FunctionPosition pos | functionInfoBlanket(m, name, arity, impl, trait, pos, selfType, blanketPath, blanketTypeParam) and pos.isSelf() ) @@ -1089,7 +1089,7 @@ private module MethodResolution { abstract predicate supportsAutoDerefAndBorrow(); - AstNode getNodeAt(FunctionTypePosition apos) { + AstNode getNodeAt(FunctionPosition apos) { result = this.getArgument(apos.asArgumentPosition()) or result = this and apos.isReturn() @@ -1113,7 +1113,7 @@ private module MethodResolution { or this.supportsAutoDerefAndBorrow() and exists(TypePath path0, Type t0, string derefChain0 | - this.hasNoCompatibleTarget(derefChain0, _) and + this.hasNoCompatibleTargetBorrow(derefChain0) and t0 = this.getACandidateReceiverTypeAtNoBorrow(path0, derefChain0) | path0.isCons(TRefTypeParameter(), path) and @@ -1131,15 +1131,16 @@ private module MethodResolution { /** * Holds if the method inside `i` with matching name and arity can be ruled * out as a target of this call, because the candidate receiver type represented - * by `derefChainBorrow` is incompatible with the `self` parameter type. + * by `derefChain` and `borrow` is incompatible with the `self` parameter type. */ pragma[nomagic] - private predicate hasIncompatibleTarget(ImplOrTraitItemNode i, string derefChainBorrow) { - ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, - derefChainBorrow), i, _) + private predicate hasIncompatibleTarget(ImplOrTraitItemNode i, string derefChain, boolean borrow) { + ReceiverIsInstantiationOfSelfParam::argIsNotInstantiationOf(MkMethodCallCand(this, derefChain, + borrow), i, _) or TypeQualifierIsInstantiationOfImplSelf::isNotInstantiationOf(this, i, _) and - derefChainBorrow = ";" + derefChain = "" and + borrow = false } /** @@ -1147,20 +1148,22 @@ private module MethodResolution { * with trait bounds. */ pragma[nomagic] - Type getACandidateReceiverTypeAtSubstituteLookupTraits(TypePath path, string derefChainBorrow) { - result = substituteLookupTraits(this.getACandidateReceiverTypeAt(path, derefChainBorrow)) + Type getACandidateReceiverTypeAtSubstituteLookupTraits( + TypePath path, string derefChain, boolean borrow + ) { + result = substituteLookupTraits(this.getACandidateReceiverTypeAt(path, derefChain, borrow)) } pragma[nomagic] - private Type getComplexStrippedType(TypePath strippedTypePath, string derefChainBorrow) { + private Type getComplexStrippedType(TypePath strippedTypePath, string derefChain, boolean borrow) { result = - this.getACandidateReceiverTypeAtSubstituteLookupTraits(strippedTypePath, derefChainBorrow) and + this.getACandidateReceiverTypeAtSubstituteLookupTraits(strippedTypePath, derefChain, borrow) and isComplexRootStripped(strippedTypePath, result) } - bindingset[strippedTypePath, strippedType, derefChainBorrow] + bindingset[strippedTypePath, strippedType, derefChain, borrow] private predicate hasNoCompatibleTargetCheck( - TypePath strippedTypePath, Type strippedType, string derefChainBorrow + TypePath strippedTypePath, Type strippedType, string derefChain, boolean borrow ) { // todo: also check that all blanket implementation candidates are incompatible forall(ImplOrTraitItemNode i | @@ -1168,16 +1171,16 @@ private module MethodResolution { or this.(MethodCallCallExpr).hasTypeQualifiedCandidate(i) | - this.hasIncompatibleTarget(i, derefChainBorrow) + this.hasIncompatibleTarget(i, derefChain, borrow) ) } /** - * Holds if the candidate receiver type represented by - * `derefChainBorrow = derefChain;` does not have a matching method target. + * Holds if the candidate receiver type represented by `derefChain` does not + * have a matching method target. */ pragma[nomagic] - predicate hasNoCompatibleTargetNoBorrow(string derefChain, string derefChainBorrow) { + predicate hasNoCompatibleTargetNoBorrow(string derefChain) { ( this.supportsAutoDerefAndBorrow() or @@ -1186,25 +1189,22 @@ private module MethodResolution { derefChain = "" ) and exists(TypePath strippedTypePath, Type strippedType | - derefChainBorrow = derefChain + ";" and not derefChain.matches("%.ref") and // no need to try a borrow if the last thing we did was a deref - strippedType = this.getComplexStrippedType(strippedTypePath, derefChainBorrow) and - this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChainBorrow) + strippedType = this.getComplexStrippedType(strippedTypePath, derefChain, false) and + this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChain, false) ) } /** - * Holds if the candidate receiver type represented by - * `derefChainBorrow = derefChain;borrow` does not have a matching method - * target. + * Holds if the candidate receiver type represented by `derefChain`, followed + * by a borrow, does not have a matching method target. */ pragma[nomagic] - predicate hasNoCompatibleTarget(string derefChain, string derefChainBorrow) { + predicate hasNoCompatibleTargetBorrow(string derefChain) { exists(TypePath strippedTypePath, Type strippedType | - derefChainBorrow = derefChain + ";borrow" and - this.hasNoCompatibleTargetNoBorrow(derefChain, _) and - strippedType = this.getComplexStrippedType(strippedTypePath, derefChainBorrow) and - this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChainBorrow) + this.hasNoCompatibleTargetNoBorrow(derefChain) and + strippedType = this.getComplexStrippedType(strippedTypePath, derefChain, true) and + this.hasNoCompatibleTargetCheck(strippedTypePath, strippedType, derefChain, true) ) } @@ -1215,28 +1215,26 @@ private module MethodResolution { * as long as the method cannot be resolved in an earlier candidate type, and possibly * applying a borrow at the end. * - * The string `derefChainBorrow` encodes the sequence of dereferences and whether a - * borrow has been applied. + * The string `derefChain` encodes the sequence of dereferences, and `borrows` indicates + * whether a borrow has been applied. * * [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers */ pragma[nomagic] - Type getACandidateReceiverTypeAt(TypePath path, string derefChainBorrow) { - exists(string derefChain | - result = this.getACandidateReceiverTypeAtNoBorrow(path, derefChain) and - derefChainBorrow = derefChain + ";" + Type getACandidateReceiverTypeAt(TypePath path, string derefChain, boolean borrow) { + result = this.getACandidateReceiverTypeAtNoBorrow(path, derefChain) and + borrow = false + or + this.supportsAutoDerefAndBorrow() and + this.hasNoCompatibleTargetNoBorrow(derefChain) and + borrow = true and + ( + path.isEmpty() and + result = TRefType() or - this.supportsAutoDerefAndBorrow() and - this.hasNoCompatibleTargetNoBorrow(derefChain, _) and - derefChainBorrow = derefChain + ";borrow" and - ( - path.isEmpty() and - result = TRefType() - or - exists(TypePath suffix | - result = this.getACandidateReceiverTypeAtNoBorrow(suffix, derefChain) and - path = TypePath::cons(TRefTypeParameter(), suffix) - ) + exists(TypePath suffix | + result = this.getACandidateReceiverTypeAtNoBorrow(suffix, derefChain) and + path = TypePath::cons(TRefTypeParameter(), suffix) ) ) } @@ -1244,23 +1242,23 @@ private module MethodResolution { /** * Gets a method that this call resolves to after having applied a sequence of * dereferences and possibly a borrow on the receiver type, encoded in the string - * `derefChainBorrow`. + * `derefChain` and the Boolean `borrow`. */ pragma[nomagic] - Method resolveCallTarget(string derefChainBorrow) { + Method resolveCallTarget(string derefChain, boolean borrow) { exists(MethodCallCand mcc | - mcc = MkMethodCallCand(this, derefChainBorrow) and + mcc = MkMethodCallCand(this, derefChain, borrow) and result = mcc.resolveCallTarget() ) } predicate receiverHasImplicitDeref(AstNode receiver) { - exists(this.resolveCallTarget(".ref;")) and + exists(this.resolveCallTarget(".ref", false)) and receiver = this.getArgument(CallImpl::TSelfArgumentPosition()) } predicate receiverHasImplicitBorrow(AstNode receiver) { - exists(this.resolveCallTarget(";borrow")) and + exists(this.resolveCallTarget("", true)) and receiver = this.getArgument(CallImpl::TSelfArgumentPosition()) } } @@ -1382,28 +1380,31 @@ private module MethodResolution { } private newtype TMethodCallCand = - MkMethodCallCand(MethodCall mc, string derefChainBorrow) { - exists(mc.getACandidateReceiverTypeAt(_, derefChainBorrow)) + MkMethodCallCand(MethodCall mc, string derefChain, boolean borrow) { + exists(mc.getACandidateReceiverTypeAt(_, derefChain, borrow)) } /** A method call tagged with a candidate receiver type. */ private class MethodCallCand extends MkMethodCallCand { MethodCall mc_; - string derefChainBorrow; + string derefChain; + boolean borrow; - MethodCallCand() { this = MkMethodCallCand(mc_, derefChainBorrow) } + MethodCallCand() { this = MkMethodCallCand(mc_, derefChain, borrow) } MethodCall getMethodCall() { result = mc_ } Type getTypeAt(TypePath path) { - result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(path, derefChainBorrow) + result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(path, derefChain, borrow) } pragma[nomagic] predicate hasNoCompatibleTarget() { - mc_.hasNoCompatibleTarget(_, derefChainBorrow) + mc_.hasNoCompatibleTargetBorrow(derefChain) and + borrow = true or - mc_.hasNoCompatibleTargetNoBorrow(_, derefChainBorrow) + mc_.hasNoCompatibleTargetNoBorrow(derefChain) and + borrow = false } pragma[nomagic] @@ -1470,18 +1471,18 @@ private module MethodResolution { Method resolveCallTarget() { exists(ImplOrTraitItemNode i | result = this.resolveCallTargetCand(i) and - not exists(FunctionTypePosition pos | + not exists(FunctionPosition pos | FunctionOverloading::functionResolutionDependsOnArgument(i, _, pos, _, _) and - pos.isPositional() + pos.isPosition() ) ) or MethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, _, result) } - predicate hasNoBorrow() { not derefChainBorrow = any(string s) + ";borrow" } + predicate hasNoBorrow() { borrow = false } - string toString() { result = mc_.toString() + " [" + derefChainBorrow + "]" } + string toString() { result = mc_.toString() + " [" + derefChain + "; " + borrow + "]" } Location getLocation() { result = mc_.getLocation() } } @@ -1583,7 +1584,7 @@ private module MethodResolution { then // inherent methods take precedence over trait methods, so only allow // trait methods when there are no matching inherent methods - MkMethodCallCand(ce, _).(MethodCallCand).hasNoInherentTarget() + MkMethodCallCand(ce, _, _).(MethodCallCand).hasNoInherentTarget() else any() } @@ -1624,11 +1625,9 @@ private module MethodResolution { * types of parameters, when needed to disambiguate the call. */ private module MethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { - predicate toCheck( - ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, AssocFunctionType t - ) { + predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) { exists(TypePath path, Type t0 | - pos.isPositional() and + pos.isPosition() and FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, path, t0) and t.appliesTo(f, pos, i) and // for now, we do not handle ambiguous targets when one of the types it iself @@ -1639,7 +1638,7 @@ private module MethodResolution { } class Call extends MethodCallCand { - Type getArgType(FunctionTypePosition pos, TypePath path) { + Type getArgType(FunctionPosition pos, TypePath path) { result = inferType(mc_.getNodeAt(pos), path) } @@ -1658,7 +1657,7 @@ private module MethodResolution { * like `foo.bar(baz)`. */ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSig { - import FunctionTypePositionMatchingInput + import FunctionPositionMatchingInput final class Declaration extends Function { TypeParameter getTypeParameter(TypeParameterPosition ppos) { @@ -1681,7 +1680,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi Type getParameterType(DeclarationPosition dpos, TypePath path) { exists(Param p, int i | p = this.getParam(i) and - i = dpos.asPositional() and + i = dpos.asPosition() and result = p.getTypeRepr().(TypeMention).resolveTypeAt(path) ) or @@ -1720,6 +1719,13 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi class AccessEnvironment = string; + bindingset[derefChain, borrow] + private AccessEnvironment encodeDerefChainBorrow(string derefChain, boolean borrow) { + exists(string suffix | if borrow = true then suffix = "borrow" else suffix = "" | + result = derefChain + ";" + suffix + ) + } + final private class MethodCallFinal = MethodResolution::MethodCall; class Access extends MethodCallFinal { @@ -1739,8 +1745,8 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi } pragma[nomagic] - private Type getInferredSelfType(string derefChainBorrow, TypePath path) { - result = this.getACandidateReceiverTypeAt(path, derefChainBorrow) + private Type getInferredSelfType(string derefChain, boolean borrow, TypePath path) { + result = this.getACandidateReceiverTypeAt(path, derefChain, borrow) } pragma[nomagic] @@ -1764,17 +1770,22 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi ) } - pragma[nomagic] + bindingset[derefChainBorrow] Type getInferredType(string derefChainBorrow, AccessPosition apos, TypePath path) { - apos.isSelf() and - result = this.getInferredSelfType(derefChainBorrow, path) + exists(string derefChain, boolean borrow | + derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and + apos.isSelf() and + result = this.getInferredSelfType(derefChain, borrow, path) + ) or - result = this.getInferredNonSelfType(apos, path) and - exists(this.getTarget(derefChainBorrow)) + result = this.getInferredNonSelfType(apos, path) } Declaration getTarget(string derefChainBorrow) { - result = this.resolveCallTarget(derefChainBorrow) // mutual recursion; resolving method calls requires resolving types and vice versa + exists(string derefChain, boolean borrow | + derefChainBorrow = encodeDerefChainBorrow(derefChain, borrow) and + result = this.resolveCallTarget(derefChain, borrow) // mutual recursion; resolving method calls requires resolving types and vice versa + ) } } } @@ -1847,11 +1858,11 @@ private module NonMethodResolution { */ pragma[nomagic] private predicate traitFunctionDependsOnArgument( - TraitItemNode trait, NonMethodFunction traitFunction, FunctionTypePosition pos, Type type, + TraitItemNode trait, NonMethodFunction traitFunction, FunctionPosition pos, Type type, ImplItemNode impl, NonMethodFunction implFunction ) { exists(TypePath path | - assocFunctionTypeAtPath(implFunction, impl, pos, path, type) and + assocFunctionTypeAt(implFunction, impl, pos, path, type) and implFunction.implements(traitFunction) and FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos, path, _) | @@ -1859,7 +1870,7 @@ private module NonMethodResolution { or // We only check that the context of the call provides relevant type information // when no argument can - not exists(FunctionTypePosition pos0 | + not exists(FunctionPosition pos0 | FunctionOverloading::traitTypeParameterOccurrence(trait, traitFunction, _, pos0, _, _) or FunctionOverloading::functionResolutionDependsOnArgument(impl, implFunction, pos0, _, _) | @@ -1871,7 +1882,7 @@ private module NonMethodResolution { pragma[nomagic] private predicate functionInfoBlanketRelevantPos( NonMethodFunction f, string name, int arity, ImplItemNode impl, Trait trait, - FunctionTypePosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam + FunctionPosition pos, AssocFunctionType t, TypePath blanketPath, TypeParam blanketTypeParam ) { functionInfoBlanket(f, name, arity, impl, trait, pos, t, blanketPath, blanketTypeParam) and ( @@ -1879,7 +1890,7 @@ private module NonMethodResolution { or // We only check that the context of the call provides relevant type information // when no argument can - not exists(FunctionTypePosition pos0 | + not exists(FunctionPosition pos0 | functionInfoBlanket(f, name, arity, impl, trait, pos0, _, _, _) and not pos0.isReturn() ) @@ -1946,19 +1957,19 @@ private module NonMethodResolution { result = this.resolveCallTargetBlanketCand(i) } - AstNode getNodeAt(FunctionTypePosition pos) { - result = this.getArg(pos.asPositional()) + AstNode getNodeAt(FunctionPosition pos) { + result = this.getArg(pos.asPosition()) or result = this and pos.isReturn() } - Type getTypeAt(FunctionTypePosition pos, TypePath path) { + Type getTypeAt(FunctionPosition pos, TypePath path) { result = inferType(this.getNodeAt(pos), path) } pragma[nomagic] predicate resolveCallTargetBlanketCandidate( - ImplItemNode impl, FunctionTypePosition pos, TypePath blanketPath, TypeParam blanketTypeParam + ImplItemNode impl, FunctionPosition pos, TypePath blanketPath, TypeParam blanketTypeParam ) { exists(string name, int arity, Trait trait, AssocFunctionType t | this.hasNameAndArity(name, arity) and @@ -1999,14 +2010,14 @@ private module NonMethodResolution { } private newtype TCallAndBlanketPos = - MkCallAndBlanketPos(NonMethodCall fc, FunctionTypePosition pos) { + MkCallAndBlanketPos(NonMethodCall fc, FunctionPosition pos) { fc.resolveCallTargetBlanketCandidate(_, pos, _, _) } /** A call tagged with a position. */ private class CallAndBlanketPos extends MkCallAndBlanketPos { NonMethodCall fc; - FunctionTypePosition pos; + FunctionPosition pos; CallAndBlanketPos() { this = MkCallAndBlanketPos(fc, pos) } @@ -2024,7 +2035,7 @@ private module NonMethodResolution { predicate hasBlanketCandidate( CallAndBlanketPos fcp, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam ) { - exists(NonMethodCall fc, FunctionTypePosition pos | + exists(NonMethodCall fc, FunctionPosition pos | fcp = MkCallAndBlanketPos(fc, pos) and fc.resolveCallTargetBlanketCandidate(impl, pos, blanketPath, blanketTypeParam) ) @@ -2046,7 +2057,7 @@ private module NonMethodResolution { predicate potentialInstantiationOf( CallAndBlanketPos fcp, TypeAbstraction abs, AssocFunctionType constraint ) { - exists(FunctionTypePosition pos | + exists(FunctionPosition pos | ArgSatisfiesBlanketConstraint::satisfiesBlanketConstraint(fcp, abs) and fcp = MkCallAndBlanketPos(_, pos) and functionInfoBlanketRelevantPos(_, _, _, abs, _, pos, constraint, _, _) @@ -2062,9 +2073,7 @@ private module NonMethodResolution { ArgIsInstantiationOf; private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig { - predicate toCheck( - ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, AssocFunctionType t - ) { + predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) { t.appliesTo(f, pos, i) and ( exists(Type t0 | @@ -2087,7 +2096,7 @@ private module NonMethodResolution { } class Call extends NonMethodCall { - Type getArgType(FunctionTypePosition pos, TypePath path) { + Type getArgType(FunctionPosition pos, TypePath path) { result = inferType(this.getNodeAt(pos), path) } @@ -2117,7 +2126,7 @@ private module NonMethodResolution { * `foo::bar(baz)` where the target is not a method. */ private module NonMethodCallMatchingInput implements MatchingInputSig { - import FunctionTypePositionMatchingInput + import FunctionPositionMatchingInput abstract class Declaration extends AstNode { abstract TypeParameter getTypeParameter(TypeParameterPosition ppos); @@ -2154,7 +2163,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { override Type getParameterType(DeclarationPosition dpos, TypePath path) { exists(int pos | result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and - pos = dpos.asPositional() + pos = dpos.asPosition() ) } @@ -2177,7 +2186,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { override Type getParameterType(DeclarationPosition dpos, TypePath path) { exists(int pos | result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and - pos = dpos.asPositional() + pos = dpos.asPosition() ) } @@ -2221,7 +2230,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { result = resolveImplOrTraitType(i, path) ) or - exists(FunctionTypePosition fpos | + exists(FunctionPosition fpos | result = MethodCallMatchingInput::Declaration.super.getParameterType(fpos, path) and dpos = fpos.getFunctionCallAdjusted(this) ) @@ -2267,7 +2276,7 @@ private Type inferNonMethodCallType(AstNode n, TypePath path) { */ private module OperationMatchingInput implements MatchingInputSig { private import codeql.rust.elements.internal.OperationImpl as OperationImpl - import FunctionTypePositionMatchingInput + import FunctionPositionMatchingInput class Declaration extends MethodCallMatchingInput::Declaration { private Method getSelfOrImpl() { @@ -2284,7 +2293,7 @@ private module OperationMatchingInput implements MatchingInputSig { exists(int borrows | OperationImpl::isOverloaded(_, _, path, method, borrows) | pos.isSelf() and borrows >= 1 or - pos.asPositional() = 0 and + pos.asPosition() = 0 and borrows >= 2 ) ) @@ -2326,7 +2335,7 @@ private module OperationMatchingInput implements MatchingInputSig { } Declaration getTarget() { - result = this.resolveCallTarget(_) // mutual recursion + result = this.resolveCallTarget(_, _) // mutual recursion } } } @@ -2760,7 +2769,7 @@ private Type inferStructPatType(AstNode n, TypePath path) { * like `let Some(x) = ...`. */ private module TupleStructPatMatchingInput implements MatchingInputSig { - import FunctionTypePositionMatchingInput + import FunctionPositionMatchingInput class Declaration = NonMethodCallMatchingInput::TupleDeclaration; @@ -2768,7 +2777,7 @@ private module TupleStructPatMatchingInput implements MatchingInputSig { Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } AstNode getNodeAt(AccessPosition apos) { - result = this.getField(apos.asPositional()) + result = this.getField(apos.asPosition()) or result = this and apos.isSelf() @@ -2987,7 +2996,7 @@ private module Cached { /** Gets an item (function or tuple struct/variant) that `call` resolves to, if any. */ cached Addressable resolveCallTarget(Call call) { - result = call.(MethodResolution::MethodCall).resolveCallTarget(_) + result = call.(MethodResolution::MethodCall).resolveCallTarget(_, _) or result = call.(NonMethodResolution::NonMethodCall).resolveCallTarget() } diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index 0b669ad4015..d015a0bf656 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -9,6 +9,7 @@ private import TypeInference /** An AST node that may mention a type. */ abstract class TypeMention extends AstNode { /** Gets the type at `path` that this mention resolves to, if any. */ + pragma[nomagic] abstract Type resolveTypeAt(TypePath path); /** Gets the type that this node resolves to, if any. */ @@ -93,7 +94,6 @@ class AliasPathTypeMention extends PathTypeMention { * Holds if this path resolved to a type alias with a rhs. that has the * resulting type at `typePath`. */ - pragma[nomagic] override Type resolveTypeAt(TypePath typePath) { result = rhs.resolveTypeAt(typePath) and not result = pathGetTypeParameter(resolved, _) @@ -245,7 +245,7 @@ class NonAliasPathTypeMention extends PathTypeMention { } pragma[nomagic] -private Type resolveImplSelfType(Impl i, TypePath path) { +private Type resolveImplSelfTypeAt(Impl i, TypePath path) { result = i.getSelfTy().(TypeMention).resolveTypeAt(path) } @@ -254,7 +254,7 @@ class ImplSelfMention extends PathTypeMention { ImplSelfMention() { this = impl.getASelfPath() } - override Type resolveTypeAt(TypePath typePath) { result = resolveImplSelfType(impl, typePath) } + override Type resolveTypeAt(TypePath typePath) { result = resolveImplSelfTypeAt(impl, typePath) } } class PathTypeReprMention extends TypeMention, PathTypeRepr { @@ -334,17 +334,14 @@ class SelfTypeParameterMention extends TypeMention instanceof Name { */ pragma[nomagic] Type resolveImplOrTraitType(ImplOrTraitItemNode i, TypePath path) { - result = resolveImplSelfType(i, path) + result = resolveImplSelfTypeAt(i, path) or result = TSelfTypeParameter(i) and path.isEmpty() } pragma[nomagic] private ImplOrTraitItemNode getSelfParamEnclosingImplOrTrait(SelfParam self) { - exists(Function f | - f = result.getAnAssocItem() and - self = f.getSelfParam() - ) + self = result.getAnAssocItem().(Function).getSelfParam() } /** @@ -360,34 +357,30 @@ class ShorthandSelfParameterMention extends TypeMention instanceof SelfParam { not super.hasTypeRepr() and encl = getSelfParamEnclosingImplOrTrait(this) and ( - encl instanceof Trait + not encl instanceof Impl or - // avoid generating a type mention if the type being implemented cannot be resolved + // avoid generating a type mention if the type being implemented does not have a type mention encl.(Impl).getSelfTy() instanceof TypeMention ) } - pragma[nomagic] private Type resolveSelfType(TypePath path) { result = resolveImplOrTraitType(encl, path) } - pragma[nomagic] - private Type inferImplicitSelfType(TypePath path) { + override Type resolveTypeAt(TypePath typePath) { if super.isRef() then // `fn f(&self, ...)` - path.isEmpty() and + typePath.isEmpty() and result = TRefType() or exists(TypePath suffix | result = this.resolveSelfType(suffix) and - path = TypePath::cons(TRefTypeParameter(), suffix) + typePath = TypePath::cons(TRefTypeParameter(), suffix) ) else // `fn f(self, ...)` - result = this.resolveSelfType(path) + result = this.resolveSelfType(typePath) } - - override Type resolveTypeAt(TypePath typePath) { result = this.inferImplicitSelfType(typePath) } } pragma[nomagic] diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll index 416f2a1b2d0..6548ed9e065 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll @@ -1,8 +1,8 @@ /** * Provides logic for identifying functions that are overloaded based on their - * argument types. While Rust does not allow for overloading inside a single + * non-`self` parameter types. While Rust does not allow for overloading inside a single * `impl` block, it is still possible for a trait to have multiple implementations - * that differ only in the types of non-`self` arguments. + * that differ only in the types of non-`self` parameters. */ private import rust @@ -75,11 +75,11 @@ private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, i bindingset[trait] pragma[inline_late] predicate traitTypeParameterOccurrence( - TraitItemNode trait, Function f, string functionName, FunctionTypePosition pos, TypePath path, + TraitItemNode trait, Function f, string functionName, FunctionPosition pos, TypePath path, TypeParameter tp ) { f = trait.getASuccessor(functionName) and - assocFunctionTypeAtPath(f, trait, pos, path, tp) and + assocFunctionTypeAt(f, trait, pos, path, tp) and tp = trait.(TraitTypeAbstraction).getATypeParameter() } @@ -90,7 +90,7 @@ predicate traitTypeParameterOccurrence( */ pragma[nomagic] predicate functionResolutionDependsOnArgument( - ImplItemNode impl, Function f, FunctionTypePosition pos, TypePath path, Type type + ImplItemNode impl, Function f, FunctionPosition pos, TypePath path, Type type ) { /* * As seen in the example below, when an implementation has a sibling for a @@ -120,7 +120,7 @@ predicate functionResolutionDependsOnArgument( exists(TraitItemNode trait, string functionName | implHasSibling(impl, trait) and traitTypeParameterOccurrence(trait, _, functionName, pos, path, _) and - assocFunctionTypeAtPath(f, impl, pos, path, type) and + assocFunctionTypeAt(f, impl, pos, path, type) and f = impl.getASuccessor(functionName) and not pos.isReturn() ) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll index b203cafbd94..ceac4cbc590 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll @@ -5,37 +5,37 @@ private import codeql.rust.internal.Type private import codeql.rust.internal.TypeMention private import codeql.rust.elements.Call -private newtype TFunctionTypePosition = - TArgumentFunctionTypePosition(ArgumentPosition pos) or - TReturnFunctionTypePosition() +private newtype TFunctionPosition = + TArgumentFunctionPosition(ArgumentPosition pos) or + TReturnFunctionPosition() /** * A position of a type related to a function. * * Either `self`, `return`, or a positional parameter index. */ -class FunctionTypePosition extends TFunctionTypePosition { +class FunctionPosition extends TFunctionPosition { predicate isSelf() { this.asArgumentPosition().isSelf() } - int asPositional() { result = this.asArgumentPosition().asPosition() } + int asPosition() { result = this.asArgumentPosition().asPosition() } - predicate isPositional() { exists(this.asPositional()) } + predicate isPosition() { exists(this.asPosition()) } - ArgumentPosition asArgumentPosition() { this = TArgumentFunctionTypePosition(result) } + ArgumentPosition asArgumentPosition() { this = TArgumentFunctionPosition(result) } - predicate isReturn() { this = TReturnFunctionTypePosition() } + predicate isReturn() { this = TReturnFunctionPosition() } /** Gets the corresponding position when `f` is invoked via a function call. */ bindingset[f] - FunctionTypePosition getFunctionCallAdjusted(Function f) { + FunctionPosition getFunctionCallAdjusted(Function f) { this.isReturn() and result = this or if f.hasSelfParam() then - this.isSelf() and result.asPositional() = 0 + this.isSelf() and result.asPosition() = 0 or - result.asPositional() = this.asPositional() + 1 + result.asPosition() = this.asPosition() + 1 else result = this } @@ -43,7 +43,7 @@ class FunctionTypePosition extends TFunctionTypePosition { this.isSelf() and result = getSelfParamTypeMention(f.getSelfParam()) or - result = f.getParam(this.asPositional()).getTypeRepr() + result = f.getParam(this.asPosition()).getTypeRepr() or this.isReturn() and result = f.getRetType().getTypeRepr() @@ -59,10 +59,10 @@ class FunctionTypePosition extends TFunctionTypePosition { /** * A helper module for implementing `Matching(WithEnvironment)InputSig` with - * `DeclarationPosition = AccessPosition = FunctionTypePosition`. + * `DeclarationPosition = AccessPosition = FunctionPosition`. */ -module FunctionTypePositionMatchingInput { - class DeclarationPosition = FunctionTypePosition; +module FunctionPositionMatchingInput { + class DeclarationPosition = FunctionPosition; class AccessPosition = DeclarationPosition; @@ -72,12 +72,12 @@ module FunctionTypePositionMatchingInput { } private newtype TAssocFunctionType = - MkAssocFunctionType(Function f, FunctionTypePosition pos, ImplOrTraitItemNode i) { + MkAssocFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) { f = i.getAnAssocItem() and exists(pos.getTypeMention(f)) } or MkInheritedAssocFunctionType( - Function f, FunctionTypePosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, + Function f, FunctionPosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, ImplOrTraitItemNode i ) { exists(AssocFunctionType inherited | @@ -127,12 +127,12 @@ private newtype TAssocFunctionType = * `self5` | `impl T2 for X` | `X` */ class AssocFunctionType extends TAssocFunctionType { - private predicate isFunctionType(Function f, FunctionTypePosition pos, ImplOrTraitItemNode i) { + private predicate isFunctionType(Function f, FunctionPosition pos, ImplOrTraitItemNode i) { this = MkAssocFunctionType(f, pos, i) } private predicate isInheritedFunctionType( - Function f, FunctionTypePosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, + Function f, FunctionPosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, ImplOrTraitItemNode i ) { this = MkInheritedAssocFunctionType(f, pos, parentMention, parent, i) @@ -142,7 +142,7 @@ class AssocFunctionType extends TAssocFunctionType { * Holds if this function type applies to the function `f` at position `pos`, * when viewed as a member of the `impl` or trait item `i`. */ - predicate appliesTo(Function f, FunctionTypePosition pos, ImplOrTraitItemNode i) { + predicate appliesTo(Function f, FunctionPosition pos, ImplOrTraitItemNode i) { this.isFunctionType(f, pos, i) or this.isInheritedFunctionType(f, pos, _, _, i) @@ -151,13 +151,13 @@ class AssocFunctionType extends TAssocFunctionType { /** Gets the type at the given path. */ pragma[nomagic] Type getDeclaredTypeAt(TypePath path) { - exists(Function f, FunctionTypePosition pos | + exists(Function f, FunctionPosition pos | this.isFunctionType(f, pos, _) and result = pos.getTypeMention(f).resolveTypeAt(path) ) or exists( - Function f, FunctionTypePosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, + Function f, FunctionPosition pos, TypeMention parentMention, ImplOrTraitItemNode parent, AssocFunctionType parentType, ImplOrTraitItemNode i | this.isInheritedFunctionType(f, pos, parentMention, parent, i) and @@ -171,7 +171,7 @@ class AssocFunctionType extends TAssocFunctionType { result = resolveImplOrTraitType(i, suffix) or exists(TypeParameter tp | - parentType.hasTypeParameterAt(prefix, tp) and + tp = parentType.getTypeParameterAt(prefix) and result = parentMention.resolveTypeAt(TypePath::singleton(tp).appendInverse(suffix)) ) ) @@ -179,19 +179,17 @@ class AssocFunctionType extends TAssocFunctionType { } pragma[nomagic] - private predicate hasTypeParameterAt(TypePath path, TypeParameter tp) { - this.getDeclaredTypeAt(path) = tp - } + private TypeParameter getTypeParameterAt(TypePath path) { result = this.getDeclaredTypeAt(path) } pragma[nomagic] private predicate hasSelfTypeParameterAt(TypePath path) { - this.hasTypeParameterAt(path, TSelfTypeParameter(_)) + this.getTypeParameterAt(path) = TSelfTypeParameter(_) } /** * Gets the type at the given path. * - * For functions belonging to a `trait`, we use the type of the trait itself instead + * For functions belonging to a trait, we use the type of the trait itself instead * of the implicit `Self` type parameter, as otherwise any type will match. * * Calls should use `substituteLookupTraits` to map receiver types to the relevant @@ -206,26 +204,16 @@ class AssocFunctionType extends TAssocFunctionType { ) } - private AstNode getReportingNode() { - exists(Function f, FunctionTypePosition pos | this.appliesTo(f, pos, _) | - pos.isSelf() and - exists(SelfParam self | self = f.getSelfParam() | - result = self.getTypeRepr() - or - not self.hasTypeRepr() and - result = self - ) - or - result = f.getParam(pos.asPositional()).getTypeRepr() - or - pos.isReturn() and - result = f.getRetType().getTypeRepr() + private TypeMention getTypeMention() { + exists(Function f, FunctionPosition pos | + this.appliesTo(f, pos, _) and + result = pos.getTypeMention(f) ) } - string toString() { result = this.getReportingNode().toString() } + string toString() { result = this.getTypeMention().toString() } - Location getLocation() { result = this.getReportingNode().getLocation() } + Location getLocation() { result = this.getTypeMention().getLocation() } } /** @@ -233,8 +221,8 @@ class AssocFunctionType extends TAssocFunctionType { * `i` is `type`. */ pragma[nomagic] -predicate assocFunctionTypeAtPath( - Function f, ImplOrTraitItemNode i, FunctionTypePosition pos, TypePath path, Type type +predicate assocFunctionTypeAt( + Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path, Type type ) { exists(AssocFunctionType aft | aft.appliesTo(f, pos, i) and @@ -313,7 +301,7 @@ signature module ArgsAreInstantiationsOfInputSig { * Holds if types need to be matched against the type `t` at position `pos` of * `f` inside `i`. */ - predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, AssocFunctionType t); + predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t); /** A call whose argument types are to be checked. */ class Call { @@ -321,7 +309,7 @@ signature module ArgsAreInstantiationsOfInputSig { Location getLocation(); - Type getArgType(FunctionTypePosition pos, TypePath path); + Type getArgType(FunctionPosition pos, TypePath path); predicate hasTargetCand(ImplOrTraitItemNode i, Function f); } @@ -334,15 +322,13 @@ signature module ArgsAreInstantiationsOfInputSig { */ module ArgsAreInstantiationsOf { pragma[nomagic] - private predicate toCheckRanked( - ImplOrTraitItemNode i, Function f, FunctionTypePosition pos, int rnk - ) { + private predicate toCheckRanked(ImplOrTraitItemNode i, Function f, FunctionPosition pos, int rnk) { Input::toCheck(i, f, pos, _) and pos = - rank[rnk + 1](FunctionTypePosition pos0, int j | + rank[rnk + 1](FunctionPosition pos0, int j | Input::toCheck(i, f, pos0, _) and ( - j = pos0.asPositional() + j = pos0.asPosition() or pos0.isSelf() and j = -1 or @@ -354,18 +340,18 @@ module ArgsAreInstantiationsOf { } private newtype TCallAndPos = - MkCallAndPos(Input::Call call, FunctionTypePosition pos) { exists(call.getArgType(pos, _)) } + MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) } /** A call tagged with a position. */ private class CallAndPos extends MkCallAndPos { Input::Call call; - FunctionTypePosition pos; + FunctionPosition pos; CallAndPos() { this = MkCallAndPos(call, pos) } Input::Call getCall() { result = call } - FunctionTypePosition getPos() { result = pos } + FunctionPosition getPos() { result = pos } Location getLocation() { result = call.getLocation() } @@ -379,7 +365,7 @@ module ArgsAreInstantiationsOf { { pragma[nomagic] private predicate potentialInstantiationOf0( - CallAndPos cp, Input::Call call, FunctionTypePosition pos, int rnk, Function f, + CallAndPos cp, Input::Call call, FunctionPosition pos, int rnk, Function f, TypeAbstraction abs, AssocFunctionType constraint ) { cp = MkCallAndPos(call, pos) and @@ -413,7 +399,7 @@ module ArgsAreInstantiationsOf { private predicate argsAreInstantiationsOfFromIndex( Input::Call call, ImplOrTraitItemNode i, Function f, int rnk ) { - exists(FunctionTypePosition pos | + exists(FunctionPosition pos | ArgIsInstantiationOfFromIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and call.hasTargetCand(i, f) and toCheckRanked(i, f, pos, rnk) diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index 855912de1f5..ff9ccf3c192 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -1118,6 +1118,7 @@ module Make1 Input1> { * For example, if this access is the method call `M(42)`, then the inferred * type at argument position `0` is `int`. */ + bindingset[e] Type getInferredType(AccessEnvironment e, AccessPosition apos, TypePath path); /** Gets the declaration that this access targets in environment `e`. */