Files
codeql/java/ql/src/Metrics/Summaries/GeneratedVsManualCoverageQuery.qll
Tom Hvitved 7024b07dd2 Java: Adapt to changes in FlowSummaryImpl
Missing manual models were added using the following code added to `FlowSummaryImpl.qll`:

```ql
    private predicate testsummaryElement(
      Input::SummarizedCallableBase c, string namespace, string type, boolean subtypes, string name,
      string signature, string ext, string originalInput, string originalOutput, string kind,
      string provenance, string model, boolean isExact
    ) {
      exists(string input, string output, Callable baseCallable |
        summaryModel(namespace, type, subtypes, name, signature, ext, originalInput, originalOutput,
          kind, provenance, model) and
        baseCallable = interpretElement(namespace, type, subtypes, name, signature, ext, isExact) and
        (
          c.asCallable() = baseCallable and input = originalInput and output = originalOutput
          or
          correspondingKotlinParameterDefaultsArgSpec(baseCallable, c.asCallable(), originalInput,
            input) and
          correspondingKotlinParameterDefaultsArgSpec(baseCallable, c.asCallable(), originalOutput,
            output)
        )
      )
    }

    private predicate testsummaryElement2(
      string namespace, string type, boolean subtypes, string name, string signature, string ext,
      string originalInput, string originalOutput, string kind, string provenance, string model,
      string namespace2, string type2
    ) {
      exists(Input::SummarizedCallableBase c |
        testsummaryElement(c, namespace2, type2, _, _, _, ext, originalInput, originalOutput, kind,
          provenance, model, false) and
        testsummaryElement(c, namespace, type, subtypes, name, _, _, _, _, _, provenance, _, true) and
        signature = paramsString(c.asCallable()) and
        not testsummaryElement(c, _, _, _, _, _, _, originalInput, originalOutput, kind, provenance,
          _, true)
      )
    }

    private string getAMissingManualModel(string namespace2, string type2) {
      exists(
        string namespace, string type, boolean subtypes, string name, string signature, string ext,
        string originalInput, string originalOutput, string kind, string provenance, string model
      |
        testsummaryElement2(namespace, type, subtypes, name, signature, ext, originalInput,
          originalOutput, kind, provenance, model, namespace2, type2) and
        result =
          "- [\"" + namespace + "\", \"" + type + "\", True, \"" + name + "\", \"" + signature +
            "\", \"\", \"" + originalInput + "\", \"" + originalOutput + "\", \"" + kind + "\", \"" +
            provenance + "\"]"
      )
    }
```
2026-01-26 12:40:15 +01:00

86 lines
3.2 KiB
Plaintext

private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.internal.ModelExclusions
private import TopJdkApis
/**
* Returns the number of `ModelApi`s with Summary MaD models
* for a given package and provenance.
*/
bindingset[package, apiSubset]
private int getNumMadModeledApis(string package, string provenance, string apiSubset) {
provenance in ["generated", "manual", "both"] and
result =
count(SummarizedCallable::Range sc |
callableSubset(sc.asCallable(), apiSubset) and
package = sc.asCallable().getCompilationUnit().getPackage().getName() and
sc.asCallable() instanceof ModelApi and
(
// "auto-only"
not sc.hasManualModel() and
any(Provenance p | sc.propagatesFlow(_, _, _, p, _, _)).isGenerated() and
provenance = "generated"
or
sc.hasManualModel() and
(
if any(Provenance p | sc.propagatesFlow(_, _, _, p, _, _)).isGenerated()
then
// "both"
provenance = "both"
else
// "manual-only"
provenance = "manual"
)
)
)
}
/** Returns the total number of `ModelApi`s for a given package. */
private int getNumApis(string package, string apiSubset) {
result =
strictcount(ModelApi api |
callableSubset(api, apiSubset) and
package = api.getCompilationUnit().getPackage().getName()
)
}
/** Holds if the given `callable` belongs to the specified `apiSubset`. */
private predicate callableSubset(Callable callable, string apiSubset) {
apiSubset = "topJdkApis" and
callable instanceof TopJdkApi
or
apiSubset = "allApis"
}
/**
* Provides MaD summary model coverage information for the given `package`
* on the given `apiSubset`.
*/
predicate modelCoverageGenVsMan(
string package, int generatedOnly, int both, int manualOnly, int non, int all, float coverage,
float generatedCoverage, float manualCoverage, float manualCoveredByGenerated,
float generatedCoveredByManual, float match, string apiSubset
) {
exists(int generated, int manual |
// count the number of APIs with generated-only, both, and manual-only MaD models for each package
generatedOnly = getNumMadModeledApis(package, "generated", apiSubset) and
both = getNumMadModeledApis(package, "both", apiSubset) and
manualOnly = getNumMadModeledApis(package, "manual", apiSubset) and
// calculate the total generated and total manual numbers
generated = generatedOnly + both and
manual = manualOnly + both and
// count the total number of `ModelApi`s for each package
all = getNumApis(package, apiSubset) and
non = all - (generatedOnly + both + manualOnly) and
// Proportion of coverage
coverage = (generatedOnly + both + manualOnly).(float) / all and
generatedCoverage = generated.(float) / all and
manualCoverage = manual.(float) / all and
// Proportion of manual models covered by generated ones
manualCoveredByGenerated = both.(float) / (both + manualOnly) and
// Proportion of generated models covered by manual ones
generatedCoveredByManual = both.(float) / (both + generatedOnly) and
// Proportion of data points that match
match = (both.(float) + non) / all
)
}