Skip to content

Commit 7fd4d19

Browse files
committed
JS: Add metric for uncalled functions
1 parent 298aa92 commit 7fd4d19

File tree

5 files changed

+102
-1
lines changed

5 files changed

+102
-1
lines changed

javascript/ql/src/meta/analysis-quality/CallGraphQuality.qll

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ class RelevantInvoke extends InvokeNode {
4040
RelevantInvoke() { not getFile() instanceof IgnoredFile }
4141
}
4242

43+
/** An call site that is relevant for analysis quality. */
44+
class RelevantFunction extends Function {
45+
RelevantFunction() {
46+
not getFile() instanceof IgnoredFile and
47+
hasBody() // ignore abstract or ambient functions
48+
}
49+
}
50+
4351
/**
4452
* Holds if `name` is a the name of an external module.
4553
*/
@@ -136,7 +144,7 @@ SourceNode externalNode() {
136144
}
137145

138146
/**
139-
* Gets a data flow node that can be resolved to a callback.
147+
* Gets a data flow node that can be resolved to a function, usually a callback.
140148
*
141149
* These are not part of the static call graph, but the data flow analysis can
142150
* track them, so we consider them resolved.
@@ -150,6 +158,26 @@ SourceNode resolvableCallback() {
150158
)
151159
}
152160

161+
/**
162+
* Gets a data flow node that can be resolved to an invocation of a callback.
163+
*
164+
* These are not part of the static call graph, but the data flow analysis can
165+
* track them, so we consider them resolved.
166+
*/
167+
SourceNode nodeLeadingToInvocation() {
168+
exists(result.getAnInvocation())
169+
or
170+
exists(Node arg |
171+
FlowSteps::argumentPassing(_, arg, _, nodeLeadingToInvocation()) and
172+
result.flowsTo(arg)
173+
)
174+
or
175+
exists(AdditionalPartialInvokeNode invoke, Node arg |
176+
invoke.isPartialArgument(arg, _, _) and
177+
result.flowsTo(arg)
178+
)
179+
}
180+
153181
/**
154182
* A call site that can be resolved to a function in the same project.
155183
*/
@@ -205,3 +233,23 @@ class NonExternalCall extends RelevantInvoke {
205233
not this instanceof ExternalCall
206234
}
207235
}
236+
237+
/**
238+
* A function with at least one call site.
239+
*/
240+
class FunctionWithCallers extends RelevantFunction {
241+
FunctionWithCallers() {
242+
FlowSteps::calls(_, this)
243+
or
244+
this = nodeLeadingToInvocation().getAstNode()
245+
}
246+
}
247+
248+
/**
249+
* A function without any call sites.
250+
*/
251+
class FunctionWithoutCallers extends RelevantFunction {
252+
FunctionWithoutCallers() {
253+
not this instanceof FunctionWithCallers
254+
}
255+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @name Called function candidates
3+
* @description The number of functions for which finding call sites is relevant
4+
* for analysis quality.
5+
* @kind metric
6+
* @metricType project
7+
* @metricAggregate sum
8+
* @tags meta
9+
* @id js/meta/called-function-candidates
10+
*/
11+
import javascript
12+
import CallGraphQuality
13+
14+
select projectRoot(), count(RelevantFunction f)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Called function ratio
3+
* @description The percentage of relevant functions for which a call site was found.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum min max avg
7+
* @tags meta
8+
* @id js/meta/called-function-ratio
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), 100.0 * count(FunctionWithCallers f) / (float) count(RelevantFunction f)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Called functions
3+
* @description The number of functions for which a call site was found.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id js/meta/called-functions
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), count(FunctionWithCallers f)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Uncalled functions
3+
* @description The number of functions for which no call site could be found.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id js/meta/uncalled-functions
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), count(FunctionWithoutCallers f)

0 commit comments

Comments
 (0)