Skip to content

Commit b3d51bf

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 041c068 commit b3d51bf

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
@@ -222,3 +222,66 @@ class ModuleWithPointsTo extends Module {
222222

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

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
@@ -92,7 +92,7 @@ class ClassObject extends Object {
9292
}
9393

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

9797
/** Returns an attribute declared on this class (not on a super-class) */
9898
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)