mirror of
https://github.com/github/codeql.git
synced 2026-02-09 19:51:07 +01:00
QL: Merge pull request #14 from github/predicate-expr-resolution
Resolve predicate expressions
This commit is contained in:
1
ql/consistency-queries/PredicateResolution.ql
Normal file
1
ql/consistency-queries/PredicateResolution.ql
Normal file
@@ -0,0 +1 @@
|
||||
import codeql_ql.ast.internal.Predicate::PredConsistency
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
52
ql/src/codeql_ql/ast/internal/Predicate.qll
Normal file
52
ql/src/codeql_ql/ast/internal/Predicate.qll
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user