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`.
*/
class TypeExpr extends TType, TypeRef {
QL::TypeExpr type;
Mocks::TypeExprOrMock type;
TypeExpr() { this = TType(type) }
@ -737,28 +737,30 @@ class TypeExpr extends TType, TypeRef {
* or db-types such as `@locateable`.
*/
string getClassName() {
result = type.getName().getValue()
result = type.asLeft().getName().getValue()
or
result = type.getChild().(QL::PrimitiveType).getValue()
result = type.asLeft().getChild().(QL::PrimitiveType).getValue()
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`.
*/
predicate isPrimitive() { type.getChild() instanceof QL::PrimitiveType }
predicate isPrimitive() { type.asLeft().getChild() instanceof QL::PrimitiveType }
/**
* 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.
* 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. */
override Type getResolvedType() {
@ -2400,18 +2402,20 @@ class ModuleExpr extends TModuleExpr, TypeRef {
/** A signature expression, either a `PredicateExpr`, a `TypeExpr`, or a `ModuleExpr`. */
class SignatureExpr extends TSignatureExpr, AstNode {
QL::SignatureExpr sig;
Mocks::SignatureExprOrMock sig;
SignatureExpr() {
toQL(this) = sig.getPredicate()
toQL(this) = sig.asLeft().getPredicate()
or
toQL(this) = sig.getTypeExpr()
toQL(this) = sig.asLeft().getTypeExpr()
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. */
QL::SignatureExpr toQL() { result = sig }
QL::SignatureExpr toQL() { result = sig.asLeft() }
/** Gets this signature expression if it represents a predicate expression. */
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.
newtype TMockAst =
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. */
MockAst fromId(string id) {
result = TMockModule(id)
or
result = TMockClass(id)
or
result = TMockTypeExpr(id)
// TODO: Other nodes.
}
@ -95,3 +98,44 @@ module MockClass {
}
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
TNewTypeBranch(QL::DatatypeBranch branch) or
TImport(QL::ImportDirective imp) or
TType(QL::TypeExpr type) or
TType(Mocks::TypeExprOrMock type) or
TDisjunction(QL::Disjunction disj) or
TConjunction(QL::Conjunction conj) or
TComparisonFormula(QL::CompTerm comp) or
@ -182,7 +182,7 @@ QL::AstNode toQL(AST::AstNode n) {
or
n = TImport(result)
or
n = TType(result)
n = TType(any(Mocks::TypeExprOrMock m | m.asLeft() = result))
or
n = TAsExpr(result)
or
@ -212,7 +212,7 @@ Mocks::MockAst toMock(AST::AstNode n) {
or
n = TClass(any(Mocks::ClassOrMock m | m.asRight() = result))
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 =

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

@ -107,10 +107,12 @@ module QlBuiltinsMocks {
override string getName() { result = "QlBuiltins" }
override string getMember(int i) {
// TODO: InstSig
i = 0 and
result instanceof EquivalenceRelation::SigClass
or
i = 1 and
result instanceof EquivalenceRelation::EdgeSig::EdgeSigModule
or
i = 2 and
result instanceof EquivalenceRelation::EquivalenceRelationModule
}
@ -122,10 +124,10 @@ module QlBuiltinsMocks {
* ```CodeQL
* module QlBuiltins {
* signature class T;
* module InstSig<T MyT> { //
* module EdgeSig<T MyT> {
* 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; //
* EquivalenceClass getEquivalenceClass(MyT a); //
* }
@ -138,6 +140,30 @@ module QlBuiltinsMocks {
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 {
EquivalenceRelationModule() { this = "Mock: QlBuiltins::EquivalenceRelation" }