https://codeql.github.com/docs/ql-language-reference/types/

类型是一个数值集合,A type is a set of values。例如类型int表示整数类型的数值集合。
一个值可以属于多个集合,即一个值可以拥有多个类型。

批注:在QL里面class是一种type,type包含class。

主数据类型

boolean, float, int, string, date
https://codeql.github.com/codeql-standard-libraries/java/type.string.html

Classes

可以通过定义一个class,来定义属于你自己的type。
类提供了一种重用和重构代码的简单方法。你可以:
1、将相关的值分组
2、在这些值上定义成员谓词
3、重写成员谓词的子类

注意:QL中的类无法用来创建一个对象,它只是表示一个逻辑属性。如果某个值满足一个类的逻辑属性,那么便认为这个值在这个类中。
批注:可以认为这个值,是这个类的成员。

定义一个类

四个步骤:
1、使用class关键字
2、指定类的名字,类名的首字母用大写
3、指定继承的type
4、类的body部分

  1. class OneTwoThree extends int {
  2. OneTwoThree() { // characteristic predicate
  3. this = 1 or this = 2 or this = 3
  4. }
  5. string getAString() { // member predicate
  6. result = "One, two or three: " + this.toString()
  7. }
  8. predicate isEven() { // member predicate
  9. this = 2
  10. }
  11. }

注意:A class in QL must always extend at least one existing type.Those types are called the base types of the class

Class bodies

类的body部分可以包含
1、characteristic predicate的声明部分
2、任意个成员谓词的声明
3、任意个成员字段的声明
当你定义一个类时,这个类会继承父类所有的非私有谓词和字段。你可以重写这些谓词和字段。

特征谓词

Characteristic predicates
在特征谓词中,可以使用this变量来限制这个类可能数值的逻辑属性。

成员谓词

Member predicates
这些谓词只适用于特定的类的成员。你可以调用某个值的成员谓词。

  1. 1.(OneTwoThree).getAString()

将会返回 "One, two or three: 1".
The expression (OneTwoThree) is a cast. It ensures that 1 has type OneTwoThree instead of just int.

字段

你可以在一个类的body里面声明很多变量,一个类可以在它的body里面声明无数个字段。
你可以在类中声明谓词时使用这些字段。与this变量非常相似,字段必须在特征谓词中进行约束。
代码示例如下:

  1. class SmallInt extends int {
  2. SmallInt() { this = [1 .. 10] }
  3. }
  4. class DivisibleInt extends SmallInt {
  5. SmallInt divisor; // declaration of the field `divisor`
  6. DivisibleInt() { this % divisor = 0 }
  7. SmallInt getADivisor() { result = divisor }
  8. }
  9. from DivisibleInt i
  10. select i, i.getADivisor()

在上面例子中, SmallInt divisor声明了一个字段divisotr,并在特征谓词中进行了约束DivisibleInt() { this % divisor = 0 },最后在声明成员谓词getADivisor时调用了这个字段SmallInt getADivisor() { result = divisor }。

具体类

Concrete classes
具体类表示的数值集合是:满足该类特征谓词的数值集合与base type表示的数值集合的交集。

抽象类

Abstract classes
可以使用abstrace关键字来标注一个类是抽象类。
抽象类表示的数值集合是:满足该类特征谓词的数值集合与所有子类表示的数值集合的并集。
如下是内置库中QueryInjection.qll中定义的QueryInjectionSink抽象类
image.png

重写成员谓词

Overriding member predicates
如果一个类从超类那里继承了一个成员谓词,那么你可以重写这个继承的谓词。
你可以定义一个与这个继承的谓词相同名称的谓词,然后增加一个override标注。
代码示例如下:

  1. class OneTwo extends OneTwoThree {
  2. OneTwo() {
  3. this = 1 or this = 2
  4. }
  5. override string getAString() {
  6. result = "One or two: " + this.toString()
  7. }
  8. }

成员谓词getAString()重写了原先定义在OneTwoThree类里面getAString()谓词。
运行下面的查询

  1. from OneTwoThree o
  2. select o, o.getAString()

查询结果如下所示
image.png
注意:与其他面向对象的语言不同,在QL中同一个类下面的不同子类don’t need to be disjoint。
例如你可以再定义一个OneTwoThree的子类TwoThree,TwoThree类与OneTwo类存在部分重叠。

  1. class TwoThree extends OneTwoThree {
  2. TwoThree() {
  3. this = 2 or this = 3
  4. }
  5. override string getAString() {
  6. result = "Two or three: " + this.toString()
  7. }
  8. }

现在数值2同时被OneTwo类和TwoThree类包含。这两个类都重写了超类中的成员谓词getAString。因此产生了两个新的”most specific”的定义。
运行下面这个查询:

  1. from OneTwoThree o
  2. select o, o.getAString()

查询结果如下
image.png

多继承

  1. class Two extends OneTwo, TwoThree {}

Two类中的所有值必须同时满足OneTwo的逻辑属性,和TwoThree的逻辑属性。因此类Two只包含了一个值2。
Two类会直接继承OneTwo类和TwoThree类的成员谓词,和间接继承OneTwoThree类和int类的成员谓词。

注意:在多继承中,如果子类继承了相同谓词名称的多个不同的定义,为了避免引起歧义子类需要重写这个谓词。
此时可以利用超级表达式,如下所示:

  1. class Two extends OneTwo,TwoThree{
  2. override string getAString() {
  3. result = OneTwo.super.getAString()
  4. }
  5. }

只有一个值2,在调用getAString谓词时,调用OneTwo类的getAString谓词
image.png

Character types and class domain types

Algebraic datatypes

Defining an algebraic datatype

Standard pattern for using algebraic datatypes

Type unions

数据库类型

Database types

Type compatibility