Skip to content

Commit 36f685c

Browse files
committed
member access
1 parent 04100d4 commit 36f685c

2 files changed

Lines changed: 217 additions & 166 deletions

File tree

rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll

Lines changed: 67 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,72 @@ private module Input3 implements InputSig3 {
461461
)
462462
}
463463

464+
abstract class Member extends AstNode {
465+
abstract TypeRepr getTypeRepr();
466+
467+
Type getDeclaringType(TypePath path) {
468+
// no case for variants as those can only be destructured using pattern matching
469+
exists(Struct s | this = [s.getStructField(_).(AstNode), s.getTupleField(_)] |
470+
result = TDataType(s) and
471+
path.isEmpty()
472+
or
473+
result = TTypeParamTypeParameter(s.getGenericParamList().getATypeParam()) and
474+
path = TypePath::singleton(result)
475+
)
476+
}
477+
478+
Type getDeclaredType(TypePath path) {
479+
result = this.getTypeRepr().(TypeMention).getTypeAt(path)
480+
}
481+
}
482+
483+
private class StructFieldDecl extends Member instanceof StructField {
484+
override TypeRepr getTypeRepr() { result = StructField.super.getTypeRepr() }
485+
}
486+
487+
private class TupleFieldDecl extends Member instanceof TupleField {
488+
override TypeRepr getTypeRepr() { result = TupleField.super.getTypeRepr() }
489+
}
490+
491+
class MemberAccess extends FieldExpr {
492+
AstNode getReceiver() { result = this.getContainer() }
493+
494+
Member getMember() {
495+
// mutual recursion; resolving fields requires resolving types and vice versa
496+
result =
497+
[
498+
resolveStructFieldExpr(this, _).(AstNode),
499+
resolveTupleFieldExpr(this, _)
500+
]
501+
}
502+
}
503+
504+
Type inferMemberAccessReceiverType(MemberAccess ma, TypePath path) {
505+
exists(TypePath path0 | result = inferType(ma.getReceiver(), path0) |
506+
// adjust for implicit deref
507+
path0.isCons(getRefTypeParameter(_), path)
508+
or
509+
not path0.isCons(getRefTypeParameter(_), _) and
510+
not (result instanceof RefType and path0.isEmpty()) and
511+
path = path0
512+
)
513+
}
514+
515+
Type inferMemberAccessReceiverTypeContextual(AstNode n, TypePath path) {
516+
exists(TypePath path0, Type receiverType |
517+
result = M3::inferMemberAccessReceiverTypeContextualDefault(_, n, path0) and
518+
receiverType = inferType(n)
519+
|
520+
if receiverType instanceof RefType
521+
then
522+
// adjust for implicit deref
523+
not path0.isCons(getRefTypeParameter(_), _) and
524+
not (path0.isEmpty() and result instanceof RefType) and
525+
path = TypePath::cons(getRefTypeParameter(_), path0)
526+
else path = path0
527+
)
528+
}
529+
464530
predicate inferStepCertain(AstNode n1, TypePath path1, AstNode n2, TypePath path2) {
465531
n1 =
466532
any(IdentPat ip |
@@ -641,8 +707,6 @@ private module Input3 implements InputSig3 {
641707
result = inferOperationType(n, pos, path)
642708
)
643709
or
644-
result = inferFieldExprType(n, path, false)
645-
or
646710
result = inferTryExprType(n, path)
647711
or
648712
result = inferLiteralType(n, path, false)
@@ -668,8 +732,6 @@ private module Input3 implements InputSig3 {
668732
or
669733
result = inferOperationType(n, pos, path)
670734
)
671-
or
672-
result = inferFieldExprType(n, path, true)
673735
}
674736
}
675737

@@ -2848,7 +2910,7 @@ private Type inferCallArgumentTypeContextual(
28482910
) {
28492911
exists(string derefChainBorrow |
28502912
FunctionCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow) and
2851-
result = M3::inferCallArgumentTypeContextual(call, derefChainBorrow, pos, n, path)
2913+
result = M3::inferCallArgumentTypeContextualDefault(call, derefChainBorrow, pos, n, path)
28522914
)
28532915
}
28542916

@@ -3218,161 +3280,6 @@ TupleField resolveTupleFieldExpr(FieldExpr fe, DerefChain derefChain) {
32183280
)
32193281
}
32203282

3221-
/**
3222-
* A matching configuration for resolving types of field expressions like `x.field`.
3223-
*/
3224-
private module FieldExprMatchingInput implements MatchingInputSig {
3225-
private newtype TDeclarationPosition =
3226-
TSelfDeclarationPosition() or
3227-
TFieldPos()
3228-
3229-
class DeclarationPosition extends TDeclarationPosition {
3230-
predicate isSelf() { this = TSelfDeclarationPosition() }
3231-
3232-
predicate isField() { this = TFieldPos() }
3233-
3234-
string toString() {
3235-
this.isSelf() and
3236-
result = "self"
3237-
or
3238-
this.isField() and
3239-
result = "(field)"
3240-
}
3241-
}
3242-
3243-
private newtype TDeclaration =
3244-
TStructFieldDecl(StructField sf) or
3245-
TTupleFieldDecl(TupleField tf)
3246-
3247-
abstract class Declaration extends TDeclaration {
3248-
TypeParameter getTypeParameter(TypeParameterPosition ppos) { none() }
3249-
3250-
abstract Type getDeclaredType(DeclarationPosition dpos, TypePath path);
3251-
3252-
abstract string toString();
3253-
3254-
abstract Location getLocation();
3255-
}
3256-
3257-
abstract private class StructOrTupleFieldDecl extends Declaration {
3258-
abstract AstNode getAstNode();
3259-
3260-
abstract TypeRepr getTypeRepr();
3261-
3262-
override Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
3263-
dpos.isSelf() and
3264-
// no case for variants as those can only be destructured using pattern matching
3265-
exists(Struct s | this.getAstNode() = [s.getStructField(_).(AstNode), s.getTupleField(_)] |
3266-
result = TDataType(s) and
3267-
path.isEmpty()
3268-
or
3269-
result = TTypeParamTypeParameter(s.getGenericParamList().getATypeParam()) and
3270-
path = TypePath::singleton(result)
3271-
)
3272-
or
3273-
dpos.isField() and
3274-
result = this.getTypeRepr().(TypeMention).getTypeAt(path)
3275-
}
3276-
3277-
override string toString() { result = this.getAstNode().toString() }
3278-
3279-
override Location getLocation() { result = this.getAstNode().getLocation() }
3280-
}
3281-
3282-
private class StructFieldDecl extends StructOrTupleFieldDecl, TStructFieldDecl {
3283-
private StructField sf;
3284-
3285-
StructFieldDecl() { this = TStructFieldDecl(sf) }
3286-
3287-
override AstNode getAstNode() { result = sf }
3288-
3289-
override TypeRepr getTypeRepr() { result = sf.getTypeRepr() }
3290-
}
3291-
3292-
private class TupleFieldDecl extends StructOrTupleFieldDecl, TTupleFieldDecl {
3293-
private TupleField tf;
3294-
3295-
TupleFieldDecl() { this = TTupleFieldDecl(tf) }
3296-
3297-
override AstNode getAstNode() { result = tf }
3298-
3299-
override TypeRepr getTypeRepr() { result = tf.getTypeRepr() }
3300-
}
3301-
3302-
class AccessPosition = DeclarationPosition;
3303-
3304-
class Access extends FieldExpr {
3305-
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
3306-
3307-
AstNode getNodeAt(AccessPosition apos) {
3308-
result = this.getContainer() and
3309-
apos.isSelf()
3310-
or
3311-
result = this and
3312-
apos.isField()
3313-
}
3314-
3315-
Type getInferredType(AccessPosition apos, TypePath path) {
3316-
exists(TypePath path0 | result = inferType(this.getNodeAt(apos), path0) |
3317-
if apos.isSelf()
3318-
then
3319-
// adjust for implicit deref
3320-
path0.isCons(getRefTypeParameter(_), path)
3321-
or
3322-
not path0.isCons(getRefTypeParameter(_), _) and
3323-
not (result instanceof RefType and path0.isEmpty()) and
3324-
path = path0
3325-
else path = path0
3326-
)
3327-
}
3328-
3329-
Declaration getTarget() {
3330-
// mutual recursion; resolving fields requires resolving types and vice versa
3331-
result =
3332-
[
3333-
TStructFieldDecl(resolveStructFieldExpr(this, _)).(TDeclaration),
3334-
TTupleFieldDecl(resolveTupleFieldExpr(this, _))
3335-
]
3336-
}
3337-
}
3338-
3339-
predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) {
3340-
apos = dpos
3341-
}
3342-
}
3343-
3344-
private module FieldExprMatching = Matching<FieldExprMatchingInput>;
3345-
3346-
/**
3347-
* Gets the type of `n` at `path`, where `n` is either a field expression or
3348-
* the receiver of field expression call.
3349-
*/
3350-
pragma[nomagic]
3351-
private Type inferFieldExprType(AstNode n, TypePath path, boolean topDown) {
3352-
exists(
3353-
FieldExprMatchingInput::Access a, FieldExprMatchingInput::AccessPosition apos, TypePath path0
3354-
|
3355-
n = a.getNodeAt(apos) and
3356-
result = FieldExprMatching::inferAccessType(a, apos, path0)
3357-
|
3358-
if apos.isSelf()
3359-
then
3360-
topDown = true and
3361-
exists(Type receiverType | receiverType = inferType(n) |
3362-
if receiverType instanceof RefType
3363-
then
3364-
// adjust for implicit deref
3365-
not path0.isCons(getRefTypeParameter(_), _) and
3366-
not (path0.isEmpty() and result instanceof RefType) and
3367-
path = TypePath::cons(getRefTypeParameter(_), path0)
3368-
else path = path0
3369-
)
3370-
else (
3371-
topDown = false and path = path0
3372-
)
3373-
)
3374-
}
3375-
33763283
/** Gets the root type of the reference expression `ref`. */
33773284
pragma[nomagic]
33783285
private Type inferRefExprType(RefExpr ref) {

0 commit comments

Comments
 (0)