Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 746c577

Browse files
committed
Python: CG trace: Update naming and add QLDoc
1 parent 67b4516 commit 746c577

3 files changed

Lines changed: 52 additions & 31 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import RecordedCalls
22

33
from PointsToBasedCallGraph::ResolvableRecordedCall rc
4-
select rc.getCall(), "-->", rc.getCalleeValue()
4+
select rc.getACall(), "-->", rc.getCalleeValue()

python/tools/recorded-call-graph-metrics/ql/PointsToNotFound.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import RecordedCalls
22

33
from IdentifiedRecordedCall rc
44
where not rc instanceof PointsToBasedCallGraph::ResolvableRecordedCall
5-
select rc, rc.getCall()
5+
select rc, rc.getACall()

python/tools/recorded-call-graph-metrics/ql/RecordedCalls.qll

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,35 @@ import semmle.python.types.Builtins
33
import semmle.python.objects.Callables
44
import BytecodeExpr
55

6+
/** The XML data for a recorded call (includes all data). */
67
class XMLRecordedCall extends XMLElement {
78
XMLRecordedCall() { this.hasName("recorded_call") }
89

9-
Call getCall() { result = this.getXMLCall().getCall() }
10-
10+
/** Gets the XML data for the call. */
1111
XMLCall getXMLCall() { result.getParent() = this }
1212

13-
Function getPythonCallee() { result = this.getXMLCallee().(XMLPythonCallee).getCallee() }
14-
15-
Builtin getBuiltinCallee() { result = this.getXMLCallee().(XMLExternalCallee).getCallee() }
13+
/** Gets a call matching the recorded information. */
14+
Call getACall() { result = this.getXMLCall().getACall() }
1615

16+
/** Gets the XML data for the callee. */
1717
XMLCallee getXMLCallee() { result.getParent() = this }
1818

19-
/** Get a different `XMLRecordedCall` with the same result-set for `getCall`. */
19+
/** Gets a python function matching the recorded information of the callee. */
20+
Function getAPythonCallee() { result = this.getXMLCallee().(XMLPythonCallee).getACallee() }
21+
22+
/** Gets a builtin function matching the recorded information of the callee. */
23+
Builtin getABuiltinCallee() { result = this.getXMLCallee().(XMLExternalCallee).getACallee() }
24+
25+
/** Get a different `XMLRecordedCall` with the same result-set for `getACall`. */
2026
XMLRecordedCall getOtherWithSameSetOfCalls() {
2127
// `rc` is for a different bytecode instruction on same line
2228
not result.getXMLCall().get_inst_index_data() = this.getXMLCall().get_inst_index_data() and
2329
result.getXMLCall().get_filename_data() = this.getXMLCall().get_filename_data() and
2430
result.getXMLCall().get_linenum_data() = this.getXMLCall().get_linenum_data() and
25-
// set of calls is equal
26-
// 1. this.getCall() issubset result.getCall()
27-
not exists(Call call | call = this.getCall() | not result.getCall() = call) and
28-
// 2. result.getCall() issubset this.getCall()
29-
not exists(Call call | call = result.getCall() | not this.getCall() = call)
31+
// set of calls are equal
32+
forall(Call call | call = this.getACall() or call = result.getACall() |
33+
call = this.getACall() and call = result.getACall()
34+
)
3035
}
3136

3237
override string toString() {
@@ -46,6 +51,7 @@ class XMLRecordedCall extends XMLElement {
4651
}
4752
}
4853

54+
/** The XML data for the call part a recorded call. */
4955
class XMLCall extends XMLElement {
5056
XMLCall() { this.hasName("Call") }
5157

@@ -55,11 +61,13 @@ class XMLCall extends XMLElement {
5561

5662
int get_inst_index_data() { result = this.getAChild("inst_index").getTextValue().toInt() }
5763

58-
Call getCall() {
64+
/** Gets a call that matches the recorded information. */
65+
Call getACall() {
5966
// TODO: do we handle calls spanning multiple lines?
6067
this.matchBytecodeExpr(result, this.getAChild("bytecode_expr").getAChild())
6168
}
6269

70+
/** Holds if `expr` can be fully matched with `bytecode`. */
6371
private predicate matchBytecodeExpr(Expr expr, XMLBytecodeExpr bytecode) {
6472
exists(Call parent_call, XMLBytecodeCall parent_bytecode_call |
6573
parent_call
@@ -77,6 +85,7 @@ class XMLCall extends XMLElement {
7785
bytecode.(XMLBytecodeAttribute).get_object_data())
7886
or
7987
matchBytecodeExpr(expr.(Call).getFunc(), bytecode.(XMLBytecodeCall).get_function_data())
88+
//
8089
// I considered allowing a partial match as well. That is, if the bytecode
8190
// expression information only tells us `<unknown>.foo()`, and we find an AST
8291
// expression that matches on `.foo()`, that is good enough.
@@ -92,8 +101,10 @@ class XMLCall extends XMLElement {
92101
}
93102
}
94103

104+
/** The XML data for the callee part a recorded call. */
95105
abstract class XMLCallee extends XMLElement { }
96106

107+
/** The XML data for the callee part a recorded call, when the callee is a Python function. */
97108
class XMLPythonCallee extends XMLCallee {
98109
XMLPythonCallee() { this.hasName("PythonCallee") }
99110

@@ -103,7 +114,7 @@ class XMLPythonCallee extends XMLCallee {
103114

104115
string get_funcname_data() { result = this.getAChild("funcname").getTextValue() }
105116

106-
Function getCallee() {
117+
Function getACallee() {
107118
result.getLocation().hasLocationInfo(this.get_filename_data(), this.get_linenum_data(), _, _, _)
108119
or
109120
// if function has decorator, the call will be recorded going to the first
@@ -114,14 +125,15 @@ class XMLPythonCallee extends XMLCallee {
114125
}
115126
}
116127

128+
/** The XML data for the callee part a recorded call, when the callee is a C function or builtin. */
117129
class XMLExternalCallee extends XMLCallee {
118130
XMLExternalCallee() { this.hasName("ExternalCallee") }
119131

120132
string get_module_data() { result = this.getAChild("module").getTextValue() }
121133

122134
string get_qualname_data() { result = this.getAChild("qualname").getTextValue() }
123135

124-
Builtin getCallee() {
136+
Builtin getACallee() {
125137
exists(Builtin mod |
126138
not this.get_module_data() = "None" and
127139
mod.isModule() and
@@ -135,6 +147,10 @@ class XMLExternalCallee extends XMLCallee {
135147
}
136148
}
137149

150+
/**
151+
* Helper predicate. If parent = `builtins` and qualname = `list.append`, it will
152+
* return the result of `builtins.list.append`.class
153+
*/
138154
private Builtin traverse_qualname(Builtin parent, string qualname) {
139155
not qualname = "__objclass__" and
140156
not qualname.matches("%.%") and
@@ -150,15 +166,15 @@ private Builtin traverse_qualname(Builtin parent, string qualname) {
150166
}
151167

152168
/**
153-
* Class of recorded calls where we can identify both the `call` and the `callee`.
169+
* Class of recorded calls where we can identify both the `call` and the `callee` uniquely.
154170
*/
155171
class IdentifiedRecordedCall extends XMLRecordedCall {
156172
IdentifiedRecordedCall() {
157-
strictcount(this.getCall()) = 1 and
173+
strictcount(this.getACall()) = 1 and
158174
(
159-
strictcount(this.getPythonCallee()) = 1
175+
strictcount(this.getAPythonCallee()) = 1
160176
or
161-
strictcount(this.getBuiltinCallee()) = 1
177+
strictcount(this.getABuiltinCallee()) = 1
162178
)
163179
or
164180
// Handle case where the same function is called multiple times in one line, for
@@ -169,19 +185,19 @@ class IdentifiedRecordedCall extends XMLRecordedCall {
169185
// without this `strictcount`, in the case `func(); func(); func()`, if 1 of the calls
170186
// is not recorded, we woulld still mark the other two recorded calls as valid
171187
// (which is not following the rules above). + 1 to count `this` as well.
172-
strictcount(this.getCall()) = strictcount(this.getOtherWithSameSetOfCalls()) + 1 and
188+
strictcount(this.getACall()) = strictcount(this.getOtherWithSameSetOfCalls()) + 1 and
173189
forex(XMLRecordedCall rc | rc = this.getOtherWithSameSetOfCalls() |
174-
unique(Function f | f = this.getPythonCallee()) =
175-
unique(Function f | f = rc.getPythonCallee())
190+
unique(Function f | f = this.getAPythonCallee()) =
191+
unique(Function f | f = rc.getAPythonCallee())
176192
or
177-
unique(Builtin b | b = this.getBuiltinCallee()) =
178-
unique(Builtin b | b = rc.getBuiltinCallee())
193+
unique(Builtin b | b = this.getABuiltinCallee()) =
194+
unique(Builtin b | b = rc.getABuiltinCallee())
179195
)
180196
}
181197

182198
override string toString() {
183199
exists(string callee_str |
184-
exists(Function callee, string path | callee = this.getPythonCallee() |
200+
exists(Function callee, string path | callee = this.getAPythonCallee() |
185201
(
186202
path = callee.getLocation().getFile().getRelativePath()
187203
or
@@ -192,13 +208,16 @@ class IdentifiedRecordedCall extends XMLRecordedCall {
192208
callee.toString() + " (" + path + ":" + callee.getLocation().getStartLine() + ")"
193209
)
194210
or
195-
callee_str = this.getBuiltinCallee().toString()
211+
callee_str = this.getABuiltinCallee().toString()
196212
|
197213
result = super.toString() + " --> " + callee_str
198214
)
199215
}
200216
}
201217

218+
/**
219+
* Class of recorded calls where we cannot identify both the `call` and the `callee` uniquely.
220+
*/
202221
class UnidentifiedRecordedCall extends XMLRecordedCall {
203222
UnidentifiedRecordedCall() { not this instanceof IdentifiedRecordedCall }
204223
}
@@ -216,26 +235,28 @@ class IgnoredRecordedCall extends XMLRecordedCall {
216235
}
217236
}
218237

238+
/** Provides classes for call-graph resolution by using points-to. */
219239
module PointsToBasedCallGraph {
240+
/** An IdentifiedRecordedCall that can be resolved with points-to */
220241
class ResolvableRecordedCall extends IdentifiedRecordedCall {
221242
Value calleeValue;
222243

223244
ResolvableRecordedCall() {
224245
exists(Call call, XMLCallee xmlCallee |
225-
call = this.getCall() and
246+
call = this.getACall() and
226247
calleeValue.getACall() = call.getAFlowNode() and
227248
xmlCallee = this.getXMLCallee() and
228249
(
229250
xmlCallee instanceof XMLPythonCallee and
230-
calleeValue.(PythonFunctionValue).getScope() = xmlCallee.(XMLPythonCallee).getCallee()
251+
calleeValue.(PythonFunctionValue).getScope() = xmlCallee.(XMLPythonCallee).getACallee()
231252
or
232253
xmlCallee instanceof XMLExternalCallee and
233254
calleeValue.(BuiltinFunctionObjectInternal).getBuiltin() =
234-
xmlCallee.(XMLExternalCallee).getCallee()
255+
xmlCallee.(XMLExternalCallee).getACallee()
235256
or
236257
xmlCallee instanceof XMLExternalCallee and
237258
calleeValue.(BuiltinMethodObjectInternal).getBuiltin() =
238-
xmlCallee.(XMLExternalCallee).getCallee()
259+
xmlCallee.(XMLExternalCallee).getACallee()
239260
)
240261
)
241262
}

0 commit comments

Comments
 (0)