add a mock TypeExpr, and use it

This commit is contained in:
erik-krogh 2022-12-01 13:24:36 +01:00
Родитель 5db2f0aba0
Коммит 4dc52379ad
Не найден ключ, соответствующий данной подписи
4 изменённых файлов: 93 добавлений и 19 удалений

Просмотреть файл

@ -724,7 +724,7 @@ class FieldDecl extends TFieldDecl, AstNode {
* A type reference, such as `DataFlow::Node`. * A type reference, such as `DataFlow::Node`.
*/ */
class TypeExpr extends TType, TypeRef { class TypeExpr extends TType, TypeRef {
QL::TypeExpr type; Mocks::TypeExprOrMock type;
TypeExpr() { this = TType(type) } TypeExpr() { this = TType(type) }
@ -737,28 +737,30 @@ class TypeExpr extends TType, TypeRef {
* or db-types such as `@locateable`. * or db-types such as `@locateable`.
*/ */
string getClassName() { string getClassName() {
result = type.getName().getValue() result = type.asLeft().getName().getValue()
or or
result = type.getChild().(QL::PrimitiveType).getValue() result = type.asLeft().getChild().(QL::PrimitiveType).getValue()
or or
result = type.getChild().(QL::Dbtype).getValue() result = type.asLeft().getChild().(QL::Dbtype).getValue()
or
result = type.asRight().getClassName()
} }
/** /**
* Holds if this type is a primitive such as `string` or `int`. * Holds if this type is a primitive such as `string` or `int`.
*/ */
predicate isPrimitive() { type.getChild() instanceof QL::PrimitiveType } predicate isPrimitive() { type.asLeft().getChild() instanceof QL::PrimitiveType }
/** /**
* Holds if this type is a db-type. * Holds if this type is a db-type.
*/ */
predicate isDBType() { type.getChild() instanceof QL::Dbtype } predicate isDBType() { type.asLeft().getChild() instanceof QL::Dbtype }
/** /**
* Gets the module of the type, if it exists. * Gets the module of the type, if it exists.
* E.g. `DataFlow` in `DataFlow::Node`. * E.g. `DataFlow` in `DataFlow::Node`.
*/ */
ModuleExpr getModule() { toQL(result) = type.getQualifier() } ModuleExpr getModule() { toQL(result) = type.asLeft().getQualifier() }
/** Gets the type that this type reference refers to. */ /** Gets the type that this type reference refers to. */
override Type getResolvedType() { override Type getResolvedType() {
@ -2400,18 +2402,20 @@ class ModuleExpr extends TModuleExpr, TypeRef {
/** A signature expression, either a `PredicateExpr`, a `TypeExpr`, or a `ModuleExpr`. */ /** A signature expression, either a `PredicateExpr`, a `TypeExpr`, or a `ModuleExpr`. */
class SignatureExpr extends TSignatureExpr, AstNode { class SignatureExpr extends TSignatureExpr, AstNode {
QL::SignatureExpr sig; Mocks::SignatureExprOrMock sig;
SignatureExpr() { SignatureExpr() {
toQL(this) = sig.getPredicate() toQL(this) = sig.asLeft().getPredicate()
or or
toQL(this) = sig.getTypeExpr() toQL(this) = sig.asLeft().getTypeExpr()
or or
toQL(this) = sig.getModExpr() toMock(this) = sig.asRight()
or
toQL(this) = sig.asLeft().getModExpr()
} }
/** Gets the generated AST node that contains this signature expression. */ /** Gets the generated AST node that contains this signature expression. */
QL::SignatureExpr toQL() { result = sig } QL::SignatureExpr toQL() { result = sig.asLeft() }
/** Gets this signature expression if it represents a predicate expression. */ /** Gets this signature expression if it represents a predicate expression. */
PredicateExpr asPredicate() { result = this } PredicateExpr asPredicate() { result = this }

Просмотреть файл

@ -16,13 +16,16 @@ private import codeql.util.Either
// 3: The Either type gets a type without bindingset on the charpred/toString. // 3: The Either type gets a type without bindingset on the charpred/toString.
newtype TMockAst = newtype TMockAst =
TMockModule(string id) { id instanceof MockModule::Range } or TMockModule(string id) { id instanceof MockModule::Range } or
TMockClass(string id) { id instanceof MockClass::Range } TMockClass(string id) { id instanceof MockClass::Range } or
TMockTypeExpr(string id) { id instanceof MockTypeExpr::Range }
/** Gets a mocked Ast node from the string ID that represents it. */ /** Gets a mocked Ast node from the string ID that represents it. */
MockAst fromId(string id) { MockAst fromId(string id) {
result = TMockModule(id) result = TMockModule(id)
or or
result = TMockClass(id) result = TMockClass(id)
or
result = TMockTypeExpr(id)
// TODO: Other nodes. // TODO: Other nodes.
} }
@ -95,3 +98,44 @@ module MockClass {
} }
class ClassOrMock = Either<QL::Dataclass, MockClass>::Either; class ClassOrMock = Either<QL::Dataclass, MockClass>::Either;
/**
* A mocked `SignatureExpr`.
* This is special because it is either a `PredicateExpr`, a `TypeExpr`, or a `ModuleExpr`.
* // TODO: `PredicateExpr` and `ModuleExpr` are not implemented yet.
*/
class MockSignatureExpr extends MockAst {
string range;
MockSignatureExpr() {
this = TMockTypeExpr(range)
// TODO: or this = TMockPredicateExpr(range)
// TODO: or this = TMockModuleExpr(range)
}
}
/**
* A mocked `TypeExpr`.
* Extend `MockTypeExpr::Range` to add new mocked type expressions.
*/
class MockTypeExpr extends MockSignatureExpr, TMockTypeExpr {
override MockTypeExpr::Range range;
MockTypeExpr() { this = TMockTypeExpr(range) }
final string getClassName() { result = range.getClassName() }
}
module MockTypeExpr {
abstract class Range extends string {
bindingset[this]
Range() { this = this }
/** Gets the name of the type. */
abstract string getClassName();
}
}
class TypeExprOrMock = Either<QL::TypeExpr, MockTypeExpr>::Either;
class SignatureExprOrMock = Either<QL::SignatureExpr, MockSignatureExpr>::Either;

Просмотреть файл

@ -21,7 +21,7 @@ newtype TAstNode =
TNewType(QL::Datatype dt) or TNewType(QL::Datatype dt) or
TNewTypeBranch(QL::DatatypeBranch branch) or TNewTypeBranch(QL::DatatypeBranch branch) or
TImport(QL::ImportDirective imp) or TImport(QL::ImportDirective imp) or
TType(QL::TypeExpr type) or TType(Mocks::TypeExprOrMock type) or
TDisjunction(QL::Disjunction disj) or TDisjunction(QL::Disjunction disj) or
TConjunction(QL::Conjunction conj) or TConjunction(QL::Conjunction conj) or
TComparisonFormula(QL::CompTerm comp) or TComparisonFormula(QL::CompTerm comp) or
@ -182,7 +182,7 @@ QL::AstNode toQL(AST::AstNode n) {
or or
n = TImport(result) n = TImport(result)
or or
n = TType(result) n = TType(any(Mocks::TypeExprOrMock m | m.asLeft() = result))
or or
n = TAsExpr(result) n = TAsExpr(result)
or or
@ -212,7 +212,7 @@ Mocks::MockAst toMock(AST::AstNode n) {
or or
n = TClass(any(Mocks::ClassOrMock m | m.asRight() = result)) n = TClass(any(Mocks::ClassOrMock m | m.asRight() = result))
or or
none() // TODO: Remove, this is to loosen the type of `toMock` to avoid type-errors in WIP code. n = TType(any(Mocks::TypeExprOrMock m | m.asRight() = result))
} }
class TPredicate = class TPredicate =

Просмотреть файл

@ -107,10 +107,12 @@ module QlBuiltinsMocks {
override string getName() { result = "QlBuiltins" } override string getName() { result = "QlBuiltins" }
override string getMember(int i) { override string getMember(int i) {
// TODO: InstSig
i = 0 and i = 0 and
result instanceof EquivalenceRelation::SigClass result instanceof EquivalenceRelation::SigClass
or or
i = 1 and
result instanceof EquivalenceRelation::EdgeSig::EdgeSigModule
or
i = 2 and i = 2 and
result instanceof EquivalenceRelation::EquivalenceRelationModule result instanceof EquivalenceRelation::EquivalenceRelationModule
} }
@ -122,10 +124,10 @@ module QlBuiltinsMocks {
* ```CodeQL * ```CodeQL
* module QlBuiltins { * module QlBuiltins {
* signature class T; * signature class T;
* module InstSig<T MyT> { // * module EdgeSig<T MyT> {
* signature predicate edgeSig(MyT a, MyT b); // * signature predicate edgeSig(MyT a, MyT b); //
* } * }
* module EquivalenceRelation<T MyT, InstSig<MyT>::edgeSig/2 edge> { // * module EquivalenceRelation<T MyT, EdgeSig<MyT>::edgeSig/2 edge> { //
* class EquivalenceClass; // * class EquivalenceClass; //
* EquivalenceClass getEquivalenceClass(MyT a); // * EquivalenceClass getEquivalenceClass(MyT a); //
* } * }
@ -138,6 +140,30 @@ module QlBuiltinsMocks {
override string getName() { result = "T" } override string getName() { result = "T" }
} }
module EdgeSig {
class EdgeSigModule extends MockModule::Range {
EdgeSigModule() { this = "Mock: QlBuiltins::EdgeSig" }
override string getName() { result = "EdgeSig" }
override predicate hasTypeParam(int i, string type, string name) {
i = 0 and name = "MyT" and type instanceof EdgeSigType
}
override string getMember(int i) {
// i = 0 and
// result instanceof EdgeSig::EdgeSigPredicate
none() // TODO:
}
}
class EdgeSigType extends MockTypeExpr::Range {
EdgeSigType() { this = "Mock: QlBuiltins::EdgeSig::MyT" }
override string getClassName() { result = "MyT" }
}
}
class EquivalenceRelationModule extends MockModule::Range { class EquivalenceRelationModule extends MockModule::Range {
EquivalenceRelationModule() { this = "Mock: QlBuiltins::EquivalenceRelation" } EquivalenceRelationModule() { this = "Mock: QlBuiltins::EquivalenceRelation" }