JavaScript 和 TypeScript 代码的基本查询¶
学习使用带有 CodeQL 扩展的 Visual Studio Code 编写和运行简单的 CodeQL 查询。
有关安装用于 Visual Studio 代码的 CodeQL 扩展的信息,请参阅“安装用于 Visual Studio Code 的 CodeQL”。
关于查询¶
在 JavaScript 和 TypeScript 中,任何表达式都可以转换为表达式语句。虽然这在某些情况下很方便,但它也可能很危险。例如,假设一位程序员想通过赋值 x = 42
将新值分配给变量 x
。但是,他们不小心输入了两个等号,生成了比较语句 x == 42
。这是有效的 JavaScript,因此不会生成任何错误。该语句只是将 x
与 42
进行比较,然后丢弃比较结果。
您将运行的查询将查找此问题。该查询搜索那些纯粹的表达式 e
,即它们的计算不会导致任何副作用,但会作为表达式语句出现。
查找用于实验的 CodeQL 数据库¶
在开始为 JavaScript/TypeScript 代码编写查询之前,您需要一个 CodeQL 数据库来运行它们。最简单的方法是直接从 GitHub.com 下载使用 JavaScript/TypeScript 的存储库的数据库。
- 在 Visual Studio Code 中,单击左侧边栏中的 **QL** 图标
以显示 CodeQL 扩展。
- 单击 **从 GitHub 获取** 或 GitHub 徽标
,它位于 CodeQL 扩展的顶部,以打开一个条目字段。
- 将存储库的 URL 复制到该字段中,然后按键盘 **Enter** 键。例如,https://github.com/ajaxorg/ace。
- 可选地,如果存储库有多个 CodeQL 数据库可用,请选择
javascript
以下载从 JavaScript/TypeScript 代码创建的数据库。
有关数据库下载进度的信息将显示在 Visual Studio Code 的右下角。下载完成后,将在 CodeQL 扩展的 **数据库** 部分中显示带有复选标记的数据库(请参阅下面的屏幕截图)。
运行快速查询¶
用于 Visual Studio Code 的 CodeQL 扩展将多个 **CodeQL:** 命令添加到命令面板中,包括 **快速查询**,您可以使用它在没有任何设置的情况下运行查询。
从 Visual Studio Code 中的命令面板中,选择 **CodeQL: 快速查询**。
片刻之后,将打开一个新的标签 *quick-query.ql*,您可以为当前选定的 CodeQL 数据库(此处为
javascript
数据库)编写查询。如果您被提示将工作区重新加载为多文件夹工作区以允许快速查询,请接受或使用入门工作流创建新的工作区。
在快速查询标签中,删除
select ""
,并将以下查询粘贴到导入语句import javascript
下面。from Expr e where e.isPure() and e.getParent() instanceof ExprStmt select e, "This expression has no effect."
将查询保存在其默认位置(工作区下名为
GitHub.vscode-codeql/quick-queries
的临时“快速查询”目录中)。右键单击查询标签,然后选择 **CodeQL: 在所选数据库上运行查询**。(或者,从命令面板中运行该命令。)
查询将需要几分钟才能返回结果。查询完成后,结果将显示在 CodeQL 查询结果视图中,位于主编辑器视图旁边。
查询结果列在两列中,对应于查询的
select
子句中的表达式。第一列对应于表达式e
,并链接到项目源代码中e
出现的位置。第二列是警报消息。

如果找到任何匹配的代码,请单击 e
列中的一条链接以打开文件并突出显示匹配的表达式。

注意
如果您想将实验性查询移到更持久的位置,则需要移动整个
Quick Queries
目录。该目录是一个 CodeQL 包,具有qlpack.yml
文件,该文件将内容定义为 JavaScript/TypeScript CodeQL 数据库的查询。有关 CodeQL 包的更多信息,请参阅“管理 CodeQL 查询包和库包”。
关于查询结构¶
在最初的 import
语句之后,这个简单的查询包含三个部分,它们与 SQL 查询的 FROM、WHERE 和 SELECT 部分具有类似的用途。
查询部分 | 目的 | 细节 |
---|---|---|
import javascript |
导入 JavaScript 和 TypeScript 的标准 CodeQL 库。 | 每个查询都以一个或多个 import 语句开头。 |
from Expr e |
定义查询的变量。声明的格式为:<type> <variable name> |
e 被声明为一个变量,它遍历表达式。 |
where e.isPure() and e.getParent() instanceof ExprStmt |
定义变量的条件。 |
|
select e, "This expression has no effect." |
定义对每个匹配项进行报告的内容。 用于查找不良编码实践实例的查询的 |
报告包含解释问题的字符串的表达式。 |
扩展查询¶
查询编写本质上是一个迭代过程。您编写一个简单的查询,然后在运行它时,您会发现以前没有考虑过的示例,或者发现改进的机会。
删除误报结果¶
浏览基本查询的结果表明可以改进它。在结果中,您可能会发现 use strict
指令。这些指令由支持严格模式的现代浏览器以特殊方式解释,因此这些表达式确实有作用。
要从结果中删除指令
将
where
子句扩展为包含以下额外条件and not e.getParent() instanceof Directive
现在,
where
子句为where e.isPure() and e.getParent() instanceof ExprStmt and not e.getParent() instanceof Directive
重新运行查询。
现在,结果更少了,因为
use strict
指令不再被报告。
改进后的查询在示例项目上找到了多个结果,包括以下结果

point.bias == -1;
按编写方式,此语句将 point.bias
与 -1
进行比较,然后丢弃结果。最有可能的是,它原本应该是一个赋值语句 point.bias = -1
。