Merge pull request #13 from github/type-expr-resolution

Type expression resolution
This commit is contained in:
Joe Farebrother
2021-05-27 15:48:20 +01:00
committed by GitHub
7 changed files with 366 additions and 21 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" }
@@ -221,6 +222,8 @@ class Type extends TType, AstNode {
or
result.(Class).getUnionMember() = this
}
Type getResolvedType() { resolveTypeExpr(this, result) }
}
/**
@@ -320,19 +323,15 @@ 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()
}
/** Gets the type of one of the members that this class is defined to be a union of. */
Type getUnionMember() {
TypeExpr getUnionMember() {
toGenerated(result) = cls.getChild(_).(Generated::TypeUnionBody).getChild(_)
}
}
@@ -466,7 +465,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) }
}
@@ -746,10 +747,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,264 @@
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) { isActualClass(c) } or
TNewType(NewType n) or
TNewTypeBranch(NewTypeBranch b) or
TPrimitive(string s) { primTypeName(s) } or
TUnion(Class c) { exists(c.getUnionMember()) } or
TDontCare() or
TClassChar(Class c) { isActualClass(c) } or
TClassDomain(Class c) { isActualClass(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"] }
private predicate isActualClass(Class c) {
not exists(c.getAliasType()) and
not exists(c.getUnionMember())
}
/**
* 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 }
NewTypeBranchType getABranch() { result = TNewTypeBranch(decl.getABranch()) }
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())
or
result.(UnionType).getUnionMember() = this
}
override Type getAnInternalSuperType() {
result = getASuperType()
or
result = super.getAnInternalSuperType()
}
}
class UnionType extends Type, TUnion {
Class decl;
UnionType() { this = TUnion(decl) }
override Class getDeclaration() { result = decl }
override string getName() { result = decl.getName() }
Type getUnionMember() { result = decl.getUnionMember().getResolvedType() }
}
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).getEnclosing*()
)
}
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(Class ty | t = TUnion(ty) |
getEnclosingModule(ty) = m and
ty.getName() = name and
public = getPublicBool(ty)
)
or
exists(Class ty | t = ty.getAliasType().getResolvedType() |
getEnclosingModule(ty) = m and
ty.getName() = name and
public = getPublicBool(ty)
)
or
exists(Import im |
getEnclosingModule(im) = m and
not exists(im.importedAs()) and
public = getPublicBool(im) and
defines(im.getResolvedModule(), name, t, true)
)
}
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, t0)) and
c > 1 and
resolveTypeExpr(te, t)
}
}

View File

@@ -9,13 +9,53 @@
import ql
import codeql_ql.ast.internal.Module
import codeql_ql.ast.internal.Type
import codeql.IDEContextual
external string selectedSourceFile();
from ModuleRef ref, FileOrModule target, string kind
where
newtype TLoc =
TAst(AstNode n) or
TFileOrModule(FileOrModule m)
class Loc extends TLoc {
string toString() { result = "" }
AstNode asAst() { this = TAst(result) }
FileOrModule asMod() { this = TFileOrModule(result) }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(AstNode n | this = TAst(n) |
n.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
or
exists(FileOrModule m | this = TFileOrModule(m) |
m.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
}
}
predicate resolveModule(ModuleRef ref, FileOrModule target, string kind) {
target = ref.getResolvedModule() and
kind = "module" and
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
predicate resolveType(TypeExpr ref, AstNode target, string kind) {
target = ref.getResolvedType().getDeclaration() and
kind = "type" and
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
predicate resolve(Loc ref, Loc target, string kind) {
resolveModule(ref.asAst(), target.asMod(), kind)
or
resolveType(ref.asAst(), target.asAst(), kind)
}
from Loc ref, Loc target, string kind
where resolve(ref, target, kind)
select ref, target, kind

View File

@@ -13,9 +13,48 @@ import codeql.IDEContextual
external string selectedSourceFile();
from ModuleRef ref, FileOrModule target, string kind
where
newtype TLoc =
TAst(AstNode n) or
TFileOrModule(FileOrModule m)
class Loc extends TLoc {
string toString() { result = "" }
AstNode asAst() { this = TAst(result) }
FileOrModule asMod() { this = TFileOrModule(result) }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(AstNode n | this = TAst(n) |
n.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
or
exists(FileOrModule m | this = TFileOrModule(m) |
m.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
}
}
predicate resolveModule(ModuleRef ref, FileOrModule target, string kind) {
target = ref.getResolvedModule() and
kind = "module" and
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
predicate resolveType(TypeExpr ref, AstNode target, string kind) {
target = ref.getResolvedType().getDeclaration() and
kind = "type" and
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
predicate resolve(Loc ref, Loc target, string kind) {
resolveModule(ref.asAst(), target.asMod(), kind)
or
resolveType(ref.asAst(), target.asAst(), kind)
}
from Loc ref, Loc target, string kind
where resolve(ref, target, kind)
select ref, target, kind