庫文件類介紹,可以分為五類:
- 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), 構(gòu)造器 (Constructor), 和變量 (Variable).
這些類型的父類是Element,這個(gè)類提供了通用的predicates:獲取元素名以及判斷兩個(gè)元素是否nested inside each other。
類Callable是類Method和Constructor的父類,可以用于判斷一個(gè)元素是否是方法或者構(gòu)造器。
Types
Type有很多子類型,包括:
-
PrimitiveType(基本數(shù)據(jù)類型):包括boolean,byte,char,double,float,int,long,short,void,<nulltype>。 -
RefType(引用數(shù)據(jù)類型),它有如下幾個(gè)子類:
-
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
引用數(shù)據(jù)類型也可以根據(jù)聲明的范圍分為兩類:
-
TopLevelType:在編譯單元中定義為top-level的引用數(shù)據(jù)類型 -
NestedType:在其他類型內(nèi)部定義的引用數(shù)據(jù)類型
例如,查找top-level類型的名字與編譯單元的名字不同的:
import java
from TopLevelType tl
where tl.getName() != tl.getCompilationUnit().getName()
select tl
更加具體的,還可以定義
-
TopLevelClass:在編譯單元中定義的top-level的類 -
NestedClass:在其他類型內(nèi)部定義的類:比如,LocalClass,在方法或者構(gòu)造器內(nèi)定義的類;AnonymousClass匿名類。
同時(shí),也定義了java中的單例類,它們與java中的含義類似:TypeObject,TypeCloneable,TypeRuntime,TypeSerializable,TypeString,TypeSystemandTypeClass。
例如,找到直接繼承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或者其他類型),本地變量,或者參數(shù)。
與此相對,有三個(gè)子類:
-
Field表示java中的成員屬性。 -
LocalVariableDecl表示本地變量。 -
Parameter表示方法或者構(gòu)造器的參數(shù)。
Abstract syntax tree
這個(gè)分類中的類表示抽象語法樹(AST)的節(jié)點(diǎn),也就是statements(Stmt類)和expressions(Expr類)。
Stmt類和Expr類有一些成員謂詞:
-
Expr.getAChildExpr返回指定的expression的子expression. -
Stmt.getAChild返回直接在指定statement內(nèi)部的statement或者expression. -
Expr.getParent和Stmt.getParent返回AST節(jié)點(diǎn)的父節(jié)點(diǎn)。
例如,找到所有父節(jié)點(diǎn)為return語句的expression:
import java
from Expr e
where e.getParent() instanceof ReturnStmt
select e
例如,找到所有父節(jié)點(diǎn)為if表達(dá)式的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
根據(jù)上面的例子,可以得到:
一個(gè)expression的父節(jié)點(diǎn)可能不是expression,它可能是statement,比如IfStmt。與此類似,一個(gè)statement的父節(jié)點(diǎn)不一定是statement,它可能是一個(gè)方法或者構(gòu)造器。因此,QL java類庫提供了兩個(gè)抽象類:ExprParent和StmtParent,前者表示任何可能成為expression父節(jié)點(diǎn)的節(jié)點(diǎn),后者表示任何可能成為statement父節(jié)點(diǎn)的節(jié)點(diǎn)。
Metadata
包括[annotations]注解和[Javadoc]注釋。
類Annotatable是程序中可以被注解的程序元素的父類。這些可以被注解的程序元素包括:包、引用類型、成員屬性、方法、構(gòu)造器,局部變量聲明等。針對這些元素,謂詞getAnAnnotation可以獲取這些謂詞的注解。
例如,獲取所有構(gòu)造器的注解:
import java
from Constructor c
select c.getAnAnnotation()
例如,獲取構(gòu)造器類型為“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有一個(gè)成員謂詞getDoc,返回一個(gè)委派的Documentable對象。
例如,找到所有私有屬性上的javadoc注釋:
import java
from Field f, Javadoc jdoc
where f.isPrivate() and
jdoc = f.getDoc().getJavadoc()
select jdoc
例如,找到所有私有屬性上的javadoc注釋并且含有作者標(biāo)簽。
import java
from Field f, Javadoc jdoc, AuthorTag at
where f.isPrivate() and
jdoc = f.getDoc().getJavadoc() and
at.getParent+() = jdoc
select at
其中,“getParent+”表示任意深度的,都會(huì)返回。
Metrics
metrics相關(guān)的并非使用成員謂詞,而是使用delegate類來實(shí)現(xiàn)的。
包括六個(gè)類:MetricElement, MetricPackage, MetricRefType, MetricField, MetricCallable, MetricStmt.
比如,返回所有圈復(fù)雜度大于40的方法:
import java
from Method m, MetricCallable mc
where mc = m.getMetrics() and
mc.getCyclomaticComplexity() > 40
select m
Call Graph
Callable類包括方法和構(gòu)造函數(shù)。
例如,找到所有調(diào)用println方法的地方:
import java
from Call c, Method m
where m = c.getCallee() and
m.hasName("println")
select c
找到從未被調(diào)用的構(gòu)造器和方法:
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