CodeQL的java库(一)
codeql的java库
CodeQL有一个用于分析从Java项目中提取分析CodeQL数据库的扩展库。这个库中的类以面向对象的形式显示数据库中的数据,并提供抽象和谓词来帮助您完成常见的分析任务。该库的实现为一组QL模块,即扩展名为.qll的文件。java.qll模块导入所有核心Java库模块,因此您可以通过以下方式开始查询codeql扫描完成的结果。
import java
本文的其余部分简要总结了这个库提供的最重要的类和动词。
注意:本文中的示例说明了不同库类返回的结果类型。这些结果本身并不有趣,但可以作为开发更复杂查询的基础。本系列文章中也介绍了如何使对一个简单的查询并对其进行微调,以方便您精确地找到您感兴趣的结果。
类摘要
标准Java库中最重要的类可以分为五大类:
1)表示程序元素的类(如类和方法)
2)表示AST节点的类(如语句和表达式)
3)用于表示元数据的类(如注释和注释)
4)计算度量的类(例如圈复杂度和耦合)
5)用于导航程序调用图的类
对于以上每一个最重要的类别,我们将对这些类别中每一个类别进行简要的描述。
表示程序元素的类
这些类表示命名的程序元素:包( Package )、编译单元( CompilationUnit )、类型( Type )、方法( Method )、构造函数( Constructor )和变量( Variable )。
它们共同的超类是 Element ,它提供了通用成员谓词,用于确定程序元素的名称并检查两个元素是否嵌套在彼此内部。
引用可能是方法或构造函数的元素通常在使用中很方便; Callable 是 Method
和 Constructor 的通用超类,可用于此目的。
类型
Type
这个类有许多子类用于表示不同类型的类型:
PrimitiveType
表示一个基本类型,即 boolean
, byte
, char
, double
, float
, int
, long
, short
之一;此外codeQL还将 void
和 <nulltype> (空文本的类型)划分为基本类型。
RefType
表示引用(即非基元)类型;它又有几个子类:
Class
表示Java类。
Interface 表示Java接口。
EnumType 表示Java枚举类型。
Array
表示Java数组类型。
例如,以下查询查找程序中所有 int
类型的变量:
import java
from Variable v, PrimitiveType pt
where pt = v.getType() and
pt.hasName("int")
select v
引用类型也根据其声明范围进行分类:
TopLevelType
表示在编译单元的顶层声明的引用类型。
NestedType
是在另一个类型内声明的类型。
例如,此查询查找与其编译单元的名称不同的所有顶级类型:
import java
from TopLevelType tl
where tl.getName() != tl.getCompilationUnit().getName()
select tl
还有几个更细分的类:
TopLevelClass
表示在编译单元的顶层声明的类。
NestedClass
表示在另一个类型中声明的类,例如:
LocalClass ,它是在方法或构造函数中声明的类。
AnonymousClass ,它是一个匿名类。
最后,这个库还有许多封装常用Java标准库类的单例类: TypeObject
, TypeCloneable
, TypeRuntime
, TypeSerializable
, TypeString
, TypeSystem
和TypeClass
.每个CodeQL类代表由其名称所指向的标准Java类。
例如,我们可以编写一个查询来查找所有的嵌套类:
import java
from NestedClass nc
where nc.getASupertype() instanceof TypeObject
select nc
泛型
还有几个类型的子类用于处理泛型。
GenericType
可以是 GenericInterface
或 GenericClass 。它表示从Java标准库中指向一个泛型类型声明,例如 java.util.Map
:
package java.util.;
public interface Map<K, V> {
int size();
// ...
}
类型参数(如本例中的K和V)由类 TypeVariable 表示。
泛型类型的参数化实例提供一个具体的类型来实例化类型参数,如 Map<String, File>
中所示。这样的类型由 ParameterizedType 表示,它不同于代表实例化它的泛型类型的 GenericType
。要从 ParameterizedType
转换到其对应的 GenericType ,可以使用谓词 getSourceDeclaration 。
例如,我们可以使用以下查询来查找 java.util.Map :
import java
from GenericInterface map, ParameterizedType pt
where map.hasQualifiedName("java.util", "Map") and
pt.getSourceDeclaration() = map
select pt
一般来说,泛型类型可能会限制类型参数可以绑定到哪些类型。例如,从字符串到数字的映射类型可以声明如下:
class StringToNumMap<N extends Number> implements Map<String, N> { // ... }
这意味着 StringToNumberMap
的参数化实例只能用类型 Number
或其子类型之一实例化类型参数 N
,但不能实例化 File 。我们说N
是一个有界类型参数,其上界是 Number
。在QL中,可以使用谓词 getATypeBound 查询类型变量的类型绑定。类型边界本身由 TypeBound 类表示,它有一个成员谓词 getType
来检索变量所绑定的类型。
例如,以下查询将查找类型绑定 Number 的所有类型变量:
import java
from TypeVariable tv, TypeBound tb
where tb = tv.getATypeBound() and
tb.getType().hasQualifiedName("java.lang", "Number")
select tv
例如,在下面的代码片段中,此查询将找到 m1 ,而不是 m2 :
Map m1 = new HashMap();
Map<String, String> m2 = new HashMap<String, String>();
最后,变量可以声明为通配符类型: