Skip to content

Commit 254eabf

Browse files
authored
Merge pull request #19557 from paldepind/rust/type-mention-consistency
Rust: Only include relevant AST nodes in TypeMention
2 parents b071a46 + 5228062 commit 254eabf

File tree

8 files changed

+125
-89
lines changed

8 files changed

+125
-89
lines changed

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ private Type getRefAdjustImplicitSelfType(SelfParam self, TypePath suffix, Type
312312

313313
pragma[nomagic]
314314
private Type resolveImplSelfType(Impl i, TypePath path) {
315-
result = i.getSelfTy().(TypeReprMention).resolveTypeAt(path)
315+
result = i.getSelfTy().(TypeMention).resolveTypeAt(path)
316316
}
317317

318318
/** Gets the type at `path` of the implicitly typed `self` parameter. */
@@ -375,7 +375,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
375375

376376
Type getDeclaredType(DeclarationPosition dpos, TypePath path) {
377377
// type of a field
378-
exists(TypeReprMention tp |
378+
exists(TypeMention tp |
379379
tp = this.getField(dpos.asFieldPos()).getTypeRepr() and
380380
result = tp.resolveTypeAt(path)
381381
)
@@ -535,7 +535,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
535535

536536
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
537537
exists(int pos |
538-
result = this.getTupleField(pos).getTypeRepr().(TypeReprMention).resolveTypeAt(path) and
538+
result = this.getTupleField(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) and
539539
dpos = TPositionalDeclarationPosition(pos, false)
540540
)
541541
}
@@ -558,7 +558,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
558558

559559
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
560560
exists(int p |
561-
result = this.getTupleField(p).getTypeRepr().(TypeReprMention).resolveTypeAt(path) and
561+
result = this.getTupleField(p).getTypeRepr().(TypeMention).resolveTypeAt(path) and
562562
dpos = TPositionalDeclarationPosition(p, false)
563563
)
564564
}
@@ -606,7 +606,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
606606
}
607607

608608
override Type getReturnType(TypePath path) {
609-
result = this.getRetType().getTypeRepr().(TypeReprMention).resolveTypeAt(path)
609+
result = this.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
610610
}
611611
}
612612

@@ -644,7 +644,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
644644
private import codeql.rust.elements.internal.CallExprImpl::Impl as CallExprImpl
645645

646646
class Access extends CallExprBase {
647-
private TypeReprMention getMethodTypeArg(int i) {
647+
private TypeMention getMethodTypeArg(int i) {
648648
result = this.(MethodCallExpr).getGenericArgList().getTypeArg(i)
649649
}
650650

@@ -829,7 +829,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
829829
)
830830
or
831831
dpos.isField() and
832-
result = this.getTypeRepr().(TypeReprMention).resolveTypeAt(path)
832+
result = this.getTypeRepr().(TypeMention).resolveTypeAt(path)
833833
}
834834
}
835835

rust/ql/lib/codeql/rust/internal/TypeInferenceConsistency.qll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,28 @@
22
* Provides classes for recognizing type inference inconsistencies.
33
*/
44

5+
private import Type
6+
private import TypeMention
7+
private import TypeInference::Consistency as Consistency
58
import TypeInference::Consistency
9+
10+
query predicate illFormedTypeMention(TypeMention tm) {
11+
Consistency::illFormedTypeMention(tm) and
12+
// Only include inconsistencies in the source, as we otherwise get
13+
// inconsistencies from library code in every project.
14+
tm.fromSource()
15+
}
16+
17+
int getTypeInferenceInconsistencyCounts(string type) {
18+
type = "Missing type parameter ID" and
19+
result = count(TypeParameter tp | missingTypeParameterId(tp) | tp)
20+
or
21+
type = "Non-functional type parameter ID" and
22+
result = count(TypeParameter tp | nonFunctionalTypeParameterId(tp) | tp)
23+
or
24+
type = "Non-injective type parameter ID" and
25+
result = count(TypeParameter tp | nonInjectiveTypeParameterId(tp, _) | tp)
26+
or
27+
type = "Ill-formed type mention" and
28+
result = count(TypeMention tm | illFormedTypeMention(tm) | tm)
29+
}

rust/ql/lib/codeql/rust/internal/TypeMention.qll

Lines changed: 68 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -31,53 +31,33 @@ abstract class TypeMention extends AstNode {
3131
Type resolveTypeAt(TypePath path) { result = this.getMentionAt(path).resolveType() }
3232
}
3333

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

37-
override TypeReprMention getTypeArgument(int i) {
38-
result = this.(ArrayTypeRepr).getElementTypeRepr() and
39-
i = 0
40-
or
41-
result = this.(RefTypeRepr).getTypeRepr() and
42-
i = 0
43-
or
44-
result = this.(PathTypeRepr).getPath().(PathMention).getTypeArgument(i)
45-
}
37+
override Type resolveType() { result = TArrayType() }
38+
}
4639

47-
override Type resolveType() {
48-
this instanceof ArrayTypeRepr and
49-
result = TArrayType()
50-
or
51-
this instanceof RefTypeRepr and
52-
result = TRefType()
53-
or
54-
result = this.(PathTypeRepr).getPath().(PathMention).resolveType()
55-
}
40+
class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
41+
override TypeMention getTypeArgument(int i) { result = super.getTypeRepr() and i = 0 }
5642

57-
override Type resolveTypeAt(TypePath path) {
58-
result = this.(PathTypeRepr).getPath().(PathMention).resolveTypeAt(path)
59-
or
60-
not exists(this.(PathTypeRepr).getPath()) and
61-
result = super.resolveTypeAt(path)
62-
}
43+
override Type resolveType() { result = TRefType() }
6344
}
6445

65-
/** Holds if `path` resolves to the type alias `alias` with the definition `rhs`. */
66-
private predicate resolvePathAlias(Path path, TypeAlias alias, TypeReprMention rhs) {
67-
alias = resolvePath(path) and rhs = alias.getTypeRepr()
68-
}
46+
class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
47+
Path path;
48+
ItemNode resolved;
6949

70-
abstract class PathMention extends TypeMention, Path {
71-
override TypeMention getTypeArgument(int i) {
72-
result = this.getSegment().getGenericArgList().getTypeArg(i)
50+
PathTypeReprMention() {
51+
path = super.getPath() and
52+
// NOTE: This excludes unresolvable paths which is intentional as these
53+
// don't add value to the type inference anyway.
54+
resolved = resolvePath(path)
7355
}
74-
}
7556

76-
class NonAliasPathMention extends PathMention {
77-
NonAliasPathMention() { not resolvePathAlias(this, _, _) }
57+
ItemNode getResolved() { result = resolved }
7858

7959
override TypeMention getTypeArgument(int i) {
80-
result = super.getTypeArgument(i)
60+
result = path.getSegment().getGenericArgList().getTypeArg(i)
8161
or
8262
// `Self` paths inside `impl` blocks have implicit type arguments that are
8363
// the type parameters of the `impl` block. For example, in
@@ -92,106 +72,112 @@ class NonAliasPathMention extends PathMention {
9272
//
9373
// the `Self` return type is shorthand for `Foo<T>`.
9474
exists(ImplItemNode node |
95-
this = node.getASelfPath() and
75+
path = node.getASelfPath() and
9676
result = node.(ImplItemNode).getSelfPath().getSegment().getGenericArgList().getTypeArg(i)
9777
)
9878
or
99-
// If `this` is the trait of an `impl` block then any associated types
79+
// If `path` is the trait of an `impl` block then any associated types
10080
// defined in the `impl` block are type arguments to the trait.
10181
//
10282
// For instance, for a trait implementation like this
10383
// ```rust
10484
// impl MyTrait for MyType {
105-
// ^^^^^^^ this
85+
// ^^^^^^^ path
10686
// type AssociatedType = i64
10787
// ^^^ result
10888
// // ...
10989
// }
11090
// ```
11191
// the rhs. of the type alias is a type argument to the trait.
11292
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias |
113-
this = impl.getTraitPath() and
114-
param.getTrait() = resolvePath(this) and
93+
path = impl.getTraitPath() and
94+
param.getTrait() = resolved and
11595
alias = impl.getASuccessor(param.getTypeAlias().getName().getText()) and
11696
result = alias.getTypeRepr() and
11797
param.getIndex() = i
11898
)
11999
}
120100

101+
/**
102+
* Holds if this path resolved to a type alias with a rhs. that has the
103+
* resulting type at `typePath`.
104+
*/
105+
Type aliasResolveTypeAt(TypePath typePath) {
106+
exists(TypeAlias alias, TypeMention rhs | alias = resolved and rhs = alias.getTypeRepr() |
107+
result = rhs.resolveTypeAt(typePath) and
108+
not result = pathGetTypeParameter(alias, _)
109+
or
110+
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
111+
tp = rhs.resolveTypeAt(prefix) and
112+
tp = pathGetTypeParameter(alias, i) and
113+
arg = path.getSegment().getGenericArgList().getTypeArg(i) and
114+
result = arg.resolveTypeAt(suffix) and
115+
typePath = prefix.append(suffix)
116+
)
117+
)
118+
}
119+
121120
override Type resolveType() {
122-
exists(ItemNode i | i = resolvePath(this) |
123-
result = TStruct(i)
121+
result = this.aliasResolveTypeAt(TypePath::nil())
122+
or
123+
not exists(resolved.(TypeAlias).getTypeRepr()) and
124+
(
125+
result = TStruct(resolved)
124126
or
125-
result = TEnum(i)
127+
result = TEnum(resolved)
126128
or
127-
exists(TraitItemNode trait | trait = i |
129+
exists(TraitItemNode trait | trait = resolved |
128130
// If this is a `Self` path, then it resolves to the implicit `Self`
129131
// type parameter, otherwise it is a trait bound.
130-
if this = trait.getASelfPath()
132+
if super.getPath() = trait.getASelfPath()
131133
then result = TSelfTypeParameter(trait)
132134
else result = TTrait(trait)
133135
)
134136
or
135-
result = TTypeParamTypeParameter(i)
137+
result = TTypeParamTypeParameter(resolved)
136138
or
137-
exists(TypeAlias alias | alias = i |
139+
exists(TypeAlias alias | alias = resolved |
138140
result.(AssociatedTypeTypeParameter).getTypeAlias() = alias
139141
or
140-
result = alias.getTypeRepr().(TypeReprMention).resolveType()
142+
result = alias.getTypeRepr().(TypeMention).resolveType()
141143
)
142144
)
143145
}
144-
}
145-
146-
class AliasPathMention extends PathMention {
147-
TypeAlias alias;
148-
TypeReprMention rhs;
149-
150-
AliasPathMention() { resolvePathAlias(this, alias, rhs) }
151-
152-
/** Get the `i`th type parameter of the alias itself. */
153-
private TypeParameter getTypeParameter(int i) {
154-
result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i))
155-
}
156-
157-
override Type resolveType() { result = rhs.resolveType() }
158146

159-
override Type resolveTypeAt(TypePath path) {
160-
result = rhs.resolveTypeAt(path) and
161-
not result = this.getTypeParameter(_)
147+
override Type resolveTypeAt(TypePath typePath) {
148+
result = this.aliasResolveTypeAt(typePath)
162149
or
163-
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
164-
tp = rhs.resolveTypeAt(prefix) and
165-
tp = this.getTypeParameter(i) and
166-
arg = this.getTypeArgument(i) and
167-
result = arg.resolveTypeAt(suffix) and
168-
path = prefix.append(suffix)
169-
)
150+
not exists(resolved.(TypeAlias).getTypeRepr()) and
151+
result = super.resolveTypeAt(typePath)
170152
}
171153
}
172154

155+
private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) {
156+
result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i))
157+
}
158+
173159
// Used to represent implicit `Self` type arguments in traits and `impl` blocks,
174160
// see `PathMention` for details.
175-
class TypeParamMention extends TypeMention, TypeParam {
176-
override TypeReprMention getTypeArgument(int i) { none() }
161+
class TypeParamMention extends TypeMention instanceof TypeParam {
162+
override TypeMention getTypeArgument(int i) { none() }
177163

178164
override Type resolveType() { result = TTypeParamTypeParameter(this) }
179165
}
180166

181167
// Used to represent implicit type arguments for associated types in traits.
182-
class TypeAliasMention extends TypeMention, TypeAlias {
168+
class TypeAliasMention extends TypeMention instanceof TypeAlias {
183169
private Type t;
184170

185171
TypeAliasMention() { t = TAssociatedTypeTypeParameter(this) }
186172

187-
override TypeReprMention getTypeArgument(int i) { none() }
173+
override TypeMention getTypeArgument(int i) { none() }
188174

189175
override Type resolveType() { result = t }
190176
}
191177

192-
class TraitMention extends TypeMention, TraitItemNode {
178+
class TraitMention extends TypeMention instanceof TraitItemNode {
193179
override TypeMention getTypeArgument(int i) {
194-
result = this.getTypeParam(i)
180+
result = super.getTypeParam(i)
195181
or
196182
traitAliasIndex(this, i, result)
197183
}
@@ -203,7 +189,7 @@ class TraitMention extends TypeMention, TraitItemNode {
203189
// appears in the AST, we (somewhat arbitrarily) choose the name of a trait as a
204190
// type mention. This works because there is a one-to-one correspondence between
205191
// a trait and its name.
206-
class SelfTypeParameterMention extends TypeMention, Name {
192+
class SelfTypeParameterMention extends TypeMention instanceof Name {
207193
Trait trait;
208194

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

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

215-
override TypeReprMention getTypeArgument(int i) { none() }
201+
override TypeMention getTypeArgument(int i) { none() }
216202
}

rust/ql/src/queries/summary/Stats.qll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import codeql.rust.dataflow.internal.DataFlowImpl
88
private import codeql.rust.dataflow.internal.TaintTrackingImpl
99
private import codeql.rust.internal.AstConsistency as AstConsistency
1010
private import codeql.rust.internal.PathResolutionConsistency as PathResolutionConsistency
11+
private import codeql.rust.internal.TypeInferenceConsistency as TypeInferenceConsistency
1112
private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency
1213
private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency
1314
private import codeql.rust.dataflow.internal.SsaImpl::Consistency as SsaConsistency
@@ -52,6 +53,13 @@ int getTotalPathResolutionInconsistencies() {
5253
sum(string type | | PathResolutionConsistency::getPathResolutionInconsistencyCounts(type))
5354
}
5455

56+
/**
57+
* Gets a count of the total number of type inference inconsistencies in the database.
58+
*/
59+
int getTotalTypeInferenceInconsistencies() {
60+
result = sum(string type | | TypeInferenceConsistency::getTypeInferenceInconsistencyCounts(type))
61+
}
62+
5563
/**
5664
* Gets a count of the total number of control flow graph inconsistencies in the database.
5765
*/
@@ -159,6 +167,13 @@ predicate inconsistencyStats(string key, int value) {
159167
key = "Inconsistencies - data flow" and value = getTotalDataFlowInconsistencies()
160168
}
161169

170+
/**
171+
* Gets summary statistics about inconsistencies related to type inference.
172+
*/
173+
predicate typeInferenceInconsistencyStats(string key, int value) {
174+
key = "Inconsistencies - Type inference" and value = getTotalTypeInferenceInconsistencies()
175+
}
176+
162177
/**
163178
* Gets summary statistics about taint.
164179
*/

rust/ql/src/queries/summary/SummaryStats.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ where
1717
or
1818
inconsistencyStats(key, value)
1919
or
20+
typeInferenceInconsistencyStats(key, value)
21+
or
2022
taintStats(key, value)
2123
select key, value order by key
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
illFormedTypeMention
2+
| sqlx.rs:158:13:158:81 | ...::BoxDynError |
3+
| sqlx.rs:160:17:160:86 | ...::BoxDynError |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
illFormedTypeMention
2+
| main.rs:403:18:403:24 | FuncPtr |

shared/typeinference/codeql/typeinference/internal/TypeInference.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13141314
getTypeParameterId(tp1) = getTypeParameterId(tp2) and
13151315
tp1 != tp2
13161316
}
1317+
1318+
query predicate illFormedTypeMention(TypeMention tm) {
1319+
not exists(tm.resolveTypeAt(TypePath::nil())) and exists(tm.getLocation())
1320+
}
13171321
}
13181322
}
13191323
}

0 commit comments

Comments
 (0)