mirror of
https://github.com/github/codeql.git
synced 2026-02-08 19:21:07 +01:00
Merge pull request #13 from github/type-expr-resolution
Type expression resolution
This commit is contained in:
@@ -1 +1 @@
|
||||
import codeql_ql.ast.internal.Module::Consistency
|
||||
import codeql_ql.ast.internal.Module::ModConsistency
|
||||
|
||||
1
ql/consistency-queries/TypeResolution.ql
Normal file
1
ql/consistency-queries/TypeResolution.ql
Normal file
@@ -0,0 +1 @@
|
||||
import codeql_ql.ast.internal.Type::TyConsistency
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
|
||||
@@ -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)/.*")
|
||||
|
||||
264
ql/src/codeql_ql/ast/internal/Type.qll
Normal file
264
ql/src/codeql_ql/ast/internal/Type.qll
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user