CodeQL 文档

变量

QL 中的变量与代数或逻辑中的变量使用方式类似。它们代表值集,这些值通常由公式限制。

这与某些其他编程语言中的变量不同,在其他编程语言中,变量代表可能包含数据的内存位置。该数据也可能随着时间的推移而改变。例如,在 QL 中,n = n + 1 是一个等式 公式,它仅在 n 等于 n + 1 时成立(因此实际上它对任何数值都不成立)。在 Java 中,n = n + 1 不是等式,而是将 1 添加到当前值,从而改变 n 值的赋值。

声明变量

所有变量声明都包含一个 类型 和一个变量名称。该名称可以是任何以小写字母开头的 标识符

例如,int iSsaDefinitionNode nodeLocalScopeVariable lsv 分别声明了类型为 intSsaDefinitionNodeLocalScopeVariable 的变量 inodelsv

变量声明出现在不同的上下文中,例如在 select 子句 中,在 量化公式 内部,作为 谓词 的参数,以及更多其他情况。

从概念上讲,您可以将变量视为包含其类型允许的所有值,但要受任何进一步约束的限制。

例如,考虑以下 select 子句

from int i
where i in [0 .. 9]
select i

仅根据其类型,变量 i 可以包含所有整数。但是,它受公式 i in [0 .. 9] 的限制。因此,select 子句的结果是 09(含)之间的十个数。

顺便说一下,请注意以下查询会导致编译时错误

from int i
select i

理论上,它将有无数个结果,因为变量 i 没有限制为有限数量的可能值。有关更多信息,请参阅“绑定”。

自由变量和绑定变量

变量可以具有不同的作用。一些变量是自由的,它们的值直接影响使用它们的 表达式 的值,或使用它们的 公式 是否成立。其他变量称为绑定变量,它们被限制为特定值集。

通过一个例子,理解这种区别可能最容易。请查看以下表达式

"hello".indexOf("l")

min(float f | f in [-3 .. 3])

(i + 7) * 3

x.sqrt()

第一个表达式没有任何变量。它查找字符串 "hello""l" 出现的位置的(从零开始的)索引,因此它评估为 23

第二个表达式评估为 -3,即 [-3 .. 3] 范围内的最小值。尽管此表达式使用变量 f,但它只是一个占位符或“虚拟”变量,您无法为其分配任何值。您可以用其他变量替换 f,而不会改变表达式的含义。例如,min(float f | f in [-3 .. 3]) 始终等于 min(float other | other in [-3 .. 3])。这是一个绑定变量的示例。

那么表达式 (i + 7) * 3x.sqrt() 呢?在这两种情况下,表达式的值取决于为变量 ix 分别分配的值。换句话说,变量的值会影响表达式的值。这些是自由变量的示例。

同样,如果公式包含自由变量,那么公式是否成立取决于分配给这些变量的值 [1]。例如

"hello".indexOf("l") = 1

min(float f | f in [-3 .. 3]) = -3

(i + 7) * 3 instanceof int

exists(float y | x.sqrt() = y)

第一个公式不包含任何变量,并且它永远不会成立(因为 "hello".indexOf("l") 的值为 23,永远不会是 1)。

第二个公式只包含一个绑定变量,因此不受对该变量更改的影响。由于 min(float f | f in [-3 .. 3]) 等于 -3,因此此公式始终成立。

第三个公式包含一个自由变量 i。公式是否成立取决于分配给 i 的值。例如,如果 i 被分配为 12(或任何其他 int),那么该公式成立。另一方面,如果 i 被分配为 3.5,那么它就不成立。

最后一个公式包含一个自由变量 x 和一个绑定变量 y。如果 x 被分配一个非负数,那么最后的公式成立。另一方面,如果 x 被分配为 -9(例如),那么该公式就不成立。变量 y 不会影响公式是否成立。

有关如何计算对自由变量的赋值的更多信息,请参阅“QL 程序的评估”。

脚注

[1]这是一个略微简化的说法。有一些公式始终为真或始终为假,无论对它们自由变量的赋值如何。但是,在编写 QL 时,您通常不会使用它们。例如,a = a 始终为真(称为 重言式),而 x and not x 始终为假。
  • ©GitHub, Inc.
  • 条款
  • 隐私