From 89502d63e530542c38de4a8694736270ee2baf7f Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 6 Feb 2025 10:46:25 +0100 Subject: [PATCH 1/2] Rust: Implement database quality telemetry query --- csharp/ql/src/Telemetry/DatabaseQuality.qll | 28 +------- java/ql/src/Telemetry/DatabaseQuality.qll | 28 +------- .../src/queries/telemetry/DatabaseQuality.qll | 46 +++++++++++++ .../telemetry/DatabaseQualityDiagnostics.ql | 41 ++++++++++++ .../queries/telemetry/ExtractorInformation.ql | 65 +++++++++++++++++++ shared/util/codeql/util/ReportStats.qll | 31 +++++++++ 6 files changed, 185 insertions(+), 54 deletions(-) create mode 100644 rust/ql/src/queries/telemetry/DatabaseQuality.qll create mode 100644 rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql create mode 100644 rust/ql/src/queries/telemetry/ExtractorInformation.ql create mode 100644 shared/util/codeql/util/ReportStats.qll diff --git a/csharp/ql/src/Telemetry/DatabaseQuality.qll b/csharp/ql/src/Telemetry/DatabaseQuality.qll index eba5ebb52114..fa6c70dbc51f 100644 --- a/csharp/ql/src/Telemetry/DatabaseQuality.qll +++ b/csharp/ql/src/Telemetry/DatabaseQuality.qll @@ -4,33 +4,7 @@ */ import csharp - -signature module StatsSig { - int getNumberOfOk(); - - int getNumberOfNotOk(); - - string getOkText(); - - string getNotOkText(); -} - -module ReportStats { - predicate numberOfOk(string key, int value) { - value = Stats::getNumberOfOk() and - key = "Number of " + Stats::getOkText() - } - - predicate numberOfNotOk(string key, int value) { - value = Stats::getNumberOfNotOk() and - key = "Number of " + Stats::getNotOkText() - } - - predicate percentageOfOk(string key, float value) { - value = Stats::getNumberOfOk() * 100.0 / (Stats::getNumberOfOk() + Stats::getNumberOfNotOk()) and - key = "Percentage of " + Stats::getOkText() - } -} +import codeql.util.ReportStats module CallTargetStats implements StatsSig { int getNumberOfOk() { result = count(Call c | exists(c.getTarget())) } diff --git a/java/ql/src/Telemetry/DatabaseQuality.qll b/java/ql/src/Telemetry/DatabaseQuality.qll index 4cbdca0acba7..01ab8a1121d4 100644 --- a/java/ql/src/Telemetry/DatabaseQuality.qll +++ b/java/ql/src/Telemetry/DatabaseQuality.qll @@ -4,33 +4,7 @@ */ import java - -signature module StatsSig { - int getNumberOfOk(); - - int getNumberOfNotOk(); - - string getOkText(); - - string getNotOkText(); -} - -module ReportStats { - predicate numberOfOk(string key, int value) { - value = Stats::getNumberOfOk() and - key = "Number of " + Stats::getOkText() - } - - predicate numberOfNotOk(string key, int value) { - value = Stats::getNumberOfNotOk() and - key = "Number of " + Stats::getNotOkText() - } - - predicate percentageOfOk(string key, float value) { - value = Stats::getNumberOfOk() * 100.0 / (Stats::getNumberOfOk() + Stats::getNumberOfNotOk()) and - key = "Percentage of " + Stats::getOkText() - } -} +import codeql.util.ReportStats module CallTargetStats implements StatsSig { int getNumberOfOk() { result = count(Call c | exists(c.getCallee())) } diff --git a/rust/ql/src/queries/telemetry/DatabaseQuality.qll b/rust/ql/src/queries/telemetry/DatabaseQuality.qll new file mode 100644 index 000000000000..8a9898efc404 --- /dev/null +++ b/rust/ql/src/queries/telemetry/DatabaseQuality.qll @@ -0,0 +1,46 @@ +/** + * Provides database quality statistics that are reported by + * `rust/telemetry/extractor-information` + * and perhaps warned about by `rust/diagnostics/database-quality`. + */ + +import rust +import codeql.util.ReportStats + +module CallTargetStats implements StatsSig { + int getNumberOfOk() { result = count(CallExprBase c | exists(c.getStaticTarget())) } + + private predicate isLambdaCall(CallExpr call) { + exists(Expr receiver | receiver = call.getFunction() | + // All calls to complex expressions and local variable accesses are lambda calls + receiver instanceof PathExpr implies receiver = any(Variable v).getAnAccess() + ) + } + + additional predicate isNotOkCall(CallExprBase c) { + not exists(c.getStaticTarget()) and + not isLambdaCall(c) + } + + int getNumberOfNotOk() { result = count(CallExprBase c | isNotOkCall(c)) } + + string getOkText() { result = "calls with call target" } + + string getNotOkText() { result = "calls with missing call target" } +} + +module MacroCallTargetStats implements StatsSig { + int getNumberOfOk() { result = count(MacroCall c | c.hasExpanded()) } + + additional predicate isNotOkCall(MacroCall c) { not c.hasExpanded() } + + int getNumberOfNotOk() { result = count(MacroCall c | isNotOkCall(c)) } + + string getOkText() { result = "macro calls with call target" } + + string getNotOkText() { result = "macro calls with missing call target" } +} + +module CallTargetStatsReport = ReportStats; + +module MacroCallTargetStatsReport = ReportStats; diff --git a/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql b/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql new file mode 100644 index 000000000000..f7c150303a8a --- /dev/null +++ b/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql @@ -0,0 +1,41 @@ +/** + * @name Low Rust analysis quality + * @description Low Rust analysis quality + * @kind diagnostic + * @id rust/diagnostic/database-quality + */ + +import rust +import DatabaseQuality +import codeql.util.Unit + +class DbQualityDiagnostic extends Unit { + DbQualityDiagnostic() { + exists(float percentageGood | + CallTargetStatsReport::percentageOfOk(_, percentageGood) + or + MacroCallTargetStatsReport::percentageOfOk(_, percentageGood) + | + percentageGood < 95 + ) + } + + string toString() { + result = + "Scanning Rust code completed successfully, but the scan encountered issues. " + + "This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- " + + + "see other CodeQL diagnostics reported on the CodeQL status page for more details of possible causes. " + + "Addressing these warnings is advisable to avoid false-positive or missing results." + } +} + +query predicate diagnosticAttributes(DbQualityDiagnostic e, string key, string value) { + exists(e) and // Quieten warning about unconstrained 'e' + key = ["visibilityCliSummaryTable", "visibilityTelemetry", "visibilityStatusPage"] and + value = "true" +} + +from DbQualityDiagnostic d +select d, d.toString(), 1 +/* Warning severity */ diff --git a/rust/ql/src/queries/telemetry/ExtractorInformation.ql b/rust/ql/src/queries/telemetry/ExtractorInformation.ql new file mode 100644 index 000000000000..f61dfe515a9e --- /dev/null +++ b/rust/ql/src/queries/telemetry/ExtractorInformation.ql @@ -0,0 +1,65 @@ +/** + * @name Rust extraction information + * @description Information about the extraction for a Rust database + * @kind metric + * @tags summary telemetry + * @id rust/telemetry/extraction-information + */ + +import rust +import DatabaseQuality +import codeql.rust.Diagnostics + +predicate fileCount(string key, int value) { + key = "Number of files" and + value = strictcount(File f) +} + +predicate fileCountByExtension(string key, int value) { + exists(string extension | + key = "Number of files with extension " + extension and + value = strictcount(File f | f.getExtension() = extension) + ) +} + +predicate numberOfLinesOfCode(string key, int value) { + key = "Number of lines of code" and + value = strictsum(File f | any() | f.getNumberOfLinesOfCode()) +} + +predicate numberOfLinesOfCodeByExtension(string key, int value) { + exists(string extension | + key = "Number of lines of code with extension " + extension and + value = strictsum(File f | f.getExtension() = extension | f.getNumberOfLinesOfCode()) + ) +} + +predicate extractorDiagnostics(string key, int value) { + exists(int severity | + key = "Number of diagnostics with severity " + severity.toString() and + value = strictcount(Diagnostic d | d.getSeverity() = severity) + ) +} + +from string key, float value +where + ( + fileCount(key, value) or + fileCountByExtension(key, value) or + numberOfLinesOfCode(key, value) or + numberOfLinesOfCodeByExtension(key, value) or + extractorDiagnostics(key, value) or + CallTargetStatsReport::numberOfOk(key, value) or + CallTargetStatsReport::numberOfNotOk(key, value) or + CallTargetStatsReport::percentageOfOk(key, value) or + MacroCallTargetStatsReport::numberOfOk(key, value) or + MacroCallTargetStatsReport::numberOfNotOk(key, value) or + MacroCallTargetStatsReport::percentageOfOk(key, value) + ) and + /* Infinity */ + value != 1.0 / 0.0 and + /* -Infinity */ + value != -1.0 / 0.0 and + /* NaN */ + value != 0.0 / 0.0 +select key, value diff --git a/shared/util/codeql/util/ReportStats.qll b/shared/util/codeql/util/ReportStats.qll new file mode 100644 index 000000000000..03f381b5b9b3 --- /dev/null +++ b/shared/util/codeql/util/ReportStats.qll @@ -0,0 +1,31 @@ +/** + * Provides the `ReportStats` module for reporting database quality statistics. + */ +module; + +signature module StatsSig { + int getNumberOfOk(); + + int getNumberOfNotOk(); + + string getOkText(); + + string getNotOkText(); +} + +module ReportStats { + predicate numberOfOk(string key, int value) { + value = Stats::getNumberOfOk() and + key = "Number of " + Stats::getOkText() + } + + predicate numberOfNotOk(string key, int value) { + value = Stats::getNumberOfNotOk() and + key = "Number of " + Stats::getNotOkText() + } + + predicate percentageOfOk(string key, float value) { + value = Stats::getNumberOfOk() * 100.0 / (Stats::getNumberOfOk() + Stats::getNumberOfNotOk()) and + key = "Percentage of " + Stats::getOkText() + } +} From 11bf4c831d0622b5310294ed121308fddfbe7833 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 7 Feb 2025 13:55:11 +0100 Subject: [PATCH 2/2] Update rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql b/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql index f7c150303a8a..c5e3645e993e 100644 --- a/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql +++ b/rust/ql/src/queries/telemetry/DatabaseQualityDiagnostics.ql @@ -38,4 +38,4 @@ query predicate diagnosticAttributes(DbQualityDiagnostic e, string key, string v from DbQualityDiagnostic d select d, d.toString(), 1 -/* Warning severity */ +/* 1 = Warning severity */