-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Rust: Implement database quality telemetry query #18697
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<CallTargetStats>; | ||
|
||
module MacroCallTargetStatsReport = ReportStats<MacroCallTargetStats>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
/* 1 = Warning severity */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's quite a bit of overlap with |
||
/* Infinity */ | ||
value != 1.0 / 0.0 and | ||
/* -Infinity */ | ||
value != -1.0 / 0.0 and | ||
/* NaN */ | ||
value != 0.0 / 0.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is hurting my maths brain, but it does seem to be the way |
||
select key, value |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<StatsSig Stats> { | ||
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() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have a
rust/ql/src/queries/diagnostics
andrust/ql/src/queries/summary
directory and this introducesrust/ql/src/queries/telemetry
as well. Are the new queries meaningfully different enough to justify a third location or should we condense back down to (any) two of them?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simply followed the same structure that we have for Java and C#.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll look into whether I can combine any of these directories after this PR is merged. Don't really want a proliferation of folders unless they're meaningfully different.