Basics

Program Elements

Types

下面是Type的几个子类

  • PrimitiveType: 表示Java中的原始类

    • booleanbytechardoublefloatintlongshort

    • QL中把voidnull也作为原始类

  • RefType: 表示引用类型(reference | non-primitive), 有如下子类

    • Class

    • Interface

    • EnumType

    • Array

  • TopLevelType: 表示声明在一个编译单元最上层的引用类型(不太懂。。。)

  • NestedType: 声明在另一个类型中的类型

    • LocalClass: 声明在一个方法或构造函数中的类

    • AnonymousClass: 匿名类

此外还有一些常用的类,顾名思义

TypeObjectTypeCloneableTypeRuntimeTypeSerializableTypeStringTypeSystemTypeClass

examples:

  • 查找所有double变量

import java

from Variable v, PrimitiveType pt
where pt = v.getType() and pt.hasName("double")
select v
  • 查找所有直接继承自Object的内部类

import java

from InnerClass ic
where ic.getASupertype() instanceof TypeObject
select ic

Generics

GenericType表示泛型,分为 GenericInterfaceGenericClass

比如java.util.Map这个接口

package java.util.;

public interface Map<K, V> {
    int size();
    // ...
}

参数KVTypeVariable表示

泛型的参数化实例(如Map<String, File>)提供了一个具体类型(这里的StringFile)来实例化类型参数,比

这里的参数化实例用ParameterizedType表示

通过getSourceDeclaration获取ParameterizedType对应的GenericType

通常,泛型可能会限制类型参数可以绑定到哪些类型,比如下面限制了一个从String到Number的map

class StringToNumMap<N extends Number> implements Map<String, N> {
    // ...
}

StringToNumberMap的参数化实例只能是Number或其子类

使用getATypeBoundgetType来得到TypeVariable类型绑定

RawType用于处理泛型的原生类型,如下m1

Map m1 = new HashMap();
Map<String, String> m2 = new HashMap<String, String>();

examples:

  • 查找java.util.Map的所有参数化实例

import java

from GenericInterface map, ParameterizedType pt
where
    map.hasQualifiedName("java.util", "Map") and
    pt.getSourceDeclaration() = map
select pt
  • 查找java.util.Map的原生类型

import java

from Variable v, RawType rt
where rt = v.getType() and
    rt.getSourceDeclaration().hasQualifiedName("java.util", "Map")
select v
  • 查找绑定到java.lang.Object的所有泛型的类型变量

import java

from TypeVariable tv, TypeBound tb
where tb = tv.getATypeBound() and
    tb.getType().hasQualifiedName("java.lang", "Object")
select tv

Variables

Variable表示Java中的变量

  • Field

  • LocalVariableDecl

  • Parameter

AST

抽象语法树中的节点

  • statement(Stmt)

  • expression(Expr)

  • Expr.getAChildExpr 返回子表达式

  • Stmt.getAChild 返回语句的下一条语句

  • Expr.getParentStmt.getParent 返回父节点

import java

from Expr e
where e.getParent() instanceof ReturnStmt
select e

返回跟在return语句后面的表达式

比如 return x+y 返回 x+y

import java

from Stmt s
where s.getParent() instanceof IfStmt
select s

返回所有if语句的then分支和else分支

import java

from Stmt s
where s.getParent() instanceof Method
select s

返回所有方法体

可见ExprStmt的父节点不一定是ExprStmt,可以使用ExprParentStmtParent表示ExprStmt可能的父节点

Metadata

元数据包括注解(annotation)和文档(javadoc)

对于packages, reference types, fields, methods, constructors, local variable declarations

这些都可以被注解,Annotatable是其父类,getAnAnnotation获取注解

寻找所有Callable(包括MethodConstructor)的注解

import java

from Callable 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

寻找私有字段的文档

import java

from Field f, Javadoc jdoc
where f.isPrivate() and
    jdoc = f.getDoc().getJavadoc()
select jdoc

Call graph

CodeQL根据Java代码生成的数据库包含了预计算的程序调用图

Callable包括方法和构造器,Call表示调用表达式(包括方法调用、new对象、用thissuper的构造器调用)

下面找出println的调用点

import java

from Call c, Method m
where m = c.getCallee() and
    m.hasName("println")
select c

Callable.getAReference返回Call调用表达式的引用点

下面找出没被调用过的方法

import java

from Callable c
where not exists(c.getAReference())
select c

Last updated