Address review comments

This commit is contained in:
Tom Hvitved
2025-03-13 14:51:23 +01:00
parent 78280af570
commit af91152f5c
17 changed files with 185 additions and 142 deletions

View File

@@ -0,0 +1,8 @@
/**
* @name Path resolution inconsistencies
* @description Lists the path resolution inconsistencies in the database. This query is intended for internal use.
* @kind table
* @id rust/diagnostics/path-resolution-consistency
*/
import codeql.rust.internal.PathResolutionConsistency

View File

@@ -0,0 +1,8 @@
/**
* @name Type inference inconsistencies
* @description Lists the type inference inconsistencies in the database. This query is intended for internal use.
* @kind table
* @id rust/diagnostics/type-inference-consistency
*/
import codeql.rust.internal.TypeInferenceConsistency

View File

@@ -27,6 +27,6 @@ module Impl {
*/
class CallExprBase extends Generated::CallExprBase {
/** Gets the static target of this call, if any. */
Callable getStaticTarget() { none() }
Callable getStaticTarget() { none() } // overridden by subclasses
}
}

View File

@@ -26,7 +26,7 @@ module Impl {
override string toAbbreviatedString() { result = "<...>" }
/** Gets the `i`th type argument of this list. */
TypeRepr getTypeArgument(int i) {
TypeRepr getTypeArg(int i) {
result =
rank[i + 1](TypeRepr res, int j |
res = this.getGenericArg(j).(TypeArg).getTypeRepr()
@@ -36,6 +36,6 @@ module Impl {
}
/** Gets a type argument of this list. */
TypeRepr getATypeArgument() { result = this.getTypeArgument(_) }
TypeRepr getATypeArg() { result = this.getTypeArg(_) }
}
}

View File

@@ -317,49 +317,53 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
}
/**
* Holds if this `impl` block is constrained. Examples:
* Holds if this `impl` block is not fully parametric. That is, the implementing
* type is generic and the implementation is not parametrically polymorphic in all
* the implementing type's arguments.
*
* Examples:
*
* ```rust
* impl Foo { ... } // unconstrained
* impl Foo { ... } // fully parametric
*
* impl<T> Foo<T> { ... } // unconstrained
* impl<T> Foo<T> { ... } // fully parametric
*
* impl Foo<i64> { ... } // constrained
* impl Foo<i64> { ... } // not fully parametric
*
* impl<T> Foo<Foo<T>> { ... } // constrained
* impl<T> Foo<Foo<T>> { ... } // not fully parametric
*
* impl<T: Trait> Foo<T> { ... } // constrained
* impl<T: Trait> Foo<T> { ... } // not fully parametric
*
* impl<T> Foo<T> where T: Trait { ... } // constrained
* impl<T> Foo<T> where T: Trait { ... } // not fully parametric
* ```
*/
pragma[nomagic]
predicate isConstrained() {
predicate isNotFullyParametric() {
exists(TypeRepr arg | arg = this.getASelfTyArg() |
not exists(this.getASelfTyTypeParamArg(arg))
or
this.getASelfTyTypeParamArg(arg).isConstrained()
this.getASelfTyTypeParamArg(arg).hasTraitBound()
)
}
/**
* Holds if this `impl` block is unconstrained. Examples:
* Holds if this `impl` block is fully parametric. Examples:
*
* ```rust
* impl Foo { ... } // unconstrained
* impl Foo { ... } // fully parametric
*
* impl<T> Foo<T> { ... } // unconstrained
* impl<T> Foo<T> { ... } // fully parametric
*
* impl Foo<i64> { ... } // constrained
* impl Foo<i64> { ... } // not fully parametric
*
* impl<T> Foo<Foo<T>> { ... } // constrained
* impl<T> Foo<Foo<T>> { ... } // not fully parametric
*
* impl<T: Trait> Foo<T> { ... } // constrained
* impl<T: Trait> Foo<T> { ... } // not fully parametric
*
* impl<T> Foo<T> where T: Trait { ... } // constrained
* impl<T> Foo<T> where T: Trait { ... } // not fully parametric
* ```
*/
predicate isUnconstrained() { not this.isConstrained() }
predicate isFullyParametric() { not this.isNotFullyParametric() }
override AssocItemNode getAnAssocItem() { result = super.getAssocItemList().getAnAssocItem() }
@@ -481,18 +485,18 @@ private class TypeParamItemNode extends ItemNode instanceof TypeParam {
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
/**
* Holds if this type parameter is constrained. Examples:
* Holds if this type parameter has a trait bound. Examples:
*
* ```rust
* impl<T> Foo<T> { ... } // unconstrained
* impl<T> Foo<T> { ... } // has no trait bound
*
* impl<T: Trait> Foo<T> { ... } // constrained
* impl<T: Trait> Foo<T> { ... } // has trait bound
*
* impl<T> Foo<T> where T: Trait { ... } // constrained
* impl<T> Foo<T> where T: Trait { ... } // has trait bound
* ```
*/
pragma[nomagic]
predicate isConstrained() {
predicate hasTraitBound() {
exists(this.getABoundPath())
or
exists(ItemNode declaringItem, WherePred wp |
@@ -503,18 +507,18 @@ private class TypeParamItemNode extends ItemNode instanceof TypeParam {
}
/**
* Holds if this type parameter is unconstrained. Examples:
* Holds if this type parameter has no trait bound. Examples:
*
* ```rust
* impl<T> Foo<T> { ... } // unconstrained
* impl<T> Foo<T> { ... } // has no trait bound
*
* impl<T: Trait> Foo<T> { ... } // constrained
* impl<T: Trait> Foo<T> { ... } // has trait bound
*
* impl<T> Foo<T> where T: Trait { ... } // constrained
* impl<T> Foo<T> where T: Trait { ... } // has trait bound
* ```
*/
pragma[nomagic]
predicate isUnconstrained() { not this.isConstrained() }
predicate hasNoTraitBound() { not this.hasTraitBound() }
override string getName() { result = TypeParam.super.getName().getText() }

View File

@@ -18,7 +18,12 @@ newtype TType =
TRefTypeParameter() or
TSelfTypeParameter()
/** A type without type arguments. */
/**
* A type without type arguments.
*
* Note that this type includes things that, strictly speaking, are not Rust
* types, such as traits and implementation blocks.
*/
abstract class Type extends TType {
/** Gets the method `name` belonging to this type, if any. */
pragma[nomagic]
@@ -72,13 +77,13 @@ abstract private class StructOrEnumType extends Type {
exists(ImplOrTraitItemNode impl | result = impl.getAnAssocItem() |
impl instanceof Trait
or
impl.(ImplItemNode).isUnconstrained()
impl.(ImplItemNode).isFullyParametric()
)
}
final override ImplMention getABaseTypeMention() {
this.asItemNode() = result.resolveSelfTy() and
result.isUnconstrained()
result.isFullyParametric()
}
}

View File

@@ -22,7 +22,7 @@ private module Input1 implements InputSig1<Location> {
// method type parameters are matched by position instead of by type
// parameter entity, to avoid extra recursion through method call resolution
TMethodTypeArgumentPosition(int pos) {
exists(any(MethodCallExpr mce).getGenericArgList().getTypeArgument(pos))
exists(any(MethodCallExpr mce).getGenericArgList().getTypeArg(pos))
} or
TTypeParamTypeArgumentPosition(TypeParam tp)
@@ -124,11 +124,13 @@ private Type inferAnnotatedType(AstNode n, TypePath path) {
}
/**
* Holds if the type of `n1` at `path1` is the same as the type of `n2` at `path2`.
* Holds if the type of `n1` at `path1` is the same as the type of `n2` at
* `path2` and type information should propagate in both directions through the
* type equality.
*/
bindingset[path1]
bindingset[path2]
private predicate typeSymmetry(AstNode n1, TypePath path1, AstNode n2, TypePath path2) {
private predicate typeEquality(AstNode n1, TypePath path1, AstNode n2, TypePath path2) {
exists(Variable v |
path1 = path2 and
n1 = v.getAnAccess()
@@ -159,11 +161,11 @@ private predicate typeSymmetry(AstNode n1, TypePath path1, AstNode n2, TypePath
}
pragma[nomagic]
private Type inferTypeSymmetry(AstNode n, TypePath path) {
private Type inferTypeEquality(AstNode n, TypePath path) {
exists(AstNode n2, TypePath path2 | result = inferType(n2, path2) |
typeSymmetry(n, path, n2, path2)
typeEquality(n, path, n2, path2)
or
typeSymmetry(n2, path2, n, path)
typeEquality(n2, path2, n, path)
)
}
@@ -222,7 +224,7 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
exists(int i |
result = path.getPart().getGenericArgList().getTypeArgument(pragma[only_bind_into](i)) and
result = path.getPart().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
tp = resolvePath(path).getTypeParam(pragma[only_bind_into](i))
)
or
@@ -316,7 +318,7 @@ private module RecordExprMatchingInput implements MatchingInputSig {
class AccessPosition = DeclarationPosition;
class Access extends RecordExpr {
Type getExplicitTypeArgument(TypeArgumentPosition apos, TypePath path) {
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
result = getExplicitTypeArgMention(this.getPath(), apos.asTypeParam()).resolveTypeAt(path)
}
@@ -535,10 +537,10 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
class Access extends CallExprBase {
private TypeReprMention getMethodTypeArg(int i) {
result = this.(MethodCallExpr).getGenericArgList().getTypeArgument(i)
result = this.(MethodCallExpr).getGenericArgList().getTypeArg(i)
}
Type getExplicitTypeArgument(TypeArgumentPosition apos, TypePath path) {
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
exists(TypeMention arg | result = arg.resolveTypeAt(path) |
arg = getExplicitTypeArgMention(CallExprImpl::getFunctionPath(this), apos.asTypeParam())
or
@@ -616,7 +618,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
pathAdj = TypePath::singleton(TRefTypeParameter()) and
tAdj = t
else
if path.startsWith(TRefTypeParameter(), _)
if path.isCons(TRefTypeParameter(), _)
then
pathAdj = path and
tAdj = t
@@ -628,10 +630,10 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
)
else (
// adjust for implicit deref
path.startsWith(TRefTypeParameter(), pathAdj) and
path.isCons(TRefTypeParameter(), pathAdj) and
tAdj = t
or
not path.startsWith(TRefTypeParameter(), _) and
not path.isCons(TRefTypeParameter(), _) and
not (t = TRefType() and path.isEmpty()) and
pathAdj = path and
tAdj = t
@@ -674,19 +676,19 @@ private Type inferCallExprBaseType(AstNode n, TypePath path) {
if receiverType = TRefType()
then
path = path0 and
path0.startsWith(TRefTypeParameter(), _)
path0.isCons(TRefTypeParameter(), _)
or
// adjust for implicit deref
not path0.startsWith(TRefTypeParameter(), _) and
not path0.isCons(TRefTypeParameter(), _) and
not (path0.isEmpty() and result = TRefType()) and
path = TypePath::cons(TRefTypeParameter(), path0)
else (
not path0.startsWith(TRefTypeParameter(), _) and
not path0.isCons(TRefTypeParameter(), _) and
not (path0.isEmpty() and result = TRefType()) and
path = path0
or
// adjust for implicit borrow
path0.startsWith(TRefTypeParameter(), path)
path0.isCons(TRefTypeParameter(), path)
)
)
else path = path0
@@ -748,7 +750,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
class AccessPosition = DeclarationPosition;
class Access extends FieldExpr {
Type getExplicitTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
AstNode getNodeAt(AccessPosition apos) {
result = this.getExpr() and
@@ -781,10 +783,10 @@ private module FieldExprMatchingInput implements MatchingInputSig {
if apos.isSelf()
then
// adjust for implicit deref
path.startsWith(TRefTypeParameter(), pathAdj) and
path.isCons(TRefTypeParameter(), pathAdj) and
tAdj = t
or
not path.startsWith(TRefTypeParameter(), _) and
not path.isCons(TRefTypeParameter(), _) and
not (t = TRefType() and path.isEmpty()) and
pathAdj = path and
tAdj = t
@@ -824,7 +826,7 @@ private Type inferFieldExprType(AstNode n, TypePath path) {
if receiverType = TRefType()
then
// adjust for implicit deref
not path0.startsWith(TRefTypeParameter(), _) and
not path0.isCons(TRefTypeParameter(), _) and
not (path0.isEmpty() and result = TRefType()) and
path = TypePath::cons(TRefTypeParameter(), path0)
else path = path0
@@ -846,7 +848,7 @@ private Type inferRefExprType(Expr e, TypePath path) {
or
e = re and
exists(TypePath exprPath | result = inferType(re.getExpr(), exprPath) |
if exprPath.startsWith(TRefTypeParameter(), _)
if exprPath.isCons(TRefTypeParameter(), _)
then
// `&x` simply means `x` when `x` already has reference type
path = exprPath
@@ -975,7 +977,7 @@ private module Cached {
Stages::TypeInference::backref() and
result = inferAnnotatedType(n, path)
or
result = inferTypeSymmetry(n, path)
result = inferTypeEquality(n, path)
or
result = inferImplicitSelfType(n, path)
or

View File

@@ -78,7 +78,7 @@ class TypeReprMention extends TypeMention, TypeRepr {
class PathMention extends TypeMention, Path {
override TypeMention getTypeArgument(int i) {
result = this.getPart().getGenericArgList().getTypeArgument(i)
result = this.getPart().getGenericArgList().getTypeArg(i)
or
// `Self` paths inside traits and `impl` blocks have implicit type arguments
// that are the type parameters of the trait or impl. For example, in
@@ -93,7 +93,7 @@ class PathMention extends TypeMention, Path {
//
// the `Self` return type is shorthand for `Foo<T>`.
exists(ImplOrTraitItemNode node | this = node.getASelfPath() |
result = node.(ImplItemNode).getSelfPath().getPart().getGenericArgList().getTypeArgument(i)
result = node.(ImplItemNode).getSelfPath().getPart().getGenericArgList().getTypeArg(i)
or
result = node.(Trait).getGenericParamList().getTypeParam(i)
)
@@ -140,7 +140,7 @@ private predicate isImplSelfTypeParam(
) {
exists(PathMention path |
selfPath = impl.getSelfPath() and
path = selfPath.getPart().getGenericArgList().getTypeArgument(i).(PathTypeRepr).getPath() and
path = selfPath.getPart().getGenericArgList().getTypeArg(i).(PathTypeRepr).getPath() and
tp = path.resolveType()
)
}

View File

@@ -1,5 +1,5 @@
/**
* Provides classes for recognizing control flow graph inconsistencies.
* Provides classes for recognizing AST inconsistencies.
*/
private import rust
@@ -75,40 +75,6 @@ query predicate multiplePositions(Element parent, int pos1, int pos2, string acc
pos1 != pos2
}
private import codeql.rust.elements.internal.PathResolution
/** Holds if `p` may resolve to multiple items including `i`. */
query predicate multiplePathResolutions(Path p, ItemNode i) {
i = resolvePath(p) and
// `use foo::bar` may use both a type `bar` and a value `bar`
not p =
any(UseTree use |
not use.isGlob() and
not use.hasUseTreeList()
).getPath() and
strictcount(resolvePath(p)) > 1
}
/** Holds if `call` has multiple static call targets including `target`. */
query predicate multipleStaticCallTargets(CallExprBase call, Callable target) {
target = call.getStaticTarget() and
strictcount(call.getStaticTarget()) > 1
}
/** Holds if `fe` resolves to multiple record fields including `field`. */
query predicate multipleRecordFields(FieldExpr fe, RecordField field) {
field = fe.getRecordField() and
strictcount(fe.getRecordField()) > 1
}
/** Holds if `fe` resolves to multiple tuple fields including `field`. */
query predicate multipleTupleFields(FieldExpr fe, TupleField field) {
field = fe.getTupleField() and
strictcount(fe.getTupleField()) > 1
}
import codeql.rust.elements.internal.TypeInference::Consistency
/**
* Gets counts of abstract syntax tree inconsistencies of each type.
*/
@@ -134,16 +100,4 @@ int getAstInconsistencyCounts(string type) {
or
type = "Multiple positions" and
result = count(Element e | multiplePositions(_, _, _, _, e) | e)
or
type = "Multiple path resolutions" and
result = count(Path p | multiplePathResolutions(p, _) | p)
or
type = "Multiple static call targets" and
result = count(CallExprBase call | multipleStaticCallTargets(call, _) | call)
or
type = "Multiple record fields" and
result = count(FieldExpr fe | multipleRecordFields(fe, _) | fe)
or
type = "Multiple tuple fields" and
result = count(FieldExpr fe | multipleTupleFields(fe, _) | fe)
}

View File

@@ -0,0 +1,53 @@
/**
* Provides classes for recognizing path resolution inconsistencies.
*/
private import rust
private import codeql.rust.elements.internal.PathResolution
/** Holds if `p` may resolve to multiple items including `i`. */
query predicate multiplePathResolutions(Path p, ItemNode i) {
i = resolvePath(p) and
// `use foo::bar` may use both a type `bar` and a value `bar`
not p =
any(UseTree use |
not use.isGlob() and
not use.hasUseTreeList()
).getPath() and
strictcount(resolvePath(p)) > 1
}
/** Holds if `call` has multiple static call targets including `target`. */
query predicate multipleStaticCallTargets(CallExprBase call, Callable target) {
target = call.getStaticTarget() and
strictcount(call.getStaticTarget()) > 1
}
/** Holds if `fe` resolves to multiple record fields including `field`. */
query predicate multipleRecordFields(FieldExpr fe, RecordField field) {
field = fe.getRecordField() and
strictcount(fe.getRecordField()) > 1
}
/** Holds if `fe` resolves to multiple tuple fields including `field`. */
query predicate multipleTupleFields(FieldExpr fe, TupleField field) {
field = fe.getTupleField() and
strictcount(fe.getTupleField()) > 1
}
/**
* Gets counts of path resolution inconsistencies of each type.
*/
int getPathResolutionInconsistencyCounts(string type) {
type = "Multiple path resolutions" and
result = count(Path p | multiplePathResolutions(p, _) | p)
or
type = "Multiple static call targets" and
result = count(CallExprBase call | multipleStaticCallTargets(call, _) | call)
or
type = "Multiple record fields" and
result = count(FieldExpr fe | multipleRecordFields(fe, _) | fe)
or
type = "Multiple tuple fields" and
result = count(FieldExpr fe | multipleTupleFields(fe, _) | fe)
}

View File

@@ -0,0 +1,5 @@
/**
* Provides classes for recognizing type inference inconsistencies.
*/
import codeql.rust.elements.internal.TypeInference::Consistency

View File

@@ -7,6 +7,7 @@ private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.internal.DataFlowImpl
private import codeql.rust.dataflow.internal.TaintTrackingImpl
private import codeql.rust.internal.AstConsistency as AstConsistency
private import codeql.rust.internal.PathResolutionConsistency as PathResolutionConsistency
private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency
private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency
private import codeql.rust.Concepts
@@ -35,6 +36,14 @@ int getTotalAstInconsistencies() {
result = sum(string type | | AstConsistency::getAstInconsistencyCounts(type))
}
/**
* Gets a count of the total number of path resolution inconsistencies in the database.
*/
int getTotalPathResolutionInconsistencies() {
result =
sum(string type | | PathResolutionConsistency::getPathResolutionInconsistencyCounts(type))
}
/**
* Gets a count of the total number of control flow graph inconsistencies in the database.
*/

View File

@@ -54,6 +54,8 @@ where
or
key = "Inconsistencies - AST" and value = getTotalAstInconsistencies()
or
key = "Inconsistencies - Path resolution" and value = getTotalPathResolutionInconsistencies()
or
key = "Inconsistencies - CFG" and value = getTotalCfgInconsistencies()
or
key = "Inconsistencies - data flow" and value = getTotalDataFlowInconsistencies()

View File

@@ -549,7 +549,7 @@ mod m13 {
}
pub fn f() {
let x = S;
let x = S {};
x.f1();
x.f2();
S::f3(&x);

View File

@@ -720,7 +720,7 @@ inferType
| main.rs:547:16:547:16 | x | | file://:0:0:0:0 | & |
| main.rs:547:16:547:16 | x | &T | main.rs:531:5:531:13 | struct S |
| main.rs:552:13:552:13 | x | | main.rs:531:5:531:13 | struct S |
| main.rs:552:17:552:17 | S | | main.rs:531:5:531:13 | struct S |
| main.rs:552:17:552:20 | S {...} | | main.rs:531:5:531:13 | struct S |
| main.rs:553:9:553:9 | x | | main.rs:531:5:531:13 | struct S |
| main.rs:553:9:553:14 | x.f1(...) | | file://:0:0:0:0 | & |
| main.rs:553:9:553:14 | x.f1(...) | &T | main.rs:531:5:531:13 | struct S |

View File

@@ -156,22 +156,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
else result = this + "." + suffix
}
/** Holds if this path starts with `prefix`, followed by `tp`. */
bindingset[this]
predicate endsWith(TypePath prefix, TypeParameter tp) {
decodeTypePathComponent(this, tp) and
prefix.isEmpty()
or
exists(int last |
last = max(this.indexOf(".")) and
prefix = this.prefix(last) and
decodeTypePathComponent(this.suffix(last + 1), tp)
)
}
/** Holds if this path starts with `tp`, followed by `suffix`. */
bindingset[this]
predicate startsWith(TypeParameter tp, TypePath suffix) {
predicate isCons(TypeParameter tp, TypePath suffix) {
decodeTypePathComponent(this, tp) and
suffix.isEmpty()
or
@@ -319,7 +306,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
immediateBase = resolveTypeMentionRoot(immediateBaseMention) and
baseTypeMentionHasTypeParameterAt(immediateBase, baseMention, prefix, mid) and
pathToTypeParam.startsWith(mid, suffix) and
pathToTypeParam.isCons(mid, suffix) and
path = prefix.append(suffix)
)
)
@@ -392,7 +379,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
baseTypeMentionHasTypeParameterAt(immediateBase, baseMention, prefix, tp) and
t = immediateBaseMention.resolveTypeAt(path0) and
path0.startsWith(tp, suffix) and
path0.isCons(tp, suffix) and
path = prefix.append(suffix)
)
)
@@ -456,13 +443,13 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Location getLocation();
/**
* Gets the type at `path` for the explicit type argument at position
* `tapos` of this access, if any.
* Gets the type at `path` for the type argument at position `tapos` of
* this access, if any.
*
* For example, in a method call like `M<int>()`, `int` is an explicit
* type argument at position `0`.
*/
Type getExplicitTypeArgument(TypeArgumentPosition tapos, TypePath path);
Type getTypeArgument(TypeArgumentPosition tapos, TypePath path);
/**
* Gets the inferred type at `path` for the position `apos` of this access.
@@ -514,8 +501,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
module Matching<MatchingInputSig Input> {
private import Input
/**
* Holds if `a` targets `target` and the type for `apos` at `path` in `a`
* is `t` after adjustment by `target`.
*/
pragma[nomagic]
private predicate accessType(
private predicate adjustedAccessType(
Access a, AccessPosition apos, Declaration target, TypePath path, Type t
) {
target = a.getTarget() and
@@ -525,13 +516,15 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
)
}
/**
* Gets the type of the type argument at `path` in `a` that corresponds to
* the type parameter `tp` in `target`.
*/
bindingset[a, target]
pragma[inline_late]
private Type explicitTypeArgument(
Access a, Declaration target, TypeParameter tp, TypePath path
) {
private Type getTypeArgument(Access a, Declaration target, TypeParameter tp, TypePath path) {
exists(TypeArgumentPosition tapos, TypeParameterPosition tppos |
result = a.getExplicitTypeArgument(tapos, path) and
result = a.getTypeArgument(tapos, path) and
tp = target.getTypeParameter(tppos) and
typeArgumentParameterPositionMatch(tapos, tppos)
)
@@ -546,9 +539,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Access a, Declaration target, TypePath path, Type t, TypeParameter tp
) {
exists(AccessPosition apos, DeclarationPosition dpos, TypePath pathToTypeParam |
accessType(a, apos, target, pathToTypeParam.append(path), t) and
adjustedAccessType(a, apos, target, pathToTypeParam.append(path), t) and
tp = target.getDeclaredType(dpos, pathToTypeParam) and
not exists(explicitTypeArgument(a, target, tp, _)) and
not exists(getTypeArgument(a, target, tp, _)) and
accessDeclarationPositionMatch(apos, dpos)
)
}
@@ -556,7 +549,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
private module AccessBaseType {
private predicate relevantAccess(Access a, AccessPosition apos) {
exists(Declaration target |
accessType(a, apos, target, _, _) and
adjustedAccessType(a, apos, target, _, _) and
target.getDeclaredType(_, _) instanceof TypeParameter
)
}
@@ -572,7 +565,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
relevantAccess(a, apos) and
exists(TypePath path0 |
result = a.getInferredType(apos, path0) and
path0.startsWith(tp, suffix)
path0.isCons(tp, suffix)
)
}
@@ -611,9 +604,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
exists(Type sub | sub = inferRootType(a, apos) |
baseTypeMentionHasNonTypeParameterAt(sub, baseMention, path, t)
or
exists(TypePath prefix, TypePath suffix, TypeParameter i |
baseTypeMentionHasTypeParameterAt(sub, baseMention, prefix, i) and
t = inferTypeAt(a, apos, i, suffix) and
exists(TypePath prefix, TypePath suffix, TypeParameter tp |
baseTypeMentionHasTypeParameterAt(sub, baseMention, prefix, tp) and
t = inferTypeAt(a, apos, tp, suffix) and
path = prefix.append(suffix)
)
)
@@ -636,7 +629,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Declaration decl, DeclarationPosition dpos, Type base, TypePath path, Type t
) {
t = decl.getDeclaredType(dpos, path) and
path.startsWith(base.getATypeParameter(), _)
path.isCons(base.getATypeParameter(), _)
}
/**
@@ -677,7 +670,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
exists(AccessPosition apos, DeclarationPosition dpos, Type base, TypePath pathToTypeParam |
accessBaseType(a, apos, target, base, pathToTypeParam.append(path), t) and
declarationBaseType(target, dpos, base, pathToTypeParam, tp) and
not exists(explicitTypeArgument(a, target, tp, _)) and
not exists(getTypeArgument(a, target, tp, _)) and
accessDeclarationPositionMatch(apos, dpos)
)
}
@@ -687,7 +680,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
Access a, Declaration target, TypePath path, Type t, TypeParameter tp
) {
target = a.getTarget() and
t = explicitTypeArgument(a, target, tp, path)
t = getTypeArgument(a, target, tp, path)
}
pragma[nomagic]