Skip to content

Commit f0465f4

Browse files
committed
Python: Get rid of some get...Object methods
This frees `Class.qll`, `Exprs.qll`, and `Function.qll` from the clutches of points-to. For the somewhat complicated setup with `getLiteralObject` (an abstract method), I opted for a slightly ugly but workable solution of just defining a predicate on `ImmutableLiteral` that inlines each predicate body, special-cased to the specific instance to which it applies.
1 parent 78c33ab commit f0465f4

File tree

8 files changed

+72
-51
lines changed

8 files changed

+72
-51
lines changed

python/ql/lib/LegacyPointsTo.qll

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,66 @@ class ModuleWithPointsTo extends Module {
221221

222222
override string getAQlClass() { none() }
223223
}
224+
225+
/**
226+
* An extension of `Function` that provides points-to related methods.
227+
*/
228+
class FunctionWithPointsTo extends Function {
229+
/** Gets the FunctionObject corresponding to this function */
230+
FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() }
231+
232+
override string getAQlClass() { none() }
233+
}
234+
235+
/**
236+
* An extension of `Class` that provides points-to related methods.
237+
*/
238+
class ClassWithPointsTo extends Class {
239+
/** Gets the ClassObject corresponding to this class */
240+
ClassObject getClassObject() { result.getOrigin() = this.getParent() }
241+
242+
override string getAQlClass() { none() }
243+
}
244+
245+
Object getLiteralObject(ImmutableLiteral l) {
246+
l instanceof IntegerLiteral and
247+
(
248+
py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, l.(Num).getN())
249+
or
250+
py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, l.(Num).getN())
251+
)
252+
or
253+
l instanceof FloatLiteral and
254+
py_cobjecttypes(result, theFloatType()) and
255+
py_cobjectnames(result, l.(Num).getN())
256+
or
257+
l instanceof ImaginaryLiteral and
258+
py_cobjecttypes(result, theComplexType()) and
259+
py_cobjectnames(result, l.(Num).getN())
260+
or
261+
l instanceof NegativeIntegerLiteral and
262+
(
263+
(py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and
264+
py_cobjectnames(result, "-" + l.(UnaryExpr).getOperand().(IntegerLiteral).getN())
265+
)
266+
or
267+
l instanceof Bytes and
268+
py_cobjecttypes(result, theBytesType()) and
269+
py_cobjectnames(result, l.(Bytes).quotedString())
270+
or
271+
l instanceof Unicode and
272+
py_cobjecttypes(result, theUnicodeType()) and
273+
py_cobjectnames(result, l.(Unicode).quotedString())
274+
or
275+
l instanceof True and
276+
name_consts(l, "True") and
277+
result = theTrueObject()
278+
or
279+
l instanceof False and
280+
name_consts(l, "False") and
281+
result = theFalseObject()
282+
or
283+
l instanceof None and
284+
name_consts(l, "None") and
285+
result = theNoneObject()
286+
}

python/ql/lib/semmle/python/Class.qll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,6 @@ class Class extends Class_, Scope, AstNode {
141141
/** Gets the metaclass expression */
142142
Expr getMetaClass() { result = this.getParent().getMetaClass() }
143143

144-
/** Gets the ClassObject corresponding to this class */
145-
ClassObject getClassObject() { result.getOrigin() = this.getParent() }
146-
147144
/** Gets the nth base of this class definition. */
148145
Expr getBase(int index) { result = this.getParent().getBase(index) }
149146

python/ql/lib/semmle/python/Exprs.qll

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -240,17 +240,12 @@ class Bytes extends StringLiteral {
240240
/* syntax: b"hello" */
241241
Bytes() { not this.isUnicode() }
242242

243-
override Object getLiteralObject() {
244-
py_cobjecttypes(result, theBytesType()) and
245-
py_cobjectnames(result, this.quotedString())
246-
}
247-
248243
/**
249244
* The extractor puts quotes into the name of each string (to prevent "0" clashing with 0).
250245
* The following predicate help us match up a string/byte literals in the source
251246
* which the equivalent object.
252247
*/
253-
private string quotedString() {
248+
string quotedString() {
254249
exists(string b_unquoted | b_unquoted = this.getS() | result = "b'" + b_unquoted + "'")
255250
}
256251
}
@@ -266,8 +261,6 @@ class Ellipsis extends Ellipsis_ {
266261
* Consists of string (both unicode and byte) literals and numeric literals.
267262
*/
268263
abstract class ImmutableLiteral extends Expr {
269-
abstract Object getLiteralObject();
270-
271264
abstract boolean booleanValue();
272265
}
273266

@@ -292,12 +285,6 @@ class IntegerLiteral extends Num {
292285

293286
override string toString() { result = "IntegerLiteral" }
294287

295-
override Object getLiteralObject() {
296-
py_cobjecttypes(result, theIntType()) and py_cobjectnames(result, this.getN())
297-
or
298-
py_cobjecttypes(result, theLongType()) and py_cobjectnames(result, this.getN())
299-
}
300-
301288
override boolean booleanValue() {
302289
this.getValue() = 0 and result = false
303290
or
@@ -317,10 +304,6 @@ class FloatLiteral extends Num {
317304

318305
override string toString() { result = "FloatLiteral" }
319306

320-
override Object getLiteralObject() {
321-
py_cobjecttypes(result, theFloatType()) and py_cobjectnames(result, this.getN())
322-
}
323-
324307
override boolean booleanValue() {
325308
this.getValue() = 0.0 and result = false
326309
or
@@ -343,10 +326,6 @@ class ImaginaryLiteral extends Num {
343326

344327
override string toString() { result = "ImaginaryLiteral" }
345328

346-
override Object getLiteralObject() {
347-
py_cobjecttypes(result, theComplexType()) and py_cobjectnames(result, this.getN())
348-
}
349-
350329
override boolean booleanValue() {
351330
this.getValue() = 0.0 and result = false
352331
or
@@ -365,11 +344,6 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr {
365344

366345
override boolean booleanValue() { result = this.getOperand().(IntegerLiteral).booleanValue() }
367346

368-
override Object getLiteralObject() {
369-
(py_cobjecttypes(result, theIntType()) or py_cobjecttypes(result, theLongType())) and
370-
py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN())
371-
}
372-
373347
/**
374348
* Gets the (integer) value of this constant. Will not return a result if the value does not fit into
375349
* a 32 bit signed value
@@ -385,11 +359,6 @@ class Unicode extends StringLiteral {
385359
/* syntax: "hello" */
386360
Unicode() { this.isUnicode() }
387361

388-
override Object getLiteralObject() {
389-
py_cobjecttypes(result, theUnicodeType()) and
390-
py_cobjectnames(result, this.quotedString())
391-
}
392-
393362
/**
394363
* Gets the quoted representation fo this string.
395364
*
@@ -593,12 +562,10 @@ class StringLiteral extends Str_, ImmutableLiteral {
593562
this.getText() != "" and result = true
594563
}
595564

596-
override Object getLiteralObject() { none() }
597-
598565
override string toString() { result = "StringLiteral" }
599566
}
600567

601-
private predicate name_consts(Name_ n, string id) {
568+
predicate name_consts(Name_ n, string id) {
602569
exists(Variable v | py_variables(v, n) and id = v.getId() |
603570
id = "True" or id = "False" or id = "None"
604571
)
@@ -627,8 +594,6 @@ class True extends BooleanLiteral {
627594
/* syntax: True */
628595
True() { name_consts(this, "True") }
629596

630-
override Object getLiteralObject() { name_consts(this, "True") and result = theTrueObject() }
631-
632597
override boolean booleanValue() { result = true }
633598
}
634599

@@ -637,8 +602,6 @@ class False extends BooleanLiteral {
637602
/* syntax: False */
638603
False() { name_consts(this, "False") }
639604

640-
override Object getLiteralObject() { name_consts(this, "False") and result = theFalseObject() }
641-
642605
override boolean booleanValue() { result = false }
643606
}
644607

@@ -647,8 +610,6 @@ class None extends NameConstant {
647610
/* syntax: None */
648611
None() { name_consts(this, "None") }
649612

650-
override Object getLiteralObject() { name_consts(this, "None") and result = theNoneObject() }
651-
652613
override boolean booleanValue() { result = false }
653614
}
654615

python/ql/lib/semmle/python/Function.qll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ class Function extends Function_, Scope, AstNode {
8787
/** Gets the metrics for this function */
8888
FunctionMetrics getMetrics() { result = this }
8989

90-
/** Gets the FunctionObject corresponding to this function */
91-
FunctionObject getFunctionObject() { result.getOrigin() = this.getDefinition() }
92-
9390
/**
9491
* Whether this function is a procedure, that is, it has no explicit return statement and always returns None.
9592
* Note that generator and async functions are not procedures as they return generators and coroutines respectively.

python/ql/lib/semmle/python/types/ClassObject.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class ClassObject extends Object {
8989
}
9090

9191
/** Gets the scope associated with this class, if it is not a builtin class */
92-
Class getPyClass() { result.getClassObject() = this }
92+
ClassWithPointsTo getPyClass() { result.getClassObject() = this }
9393

9494
/** Returns an attribute declared on this class (not on a super-class) */
9595
Object declaredAttribute(string name) {

python/ql/test/2/extractor-tests/normalise/Numbers.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
*/
88

99
import python
10+
private import LegacyPointsTo
1011

1112
from NumericObject n
1213
where
13-
exists(IntegerLiteral i | i.getLiteralObject() = n |
14+
exists(IntegerLiteral i | getLiteralObject(i) = n |
1415
i.getEnclosingModule().getFile().getShortName() = "test.py"
1516
)
1617
select n.toString(), n.repr()
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* Test that there are no literals that do not have a corresponding object. */
22
import python
3+
private import LegacyPointsTo
34

45
string repr(Expr e) {
56
result = e.(Num).getN() or
@@ -8,5 +9,5 @@ string repr(Expr e) {
89
}
910

1011
from ImmutableLiteral l
11-
where not exists(l.getLiteralObject())
12+
where not exists(getLiteralObject(l))
1213
select l.getLocation().getStartLine(), repr(l)
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* Test that there are no literals that do not have a corresponding object. */
22
import python
3+
private import LegacyPointsTo
34

45
string repr(Expr e) {
56
result = e.(Num).getN() or
@@ -8,5 +9,5 @@ string repr(Expr e) {
89
}
910

1011
from ImmutableLiteral l
11-
where not exists(l.getLiteralObject())
12+
where not exists(getLiteralObject(l))
1213
select l.getLocation().getStartLine(), repr(l)

0 commit comments

Comments
 (0)