库文件类介绍,可以分为五类:
- Classes for representing program elements (such as classes and methods)
- Classes for representing AST nodes (such as statements and expressions)
- Classes for representing metadata (such as annotations and comments)
- Classes for computing metrics (such as cyclomatic complexity and coupling)
- Classes for navigating the program’s call graph
Program elements
这些类表示命名的程序元素,比如包 (Package
), 编译单元 (CompilationUnit
), 类型 (Type
), 方法 (Method
), 构造器 (Constructor
), 和变量 (Variable
).
这些类型的父类是Element
,这个类提供了通用的predicates:获取元素名以及判断两个元素是否nested inside each other。
类Callable
是类Method
和Constructor
的父类,可以用于判断一个元素是否是方法或者构造器。
Types
Type
有很多子类型,包括:
-
PrimitiveType
(基本数据类型):包括boolean
,byte
,char
,double
,float
,int
,long
,short
,void
,<nulltype>
。 -
RefType
(引用数据类型),它有如下几个子类:
-
Class
:表示java的类 -
Interface
:表示java的接口 -
EnumType
:表示java的枚举类型 -
Array
:表示java的array类型
例如,查找代码中的所有int类型
import java
from Variable v, PrimitiveType pt
where pt = v.getType() and
pt.hasName("int")
select v
引用数据类型也可以根据声明的范围分为两类:
-
TopLevelType
:在编译单元中定义为top-level的引用数据类型 -
NestedType
:在其他类型内部定义的引用数据类型
例如,查找top-level类型的名字与编译单元的名字不同的:
import java
from TopLevelType tl
where tl.getName() != tl.getCompilationUnit().getName()
select tl
更加具体的,还可以定义
-
TopLevelClass
:在编译单元中定义的top-level的类 -
NestedClass
:在其他类型内部定义的类:比如,LocalClass
,在方法或者构造器内定义的类;AnonymousClass
匿名类。
同时,也定义了java中的单例类,它们与java中的含义类似:TypeObject
,TypeCloneable
,TypeRuntime
,TypeSerializable
,TypeString
,TypeSystem
andTypeClass
。
例如,找到直接继承Object的nested class:
import java
from NestedClass nc
where nc.getASupertype() instanceof TypeObject
select nc
Generics
Type
也有一些子类,用于处理generic types。
GenericType
是GenericInterface
或者GenericClass
。
例如,查找所有使用了map泛型的地方:
import java
from GenericInterface map, ParameterizedType pt
where map.hasQualifiedName("java.util", "Map") and
pt.getSourceDeclaration() = map
select pt
Variables
类Variable
表示java类中的变量,比如类中的成员属性(static或者其他类型),本地变量,或者参数。
与此相对,有三个子类:
-
Field
表示java中的成员属性。 -
LocalVariableDecl
表示本地变量。 -
Parameter
表示方法或者构造器的参数。
Abstract syntax tree
这个分类中的类表示抽象语法树(AST)的节点,也就是statements(Stmt
类)和expressions(Expr
类)。
Stmt
类和Expr
类有一些成员谓词:
-
Expr.getAChildExpr
返回指定的expression的子expression. -
Stmt.getAChild
返回直接在指定statement内部的statement或者expression. -
Expr.getParent
和Stmt.getParent
返回AST节点的父节点。
例如,找到所有父节点为return语句的expression:
import java
from Expr e
where e.getParent() instanceof ReturnStmt
select e
例如,找到所有父节点为if表达式的statement:
import java
from Stmt s
where s.getParent() instanceof IfStmt
select s
例如,找到所有method体:
import java
from Stmt s
where s.getParent() instanceof Method
select s
根据上面的例子,可以得到:
一个expression的父节点可能不是expression,它可能是statement,比如IfStmt。与此类似,一个statement的父节点不一定是statement,它可能是一个方法或者构造器。因此,QL java类库提供了两个抽象类:ExprParent
和StmtParent
,前者表示任何可能成为expression父节点的节点,后者表示任何可能成为statement父节点的节点。
Metadata
包括[annotations]注解和[Javadoc]注释。
类Annotatable
是程序中可以被注解的程序元素的父类。这些可以被注解的程序元素包括:包、引用类型、成员属性、方法、构造器,局部变量声明等。针对这些元素,谓词getAnAnnotation
可以获取这些谓词的注解。
例如,获取所有构造器的注解:
import java
from Constructor c
select c.getAnAnnotation()
例如,获取构造器类型为“Deprecated”的注解:
import java
from Constructor c, Annotation ann, AnnotationType anntp
where ann = c.getAnAnnotation() and
anntp = ann.getType() and
anntp.hasQualifiedName("java.lang", "Deprecated")
select ann
针对JavaDoc,类Element
有一个成员谓词getDoc
,返回一个委派的Documentable
对象。
例如,找到所有私有属性上的javadoc注释:
import java
from Field f, Javadoc jdoc
where f.isPrivate() and
jdoc = f.getDoc().getJavadoc()
select jdoc
例如,找到所有私有属性上的javadoc注释并且含有作者标签。
import java
from Field f, Javadoc jdoc, AuthorTag at
where f.isPrivate() and
jdoc = f.getDoc().getJavadoc() and
at.getParent+() = jdoc
select at
其中,“getParent+”表示任意深度的,都会返回。
Metrics
metrics相关的并非使用成员谓词,而是使用delegate类来实现的。
包括六个类:MetricElement
, MetricPackage
, MetricRefType
, MetricField
, MetricCallable
, MetricStmt
.
比如,返回所有圈复杂度大于40的方法:
import java
from Method m, MetricCallable mc
where mc = m.getMetrics() and
mc.getCyclomaticComplexity() > 40
select m
Call Graph
Callable
类包括方法和构造函数。
例如,找到所有调用println方法的地方:
import java
from Call c, Method m
where m = c.getCallee() and
m.hasName("println")
select c
找到从未被调用的构造器和方法:
import java
from Callable c
where not exists(c.getAReference())
select c
Reference
https://help.semmle.com/QL/learn-ql/java/introduce-libraries-java.html