Skip to content

Commit 102fd11

Browse files
committed
JS: Change to queries of @kind metric
1 parent 207ed1e commit 102fd11

File tree

5 files changed

+110
-49
lines changed

5 files changed

+110
-49
lines changed

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

Lines changed: 58 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
/**
2-
* @name Call graph quality
3-
* @description Measures the number of resolved and unresolved calls, for diagnostic purposes.
4-
* @id js/meta/call-graph-quality
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.
54
*/
65

7-
import javascript::DataFlow
8-
import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
9-
import semmle.javascript.dependencies.Dependencies
10-
import semmle.javascript.dependencies.FrameworkLibraries
11-
import semmle.javascript.frameworks.Testing
6+
import javascript
7+
8+
private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
9+
private import semmle.javascript.dependencies.Dependencies
10+
private import semmle.javascript.dependencies.FrameworkLibraries
11+
private import semmle.javascript.frameworks.Testing
12+
private import DataFlow
13+
14+
/**
15+
* Gets the root folder of the snapshot.
16+
*
17+
* This is selected as the location for project-wide metrics.
18+
*/
19+
Folder projectRoot() { result.getRelativePath() = "" }
1220

1321
/** A file we ignore because it is a test file or compiled/generated/bundled code. */
1422
class IgnoredFile extends File {
@@ -140,59 +148,60 @@ SourceNode resolvableCallback() {
140148
}
141149

142150
/**
143-
* Gets a call site that can be resolved to an function in the same project.
151+
* Acall site that can be resolved to a function in the same project.
144152
*/
145-
RelevantInvoke resolvedCall() {
146-
FlowSteps::calls(result, _)
147-
or
148-
result = resolvableCallback().getAnInvocation()
153+
class ResolvedCall extends RelevantInvoke {
154+
ResolvedCall() {
155+
FlowSteps::calls(this, _)
156+
or
157+
this = resolvableCallback().getAnInvocation()
158+
}
149159
}
150160

151161
/**
152-
* Gets a call site that is believed to call an external function.
162+
* A call site that is believed to call an external function.
153163
*/
154-
RelevantInvoke externalCall() {
155-
not result = resolvedCall() and // avoid double counting
156-
(
157-
// Call to modelled external library
158-
result = externalNode()
159-
or
160-
// 'require' call or similar
161-
result = moduleImport(_)
162-
or
163-
// Resolved to externs file
164-
exists(result.(InvokeNode).getACallee(1))
165-
or
166-
// Modelled as taint step but isn't from an NPM module. E.g. `substring` or `push`.
167-
exists(TaintTracking::AdditionalTaintStep step |
168-
step.step(_, result)
164+
class ExternalCall extends RelevantInvoke {
165+
ExternalCall() {
166+
not this instanceof ResolvedCall and // avoid double counting
167+
(
168+
// Call to modelled external library
169+
this = externalNode()
169170
or
170-
step.step(result.getAnArgument(), _)
171+
// 'require' call or similar
172+
this = moduleImport(_)
171173
or
172-
step.step(_, result.getCallback(_).getParameter(_))
173-
)
174-
or
175-
// Commonly used methods that are usually external and not found by the above
176-
exists(string name | name = result.(MethodCallNode).getMethodName() |
177-
name = "indexOf" or
178-
name = "lastIndexOf" or
179-
name = "then"
174+
// Resolved to externs file
175+
exists(this.(InvokeNode).getACallee(1))
176+
or
177+
// Modelled as taint step but isn't from an NPM module. E.g. `substring` or `push`.
178+
exists(TaintTracking::AdditionalTaintStep step |
179+
step.step(_, this)
180+
or
181+
step.step(this.getAnArgument(), _)
182+
)
183+
or
184+
// Modelled as remote flow but not found by the above for whatever reason
185+
this instanceof RemoteFlowSource
180186
)
181-
)
187+
}
182188
}
183189

184190
/**
185191
* Gets a call site that could not be resolved.
186192
*/
187-
RelevantInvoke unresolvedCall() {
188-
not result = resolvedCall() and
189-
not result = externalCall()
193+
class UnresolvedCall extends RelevantInvoke {
194+
UnresolvedCall() {
195+
not this instanceof ResolvedCall and
196+
not this instanceof ExternalCall
197+
}
190198
}
191199

192-
// Name all columns in the 'from' clause to get named columns in metadata
193-
from int resolved, int calls, float ratio
194-
where
195-
calls = count(resolvedCall()) + count(unresolvedCall()) and
196-
resolved = count(resolvedCall()) and
197-
ratio = resolved / (float)calls
198-
select resolved, calls, ratio
200+
/**
201+
* A call that is believed to call a function within the same project.
202+
*/
203+
class NonExternalCall extends RelevantInvoke {
204+
NonExternalCall() {
205+
not this instanceof ExternalCall
206+
}
207+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Resolvable call site candidates
3+
* @description The number of non-external calls in the program.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id js/meta/resolved-call-candidates
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), count(NonExternalCall call)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Resolved call ratio
3+
* @description The percentage of non-external calls that could be resolved to its target.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum min max avg
7+
* @tags meta
8+
* @id js/meta/resolved-call-ratio
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), 100.0 * count(ResolvedCall call) / (float) count(NonExternalCall call)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Resolved calls
3+
* @description The number of calls that could be resolved to its target.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id js/meta/resolved-calls
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), count(ResolvedCall call)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Unresolved calls
3+
* @description The number of calls that could not be resolved to its target.
4+
* @kind metric
5+
* @metricType project
6+
* @metricAggregate sum
7+
* @tags meta
8+
* @id js/meta/unresolved-calls
9+
*/
10+
import javascript
11+
import CallGraphQuality
12+
13+
select projectRoot(), count(UnresolvedCall call)

0 commit comments

Comments
 (0)