diff --git a/ql/src/codeql_ql/ast/Ast.qll b/ql/src/codeql_ql/ast/Ast.qll index b97cf137fca..c431396b50a 100644 --- a/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/src/codeql_ql/ast/Ast.qll @@ -106,6 +106,8 @@ class Predicate extends TPredicate, AstNode { */ VarDecl getParameter(int i) { none() } + int getArity() { result = count(getParameter(_)) } + // TODO: ReturnType. override AstNode getAChild(string pred) { pred = "getBody" and result = this.getBody() @@ -212,11 +214,22 @@ class ClassPredicate extends TClassPredicate, Predicate { override Class getParent() { result.getAClassPredicate() = this } + predicate isPrivate() { + exists(Generated::ClassMember member | + pred = member.getChild(_) and + member.getAFieldOrChild().(Generated::Annotation).getName().getValue() = "private" + ) + } + override VarDecl getParameter(int i) { toGenerated(result) = rank[i](Generated::VarDecl decl, int index | decl = pred.getChild(index) | decl order by index) } + ClassType getDeclaringType() { result.getDeclaration() = getParent() } + + predicate overrides(ClassPredicate other) { predOverrides(this, other) } + override AstNode getAChild(string pred_name) { pred_name = "getBody" and result = this.getBody() or @@ -270,6 +283,18 @@ class VarDecl extends TVarDecl, AstNode { TypeExpr getType() { toGenerated(result) = var.getChild(0) } + predicate isPrivate() { + exists(Generated::ClassMember member | + var = member.getChild(_).(Generated::Field).getChild() and + member.getAFieldOrChild().(Generated::Annotation).getName().getValue() = "private" + ) + } + + /** If this is a field, returns the class type that declares it. */ + ClassType getDeclaringType() { result.getDeclaration().getAField() = this } + + predicate overrides(VarDecl other) { fieldOverrides(this, other) } + override AstNode getAChild(string pred) { pred = "getType" and result = this.getType() } } @@ -451,6 +476,9 @@ class Class extends TClass, TypeDeclaration, ModuleDeclaration { toGenerated(result) = cls.getChild(_).(Generated::TypeUnionBody).getChild(_) } + /** Gets the class type defined by this class declaration. */ + Type getType() { result.getDeclaration() = this } + override AstNode getAChild(string pred) { pred = "getAliasType" and result = this.getAliasType() or diff --git a/ql/src/codeql_ql/ast/internal/Type.qll b/ql/src/codeql_ql/ast/internal/Type.qll index baacb7ba7d3..2bed32e3286 100644 --- a/ql/src/codeql_ql/ast/internal/Type.qll +++ b/ql/src/codeql_ql/ast/internal/Type.qll @@ -77,6 +77,63 @@ class ClassType extends Type, TClass { or result = super.getAnInternalSuperType() } + + ClassPredicate getClassPredicate(string name, int arity) { + result = classPredCandidate(this, name, arity) and + not exists(ClassPredicate other | other = classPredCandidate(this, name, arity) | + other.getDeclaringType().getASuperType+() = result.getDeclaringType() + ) + } + + VarDecl getField(string name) { + result = fieldCandidate(this, name) and + not exists(VarDecl other | other = fieldCandidate(this, name) | + other.getDeclaringType().getASuperType+() = result.getDeclaringType() + ) + } +} + +private ClassPredicate declaredPred(ClassType ty, string name, int arity) { + result = ty.getDeclaration().getAClassPredicate() and + result.getName() = name and + result.getArity() = arity +} + +private ClassPredicate classPredCandidate(ClassType ty, string name, int arity) { + result = declaredPred(ty, name, arity) + or + not exists(declaredPred(ty, name, arity)) and + result = inherClassPredCandidate(ty, name, arity) +} + +private ClassPredicate inherClassPredCandidate(ClassType ty, string name, int arity) { + result = classPredCandidate(ty.getASuperType(), name, arity) and + not result.isPrivate() +} + +predicate predOverrides(ClassPredicate sub, ClassPredicate sup) { + sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity()) +} + +private VarDecl declaredField(ClassType ty, string name) { + result = ty.getDeclaration().getAField() and + result.getName() = name +} + +private VarDecl fieldCandidate(ClassType ty, string name) { + result = declaredField(ty, name) + or + not exists(declaredField(ty, name)) and + result = inherFieldCandidate(ty, name) +} + +private VarDecl inherFieldCandidate(ClassType ty, string name) { + result = fieldCandidate(ty.getASuperType(), name) and + not result.isPrivate() +} + +predicate fieldOverrides(VarDecl sub, VarDecl sup) { + sup = inherFieldCandidate(sub.getDeclaringType(), sub.getName()) } class ClassCharType extends Type, TClassChar {