Skip to content

Commit 179bae8

Browse files
authored
Merge pull request #19025 from hvitved/rust/rust-analyzer-comparison
Rust: Add telemetry for comparing against `rust-analyzer`
2 parents 2750d1d + 89f6245 commit 179bae8

File tree

2 files changed

+152
-1
lines changed

2 files changed

+152
-1
lines changed

rust/ql/src/queries/telemetry/ExtractorInformation.ql

+18-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import rust
1010
import DatabaseQuality
11+
import RustAnalyzerComparison
1112
import codeql.rust.Diagnostics
1213

1314
predicate fileCount(string key, int value) {
@@ -41,6 +42,20 @@ predicate extractorDiagnostics(string key, int value) {
4142
)
4243
}
4344

45+
predicate pathResolutionCompare(string key, int value) {
46+
exists(string suffix |
47+
PathResolutionCompare::summary(suffix, value) and
48+
key = "Rust-analyzer path resolution comparison: " + suffix
49+
)
50+
}
51+
52+
predicate callGraphCompare(string key, int value) {
53+
exists(string suffix |
54+
CallGraphCompare::summary(suffix, value) and
55+
key = "Rust-analyzer call graph comparison: " + suffix
56+
)
57+
}
58+
4459
from string key, float value
4560
where
4661
(
@@ -54,7 +69,9 @@ where
5469
CallTargetStatsReport::percentageOfOk(key, value) or
5570
MacroCallTargetStatsReport::numberOfOk(key, value) or
5671
MacroCallTargetStatsReport::numberOfNotOk(key, value) or
57-
MacroCallTargetStatsReport::percentageOfOk(key, value)
72+
MacroCallTargetStatsReport::percentageOfOk(key, value) or
73+
pathResolutionCompare(key, value) or
74+
callGraphCompare(key, value)
5875
) and
5976
/* Infinity */
6077
value != 1.0 / 0.0 and
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* INTERNAL: Do not use.
3+
*
4+
* Provides functionality for comparing data from `rust-analyzer` with data computed
5+
* in QL.
6+
*/
7+
8+
import rust
9+
10+
private signature module ResolvableSig {
11+
class Source {
12+
string toString();
13+
14+
Location getLocation();
15+
}
16+
17+
class Target {
18+
string toString();
19+
20+
Location getLocation();
21+
}
22+
}
23+
24+
private signature module CompareSig<ResolvableSig R> {
25+
predicate isResolvable(R::Source s);
26+
27+
R::Target resolve(R::Source s);
28+
}
29+
30+
private module Compare<ResolvableSig R, CompareSig<R> RustAnalyzer, CompareSig<R> Ql> {
31+
private import R
32+
33+
predicate same(Source s, Target t) {
34+
t = RustAnalyzer::resolve(s) and
35+
t = Ql::resolve(s)
36+
}
37+
38+
predicate sameCount(int c) { c = count(Source s | same(s, _)) }
39+
40+
predicate diff(Source s, Target t1, Target t2) {
41+
t1 = RustAnalyzer::resolve(s) and
42+
t2 = Ql::resolve(s) and
43+
t1 != t2
44+
}
45+
46+
predicate diffCount(int c) { c = count(Source s | not same(s, _) and diff(s, _, _)) }
47+
48+
predicate rustAnalyzerUnique(Source s) {
49+
RustAnalyzer::isResolvable(s) and
50+
not Ql::isResolvable(s)
51+
}
52+
53+
predicate rustAnalyzerUniqueCount(int c) { c = count(Source s | rustAnalyzerUnique(s)) }
54+
55+
predicate qlUnique(Source s) {
56+
not RustAnalyzer::isResolvable(s) and
57+
Ql::isResolvable(s)
58+
}
59+
60+
predicate qlUniqueCount(int c) { c = count(Source s | qlUnique(s)) }
61+
62+
predicate summary(string key, int value) {
63+
key = "rust-analyzer unique" and rustAnalyzerUniqueCount(value)
64+
or
65+
key = "QL unique" and qlUniqueCount(value)
66+
or
67+
key = "same" and sameCount(value)
68+
or
69+
key = "different" and diffCount(value)
70+
}
71+
}
72+
73+
private module PathResolution implements ResolvableSig {
74+
class Source extends Resolvable {
75+
Source() { not this instanceof MethodCallExpr }
76+
}
77+
78+
class Target = Item;
79+
}
80+
81+
private module RustAnalyzerPathResolution implements CompareSig<PathResolution> {
82+
predicate isResolvable(PathResolution::Source s) { s.hasResolvedPath() }
83+
84+
Item resolve(PathResolution::Source s) { s.resolvesAsItem(result) }
85+
}
86+
87+
private module QlPathResolution implements CompareSig<PathResolution> {
88+
private import codeql.rust.internal.PathResolution
89+
90+
private Path getPath(Resolvable r) {
91+
result = r.(PathExpr).getPath()
92+
or
93+
result = r.(RecordExpr).getPath()
94+
or
95+
result = r.(PathPat).getPath()
96+
or
97+
result = r.(RecordPat).getPath()
98+
or
99+
result = r.(TupleStructPat).getPath()
100+
}
101+
102+
predicate isResolvable(PathResolution::Source s) { exists(resolve(s)) }
103+
104+
Item resolve(PathResolution::Source s) { result = resolvePath(getPath(s)) }
105+
}
106+
107+
module PathResolutionCompare =
108+
Compare<PathResolution, RustAnalyzerPathResolution, QlPathResolution>;
109+
110+
private module CallGraph implements ResolvableSig {
111+
class Source = CallExprBase;
112+
113+
class Target = Item;
114+
}
115+
116+
private module RustAnalyzerCallGraph implements CompareSig<CallGraph> {
117+
private import codeql.rust.elements.internal.CallExprBaseImpl::Impl as CallExprBaseImpl
118+
119+
predicate isResolvable(CallExprBase c) {
120+
CallExprBaseImpl::getCallResolvable(c).hasResolvedPath()
121+
}
122+
123+
Item resolve(CallExprBase c) { CallExprBaseImpl::getCallResolvable(c).resolvesAsItem(result) }
124+
}
125+
126+
private module QlCallGraph implements CompareSig<CallGraph> {
127+
private import codeql.rust.internal.PathResolution as PathResolution
128+
129+
predicate isResolvable(CallExprBase c) { exists(resolve(c)) }
130+
131+
Item resolve(CallExprBase c) { result = c.getStaticTarget() }
132+
}
133+
134+
module CallGraphCompare = Compare<CallGraph, RustAnalyzerCallGraph, QlCallGraph>;

0 commit comments

Comments
 (0)