QL: Merge pull request #14 from github/predicate-expr-resolution

Resolve predicate expressions
This commit is contained in:
Tom Hvitved
2021-05-27 20:39:39 +02:00
committed by GitHub
8 changed files with 127 additions and 31 deletions

View File

@@ -0,0 +1 @@
import codeql_ql.ast.internal.Predicate::PredConsistency

View File

@@ -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.Predicate
private import codeql_ql.ast.internal.Type
/** An AST node of a QL program */
@@ -82,6 +83,21 @@ class PredicateExpr extends TPredicateExpr, AstNode {
override string toString() { result = "predicate" }
string getName() {
exists(Generated::AritylessPredicateExpr ape, Generated::LiteralId id |
ape.getParent() = pe and
id.getParent() = ape and
result = id.getValue()
)
}
int getArity() {
exists(Generated::Integer i |
i.getParent() = pe and
result = i.getValue().toInt()
)
}
ModuleExpr getQualifier() {
exists(Generated::AritylessPredicateExpr ape |
ape.getParent() = pe and
@@ -89,6 +105,8 @@ class PredicateExpr extends TPredicateExpr, AstNode {
)
}
Predicate getResolvedPredicate() { resolvePredicateExpr(this, result) }
override AstNode getParent() {
this in [result.(ClasslessPredicate).getAlias(), result.(HigherOrderFormula).getInput(_)]
}
@@ -99,7 +117,7 @@ class PredicateExpr extends TPredicateExpr, AstNode {
/**
* A classless predicate.
*/
class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleMember {
class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclaration {
Generated::ModuleMember member;
Generated::ClasslessPredicate pred;
@@ -253,7 +271,7 @@ class TypeExpr extends TType, AstNode {
/**
* A QL module.
*/
class Module extends TModule, AstNode, ModuleMember {
class Module extends TModule, ModuleDeclaration {
Generated::Module mod;
Module() { this = TModule(mod) }
@@ -267,10 +285,7 @@ class Module extends TModule, AstNode, ModuleMember {
)
}
/**
* Gets the name of the module.
*/
string getName() { result = mod.getName().(Generated::ModuleName).getChild().getValue() }
override string getName() { result = mod.getName().(Generated::ModuleName).getChild().getValue() }
/**
* Gets a member of the module.
@@ -297,10 +312,22 @@ class ModuleMember extends TModuleMember, AstNode {
predicate isPrivate() { none() } // TODO: Implement.
}
/** A declaration. */
class Declaration extends TDeclaration, AstNode {
/** Gets the name of this declaration. */
string getName() { none() }
}
/** An entity that can be declared in a module. */
class ModuleDeclaration extends TModuleDeclaration, Declaration, ModuleMember { }
/** An type declaration. Either a `class` or a `newtype`. */
class TypeDeclaration extends TTypeDeclaration, Declaration { }
/**
* A QL class.
*/
class Class extends TClass, AstNode, ModuleMember {
class Class extends TClass, TypeDeclaration, ModuleDeclaration {
Generated::Dataclass cls;
Class() { this = TClass(cls) }
@@ -314,10 +341,7 @@ class Class extends TClass, AstNode, ModuleMember {
)
}
/**
* Gets the name of the class.
*/
string getName() { result = cls.getName().getValue() }
override string getName() { result = cls.getName().getValue() }
/**
* Gets the charateristic predicate for this class.
@@ -365,12 +389,12 @@ class Class extends TClass, AstNode, ModuleMember {
/**
* A `newtype Foo` declaration.
*/
class NewType extends TNewType, ModuleMember {
class NewType extends TNewType, TypeDeclaration, ModuleDeclaration {
Generated::Datatype type;
NewType() { this = TNewType(type) }
string getName() { result = type.getName().getValue() }
override string getName() { result = type.getName().getValue() }
override string getAPrimaryQlClass() { result = "NewType" }
@@ -390,15 +414,14 @@ class NewType extends TNewType, ModuleMember {
/**
* A branch in a `newtype`.
*/
class NewTypeBranch extends TNewTypeBranch, AstNode {
class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
Generated::DatatypeBranch branch;
NewTypeBranch() { this = TNewTypeBranch(branch) }
override string getAPrimaryQlClass() { result = "NewTypeBranch" }
/** Gets the name of this branch. */
string getName() { result = branch.getName().getValue() }
override string getName() { result = branch.getName().getValue() }
/** Gets a field in this branch. */
VarDecl getField(int i) {

View File

@@ -154,4 +154,10 @@ Generated::AstNode toGenerated(AST::AstNode n) {
class TPredicate = TCharPred or TClasslessPredicate or TClassPredicate;
class TModuleMember = TClasslessPredicate or TClass or TModule or TNewType or TImport or TSelect;
class TModuleMember = TModuleDeclaration or TImport or TSelect;
class TDeclaration = TTypeDeclaration or TModuleDeclaration;
class TTypeDeclaration = TClass or TNewType or TNewTypeBranch;
class TModuleDeclaration = TClasslessPredicate or TModule or TClass or TNewType;

View File

@@ -121,7 +121,7 @@ private predicate resolveQualifiedName(Import imp, ContainerOrModule m, int i) {
m = TFolder(c)
)
or
defines(getEnclosingModule(imp).getEnclosing*(), q, m, _)
definesModule(getEnclosingModule(imp).getEnclosing*(), q, m, _)
)
or
exists(Folder_ mid |
@@ -142,7 +142,7 @@ private predicate resolveSelectionName(Import imp, ContainerOrModule m, int i) {
or
exists(ContainerOrModule mid |
resolveSelectionName(imp, mid, i - 1) and
defines(mid, imp.getSelectionName(i), m, true)
definesModule(mid, imp.getSelectionName(i), m, true)
)
}
@@ -158,20 +158,22 @@ predicate resolve(Import imp, FileOrModule m) {
predicate resolveModuleExpr(ModuleExpr me, FileOrModule m) {
not m = TFile(any(File f | f.getExtension() = "ql")) and
not exists(me.getQualifier()) and
defines(getEnclosingModule(me).getEnclosing*(), me.getName(), m, _)
definesModule(getEnclosingModule(me).getEnclosing*(), me.getName(), m, _)
or
exists(FileOrModule mid |
resolveModuleExpr(me.getQualifier(), mid) and
defines(mid, me.getName(), m, true)
definesModule(mid, me.getName(), m, true)
)
}
private boolean getPublicBool(ModuleMember m) {
if m.isPrivate() then result = false else result = true
}
boolean getPublicBool(ModuleMember m) { if m.isPrivate() then result = false else result = true }
/** Holds if `container` defines module `m` with name `name`. */
private predicate defines(
/**
* Holds if `container` defines module `m` with name `name`.
*
* `m` may be defined either directly or through `import`s.
*/
private predicate definesModule(
ContainerOrModule container, string name, ContainerOrModule m, boolean public
) {
container = m.getEnclosing() and
@@ -188,7 +190,7 @@ private predicate defines(
container = getEnclosingModule(imp) and
resolve(imp, m0) and
not exists(imp.importedAs()) and
defines(m0, name, m, true) and
definesModule(m0, name, m, true) and
public = getPublicBool(imp)
)
or

View File

@@ -0,0 +1,52 @@
import ql
private import codeql_ql.ast.internal.Module
private predicate definesPredicate(FileOrModule m, string name, ClasslessPredicate p, boolean public) {
m = getEnclosingModule(p) and
name = p.getName() and
public = getPublicBool(p)
or
// import X
exists(Import imp, FileOrModule m0 |
m = getEnclosingModule(imp) and
m0 = imp.getResolvedModule() and
not exists(imp.importedAs()) and
definesPredicate(m0, name, p, true) and
public = getPublicBool(imp)
)
or
// predicate X = Y
exists(ClasslessPredicate alias |
m = getEnclosingModule(alias) and
name = alias.getName() and
resolvePredicateExpr(alias.getAlias(), p) and
public = getPublicBool(alias)
)
}
predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
exists(FileOrModule m, boolean public |
not exists(pe.getQualifier()) and
m = getEnclosingModule(pe).getEnclosing*() and
public = [false, true]
or
m = pe.getQualifier().getResolvedModule() and
public = true
|
definesPredicate(m, pe.getName(), p, public) and
count(p.getParameter(_)) = pe.getArity()
)
}
module PredConsistency {
query predicate noResolvePredicateExpr(PredicateExpr pe) {
not resolvePredicateExpr(pe, _) and
not pe.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
}
query predicate multipleResolvePredicateExpr(PredicateExpr pe, int c, ClasslessPredicate p) {
c = strictcount(ClasslessPredicate p0 | resolvePredicateExpr(pe, p0)) and
c > 1 and
resolvePredicateExpr(pe, p)
}
}

View File

@@ -207,10 +207,6 @@ private predicate qualifier(TypeExpr te, FileOrModule m, boolean public) {
)
}
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

View File

@@ -50,10 +50,18 @@ predicate resolveType(TypeExpr ref, AstNode target, string kind) {
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
predicate resolvePredicate(PredicateExpr ref, Predicate target, string kind) {
target = ref.getResolvedPredicate() and
kind = "predicate" 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)
or
resolvePredicate(ref.asAst(), target.asAst(), kind)
}
from Loc ref, Loc target, string kind

View File

@@ -49,10 +49,18 @@ predicate resolveType(TypeExpr ref, AstNode target, string kind) {
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
predicate resolvePredicate(PredicateExpr ref, Predicate target, string kind) {
target = ref.getResolvedPredicate() and
kind = "predicate" 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)
or
resolvePredicate(ref.asAst(), target.asAst(), kind)
}
from Loc ref, Loc target, string kind