CodeQL 文档

C# 的 CodeQL 库

分析 C# 程序时,可以使用 C# 的 CodeQL 库中大量类。

关于 C# 的 CodeQL 库

有一个广泛的核心库用于分析从 C# 项目中提取的 CodeQL 数据库。该库中的类以面向对象的形式呈现数据库中的数据,并提供抽象和谓词来帮助您完成常见的分析任务。该库实现为一组 QL 模块,即扩展名为 .qll 的文件。模块 csharp.qll 导入所有核心 C# 库模块,因此您可以通过在查询开头包含以下内容来包含整个库:

import csharp

由于所有 C# 查询都需要此,因此它在下面的代码片段中被省略了。

核心库包含所有程序元素,包括 文件类型、方法、变量语句表达式。这足以满足大多数查询,但是可以导入其他库来实现特定功能,例如控制流和数据流。有关这些其他库的信息,请参见“C# 的 CodeQL。”

类层次结构

每节包含一个类层次结构,展示 CodeQL 类之间的继承结构。例如

  • Expr
    • Operation
      • ArithmeticOperation
        • UnaryArithmeticOperation
          • UnaryMinusExprUnaryPlusExpr
          • MutatorOperation
            • IncrementOperation
              • PreIncrExprPostIncrExpr
            • DecrementOperation
              • PreDecrExprPostDecrExpr
        • BinaryArithmeticOperation
          • AddExprSubExprMulExprDivExprRemExpr

这意味着类 AddExpr 扩展了类 BinaryArithmeticOperation,而 BinaryArithmeticOperation 又扩展了类 ArithmeticOperation,以此类推。如果您想查询任何算术运算,请使用类 ArithmeticOperation,但如果您特别想将查询限制为加法运算,请使用类 AddExpr

类也可以被认为是集合,而类之间的 extends 关系定义了一个子集。类 AddExpr 的每个成员也都在类 BinaryArithmeticOperation 中。一般来说,类之间会重叠,一个实体可以是多个类的成员。

此概述省略了类层次结构中一些不太重要或中间的类。

每个类都有谓词,即关于该类的逻辑命题。它们还定义了类之间的可导航关系。谓词是继承的,例如 AddExpr 类从 BinaryArithmeticOperation 继承了谓词 getLeftOperand()getRightOperand(),并从类 Expr 继承了 getType()。这类似于面向对象编程语言中如何继承方法。

在本概述中,我们介绍了最常见和最有用的谓词。要查看每个类上可用的所有谓词的完整列表,您可以在 CodeQL 源代码中查找,使用编辑器中的自动完成,或者查看 C# 参考

练习

本主题中的每节都包含练习来检验您的理解。

练习 1:简化此查询

from BinaryArithmeticOperation op
where op instanceof AddExpr
select op

(答案)

文件

文件由类 File 表示,目录由类 Folder 表示。数据库包含编译期间使用的所有源文件和程序集。

类层次结构

  • File - 数据库中的任何文件(包括源文件、XML 和程序集)
    • SourceFile - 包含源代码的文件
  • Folder - 目录

谓词

  • getName() - 获取文件的完整路径(例如,C:\Temp\test.cs)。
  • getNumberOfLines() - 获取行数(仅限于源文件)。
  • getShortName() - 获取不带扩展名的文件名(例如,test)。
  • getBaseName() - 获取文件名和扩展名(例如,test.cs)。
  • getParent() - 获取父目录。

示例

计算源文件的数量

select count(SourceFile f)

计算代码行数,不包括目录 external

select sum(SourceFile f |
  not exists(Folder ext | ext.getShortName() = "external" |
             ext.getAFolder*().getAFile() = f) |
  f.getNumberOfLines())

练习

练习 2:编写一个查询,找到具有最大行数的源文件。提示:找到具有与任何文件中max行数相同的行数的源文件。(答案)

元素

Element 是 C# 程序所有部分的基类,并且是元素类层次结构的根。所有程序元素(例如类型、方法、语句和表达式)最终都派生自这个共同的基类。

Element 形成了程序的层次结构,可以使用 getParent()getChild() 谓词进行导航。这很像抽象语法树,也适用于程序集中的元素。

谓词

Element 类为所有程序元素提供了通用功能,包括

  • getLocation() - 获取源代码中的文本跨度。
  • getFile() - 获取包含 ElementFile
  • getParent() - 获取父 Element(如果有)。
  • getAChild() - 获取此元素的子 Element(如果有)。

示例

列出 Main.cs 中的所有元素,以及它们的 QL 类和位置

from Element e
where e.getFile().getShortName() = "Main"
select e, e.getAQlClass(), e.getLocation()

请注意,getAQlClass() 可用于所有实体,是确定某事物 QL 类的有用方法。通常,同一个元素会有多个类,所有这些类都会被 getAQlClass() 返回。

位置

Location 表示源代码或程序集中的文本部分。所有元素都有一个 Location,可以通过它们的 getLocation() 谓词获取。SourceLocation 表示源代码中的文本跨度,而 Assembly 位置表示引用的程序集。

有时元素会有多个位置,例如如果它们同时出现在源代码和程序集中。在这种情况下,只返回 SourceLocation

类层次结构

  • Location
    • SourceLocation
    • Assembly

谓词

Location 的一些谓词包括

  • getFile() - 获取 File
  • getStartLine() - 获取文本的第一行。
  • getEndLine() - 获取文本的最后一行。
  • getStartColumn() - 获取文本起点的列。
  • getEndColumn() - 获取文本终点的列。

示例

查找所有宽度为一个字符的元素

from Element e, Location l
where l = e.getLocation()
  and l.getStartLine() = l.getEndLine()
  and l.getStartColumn() = l.getEndColumn()
select e, "This element is a single character."

声明

Declaration 是程序中所有定义的实体的公共类,例如类型、方法、变量等。数据库包含源代码和所有引用程序集中的所有声明。

类层次结构

  • Element
    • Declaration
      • Callable
      • UnboundGeneric
      • ConstructedGeneric
      • Modifiable - 可修改声明,可以包含修饰符(例如 public
        • Member - 属于类型的声明
      • Assignable - 可赋值的元素
        • 变量
        • 属性
        • 索引器
        • 事件

谓词

Declaration 有用的成员谓词包括

  • getDeclaringType() - 获取包含声明的类型(如果有)。
  • getName()/hasName(string) - 获取声明的实体的名称。
  • isSourceDeclaration() - 声明是否为源代码,且不是构造类型/方法。
  • getSourceDeclaration() - 获取原始(未构造)声明。

示例

查找包含用户名声明的实体

from Declaration decl
where decl.getName().regexpMatch("[uU]ser([Nn]ame)?")
select decl, "A username."

变量

Variable 表示 C# 变量,例如字段、参数和局部变量。数据库包含来自源代码的所有变量,以及程序引用的程序集中的所有字段和参数。

类层次结构

  • Element
    • Declaration
      • Variable - 任何类型的变量
        • Field - class/struct 中的字段
          • MemberConstant - const 字段
            • EnumConstant - enum 中的字段
        • LocalScopeVariable - 范围限定为单个 Callable 的变量
          • LocalVariable - Callable 中的局部变量
            • LocalConstant - Callable 中局部定义的常量
          • Parameter - Callable 的参数

谓词

Variable 有一些常见的谓词

  • getType() - 获取该变量的 Type
  • getAnAccess() - 获取访问(读取或写入)该变量的表达式(如果有)。
  • getAnAssignedValue() - 获取分配给该变量的表达式(如果有)。
  • getInitializer() - 获取用于初始化变量的表达式(如果有)。

示例

查找所有未使用的局部变量

from LocalVariable v
where not exists(v.getAnAccess())
select v, "This local variable is unused."

类型

类型由 CodeQL 类 Type 表示,包括内置类型、接口、类、结构、枚举和类型参数。数据库包含来自程序和所有引用程序集(包括 mscorlib 和 .NET 框架)的类型。

内置类型(objectintdouble 等)在 mscorlib 中有相应的类型(System.ObjectSystem.Int32 等)。

ValueOrRefType 表示定义的类型,例如 classstructinterfaceenum

类层次结构

  • Element
    • Declaration
      • Modifiable - 可修改声明,可以包含修饰符(例如 public
        • Member - 属于类型的声明
          • Type - 所有类型
            • ValueOrRefType - 定义的类型
              • ValueType - 值类型(见下文了解更详细的层次结构)
              • RefType - 引用类型(见下文了解更详细的层次结构)
              • NestedType - 在另一个类型中定义的类型
            • VoidType - void
            • PointerType - 指针类型

ValueType 扩展为

  • ValueType - 值类型
    • SimpleType - 简单内置类型
      • BoolType - bool
      • CharType - char
      • 整数类型
        • 无符号整数类型
          • ByteType - byte
          • UShortType - unsigned short/System.UInt16
          • UIntType - unsigned int/System.UInt32
          • ULongType - unsigned long/System.UInt64
        • 有符号整数类型
          • SByteType - signed byte
          • ShortType - short/System.Int16
          • IntType - int/System.Int32
          • LongType - long/System.Int64
        • 浮点类型
          • FloatType - float/System.Single
          • DoubleType - double/System.Double
        • DecimalType - decimal/System.Decimal
      • Enum - enum
      • Struct - struct
      • 可空类型
      • 数组类型

RefType 扩展为

  • RefType
    • Class - class
      • 匿名类
      • ObjectType - object/System.Object
      • StringType - string/System.String
    • Interface - interface
    • 委托类型
    • NullType - null 的类型
    • DynamicType - dynamic
  • NestedType - 在另一个类型中定义的类型

为了简化,这些类层次结构省略了泛型类型。

谓词

ValueOrRefType 的有用成员包括

  • getQualifiedName()/hasQualifiedName(string) - 获取类型的限定名称(例如,"System.String")。
  • getABaseInterface() - 获取该类型的直接接口(如果有)。
  • getABaseType() - 获取该类型的直接基类或接口(如果有)。
  • getBaseClass() - 获取该类型的直接基类(如果有)。
  • getASubType() - 获取直接继承自该类型的直接子类型(如果有)。
  • getAMember() - 获取任何成员(字段/方法/属性等)(如果有)。
  • getAMethod() - 获取方法(如果有)。
  • getAProperty() - 获取属性(如果有)。
  • getAnIndexer() - 获取索引器(如果有)。
  • getAnEvent() - 获取事件(如果有)。
  • getAnOperator() - 获取运算符(如果有)。
  • getANestedType() - 获取嵌套类型。
  • getNamespace() - 获取封闭命名空间。

示例

查找 System.Object 的所有成员

from ObjectType object
select object.getAMember()

查找直接实现 System.Collections.IEnumerable 的所有类型

from Interface ienumerable
where ienumerable.hasQualifiedName("System.Collections.IEnumerable")
select ienumerable.getASubType()

列出 System 命名空间中的所有简单类型

select any(SimpleType t | t.getNamespace().hasName("System"))

查找所有类型为 PointerType 的变量

from Variable v
where v.fromSource()
  and v.getType() instanceof PointerType
select v

列出源文件中的所有类

from Class c
where c.fromSource()
select c

练习

练习 3:编写一个查询以列出 string 中的方法。 (答案)

练习 4:修改示例以查找所有间接实现 IEnumerable 的类型。 (答案)

练习 5:编写一个查询以查找所有以字母 A 开头的类。 (答案)

可调用对象

可调用对象由类 Callable 表示,是指可以独立调用的任何东西,例如方法、构造函数、析构函数、运算符、匿名函数、索引器和属性访问器。

数据库包含程序和所有引用程序集中的所有可调用对象。

类层次结构

  • Element
    • Declaration
      • Callable
        • 方法
          • 扩展方法
        • 构造函数
          • 静态构造函数
          • 实例构造函数
        • 析构函数
        • 运算符
          • 一元运算符
            • PlusOperator, MinusOperator, NotOperator, ComplementOperator, IncrementOperator, DecrementOperator, FalseOperator, TrueOperator
          • 二元运算符
            • AddOperator, SubOperator, MulOperator, DivOperator, RemOperator, AndOperator, OrOperator, XorOperator, LShiftOperator, RShiftOperator, EQOperator, NEOperator, LTOperator, GTOperator, LEOperator, GEOperator
          • 转换运算符
            • 隐式转换运算符
            • 显式转换运算符
        • 匿名函数表达式
          • Lambda 表达式
          • 匿名方法表达式
        • 访问器
          • 获取器
          • 设置器
          • 事件访问器
            • AddEventAccessor, RemoveEventAccessor

谓词

以下是 Callable 类的一些有用谓词。

  • getParameter(int)/getAParameter() - 获取参数。
  • calls(Callable) - 是否从一个可调用对象到另一个可调用对象存在直接调用。
  • getReturnType() - 获取返回类型。
  • getBody()/getExpressionBody() - 获取可调用对象的正文。

由于 Callable 扩展了 Declaration,它也具有来自 Declaration 的谓词,例如

  • getName()/hasName(string)
  • getSourceDeclaration()
  • getName()
  • getDeclaringType()

方法具有额外的谓词,包括

  • getAnOverridee() - 获取被此方法直接覆盖的方法。
  • getAnOverrider() - 获取直接覆盖此方法的方法。
  • getAnImplementee() - 获取此方法直接实现的接口方法。
  • getAnImplementor() - 获取直接实现此接口方法的方法。

示例

列出所有覆盖 ToString 的类型。

from Method m
where m.hasName("ToString")
select m

查找类似于 ToString 方法但没有覆盖 Object.ToString 的方法。

from Method toString, Method falseToString
where toString.hasQualifiedName("System.Object.ToString")
 and falseToString.getName().toLowerCase() = "tostring"
 and not falseToString.overrides*(toString)
 and falseToString.getNumberOfParameters() = 0
select falseToString, "This method looks like it overrides Object.ToString but it doesn't."

查找所有接受指针类型的方法。

from Method m
where m.getAParameter().getType() instanceof PointerType
select m, "This method uses pointers."

查找所有具有析构函数但不支持 IDisposable 的类。

from Class c
where c.getAMember() instanceof Destructor
  and not c.getABaseType*().hasQualifiedName("System.IDisposable")
select c, "This class has a destructor but is not IDisposable."

查找不是 privateMain 方法。

from Method m
where m.hasName("Main")
  and not m.isPrivate()
select m, "Main method should be private."

语句

语句由类 Stmt 表示,构成方法(和其他可调用对象)的正文。数据库包含源代码中的所有语句,但不包含来自引用程序集的任何语句,因为这些程序集的源代码不可用。

类层次结构

  • Element
    • ControlFlowElement
      • Stmt
        • BlockStmt - { ... }
        • ExprStmt
        • SelectionStmt
          • IfStmt - if
          • SwitchStmt - switch
        • LabeledStmt
          • ConstCase
          • DefaultCase - default
          • LabelStmt
        • LoopStmt
          • WhileStmt - while(...) { ... }
          • DoStmt - do { ... } while(...)
          • ForStmt - for
          • ForEachStmt - foreach
        • JumpStmt
          • BreakStmt - break
          • ContinueStmt - continue
          • GotoStmt - goto
            • GotoLabelStmt
            • GotoCaseStmt
            • GotoDefaultStmt
          • ThrowStmt - throw
          • ReturnStmt - return
          • YieldStmt
            • YieldBreakStmt - yield break
            • YieldReturnStmt - yield return
        • TryStmt - try
        • CatchClause - catch
          • SpecificCatchClause
          • GeneralCatchClause
        • CheckedStmt - checked
        • UncheckedStmt - unchecked
        • LockStmt - lock
        • UsingStmt - using
        • LocalVariableDeclStmt
          • LocalConstantDeclStmt
        • EmptyStmt - ;
        • UnsafeStmt - unsafe
        • FixedStmt - fixed

示例

查找长方法。

from Method m
where m.getBody().(BlockStmt).getNumberOfStmts() >= 100
select m, "This is a long method!"

查找 for(;;)

from ForStmt for
where not exists(for.getAnInitializer())
  and not exists(for.getUpdate(_))
  and not exists(for.getCondition())
select for, "Infinite loop."

查找 catch(NullDefererenceException)

from SpecificCatchClause catch
where catch.getCaughtExceptionType().hasQualifiedName("System.NullReferenceException")
select catch, "Catch NullReferenceException."

查找条件为常量的 if 语句。

from IfStmt ifStmt
where ifStmt.getCondition().hasValue()
select ifStmt, "This 'if' statement is constant."

查找 "then" 块为空的 if 语句。

from IfStmt ifStmt
where ifStmt.getThen().(BlockStmt).isEmpty()
select ifStmt, "If statement with empty 'then' block."

(BlockStmt) 是一个内联强制转换,它将查询限制在 getThen() 的结果具有 QL 类 BlockStmt 的情况,并允许使用 BlockStmt 上的谓词,例如 isEmpty()

练习

练习 6:编写一个查询来列出所有空方法。(答案)

练习 7:修改最后一个示例,以检测 "then" 块中的空语句 (;)。(答案)

练习 8:修改最后一个示例,以排除 if 语句链,其中 else 部分是另一个 if 语句。(答案)

表达式

Expr 类表示程序中的所有 C# 表达式。表达式是指产生值的任何东西,例如 a+bnew List<int>()。数据库包含来自源代码的所有表达式,但不包含来自引用程序集的任何表达式,因为这些程序集的源代码不可用。

Access 类表示对另一个 Declaration(例如变量、属性、方法或字段)的任何使用或交叉引用。 getTarget() 谓词获取正在访问的声明。

Call 类表示对 Callable 的调用,例如对 MethodAccessor 的调用,而 getTarget() 方法获取正在调用的 CallableOperation 类由算术运算、按位运算和逻辑运算组成。

一些表达式使用限定符,它是表达式操作的对象。一个典型的例子是 MethodCall。在这种情况下, getQualifier() 谓词用于获取 . 左侧的表达式,而 getArgument(int) 用于获取调用的参数。

类层次结构

  • Element
    • ControlFlowElement
      • Expr
        • LocalVariableDeclExpr
          • LocalConstantDeclExpr
        • Operation
          • 一元运算符
            • SizeofExprPointerIndirectionExprAddressOfExpr
          • 二元运算符
            • 比较运算符
              • 相等运算符
                • EQExprNEExpr
                • 关系运算符
                  • GTExprLTExprGEExprLEExpr
          • 赋值
            • 赋值运算符
              • AddOrRemoveEventExpr
                • AddEventExpr
                • RemoveEventExpr
              • 赋值算术运算符
                • AssignAddExprAssignSubExprAssignMulExprAssignDivExprAssignRemExpr
              • 赋值按位运算符
                • AssignAndExprAssignOrExprAssignXorExprAssignLShiftExprAssignRShiftExpr
            • AssignExpr
              • 成员初始化器
          • ArithmeticOperation
            • UnaryArithmeticOperation
              • UnaryMinusExprUnaryPlusExpr
              • MutatorOperation
                • IncrementOperation
                  • PreIncrExprPostIncrExpr
                • DecrementOperation
                  • PreDecrExprPostDecrExpr
            • BinaryArithmeticOperation
              • AddExprSubExprMulExprDivExprRemExpr
          • 按位运算符
            • 一元按位运算符
              • 取反运算符
            • 二元按位运算符
              • LShiftExprRShiftExprBitwiseAndExprBitwiseOrExprBitwiseXorExpr
          • 逻辑运算符
            • 一元逻辑运算符
              • 逻辑非运算符
            • 二元逻辑运算符
              • LogicalAndExprLogicalOrExprNullCoalescingExpr
            • 条件表达式
        • ParenthesisedExprCheckedExprUncheckedExprIsExprAsExprCastExprTypeofExprDefaultValueExprAwaitExprNameofExprInterpolatedStringExpr
        • 访问
          • ThisAccess
          • BaseAccess
          • 成员访问
            • 方法访问
              • 虚拟方法访问
            • FieldAccessPropertyAccessIndexerAccessEventAccessMethodAccess
          • 可赋值访问
            • 变量访问
              • 参数访问
              • 局部变量访问
              • 局部作用域变量访问
              • 字段访问
                • 成员常量访问
            • 属性访问
              • 简单属性访问
              • 虚拟属性访问
            • 索引器访问
              • 虚拟索引器访问
            • 事件访问
              • 虚拟事件访问
          • 类型访问
          • 数组访问
        • 调用
          • 属性调用
          • 索引器调用
          • 事件调用
          • 方法调用
            • 虚拟方法调用
            • 元素初始化器
          • 构造函数初始化器
          • 运算符调用
            • 变异运算符调用
          • 委托调用
          • 对象创建
            • 默认值类型对象创建
            • 类型参数对象创建
            • 匿名对象创建
        • 对象或集合初始化器
          • 对象初始化器
          • 集合初始化器
        • 委托创建
          • ExplicitDelegateCreationImplicitDelegateCreation
        • 数组初始化器
        • 数组创建
        • 匿名函数表达式
          • Lambda 表达式
          • 匿名方法表达式
        • 字面量
          • BoolLiteralCharLiteralIntegerLiteralIntLiteralLongLiteralUIntLiteralULongLiteralRealLiteralFloatLiteralDoubleLiteralDecimalLiteralStringLiteralNullLiteral

谓词

Expr 有用的谓词包括

  • getType() - 获取表达式的Type
  • getValue() - 获取编译时常量(如果有)。
  • hasValue() - 表达式是否具有编译时常量。
  • getEnclosingStmt() - 获取包含表达式的语句(如果有)。
  • getEnclosingCallable() - 获取包含表达式的可调用对象(如果有)。
  • stripCasts() - 删除所有显式或隐式转换。
  • isImplicit() - 表达式是否为隐式,例如隐式this限定符(ThisAccess)。

示例

查找仅带一个参数的String.Format调用

from MethodCall c
where c.getTarget().hasQualifiedName("System.String.Format")
  and c.getNumberOfArguments() = 1
select c, "Missing arguments to 'String.Format'."

查找所有浮点数比较

from ComparisonOperation cmp
where (cmp instanceof EQExpr or cmp instanceof NEExpr)
  and cmp.getAnOperand().getType() instanceof FloatingPointType
select cmp, "Comparison of floating point values."

查找硬编码密码

from Variable v, string value
where v.getName().regexpMatch("[pP]ass(word|wd|)")
  and value = v.getAnAssignedValue().getValue()
select v, "Hard-coded password '" + value + "'."

练习

练习 9:将之前的查询限制为字符串类型。排除空密码或空密码。(答案

属性

C# 属性由类Attribute 表示。它们可以存在于许多 C# 元素上,例如类、方法、字段和参数。数据库包含来自源代码和所有程序集引用的属性。

任何Element的属性可以通过getAnAttribute()获取,而如果你有属性,则可以通过getTarget()找到它的元素。这两个查询片段是相同的

attribute = element.getAnAttribute()
element = attribute.getTarget()

类层次结构

  • Element
    • 属性

谓词

  • getTarget() - 获取此属性适用的Element
  • getArgument(int) - 获取属性的给定参数。
  • getType() - 获取此属性的类型。请注意,类名必须以"Attribute"结尾。

示例

查找所有已过时的元素

from Element e, Attribute attribute
where e = attribute.getTarget()
  and attribute.getType().hasName("ObsoleteAttribute")
select e, "This is obsolete because " + attribute.getArgument(0).getValue()

模拟 NUnit 测试夹具

class TestFixture extends Class
{
  TestFixture() {
    this.getAnAttribute().getType().hasName("TestFixtureAttribute")
  }

  TestMethod getATest() {
    result = this.getAMethod()
  }
}

class TestMethod extends Method
{
  TestMethod() {
    this.getAnAttribute().getType().hasName("TestAttribute")
  }
}

from TestFixture f
select f, f.getATest()

练习

练习 10:编写一个查询以查找仅已过时的方法。(答案

练习 11:编写一个查询以查找所有使用Obsolete属性但没有原因字符串(即[Obsolete])的位置。(答案

练习 12:在第一个示例中,如果Obsolete属性没有原因字符串会发生什么?如何修复查询以适应这种情况?(答案


答案

练习 1

from AddExpr op
select op

select any(AddExpr op)

练习 2

from File f
where f.getNumberOfLines() = max(any(File g).getNumberOfLines())
select f

练习 3

from StringType s
select s.getAMethod()

练习 4

from Interface ienumerable
where ienumerable.hasQualifiedName("System.Collections.IEnumerable")
select ienumerable.getASubType*()

练习 5

from Class a
where a.getName().toLowerCase().matches("a%")
select a

练习 6

select any(Method m | m.getBody().(BlockStmt).isEmpty())

练习 7

from IfStmt ifStmt
where ifStmt.getThen().(BlockStmt).isEmpty() or ifStmt.getThen() instanceof EmptyStmt
select ifStmt, "If statement with empty 'then' block."

练习 8

from IfStmt ifStmt
where (ifStmt.getThen().(BlockStmt).isEmpty() or ifStmt.getThen() instanceof EmptyStmt)
  and not ifStmt.getElse() instanceof IfStmt
select ifStmt, "If statement with empty 'then' block."

练习 9

from Variable v, StringLiteral value
where v.getName().regexpMatch("[pP]ass(word|wd|)")
  and value = v.getAnAssignedValue()
  and value.getValue() != ""
select v, "Hard-coded password '" + value.getValue() + "'."

练习 10

from Method method, Attribute attribute
where method = attribute.getTarget()
  and attribute.getType().hasName("ObsoleteAttribute")
select method, "This is obsolete because " + attribute.getArgument(0).getValue()

练习 11

from Attribute attribute
where attribute.getType().hasName("ObsoleteAttribute")
  and not exists(attribute.getArgument(0))
select attribute, "Missing reason in 'Obsolete' attribute."

练习 12

查询不会返回参数丢失的结果。

以下是修复后的版本

from Element e, Attribute attribute, string reason
where e = attribute.getTarget()
  and attribute.getType().hasName("ObsoleteAttribute")
  and if exists(attribute.getArgument(0))
    then reason = attribute.getArgument(0).getValue()
    else reason = "(not given)"
select e, "This is obsolete because " + reason
  • ©GitHub, Inc.
  • 条款
  • 隐私