Skip to content

Commit fd63348

Browse files
authored
Merge pull request github#11585 from jcogs33/jcogs33/mad-metrics-query
Java: add MaD metrics query
2 parents 801f4bc + 96a0950 commit fd63348

File tree

14 files changed

+182
-6
lines changed

14 files changed

+182
-6
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,15 @@ 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 has the given provenance where `true` is
250+
* `generated` and `false` is `manual`.
251+
*/
252+
predicate hasProvenance(boolean generated) { none() }
247253
}
248254

249255
/** A callable where there is no flow via the callable. */
@@ -1012,6 +1018,10 @@ module Private {
10121018
}
10131019

10141020
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1021+
1022+
override predicate hasProvenance(boolean generated) {
1023+
summaryElement(this, _, _, _, generated)
1024+
}
10151025
}
10161026

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

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,15 @@ 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 has the given provenance where `true` is
250+
* `generated` and `false` is `manual`.
251+
*/
252+
predicate hasProvenance(boolean generated) { none() }
247253
}
248254

249255
/** A callable where there is no flow via the callable. */
@@ -1012,6 +1018,10 @@ module Private {
10121018
}
10131019

10141020
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1021+
1022+
override predicate hasProvenance(boolean generated) {
1023+
summaryElement(this, _, _, _, generated)
1024+
}
10151025
}
10161026

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

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,15 @@ 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 has the given provenance where `true` is
250+
* `generated` and `false` is `manual`.
251+
*/
252+
predicate hasProvenance(boolean generated) { none() }
247253
}
248254

249255
/** A callable where there is no flow via the callable. */
@@ -1012,6 +1018,10 @@ module Private {
10121018
}
10131019

10141020
override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
1021+
1022+
override predicate hasProvenance(boolean generated) {
1023+
summaryElement(this, _, _, _, generated)
1024+
}
10151025
}
10161026

10171027
/** Holds if component `c` of specification `spec` cannot be parsed. */
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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
10+
import semmle.code.java.dataflow.FlowSummary
11+
import utils.modelgenerator.internal.CaptureModels
12+
13+
/**
14+
* Returns the number of `DataFlowTargetApi`s with Summary MaD models
15+
* for a given package and provenance.
16+
*/
17+
bindingset[package]
18+
private int getNumMadModeledApis(string package, string provenance) {
19+
provenance in ["generated", "manual", "both"] and
20+
result =
21+
count(SummarizedCallable sc |
22+
package = sc.asCallable().getCompilationUnit().getPackage().getName() and
23+
sc.asCallable() instanceof DataFlowTargetApi and
24+
(
25+
// "auto-only"
26+
sc.isAutoGenerated() and
27+
provenance = "generated"
28+
or
29+
// "manual-only"
30+
sc.hasProvenance(false) and
31+
not sc.hasProvenance(true) and
32+
provenance = "manual"
33+
or
34+
// "both"
35+
sc.hasProvenance(false) and
36+
sc.hasProvenance(true) and
37+
provenance = "both"
38+
)
39+
)
40+
}
41+
42+
/** Returns the total number of `DataFlowTargetApi`s for a given package. */
43+
private int getNumApis(string package) {
44+
result =
45+
strictcount(DataFlowTargetApi dataFlowTargApi |
46+
package = dataFlowTargApi.getCompilationUnit().getPackage().getName()
47+
)
48+
}
49+
50+
from
51+
string package, int generatedOnly, int both, int manualOnly, int generated, int manual, int non,
52+
int all, float coverage, float generatedCoverage, float manualCoverage,
53+
float manualCoveredByGenerated, float generatedCoveredByManual, float match
54+
where
55+
// count the number of APIs with generated-only, both, and manual-only MaD models for each package
56+
generatedOnly = getNumMadModeledApis(package, "generated") and
57+
both = getNumMadModeledApis(package, "both") and
58+
manualOnly = getNumMadModeledApis(package, "manual") and
59+
// calculate the total generated and total manual numbers
60+
generated = generatedOnly + both and
61+
manual = manualOnly + both and
62+
// count the total number of `DataFlowTargetApi`s for each package
63+
all = getNumApis(package) and
64+
non = all - (generatedOnly + both + manualOnly) and
65+
// Proportion of coverage
66+
coverage = (generatedOnly + both + manualOnly).(float) / all and
67+
generatedCoverage = generated.(float) / all and
68+
manualCoverage = manual.(float) / all and
69+
// Proportion of manual models covered by generated ones
70+
manualCoveredByGenerated = both.(float) / (both + manualOnly) and
71+
// Proportion of generated models covered by manual ones
72+
generatedCoveredByManual = both.(float) / (both + generatedOnly) and
73+
// Proportion of data points that match
74+
match = (both.(float) + non) / all
75+
select package, generatedOnly, both, manualOnly, non, all, coverage, generatedCoverage,
76+
manualCoverage, manualCoveredByGenerated, generatedCoveredByManual, match order by package
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: newQuery
3+
---
4+
* Added a new query, `java/summary/generated-vs-manual-coverage`, to expose metrics for the number of API endpoints covered by generated versus manual MaD models.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| org.apache.commons.io | 14 | 1 | 1 | 2 | 18 | 0.8888888888888888 | 0.8333333333333334 | 0.1111111111111111 | 0.5 | 0.06666666666666667 | 0.16666666666666666 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Metrics/Summaries/GeneratedVsManualCoverage.ql
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.apache.commons.io;
2+
import java.io.*;
3+
import java.util.*;
4+
5+
public class IOUtils {
6+
7+
// Generated-only summaries
8+
public static BufferedInputStream buffer(InputStream inputStream) { return null; }
9+
public static void copy(InputStream input, Writer output, String inputEncoding) throws IOException { }
10+
public static long copyLarge(Reader input, Writer output) throws IOException { return 42; }
11+
public static int read(InputStream input, byte[] buffer) throws IOException { return 42; }
12+
public static void readFully(InputStream input, byte[] buffer) throws IOException { }
13+
public static byte[] readFully(InputStream input, int length) throws IOException { return null; }
14+
public static List<String> readLines(InputStream input, String encoding) throws IOException { return null; }
15+
public static BufferedReader toBufferedReader(Reader reader) { return null; }
16+
public static byte[] toByteArray(InputStream input, int size) throws IOException { return null; }
17+
public static char[] toCharArray(InputStream is, String encoding) throws IOException { return null; }
18+
public static InputStream toInputStream(String input, String encoding) throws IOException { return null; }
19+
public static String toString(InputStream input, String encoding) throws IOException { return null; }
20+
public static void write(char[] data, Writer output) throws IOException { }
21+
public static void writeChunked(char[] data, Writer output) throws IOException { }
22+
23+
// Manual-only summary (generated neutral)
24+
public static InputStream toBufferedInputStream(InputStream input) throws IOException { return null; }
25+
26+
// Both
27+
public static void writeLines(Collection<?> lines, String lineEnding, Writer writer) throws IOException { }
28+
29+
// No model
30+
public static void noSummary(String string) throws IOException { }
31+
32+
// Generated neutral
33+
public static void copy(Reader input, OutputStream output) throws IOException { }
34+
}

0 commit comments

Comments
 (0)