diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 51ddcf0cf59..85082c3e6b7 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -500,11 +500,11 @@ class PredicateExpr extends TPredicateExpr, AstNode { * A classless predicate. */ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclaration { - QL::ClasslessPredicate pred; + Mocks::ClasslessPredicateOrMock pred; ClasslessPredicate() { this = TClasslessPredicate(pred) } - override Location getLocation() { result = pred.getName().getLocation() } + override Location getLocation() { result = pred.asLeft().getName().getLocation() } /** * Gets the aliased value if this predicate is an alias @@ -513,25 +513,33 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati */ final AstNode getAlias() { exists(QL::PredicateAliasBody alias | - alias.getParent() = pred and + alias.getParent() = pred.asLeft() and toQL(result).getParent() = alias ) or - toQL(result) = pred.getChild(_).(QL::HigherOrderTerm) + toQL(result) = pred.asLeft().getChild(_).(QL::HigherOrderTerm) } override string getAPrimaryQlClass() { result = "ClasslessPredicate" } - override Formula getBody() { toQL(result) = pred.getChild(_).(QL::Body).getChild() } + override Formula getBody() { toQL(result) = pred.asLeft().getChild(_).(QL::Body).getChild() } - override string getName() { result = pred.getName().getValue() } + override string getName() { + result = pred.asLeft().getName().getValue() + or + result = pred.asRight().getName() + } override VarDecl getParameter(int i) { toQL(result) = - rank[i + 1](QL::VarDecl decl, int index | decl = pred.getChild(index) | decl order by index) + rank[i + 1](QL::VarDecl decl, int index | + decl = pred.asLeft().getChild(index) + | + decl order by index + ) } - override TypeExpr getReturnTypeExpr() { toQL(result) = pred.getReturnType() } + override TypeExpr getReturnTypeExpr() { toQL(result) = pred.asLeft().getReturnType() } override AstNode getAChild(string pred_name) { result = Predicate.super.getAChild(pred_name) diff --git a/ql/ql/src/codeql_ql/ast/internal/AstMocks.qll b/ql/ql/src/codeql_ql/ast/internal/AstMocks.qll index 70c589ab6b9..d9c2232ce09 100644 --- a/ql/ql/src/codeql_ql/ast/internal/AstMocks.qll +++ b/ql/ql/src/codeql_ql/ast/internal/AstMocks.qll @@ -17,7 +17,8 @@ private import codeql.util.Either newtype TMockAst = TMockModule(string id) { id instanceof MockModule::Range } or TMockClass(string id) { id instanceof MockClass::Range } or - TMockTypeExpr(string id) { id instanceof MockTypeExpr::Range } + TMockTypeExpr(string id) { id instanceof MockTypeExpr::Range } or + TMockClasslessPredicate(string id) { id instanceof MockClasslessPredicate::Range } /** Gets a mocked Ast node from the string ID that represents it. */ MockAst fromId(string id) { @@ -26,6 +27,8 @@ MockAst fromId(string id) { result = TMockClass(id) or result = TMockTypeExpr(id) + or + result = TMockClasslessPredicate(id) // TODO: Other nodes. } @@ -51,7 +54,7 @@ class MockModule extends MockAst, TMockModule { final MockAst getMember(int i) { result = fromId(range.getMember(i)) } final predicate hasTypeParam(int i, MockAst type, string name) { - range.hasTypeParam(i, type.toString(), name) + range.hasTypeParam(i, type.getId(), name) } } @@ -139,3 +142,32 @@ module MockTypeExpr { class TypeExprOrMock = Either::Either; class SignatureExprOrMock = Either::Either; + +/** + * A mocked `ClasslessPredicate`. + */ +class MockClasslessPredicate extends MockAst { + MockClasslessPredicate::Range range; + + MockClasslessPredicate() { this = TMockClasslessPredicate(range) } + + final string getName() { result = range.getName() } + + // TODO: VarDecl. + final MockAst getParameter(int i) { result.getId() = range.getParameter(i) } +} + +module MockClasslessPredicate { + abstract class Range extends string { + bindingset[this] + Range() { this = this } + + /** Gets the name of the predicate. */ + abstract string getName(); + + /** Gets the `i`th parameter of the predicate. */ + abstract string getParameter(int i); + } +} + +class ClasslessPredicateOrMock = Either::Either; diff --git a/ql/ql/src/codeql_ql/ast/internal/AstNodes.qll b/ql/ql/src/codeql_ql/ast/internal/AstNodes.qll index 3b1e2ea64fc..b9d084f1b67 100644 --- a/ql/ql/src/codeql_ql/ast/internal/AstNodes.qll +++ b/ql/ql/src/codeql_ql/ast/internal/AstNodes.qll @@ -9,7 +9,7 @@ newtype TAstNode = TQLDoc(QL::Qldoc qldoc) or TBlockComment(QL::BlockComment comment) or TLineComment(QL::LineComment comment) or - TClasslessPredicate(QL::ClasslessPredicate pred) or + TClasslessPredicate(Mocks::ClasslessPredicateOrMock pred) or TVarDecl(QL::VarDecl decl) or TFieldDecl(QL::Field field) or TClass(Mocks::ClassOrMock cls) or @@ -160,7 +160,7 @@ QL::AstNode toQL(AST::AstNode n) { or n = TLineComment(result) or - n = TClasslessPredicate(result) + n = TClasslessPredicate(any(Mocks::ClasslessPredicateOrMock m | m.asLeft() = result)) or n = TVarDecl(result) or @@ -213,6 +213,8 @@ Mocks::MockAst toMock(AST::AstNode n) { n = TClass(any(Mocks::ClassOrMock m | m.asRight() = result)) or n = TType(any(Mocks::TypeExprOrMock m | m.asRight() = result)) + or + n = TClasslessPredicate(any(Mocks::ClasslessPredicateOrMock m | m.asRight() = result)) } class TPredicate = diff --git a/ql/ql/src/codeql_ql/ast/internal/Builtins.qll b/ql/ql/src/codeql_ql/ast/internal/Builtins.qll index f142dd5e19e..aa79fa6e195 100644 --- a/ql/ql/src/codeql_ql/ast/internal/Builtins.qll +++ b/ql/ql/src/codeql_ql/ast/internal/Builtins.qll @@ -150,11 +150,7 @@ module QlBuiltinsMocks { i = 0 and name = "MyT" and type instanceof EdgeSigType } - override string getMember(int i) { - // i = 0 and - // result instanceof EdgeSig::EdgeSigPredicate - none() // TODO: - } + override string getMember(int i) { i = 0 and result instanceof EdgeSigPred } } class EdgeSigType extends MockTypeExpr::Range { @@ -162,6 +158,16 @@ module QlBuiltinsMocks { override string getClassName() { result = "MyT" } } + + class EdgeSigPred extends MockClasslessPredicate::Range { + EdgeSigPred() { this = "Mock: QlBuiltins::EdgeSig::edgeSig" } + + override string getName() { result = "edgeSig" } + + override string getParameter(int i) { + none() // TODO: + } + } } class EquivalenceRelationModule extends MockModule::Range {