diff --git a/rust/ql/src/queries/telemetry/ExtractorInformation.ql b/rust/ql/src/queries/telemetry/ExtractorInformation.ql index f61dfe515a9e..d47dc04ace73 100644 --- a/rust/ql/src/queries/telemetry/ExtractorInformation.ql +++ b/rust/ql/src/queries/telemetry/ExtractorInformation.ql @@ -8,6 +8,7 @@ import rust import DatabaseQuality +import RustAnalyzerComparison import codeql.rust.Diagnostics predicate fileCount(string key, int value) { @@ -41,6 +42,20 @@ predicate extractorDiagnostics(string key, int value) { ) } +predicate pathResolutionCompare(string key, int value) { + exists(string suffix | + PathResolutionCompare::summary(suffix, value) and + key = "Rust-analyzer path resolution comparison: " + suffix + ) +} + +predicate callGraphCompare(string key, int value) { + exists(string suffix | + CallGraphCompare::summary(suffix, value) and + key = "Rust-analyzer call graph comparison: " + suffix + ) +} + from string key, float value where ( @@ -54,7 +69,9 @@ where CallTargetStatsReport::percentageOfOk(key, value) or MacroCallTargetStatsReport::numberOfOk(key, value) or MacroCallTargetStatsReport::numberOfNotOk(key, value) or - MacroCallTargetStatsReport::percentageOfOk(key, value) + MacroCallTargetStatsReport::percentageOfOk(key, value) or + pathResolutionCompare(key, value) or + callGraphCompare(key, value) ) and /* Infinity */ value != 1.0 / 0.0 and diff --git a/rust/ql/src/queries/telemetry/RustAnalyzerComparison.qll b/rust/ql/src/queries/telemetry/RustAnalyzerComparison.qll new file mode 100644 index 000000000000..8abbc78bca79 --- /dev/null +++ b/rust/ql/src/queries/telemetry/RustAnalyzerComparison.qll @@ -0,0 +1,134 @@ +/** + * INTERNAL: Do not use. + * + * Provides functionality for comparing data from `rust-analyzer` with data computed + * in QL. + */ + +import rust + +private signature module ResolvableSig { + class Source { + string toString(); + + Location getLocation(); + } + + class Target { + string toString(); + + Location getLocation(); + } +} + +private signature module CompareSig { + predicate isResolvable(R::Source s); + + R::Target resolve(R::Source s); +} + +private module Compare RustAnalyzer, CompareSig Ql> { + private import R + + predicate same(Source s, Target t) { + t = RustAnalyzer::resolve(s) and + t = Ql::resolve(s) + } + + predicate sameCount(int c) { c = count(Source s | same(s, _)) } + + predicate diff(Source s, Target t1, Target t2) { + t1 = RustAnalyzer::resolve(s) and + t2 = Ql::resolve(s) and + t1 != t2 + } + + predicate diffCount(int c) { c = count(Source s | not same(s, _) and diff(s, _, _)) } + + predicate rustAnalyzerUnique(Source s) { + RustAnalyzer::isResolvable(s) and + not Ql::isResolvable(s) + } + + predicate rustAnalyzerUniqueCount(int c) { c = count(Source s | rustAnalyzerUnique(s)) } + + predicate qlUnique(Source s) { + not RustAnalyzer::isResolvable(s) and + Ql::isResolvable(s) + } + + predicate qlUniqueCount(int c) { c = count(Source s | qlUnique(s)) } + + predicate summary(string key, int value) { + key = "rust-analyzer unique" and rustAnalyzerUniqueCount(value) + or + key = "QL unique" and qlUniqueCount(value) + or + key = "same" and sameCount(value) + or + key = "different" and diffCount(value) + } +} + +private module PathResolution implements ResolvableSig { + class Source extends Resolvable { + Source() { not this instanceof MethodCallExpr } + } + + class Target = Item; +} + +private module RustAnalyzerPathResolution implements CompareSig { + predicate isResolvable(PathResolution::Source s) { s.hasResolvedPath() } + + Item resolve(PathResolution::Source s) { s.resolvesAsItem(result) } +} + +private module QlPathResolution implements CompareSig { + private import codeql.rust.internal.PathResolution + + private Path getPath(Resolvable r) { + result = r.(PathExpr).getPath() + or + result = r.(RecordExpr).getPath() + or + result = r.(PathPat).getPath() + or + result = r.(RecordPat).getPath() + or + result = r.(TupleStructPat).getPath() + } + + predicate isResolvable(PathResolution::Source s) { exists(resolve(s)) } + + Item resolve(PathResolution::Source s) { result = resolvePath(getPath(s)) } +} + +module PathResolutionCompare = + Compare; + +private module CallGraph implements ResolvableSig { + class Source = CallExprBase; + + class Target = Item; +} + +private module RustAnalyzerCallGraph implements CompareSig { + private import codeql.rust.elements.internal.CallExprBaseImpl::Impl as CallExprBaseImpl + + predicate isResolvable(CallExprBase c) { + CallExprBaseImpl::getCallResolvable(c).hasResolvedPath() + } + + Item resolve(CallExprBase c) { CallExprBaseImpl::getCallResolvable(c).resolvesAsItem(result) } +} + +private module QlCallGraph implements CompareSig { + private import codeql.rust.internal.PathResolution as PathResolution + + predicate isResolvable(CallExprBase c) { exists(resolve(c)) } + + Item resolve(CallExprBase c) { result = c.getStaticTarget() } +} + +module CallGraphCompare = Compare;