Skip to content

Commit f8c03dc

Browse files
authored
Merge pull request github#3924 from RasmusWL/python-metrics-queries-for-dist-compare
Approved by tausbn
2 parents ee13e87 + ee42d08 commit f8c03dc

File tree

6 files changed

+148
-0
lines changed

6 files changed

+148
-0
lines changed

python/ql/src/meta/MetaMetrics.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Helpers for generating meta metrics, that is, metrics about the CodeQL analysis and extractor.
3+
*/
4+
5+
import python
6+
private import semmle.python.filters.GeneratedCode
7+
private import semmle.python.filters.Tests
8+
9+
/**
10+
* Gets the root folder of the snapshot.
11+
*
12+
* This is selected as the location for project-wide metrics.
13+
*/
14+
Folder projectRoot() { result.getRelativePath() = "" }
15+
16+
/** A file we ignore because it is a test file, part of a third-party library, or compiled/generated/bundled code. */
17+
class IgnoredFile extends File {
18+
IgnoredFile() {
19+
any(TestScope ts).getLocation().getFile() = this
20+
or
21+
this instanceof GeneratedFile
22+
or
23+
// outside source root (inspired by `Scope.inSource`)
24+
not exists(this.getRelativePath())
25+
}
26+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Provides predicates for measuring the quality of the call graph, that is,
3+
* the number of calls that could be resolved to a callee.
4+
*/
5+
6+
import python
7+
import meta.MetaMetrics
8+
9+
/**
10+
* A call that is (possibly) relevant for analysis quality.
11+
* See `IgnoredFile` for details on what is excluded.
12+
*/
13+
class RelevantCall extends Call {
14+
RelevantCall() { not this.getLocation().getFile() instanceof IgnoredFile }
15+
}
16+
17+
/** Provides classes for call-graph resolution by using points-to. */
18+
module PointsToBasedCallGraph {
19+
/** A call that can be resolved by points-to. */
20+
class ResolvableCall extends RelevantCall {
21+
Value callee;
22+
23+
ResolvableCall() { callee.getACall() = this.getAFlowNode() }
24+
25+
/** Gets a resolved callee of this call. */
26+
Value getCallee() { result = callee }
27+
}
28+
29+
/** A call that cannot be resolved by points-to. */
30+
class UnresolvableCall extends RelevantCall {
31+
UnresolvableCall() { not this instanceof ResolvableCall }
32+
}
33+
34+
/**
35+
* A call that can be resolved by points-to, where the resolved callee is relevant.
36+
* Relevant callees include:
37+
* - builtins
38+
* - standard library
39+
* - source code of the project
40+
*/
41+
class ResolvableCallRelevantCallee extends ResolvableCall {
42+
ResolvableCallRelevantCallee() {
43+
callee.isBuiltin()
44+
or
45+
exists(File file |
46+
file = callee.(CallableValue).getScope().getLocation().getFile()
47+
or
48+
file = callee.(ClassValue).getScope().getLocation().getFile()
49+
|
50+
file.inStdlib()
51+
or
52+
// part of the source code of the project
53+
exists(file.getRelativePath())
54+
)
55+
}
56+
}
57+
58+
/**
59+
* A call that can be resolved by points-to, where the resolved callee is not considered relevant.
60+
* See `ResolvableCallRelevantCallee` for the definition of relevance.
61+
*/
62+
class ResolvableCallIrrelevantCallee extends ResolvableCall {
63+
ResolvableCallIrrelevantCallee() { not this instanceof ResolvableCallRelevantCallee }
64+
}
65+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* @name Ratio of resolvable call by points-to
3+
* @description The percentage of (relevant) calls that can be resolved to a callee.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum min max avg
7+
* @tags meta
8+
* @id py/meta/points-to-resolvable-call-ratio
9+
*/
10+
11+
import python
12+
import CallGraphQuality
13+
14+
select projectRoot(),
15+
100.0 * count(PointsToBasedCallGraph::ResolvableCall call) / count(RelevantCall call).(float)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @name Resolvable calls by points-to
3+
* @description The number of (relevant) calls that can be resolved to a callee.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id py/meta/points-to-resolvable-calls
9+
*/
10+
11+
import python
12+
import CallGraphQuality
13+
14+
select projectRoot(), count(PointsToBasedCallGraph::ResolvableCall call)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @name Resolvable calls by points-to, to relevant callee
3+
* @description The number of (relevant) calls that could be resolved to a callee that is relevant.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id py/meta/points-to-resolvable-calls-relevant-callee
9+
*/
10+
11+
import python
12+
import CallGraphQuality
13+
14+
select projectRoot(), count(PointsToBasedCallGraph::ResolvableCallRelevantCallee call)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @name Resolvable call candidates
3+
* @description The number of (relevant) calls in the program.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id py/meta/resolvable-call-candidates
9+
*/
10+
11+
import python
12+
import CallGraphQuality
13+
14+
select projectRoot(), count(RelevantCall call)

0 commit comments

Comments
 (0)