Skip to content

Commit b82f9b1

Browse files
Jami CogswellJami Cogswell
authored andcommitted
Java: add draft of generated vs manual MaD metrics query
1 parent 5d43c43 commit b82f9b1

File tree

7 files changed

+286
-6
lines changed

7 files changed

+286
-6
lines changed

csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,19 @@ module Public {
241241
}
242242

243243
/**
244-
* Holds if the summary is auto generated.
244+
* Holds if the summary is auto generated and not manually generated.
245245
*/
246246
predicate isAutoGenerated() { none() }
247+
248+
/**
249+
* Holds if the summary is manually generated and not auto generated.
250+
*/
251+
predicate isManuallyGenerated() { none() }
252+
253+
/**
254+
* Holds if the summary is both auto generated and manually generated.
255+
*/
256+
predicate isBothAutoAndManuallyGenerated() { none() }
247257
}
248258

249259
/** A callable with a flow summary stating there is no flow via the callable. */
@@ -991,6 +1001,20 @@ module Private {
9911001
not summaryElement(this, _, _, _, false)
9921002
}
9931003

1004+
private predicate relevantSummaryElementManual(
1005+
AccessPath inSpec, AccessPath outSpec, string kind
1006+
) {
1007+
summaryElement(this, inSpec, outSpec, kind, false) and
1008+
not summaryElement(this, _, _, _, true)
1009+
}
1010+
1011+
private predicate relevantSummaryElementBothGeneratedAndManual(
1012+
AccessPath inSpec, AccessPath outSpec, string kind
1013+
) {
1014+
summaryElement(this, inSpec, outSpec, kind, true) and
1015+
summaryElement(this, inSpec, outSpec, kind, false)
1016+
}
1017+
9941018
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
9951019
summaryElement(this, inSpec, outSpec, kind, false)
9961020
or
@@ -1012,6 +1036,12 @@ module Private {
10121036
}
10131037

10141038
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1039+
1040+
override predicate isManuallyGenerated() { this.relevantSummaryElementManual(_, _, _) }
1041+
1042+
override predicate isBothAutoAndManuallyGenerated() {
1043+
this.relevantSummaryElementBothGeneratedAndManual(_, _, _)
1044+
}
10151045
}
10161046

10171047
/** Holds if component `c` of specification `spec` cannot be parsed. */

go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,19 @@ module Public {
241241
}
242242

243243
/**
244-
* Holds if the summary is auto generated.
244+
* Holds if the summary is auto generated and not manually generated.
245245
*/
246246
predicate isAutoGenerated() { none() }
247+
248+
/**
249+
* Holds if the summary is manually generated and not auto generated.
250+
*/
251+
predicate isManuallyGenerated() { none() }
252+
253+
/**
254+
* Holds if the summary is both auto generated and manually generated.
255+
*/
256+
predicate isBothAutoAndManuallyGenerated() { none() }
247257
}
248258

249259
/** A callable with a flow summary stating there is no flow via the callable. */
@@ -991,6 +1001,20 @@ module Private {
9911001
not summaryElement(this, _, _, _, false)
9921002
}
9931003

1004+
private predicate relevantSummaryElementManual(
1005+
AccessPath inSpec, AccessPath outSpec, string kind
1006+
) {
1007+
summaryElement(this, inSpec, outSpec, kind, false) and
1008+
not summaryElement(this, _, _, _, true)
1009+
}
1010+
1011+
private predicate relevantSummaryElementBothGeneratedAndManual(
1012+
AccessPath inSpec, AccessPath outSpec, string kind
1013+
) {
1014+
summaryElement(this, inSpec, outSpec, kind, true) and
1015+
summaryElement(this, inSpec, outSpec, kind, false)
1016+
}
1017+
9941018
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
9951019
summaryElement(this, inSpec, outSpec, kind, false)
9961020
or
@@ -1012,6 +1036,12 @@ module Private {
10121036
}
10131037

10141038
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1039+
1040+
override predicate isManuallyGenerated() { this.relevantSummaryElementManual(_, _, _) }
1041+
1042+
override predicate isBothAutoAndManuallyGenerated() {
1043+
this.relevantSummaryElementBothGeneratedAndManual(_, _, _)
1044+
}
10151045
}
10161046

10171047
/** Holds if component `c` of specification `spec` cannot be parsed. */

java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,19 @@ module Public {
241241
}
242242

243243
/**
244-
* Holds if the summary is auto generated.
244+
* Holds if the summary is auto generated and not manually generated.
245245
*/
246246
predicate isAutoGenerated() { none() }
247+
248+
/**
249+
* Holds if the summary is manually generated and not auto generated.
250+
*/
251+
predicate isManuallyGenerated() { none() }
252+
253+
/**
254+
* Holds if the summary is both auto generated and manually generated.
255+
*/
256+
predicate isBothAutoAndManuallyGenerated() { none() }
247257
}
248258

249259
/** A callable with a flow summary stating there is no flow via the callable. */
@@ -991,6 +1001,20 @@ module Private {
9911001
not summaryElement(this, _, _, _, false)
9921002
}
9931003

1004+
private predicate relevantSummaryElementManual(
1005+
AccessPath inSpec, AccessPath outSpec, string kind
1006+
) {
1007+
summaryElement(this, inSpec, outSpec, kind, false) and
1008+
not summaryElement(this, _, _, _, true)
1009+
}
1010+
1011+
private predicate relevantSummaryElementBothGeneratedAndManual(
1012+
AccessPath inSpec, AccessPath outSpec, string kind
1013+
) {
1014+
summaryElement(this, inSpec, outSpec, kind, true) and
1015+
summaryElement(this, inSpec, outSpec, kind, false)
1016+
}
1017+
9941018
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
9951019
summaryElement(this, inSpec, outSpec, kind, false)
9961020
or
@@ -1012,6 +1036,12 @@ module Private {
10121036
}
10131037

10141038
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1039+
1040+
override predicate isManuallyGenerated() { this.relevantSummaryElementManual(_, _, _) }
1041+
1042+
override predicate isBothAutoAndManuallyGenerated() {
1043+
this.relevantSummaryElementBothGeneratedAndManual(_, _, _)
1044+
}
10151045
}
10161046

10171047
/** Holds if component `c` of specification `spec` cannot be parsed. */
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* @id java/summary/generated-vs-manual-coverage
3+
* @name Metrics of generated versus manual MaD coverage
4+
* @description Expose metrics for the number of API endpoints covered by generated versus manual MaD models.
5+
* @kind table
6+
* @tags summary
7+
*/
8+
9+
//import java // not needed I guess
10+
import semmle.code.java.dataflow.FlowSummary // for SummarizedCallable
11+
import utils.modelgenerator.internal.CaptureModels // for DataFlowTargetApi
12+
13+
// ! improve QLDoc?
14+
/**
15+
* A callable for a given library that is modeled by MaD.
16+
* Specifically, this callable is the intersection of
17+
* DataFlowTargetApis and SummarizedCallables.
18+
*/
19+
class MadModeledCallable extends SummarizedCallableBase {
20+
// ! better name for this class?
21+
MadModeledCallable() {
22+
this instanceof SummarizedCallable and
23+
exists(DataFlowTargetApi dataFlowTargApi |
24+
this.asCallable() = dataFlowTargApi and
25+
not exists(FunctionalExpr funcExpr | dataFlowTargApi = funcExpr.asMethod()) // ! remove this if DataFlowTargetApi itself is adjusted to exclude FunctionalExpr (see static-team slack thread)
26+
)
27+
}
28+
}
29+
30+
// ! move to other file
31+
/**
32+
* Returns the number of APIs with MaD models
33+
* for a given package and provenance.
34+
*/
35+
float getNumMadModels(string package, string provenance) {
36+
exists(MadModeledCallable mc |
37+
package = mc.asCallable().getDeclaringType().getPackage().toString() and
38+
provenance in ["generated", "manual", "both"]
39+
|
40+
result =
41+
count(MadModeledCallable c |
42+
package = c.asCallable().getDeclaringType().getPackage().toString() and
43+
(
44+
c.(SummarizedCallable).isAutoGenerated() and // generated and NOT manual = "auto-only"
45+
provenance = "generated"
46+
or
47+
c.(SummarizedCallable).isManuallyGenerated() and // manual and NOT generated = "manual-only"
48+
provenance = "manual"
49+
or
50+
c.(SummarizedCallable).isBothAutoAndManuallyGenerated() and // BOTH generated and manual = "both"
51+
provenance = "both"
52+
)
53+
)
54+
)
55+
}
56+
57+
// ! move to other file
58+
/**
59+
* Returns the number of APIs without MaD
60+
* models for a given package.
61+
*/
62+
float getNumApisWithoutMadModel(string package) {
63+
exists(DataFlowTargetApi dataFlowTargApi |
64+
package = dataFlowTargApi.getDeclaringType().getPackage().toString() and
65+
not exists(FunctionalExpr fe | dataFlowTargApi = fe.asMethod()) // remove lambdas // ! remove this if DataFlowTargetApi itself is adjusted to exclude FunctionalExpr (see static-team slack thread)
66+
|
67+
result =
68+
count(DataFlowTargetApi d |
69+
package = d.getDeclaringType().getPackage().toString() and
70+
not exists(FunctionalExpr funcExpr | d = funcExpr.asMethod()) and // remove lambdas // ! remove this if DataFlowTargetApi itself is adjusted to exclude FunctionalExpr (see static-team slack thread)
71+
not exists(SummarizedCallable sc | d = sc.asCallable()) // set minus with SummarizedCallables
72+
)
73+
)
74+
}
75+
76+
// ! Note: adjust metric formulas as needed after more discussion with Yorck
77+
/*
78+
* metric1:
79+
* Proportion of manual models covered by automation: “both” / (“both” + “manual-only”)
80+
* Auto-generated vs all positive manual (percentage of manual models covered by auto-generation)
81+
*/
82+
83+
/*
84+
* metric2:
85+
* Coverage relative to total number of APIs: (“auto-only” + “both” + “manual-only”) / “all”
86+
* Auto-generated vs specific pos+neg subset (top-N manual, random)
87+
*/
88+
89+
from
90+
string package, float generated, float manual, float both, float notModeled, float all,
91+
float metric1, float metric2
92+
where
93+
generated = getNumMadModels(package, "generated") and
94+
manual = getNumMadModels(package, "manual") and
95+
both = getNumMadModels(package, "both") and
96+
notModeled = getNumApisWithoutMadModel(package) and // ! better name for this?, "none" is a reserved keyword :(
97+
all = generated + manual + both + notModeled and
98+
metric1 = (both / (both + manual)) and
99+
metric2 = (generated + both + manual) / all
100+
select package, generated, manual, both, notModeled, all, metric1, metric2 order by package

python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,19 @@ module Public {
241241
}
242242

243243
/**
244-
* Holds if the summary is auto generated.
244+
* Holds if the summary is auto generated and not manually generated.
245245
*/
246246
predicate isAutoGenerated() { none() }
247+
248+
/**
249+
* Holds if the summary is manually generated and not auto generated.
250+
*/
251+
predicate isManuallyGenerated() { none() }
252+
253+
/**
254+
* Holds if the summary is both auto generated and manually generated.
255+
*/
256+
predicate isBothAutoAndManuallyGenerated() { none() }
247257
}
248258

249259
/** A callable with a flow summary stating there is no flow via the callable. */
@@ -991,6 +1001,20 @@ module Private {
9911001
not summaryElement(this, _, _, _, false)
9921002
}
9931003

1004+
private predicate relevantSummaryElementManual(
1005+
AccessPath inSpec, AccessPath outSpec, string kind
1006+
) {
1007+
summaryElement(this, inSpec, outSpec, kind, false) and
1008+
not summaryElement(this, _, _, _, true)
1009+
}
1010+
1011+
private predicate relevantSummaryElementBothGeneratedAndManual(
1012+
AccessPath inSpec, AccessPath outSpec, string kind
1013+
) {
1014+
summaryElement(this, inSpec, outSpec, kind, true) and
1015+
summaryElement(this, inSpec, outSpec, kind, false)
1016+
}
1017+
9941018
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
9951019
summaryElement(this, inSpec, outSpec, kind, false)
9961020
or
@@ -1012,6 +1036,12 @@ module Private {
10121036
}
10131037

10141038
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1039+
1040+
override predicate isManuallyGenerated() { this.relevantSummaryElementManual(_, _, _) }
1041+
1042+
override predicate isBothAutoAndManuallyGenerated() {
1043+
this.relevantSummaryElementBothGeneratedAndManual(_, _, _)
1044+
}
10151045
}
10161046

10171047
/** Holds if component `c` of specification `spec` cannot be parsed. */

ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,19 @@ module Public {
241241
}
242242

243243
/**
244-
* Holds if the summary is auto generated.
244+
* Holds if the summary is auto generated and not manually generated.
245245
*/
246246
predicate isAutoGenerated() { none() }
247+
248+
/**
249+
* Holds if the summary is manually generated and not auto generated.
250+
*/
251+
predicate isManuallyGenerated() { none() }
252+
253+
/**
254+
* Holds if the summary is both auto generated and manually generated.
255+
*/
256+
predicate isBothAutoAndManuallyGenerated() { none() }
247257
}
248258

249259
/** A callable with a flow summary stating there is no flow via the callable. */
@@ -991,6 +1001,20 @@ module Private {
9911001
not summaryElement(this, _, _, _, false)
9921002
}
9931003

1004+
private predicate relevantSummaryElementManual(
1005+
AccessPath inSpec, AccessPath outSpec, string kind
1006+
) {
1007+
summaryElement(this, inSpec, outSpec, kind, false) and
1008+
not summaryElement(this, _, _, _, true)
1009+
}
1010+
1011+
private predicate relevantSummaryElementBothGeneratedAndManual(
1012+
AccessPath inSpec, AccessPath outSpec, string kind
1013+
) {
1014+
summaryElement(this, inSpec, outSpec, kind, true) and
1015+
summaryElement(this, inSpec, outSpec, kind, false)
1016+
}
1017+
9941018
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
9951019
summaryElement(this, inSpec, outSpec, kind, false)
9961020
or
@@ -1012,6 +1036,12 @@ module Private {
10121036
}
10131037

10141038
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1039+
1040+
override predicate isManuallyGenerated() { this.relevantSummaryElementManual(_, _, _) }
1041+
1042+
override predicate isBothAutoAndManuallyGenerated() {
1043+
this.relevantSummaryElementBothGeneratedAndManual(_, _, _)
1044+
}
10151045
}
10161046

10171047
/** Holds if component `c` of specification `spec` cannot be parsed. */

0 commit comments

Comments
 (0)