Ruby 代码的基本查询¶
了解如何使用带有 CodeQL 扩展的 Visual Studio Code 编写和运行简单的 CodeQL 查询。
有关为 Visual Studio Code 安装 CodeQL 扩展的信息,请参阅“安装适用于 Visual Studio Code 的 CodeQL”。
查找用于实验的 CodeQL 数据库¶
在开始为 Ruby 代码编写查询之前,您需要一个 CodeQL 数据库来运行这些查询。最简单的方法是从 GitHub.com 直接下载使用 Ruby 的存储库的数据库。
- 在 Visual Studio Code 中,单击左侧边栏中的 **QL** 图标
以显示 CodeQL 扩展。
- 单击 CodeQL 扩展顶部的 **从 GitHub** 或 GitHub 徽标
以打开一个条目字段。
- 将存储库的 URL 复制到字段中,然后按键盘 **Enter** 键。例如,https://github.com/discourse/discourse。
- 可选:如果存储库有多个可用的 CodeQL 数据库,请选择
ruby
以下载从 Ruby 代码创建的数据库。
有关数据库下载进度的信息将显示在 Visual Studio Code 的右下角。下载完成后,该数据库将在 CodeQL 扩展的 **数据库** 部分显示带有复选标记(见下图)。
运行快速查询¶
适用于 Visual Studio Code 的 CodeQL 扩展将多个 **CodeQL:** 命令添加到命令面板,包括 **快速查询**,您可以使用它在没有任何设置的情况下运行查询。
从 Visual Studio Code 中的命令面板中,选择 **CodeQL: 快速查询**。
片刻之后,将打开一个名为 *quick-query.ql* 的新选项卡,您可以为当前选定的 CodeQL 数据库(此处为
ruby
数据库)编写查询。如果您被提示将工作区重新加载为多文件夹工作区以允许快速查询,请接受或使用入门工作流创建一个新工作区。
在快速查询选项卡中,删除内容并粘贴以下查询。
import codeql.ruby.AST from IfExpr ifexpr where not exists(ifexpr.getThen()) select ifexpr, "This 'if' expression is redundant."
将查询保存在其默认位置(工作区中
GitHub.vscode-codeql/quick-queries
下的临时“快速查询”目录)。在查询选项卡中右键单击,然后选择 **CodeQL: 在选定数据库上运行查询**。(或者,从命令面板运行该命令。)
查询将需要几分钟才能返回结果。查询完成后,结果将显示在 CodeQL 查询结果视图中,位于主编辑器视图旁边。
查询结果列在两列中,分别对应于查询的
select
子句中的表达式。第一列对应于表达式ifexpr
,并链接到项目中ifexpr
出现的位置。第二列是警报消息。

如果找到任何匹配的代码,请单击 ifexpr
列中的链接以打开文件并突出显示匹配的 if
语句。

注意
如果您想将实验性查询移到更永久的位置,则需要移动整个
Quick Queries
目录。该目录是一个 CodeQL 包,包含一个qlpack.yml
文件,该文件将内容定义为针对 Ruby CodeQL 数据库的查询。有关 CodeQL 包的更多信息,请参阅“管理 CodeQL 查询包和库包”。
关于查询结构¶
在初始的 import
语句之后,这个简单的查询包含三个部分,它们的功能与 SQL 查询的 FROM、WHERE 和 SELECT 部分类似。
查询部分 | 目的 | 详细信息 |
---|---|---|
import codeql.ruby.AST |
导入适用于 Ruby 的标准 CodeQL AST 库。 | 每个查询都以一个或多个 import 语句开头。 |
from IfExpr ifexpr |
定义查询的变量。声明的格式为:<type> <variable name> |
我们使用:一个 IfExpr 变量用于 if 表达式。 |
where not exists(ifexpr.getThen()) |
定义变量的条件。 |
|
select ifexpr, "This 'if' expression is redundant." |
定义要为每个匹配项报告的内容。 用于查找不良编码实践实例的查询的 |
使用解释问题的字符串报告生成的 if 表达式。 |
扩展查询¶
查询编写是一个固有的迭代过程。您编写一个简单的查询,然后在运行它时,发现之前没有考虑到的示例或改进的机会。
删除误报结果¶
浏览基本查询的结果表明可以改进它。在结果中,您可能会发现具有 else
分支的 if
语句的示例,其中空 then
分支确实起作用。例如
if option == "-verbose"
# nothing to do - handled earlier
else
error "unrecognized option"
在这种情况下,将具有空 then
分支的 if
语句识别为冗余是一个误报。一种解决方法是修改查询,以选择同时缺少 then
和 else
分支的 if
语句。
要排除具有 else
分支的 if
语句
在 where 子句中添加以下内容
and not exists(ifstmt.getElse())
现在
where
子句为where not exists(ifexpr.getThen()) and not exists(ifexpr.getElse())
重新运行查询。
现在结果更少了,因为不再包含具有
else
分支的if
表达式。