QL: Add type expression resolution

This commit is contained in:
Joe Farebrother
2021-05-27 14:45:42 +01:00
parent 158b50f482
commit d5bf0cb33f
5 changed files with 249 additions and 16 deletions

View File

@@ -1 +1 @@
import codeql_ql.ast.internal.Module::Consistency
import codeql_ql.ast.internal.Module::ModConsistency

View File

@@ -0,0 +1 @@
import codeql_ql.ast.internal.Type::TyConsistency

View File

@@ -1,6 +1,7 @@
import ql
private import codeql_ql.ast.internal.AstNodes
private import codeql_ql.ast.internal.Module
private import codeql_ql.ast.internal.Type
/** An AST node of a QL program */
class AstNode extends TAstNode {
@@ -169,16 +170,16 @@ class VarDecl extends TVarDecl, AstNode {
result.(Quantifier).getAnArgument() = this
}
Type getType() { toGenerated(result) = var.getChild(0) }
TypeExpr getType() { toGenerated(result) = var.getChild(0) }
}
/**
* A type, such as `DataFlow::Node`.
* A type reference, such as `DataFlow::Node`.
*/
class Type extends TType, AstNode {
class TypeExpr extends TType, AstNode {
Generated::TypeExpr type;
Type() { this = TType(type) }
TypeExpr() { this = TType(type) }
override string getAPrimaryQlClass() { result = "Type" }
@@ -219,6 +220,8 @@ class Type extends TType, AstNode {
or
result.(Class).getAliasType() = this
}
Type getResolvedType() { resolveTypeExpr(this, result) }
}
/**
@@ -318,14 +321,10 @@ class Class extends TClass, AstNode, ModuleMember {
cls.getChild(_).(Generated::ClassMember).getChild(_).(Generated::Field).getChild()
}
/**
* Gets a super-type for this class.
* That is: a type after the `extends` keyword.
*/
Type getASuperType() { toGenerated(result) = cls.getChild(_) }
TypeExpr getASuperType() { toGenerated(result) = cls.getChild(_) }
/** Gets the type that this class is defined to be an alias of. */
Type getAliasType() {
TypeExpr getAliasType() {
toGenerated(result) = cls.getChild(_).(Generated::TypeAliasBody).getChild()
}
}
@@ -459,7 +458,9 @@ class InlineCast extends TInlineCast, Expr {
override string getAPrimaryQlClass() { result = "InlineCast" }
Type getType() { toGenerated(result) = expr.getChild(_).(Generated::QualifiedRhs).getChild(_) }
TypeExpr getType() {
toGenerated(result) = expr.getChild(_).(Generated::QualifiedRhs).getChild(_)
}
Expr getBase() { toGenerated(result) = expr.getChild(0) }
}
@@ -739,10 +740,10 @@ class InstanceOf extends TInstanceOf, Formula {
Expr getExpr() { toGenerated(result) = inst.getChild(0) }
/** Gets the reference to the type being checked. */
Type getType() { toGenerated(result) = inst.getChild(1) }
TypeExpr getType() { toGenerated(result) = inst.getChild(1) }
/** Gets the type being checked. */
//QLType getType() { result = getTypeRef().getType() }
//QLTypeExpr getType() { result = getTypeRef().getType() }
override string getAPrimaryQlClass() { result = "InstanceOf" }
}

View File

@@ -80,7 +80,7 @@ private Module getEnclosingModule0(AstNode n) {
AstNodes::toGenerated(result) = parent*(AstNodes::toGenerated(n).getParent())
}
private ContainerOrModule getEnclosingModule(AstNode n) {
ContainerOrModule getEnclosingModule(AstNode n) {
result = TModule(getEnclosingModule0(n))
or
not exists(getEnclosingModule0(n)) and
@@ -209,7 +209,7 @@ private predicate defines(
)
}
module Consistency {
module ModConsistency {
query predicate noResolve(Import imp) {
not resolve(imp, _) and
not imp.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")

View File

@@ -0,0 +1,231 @@
import ql
private import codeql_ql.ast.internal.AstNodes as AstNodes
private import codeql_ql.ast.internal.TreeSitter
private import codeql_ql.ast.internal.Module
private newtype TType =
TClass(Class c) or
TNewType(NewType n) or
TNewTypeBranch(NewTypeBranch b) or
TPrimitive(string s) { primTypeName(s) } or
// TUnion(...) or
TDontCare() or
TClassChar(Class c) or
TClassDomain(Class c) or
TDatabase(string s) { exists(TypeExpr t | t.isDBType() and s = t.getClassName()) }
private predicate primTypeName(string s) { s = ["int", "float", "string", "boolean", "date"] }
/**
* A type, such as `int` or `Node`.
*/
class Type extends TType {
string toString() { result = getName() }
string getName() { result = "???" }
/**
* Gets a supertype of this type. This follows the user-visible type heirarchy,
* and doesn't include internal types like thecharacteristic and domain types of classes.
*/
Type getASuperType() { none() }
/**
* Gets a supertype of this type in the internal heirarchy,
* which includes the characteristic and domain types of classes.
*/
Type getAnInternalSuperType() { result = TDontCare() }
AstNode getDeclaration() { none() }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
if exists(getDeclaration())
then
getDeclaration()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
else (
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
)
}
}
class ClassType extends Type, TClass {
Class decl;
ClassType() { this = TClass(decl) }
override string getName() { result = decl.getName() }
override Class getDeclaration() { result = decl }
override Type getASuperType() { result = decl.getASuperType().getResolvedType() }
override Type getAnInternalSuperType() {
result.(ClassCharType).getClassType() = this
or
result = super.getAnInternalSuperType()
}
}
class ClassCharType extends Type, TClassChar {
Class decl;
ClassCharType() { this = TClassChar(decl) }
override string getName() { exists(string n | n = decl.getName() | result = n + "." + n) }
override Class getDeclaration() { result = decl }
ClassType getClassType() { result = TClass(decl) }
override Type getAnInternalSuperType() {
result.(ClassDomainType).getClassType() = this.getClassType()
}
}
class ClassDomainType extends Type, TClassDomain {
Class decl;
ClassDomainType() { this = TClassDomain(decl) }
override string getName() { result = decl.getName() + ".extends" }
override Class getDeclaration() { result = decl }
ClassType getClassType() { result = TClass(decl) }
override Type getAnInternalSuperType() { result = getClassType().getASuperType() }
}
class PrimitiveType extends Type, TPrimitive {
string name;
PrimitiveType() { this = TPrimitive(name) }
override string getName() { result = name }
override Type getASuperType() { name = "int" and result.(PrimitiveType).getName() = "float" }
override Type getAnInternalSuperType() {
result = getASuperType()
or
result = super.getAnInternalSuperType()
}
}
class DontCareType extends Type, TDontCare {
override string getName() { result = "_" }
override Type getAnInternalSuperType() { none() }
}
class NewTypeType extends Type, TNewType {
NewType decl;
NewTypeType() { this = TNewType(decl) }
override NewType getDeclaration() { result = decl }
override string getName() { result = decl.getName() }
}
class NewTypeBranchType extends Type, TNewTypeBranch {
NewTypeBranch decl;
NewTypeBranchType() { this = TNewTypeBranch(decl) }
override NewTypeBranch getDeclaration() { result = decl }
override string getName() { result = decl.getName() }
override Type getASuperType() { result = TNewType(decl.getParent()) }
override Type getAnInternalSuperType() {
result = getASuperType()
or
result = super.getAnInternalSuperType()
}
}
class DatabaseType extends Type, TDatabase {
string name;
DatabaseType() { this = TDatabase(name) }
override string getName() { result = name }
}
predicate resolveTypeExpr(TypeExpr te, Type t) {
if te.isDBType()
then t = TDatabase(te.getClassName())
else
if primTypeName(te.getClassName())
then t = TPrimitive(te.getClassName())
else
exists(FileOrModule m, boolean public | qualifier(te, m, public) |
defines(m, te.getClassName(), t, public)
)
}
private predicate qualifier(TypeExpr te, FileOrModule m, boolean public) {
if exists(te.getModule())
then (
public = true and m = te.getModule().getResolvedModule()
) else (
(public = true or public = false) and
m = getEnclosingModule(te)
)
}
private boolean getPublicBool(ModuleMember m) {
if m.isPrivate() then result = false else result = true
}
private predicate defines(FileOrModule m, string name, Type t, boolean public) {
exists(Class ty | t = TClass(ty) |
getEnclosingModule(ty) = m and
ty.getName() = name and
public = getPublicBool(ty)
)
or
exists(NewType ty | t = TNewType(ty) |
getEnclosingModule(ty) = m and
ty.getName() = name and
public = getPublicBool(ty)
)
or
exists(NewTypeBranch ty | t = TNewTypeBranch(ty) |
getEnclosingModule(ty) = m and
ty.getName() = name and
public = getPublicBool(ty.getParent())
)
or
exists(Import im |
getEnclosingModule(im) = m and
not exists(im.importedAs()) and
public = getPublicBool(im) and
defines(im.getResolvedModule(), name, t, true)
)
or
defines(m.getEnclosing(), name, t, public)
}
module TyConsistency {
query predicate noResolve(TypeExpr te) {
not resolveTypeExpr(te, _) and
not te.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
}
query predicate multipleResolve(TypeExpr te, int c, Type t) {
c = strictcount(Type t0 | resolveTypeExpr(te, t)) and
c > 1 and
resolveTypeExpr(te, t)
}
}