[Learning CodeQL] [CodeQL for Java][CodeQL library for Java]

庫文件類介紹,可以分為五類:

  • 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是類MethodConstructor的父類,可以用于判斷一個(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, TypeSystem and TypeClass。
    例如,找到直接繼承Object的nested class:
import java

from NestedClass nc
where nc.getASupertype() instanceof TypeObject
select nc
Generics

Type也有一些子類,用于處理generic types。
GenericTypeGenericInterface或者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.getParentStmt.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è)抽象類:ExprParentStmtParent,前者表示任何可能成為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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容