CodeQL 文档

Ruby 代码的基本查询

了解如何使用带有 CodeQL 扩展的 Visual Studio Code 编写和运行简单的 CodeQL 查询。

有关为 Visual Studio Code 安装 CodeQL 扩展的信息,请参阅“安装适用于 Visual Studio Code 的 CodeQL”。

关于查询

我们将要运行的查询对代码执行基本搜索,以查找冗余的 if 表达式,即这些表达式具有空的 then 分支。例如,类似以下代码:

if error
  # Handle the error

查找用于实验的 CodeQL 数据库

在开始为 Ruby 代码编写查询之前,您需要一个 CodeQL 数据库来运行这些查询。最简单的方法是从 GitHub.com 直接下载使用 Ruby 的存储库的数据库。

  1. 在 Visual Studio Code 中,单击左侧边栏中的 **QL** 图标 CodeQL 扩展的图标。 以显示 CodeQL 扩展。
  2. 单击 CodeQL 扩展顶部的 **从 GitHub** 或 GitHub 徽标 CodeQL 扩展选项的图标,用于从 GitHub 下载 CodeQL 数据库。 以打开一个条目字段。
  3. 将存储库的 URL 复制到字段中,然后按键盘 **Enter** 键。例如,https://github.com/discourse/discourse
  4. 可选:如果存储库有多个可用的 CodeQL 数据库,请选择 ruby 以下载从 Ruby 代码创建的数据库。

有关数据库下载进度的信息将显示在 Visual Studio Code 的右下角。下载完成后,该数据库将在 CodeQL 扩展的 **数据库** 部分显示带有复选标记(见下图)。

运行快速查询

适用于 Visual Studio Code 的 CodeQL 扩展将多个 **CodeQL:** 命令添加到命令面板,包括 **快速查询**,您可以使用它在没有任何设置的情况下运行查询。

  1. 从 Visual Studio Code 中的命令面板中,选择 **CodeQL: 快速查询**。

  2. 片刻之后,将打开一个名为 *quick-query.ql* 的新选项卡,您可以为当前选定的 CodeQL 数据库(此处为 ruby 数据库)编写查询。如果您被提示将工作区重新加载为多文件夹工作区以允许快速查询,请接受或使用入门工作流创建一个新工作区。

    image-quick-query

  1. 在快速查询选项卡中,删除内容并粘贴以下查询。

    import codeql.ruby.AST
    
    from IfExpr ifexpr
    where
    not exists(ifexpr.getThen())
    select ifexpr, "This 'if' expression is redundant."
    
  1. 将查询保存在其默认位置(工作区中 GitHub.vscode-codeql/quick-queries 下的临时“快速查询”目录)。

  2. 在查询选项卡中右键单击,然后选择 **CodeQL: 在选定数据库上运行查询**。(或者,从命令面板运行该命令。)

    查询将需要几分钟才能返回结果。查询完成后,结果将显示在 CodeQL 查询结果视图中,位于主编辑器视图旁边。

    查询结果列在两列中,分别对应于查询的 select 子句中的表达式。第一列对应于表达式 ifexpr,并链接到项目中 ifexpr 出现的位置。第二列是警报消息。

../../_images/basic-ruby-query-results-1.png

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

../../_images/basic-ruby-query-results-2.png

注意

如果您想将实验性查询移到更永久的位置,则需要移动整个 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()) 定义变量的条件。

ifexpr.getThen():获取 if 表达式的 then 分支。

exists(...):要求存在匹配的元素,在本例中为 then 分支。

select ifexpr, "This 'if' expression is redundant."

定义要为每个匹配项报告的内容。

用于查找不良编码实践实例的查询的 select 语句始终采用以下形式:select <program element>, "<alert message>"

使用解释问题的字符串报告生成的 if 表达式。

扩展查询

查询编写是一个固有的迭代过程。您编写一个简单的查询,然后在运行它时,发现之前没有考虑到的示例或改进的机会。

删除误报结果

浏览基本查询的结果表明可以改进它。在结果中,您可能会发现具有 else 分支的 if 语句的示例,其中空 then 分支确实起作用。例如

if option == "-verbose"
  # nothing to do - handled earlier
else
  error "unrecognized option"

在这种情况下,将具有空 then 分支的 if 语句识别为冗余是一个误报。一种解决方法是修改查询,以选择同时缺少 thenelse 分支的 if 语句。

要排除具有 else 分支的 if 语句

  1. 在 where 子句中添加以下内容

    and not exists(ifstmt.getElse())
    

    现在 where 子句为

    where
       not exists(ifexpr.getThen()) and
       not exists(ifexpr.getElse())
    
  2. 重新运行查询。

    现在结果更少了,因为不再包含具有 else 分支的 if 表达式。

  • ©GitHub, Inc.
  • 条款
  • 隐私