Java: add diagnostic query indicating low database quality

This commit is contained in:
Chris Smowton
2024-06-21 17:00:14 +01:00
parent 6c727b1e7d
commit f397ab2d72
3 changed files with 106 additions and 59 deletions

View File

@@ -0,0 +1,65 @@
/**
* Provides database quality statistics that are reported by java/telemetry/extractor-information
* and perhaps warned about by java/diagnostics/database-quality.
*/
import java
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()
}
}
module CallTargetStats implements StatsSig {
int getNumberOfOk() { result = count(Call c | exists(c.getCallee())) }
int getNumberOfNotOk() { result = count(Call c | not exists(c.getCallee())) }
string getOkText() { result = "calls with call target" }
string getNotOkText() { result = "calls with missing call target" }
}
private class SourceExpr extends Expr {
SourceExpr() { this.getFile().isSourceFile() }
}
private predicate hasGoodType(Expr e) {
exists(e.getType()) and not e.getType() instanceof ErrorType
}
module ExprTypeStats implements StatsSig {
int getNumberOfOk() { result = count(SourceExpr e | hasGoodType(e)) }
int getNumberOfNotOk() { result = count(SourceExpr e | not hasGoodType(e)) }
string getOkText() { result = "expressions with known type" }
string getNotOkText() { result = "expressions with unknown type" }
}
module CallTargetStatsReport = ReportStats<CallTargetStats>;
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;

View File

@@ -0,0 +1,40 @@
/**
* @name Low Java analysis quality
* @description Low Java analysis quality
* @kind diagnostic
* @id java/diagnostic/database-quality
*/
import java
import DatabaseQuality
private newtype TDbQualityDiagnostic =
TTheDbQualityDiagnostic() {
exists(float percentageGood |
CallTargetStatsReport::percentageOfOk(_, percentageGood)
or
ExprTypeStatsReport::percentageOfOk(_, percentageGood)
|
percentageGood < 95
)
}
class DbQualityDiagnostic extends TDbQualityDiagnostic {
string toString() {
result =
"There were significant issues scanning Java code. " +
"This may be caused by problems identifying dependencies or use of generated source code, among other reasons -- "
+ "see other CodeQL diagnostics reported here for more details of possible causes. " +
"This may lead to false-positive or missing results. Consider analysing Java using the `autobuild` or `manual` build modes."
}
}
query predicate diagnosticAttributes(DbQualityDiagnostic e, string key, string value) {
e = e and // Quieten warning about unconstrained 'e'
key = ["visibilityCliSummaryTable", "visibilityTelemetry", "visibilityStatusPage"] and
value = "true"
}
from DbQualityDiagnostic d
select d, d.toString(), 1
/* Warning severity */

View File

@@ -8,6 +8,7 @@
import java
import semmle.code.java.Diagnostics
import DatabaseQuality
extensible predicate extractorInformationSkipKey(string key);
@@ -85,65 +86,6 @@ predicate extractorTotalDiagnostics(string key, int value) {
)
}
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()
}
}
module CallTargetStats implements StatsSig {
int getNumberOfOk() { result = count(Call c | exists(c.getCallee())) }
int getNumberOfNotOk() { result = count(Call c | not exists(c.getCallee())) }
string getOkText() { result = "calls with call target" }
string getNotOkText() { result = "calls with missing call target" }
}
private class SourceExpr extends Expr {
SourceExpr() { this.getFile().isSourceFile() }
}
private predicate hasGoodType(Expr e) {
exists(e.getType()) and not e.getType() instanceof ErrorType
}
module ExprTypeStats implements StatsSig {
int getNumberOfOk() { result = count(SourceExpr e | hasGoodType(e)) }
int getNumberOfNotOk() { result = count(SourceExpr e | not hasGoodType(e)) }
string getOkText() { result = "expressions with known type" }
string getNotOkText() { result = "expressions with unknown type" }
}
module CallTargetStatsReport = ReportStats<CallTargetStats>;
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;
from string key, int value
where
not exists(string pattern | extractorInformationSkipKey(pattern) and key.matches(pattern)) and