mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Address review comments
This commit is contained in:
8
rust/ql/consistency-queries/PathResolutionConsistency.ql
Normal file
8
rust/ql/consistency-queries/PathResolutionConsistency.ql
Normal 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
|
||||
8
rust/ql/consistency-queries/TypeInferenceConsistency.ql
Normal file
8
rust/ql/consistency-queries/TypeInferenceConsistency.ql
Normal 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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(_) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Provides classes for recognizing type inference inconsistencies.
|
||||
*/
|
||||
|
||||
import codeql.rust.elements.internal.TypeInference::Consistency
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -549,7 +549,7 @@ mod m13 {
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let x = S;
|
||||
let x = S {};
|
||||
x.f1();
|
||||
x.f2();
|
||||
S::f3(&x);
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user