Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Rust: Only include relevant AST nodes in TypeMention #19557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions 14 rust/ql/lib/codeql/rust/internal/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ private Type getRefAdjustImplicitSelfType(SelfParam self, TypePath suffix, Type

pragma[nomagic]
private Type resolveImplSelfType(Impl i, TypePath path) {
result = i.getSelfTy().(TypeReprMention).resolveTypeAt(path)
result = i.getSelfTy().(TypeMention).resolveTypeAt(path)
}

/** Gets the type at `path` of the implicitly typed `self` parameter. */
Expand Down Expand Up @@ -377,7 +377,7 @@ private module StructExprMatchingInput implements MatchingInputSig {

Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
// type of a field
exists(TypeReprMention tp |
exists(TypeMention tp |
tp = this.getField(dpos.asFieldPos()).getTypeRepr() and
result = tp.resolveTypeAt(path)
)
Expand Down Expand Up @@ -537,7 +537,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {

override Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(int pos |
result = this.getTupleField(pos).getTypeRepr().(TypeReprMention).resolveTypeAt(path) and
result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and
dpos = TPositionalDeclarationPosition(pos, false)
)
}
Expand All @@ -560,7 +560,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {

override Type getParameterType(DeclarationPosition dpos, TypePath path) {
exists(int p |
result = this.getTupleField(p).getTypeRepr().(TypeReprMention).resolveTypeAt(path) and
result = this.getTupleField(p).getTypeRepr().(TypeMention).resolveTypeAt(path) and
dpos = TPositionalDeclarationPosition(p, false)
)
}
Expand Down Expand Up @@ -608,7 +608,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
}

override Type getReturnType(TypePath path) {
result = this.getRetType().getTypeRepr().(TypeReprMention).resolveTypeAt(path)
result = this.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
}
}

Expand Down Expand Up @@ -646,7 +646,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl

class Access extends CallExprBase {
private TypeReprMention getMethodTypeArg(int i) {
private TypeMention getMethodTypeArg(int i) {
result = this.(MethodCallExpr).getGenericArgList().getTypeArg(i)
}

Expand Down Expand Up @@ -831,7 +831,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
)
or
dpos.isField() and
result = this.getTypeRepr().(TypeReprMention).resolveTypeAt(path)
result = this.getTypeRepr().(TypeMention).resolveTypeAt(path)
}
}

Expand Down
24 changes: 24 additions & 0 deletions 24 rust/ql/lib/codeql/rust/internal/TypeInferenceConsistency.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,28 @@
* Provides classes for recognizing type inference inconsistencies.
*/

private import Type
private import TypeMention
private import TypeInference::Consistency as Consistency
import TypeInference::Consistency

query predicate illFormedTypeMention(TypeMention tm) {
Consistency::illFormedTypeMention(tm) and
// Only include inconsistencies in the source, as we otherwise get
// inconsistencies from library code in every project.
tm.fromSource()
}

int getTypeInferenceInconsistencyCounts(string type) {
type = "Missing type parameter ID" and
result = count(TypeParameter tp | missingTypeParameterId(tp) | tp)
or
type = "Non-functional type parameter ID" and
result = count(TypeParameter tp | nonFunctionalTypeParameterId(tp) | tp)
or
type = "Non-injective type parameter ID" and
result = count(TypeParameter tp | nonInjectiveTypeParameterId(tp, _) | tp)
or
type = "Ill-formed type mention" and
result = count(TypeMention tm | illFormedTypeMention(tm) | tm)
}
150 changes: 68 additions & 82 deletions 150 rust/ql/lib/codeql/rust/internal/TypeMention.qll
Original file line number Diff line number Diff line change
Expand Up @@ -31,53 +31,33 @@ abstract class TypeMention extends AstNode {
Type resolveTypeAt(TypePath path) { result = this.getMentionAt(path).resolveType() }
}

class TypeReprMention extends TypeMention, TypeRepr {
TypeReprMention() { not this instanceof InferTypeRepr }
class ArrayTypeReprMention extends TypeMention instanceof ArrayTypeRepr {
override TypeMention getTypeArgument(int i) { result = super.getElementTypeRepr() and i = 0 }

override TypeReprMention getTypeArgument(int i) {
result = this.(ArrayTypeRepr).getElementTypeRepr() and
i = 0
or
result = this.(RefTypeRepr).getTypeRepr() and
i = 0
or
result = this.(PathTypeRepr).getPath().(PathMention).getTypeArgument(i)
}
override Type resolveType() { result = TArrayType() }
}

override Type resolveType() {
this instanceof ArrayTypeRepr and
result = TArrayType()
or
this instanceof RefTypeRepr and
result = TRefType()
or
result = this.(PathTypeRepr).getPath().(PathMention).resolveType()
}
class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
override TypeMention getTypeArgument(int i) { result = super.getTypeRepr() and i = 0 }

override Type resolveTypeAt(TypePath path) {
result = this.(PathTypeRepr).getPath().(PathMention).resolveTypeAt(path)
or
not exists(this.(PathTypeRepr).getPath()) and
result = super.resolveTypeAt(path)
}
override Type resolveType() { result = TRefType() }
}

/** Holds if `path` resolves to the type alias `alias` with the definition `rhs`. */
private predicate resolvePathAlias(Path path, TypeAlias alias, TypeReprMention rhs) {
alias = resolvePath(path) and rhs = alias.getTypeRepr()
}
class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
Path path;
ItemNode resolved;

abstract class PathMention extends TypeMention, Path {
override TypeMention getTypeArgument(int i) {
result = this.getSegment().getGenericArgList().getTypeArg(i)
PathTypeReprMention() {
path = super.getPath() and
// NOTE: This excludes unresolvable paths which is intentional as these
// don't add value to the type inference anyway.
resolved = resolvePath(path)
}
}

class NonAliasPathMention extends PathMention {
NonAliasPathMention() { not resolvePathAlias(this, _, _) }
ItemNode getResolved() { result = resolved }

override TypeMention getTypeArgument(int i) {
result = super.getTypeArgument(i)
result = path.getSegment().getGenericArgList().getTypeArg(i)
or
// `Self` paths inside `impl` blocks have implicit type arguments that are
// the type parameters of the `impl` block. For example, in
Expand All @@ -92,106 +72,112 @@ class NonAliasPathMention extends PathMention {
//
// the `Self` return type is shorthand for `Foo<T>`.
exists(ImplItemNode node |
this = node.getASelfPath() and
path = node.getASelfPath() and
result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i)
)
or
// If `this` is the trait of an `impl` block then any associated types
// If `path` is the trait of an `impl` block then any associated types
// defined in the `impl` block are type arguments to the trait.
//
// For instance, for a trait implementation like this
// ```rust
// impl MyTrait for MyType {
// ^^^^^^^ this
// ^^^^^^^ path
// type AssociatedType = i64
// ^^^ result
// // ...
// }
// ```
// the rhs. of the type alias is a type argument to the trait.
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias |
this = impl.getTraitPath() and
param.getTrait() = resolvePath(this) and
path = impl.getTraitPath() and
param.getTrait() = resolved and
alias = impl.getASuccessor(param.getTypeAlias().getName().getText()) and
result = alias.getTypeRepr() and
param.getIndex() = i
)
}

/**
* Holds if this path resolved to a type alias with a rhs. that has the
* resulting type at `typePath`.
*/
Type aliasResolveTypeAt(TypePath typePath) {
exists(TypeAlias alias, TypeMention rhs | alias = resolved and rhs = alias.getTypeRepr() |
result = rhs.resolveTypeAt(typePath) and
not result = pathGetTypeParameter(alias, _)
or
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
tp = rhs.resolveTypeAt(prefix) and
tp = pathGetTypeParameter(alias, i) and
arg = path.getSegment().getGenericArgList().getTypeArg(i) and
result = arg.resolveTypeAt(suffix) and
typePath = prefix.append(suffix)
)
)
}

override Type resolveType() {
exists(ItemNode i | i = resolvePath(this) |
result = TStruct(i)
result = this.aliasResolveTypeAt(TypePath::nil())
or
not exists(resolved.(TypeAlias).getTypeRepr()) and
(
result = TStruct(resolved)
or
result = TEnum(i)
result = TEnum(resolved)
or
exists(TraitItemNode trait | trait = i |
exists(TraitItemNode trait | trait = resolved |
// If this is a `Self` path, then it resolves to the implicit `Self`
// type parameter, otherwise it is a trait bound.
if this = trait.getASelfPath()
if super.getPath() = trait.getASelfPath()
then result = TSelfTypeParameter(trait)
else result = TTrait(trait)
)
or
result = TTypeParamTypeParameter(i)
result = TTypeParamTypeParameter(resolved)
or
exists(TypeAlias alias | alias = i |
exists(TypeAlias alias | alias = resolved |
result.(AssociatedTypeTypeParameter).getTypeAlias() = alias
or
result = alias.getTypeRepr().(TypeReprMention).resolveType()
result = alias.getTypeRepr().(TypeMention).resolveType()
)
)
}
}

class AliasPathMention extends PathMention {
TypeAlias alias;
TypeReprMention rhs;

AliasPathMention() { resolvePathAlias(this, alias, rhs) }

/** Get the `i`th type parameter of the alias itself. */
private TypeParameter getTypeParameter(int i) {
result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i))
}

override Type resolveType() { result = rhs.resolveType() }

override Type resolveTypeAt(TypePath path) {
result = rhs.resolveTypeAt(path) and
not result = this.getTypeParameter(_)
override Type resolveTypeAt(TypePath typePath) {
result = this.aliasResolveTypeAt(typePath)
or
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
tp = rhs.resolveTypeAt(prefix) and
tp = this.getTypeParameter(i) and
arg = this.getTypeArgument(i) and
result = arg.resolveTypeAt(suffix) and
path = prefix.append(suffix)
)
not exists(resolved.(TypeAlias).getTypeRepr()) and
result = super.resolveTypeAt(typePath)
}
}

private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) {
result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i))
}

// Used to represent implicit `Self` type arguments in traits and `impl` blocks,
// see `PathMention` for details.
class TypeParamMention extends TypeMention, TypeParam {
override TypeReprMention getTypeArgument(int i) { none() }
class TypeParamMention extends TypeMention instanceof TypeParam {
override TypeMention getTypeArgument(int i) { none() }

override Type resolveType() { result = TTypeParamTypeParameter(this) }
}

// Used to represent implicit type arguments for associated types in traits.
class TypeAliasMention extends TypeMention, TypeAlias {
class TypeAliasMention extends TypeMention instanceof TypeAlias {
private Type t;

TypeAliasMention() { t = TAssociatedTypeTypeParameter(this) }

override TypeReprMention getTypeArgument(int i) { none() }
override TypeMention getTypeArgument(int i) { none() }

override Type resolveType() { result = t }
}

class TraitMention extends TypeMention, TraitItemNode {
class TraitMention extends TypeMention instanceof TraitItemNode {
override TypeMention getTypeArgument(int i) {
result = this.getTypeParam(i)
result = super.getTypeParam(i)
or
traitAliasIndex(this, i, result)
}
Expand All @@ -203,7 +189,7 @@ class TraitMention extends TypeMention, TraitItemNode {
// appears in the AST, we (somewhat arbitrarily) choose the name of a trait as a
// type mention. This works because there is a one-to-one correspondence between
// a trait and its name.
class SelfTypeParameterMention extends TypeMention, Name {
class SelfTypeParameterMention extends TypeMention instanceof Name {
Trait trait;

SelfTypeParameterMention() { trait.getName() = this }
Expand All @@ -212,5 +198,5 @@ class SelfTypeParameterMention extends TypeMention, Name {

override Type resolveType() { result = TSelfTypeParameter(trait) }

override TypeReprMention getTypeArgument(int i) { none() }
override TypeMention getTypeArgument(int i) { none() }
}
15 changes: 15 additions & 0 deletions 15 rust/ql/src/queries/summary/Stats.qll
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ 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.internal.TypeInferenceConsistency as TypeInferenceConsistency
private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency
private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency
private import codeql.rust.dataflow.internal.SsaImpl::Consistency as SsaConsistency
Expand Down Expand Up @@ -52,6 +53,13 @@ int getTotalPathResolutionInconsistencies() {
sum(string type | | PathResolutionConsistency::getPathResolutionInconsistencyCounts(type))
}

/**
* Gets a count of the total number of type inference inconsistencies in the database.
*/
int getTotalTypeInferenceInconsistencies() {
result = sum(string type | | TypeInferenceConsistency::getTypeInferenceInconsistencyCounts(type))
}

/**
* Gets a count of the total number of control flow graph inconsistencies in the database.
*/
Expand Down Expand Up @@ -159,6 +167,13 @@ predicate inconsistencyStats(string key, int value) {
key = "Inconsistencies - data flow" and value = getTotalDataFlowInconsistencies()
}

/**
* Gets summary statistics about inconsistencies related to type inference.
*/
predicate typeInferenceInconsistencyStats(string key, int value) {
key = "Inconsistencies - Type inference" and value = getTotalTypeInferenceInconsistencies()
}

/**
* Gets summary statistics about taint.
*/
Expand Down
2 changes: 2 additions & 0 deletions 2 rust/ql/src/queries/summary/SummaryStats.ql
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ where
or
inconsistencyStats(key, value)
or
typeInferenceInconsistencyStats(key, value)
or
taintStats(key, value)
select key, value order by key
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
illFormedTypeMention
| sqlx.rs:158:13:158:81 | ...::BoxDynError |
| sqlx.rs:160:17:160:86 | ...::BoxDynError |
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
illFormedTypeMention
| main.rs:403:18:403:24 | FuncPtr |
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This inconsistency is a path to a function pointer type, which doesn't have a type as we don't support function pointers types.

Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
getTypeParameterId(tp1) = getTypeParameterId(tp2) and
tp1 != tp2
}

query predicate illFormedTypeMention(TypeMention tm) {
not exists(tm.resolveTypeAt(TypePath::nil())) and exists(tm.getLocation())
}
}
}
}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.