Merge pull request #80 from github/aschackmull/calltarget-astnode

Refactor Call.getTarget to be an AstNode
This commit is contained in:
Anders Schack-Mulligen
2021-10-14 13:35:50 +02:00
committed by GitHub
8 changed files with 193 additions and 160 deletions

View File

@@ -4,6 +4,7 @@ private import codeql_ql.ast.internal.Module
private import codeql_ql.ast.internal.Predicate
import codeql_ql.ast.internal.Type
private import codeql_ql.ast.internal.Variable
private import codeql_ql.ast.internal.Builtins
bindingset[name]
private string directMember(string name) { result = name + "()" }
@@ -31,6 +32,20 @@ class AstNode extends TAstNode {
)
}
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
if exists(getLocation())
then getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
else (
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
)
}
/**
* Gets the parent in the AST for this node.
*/
@@ -177,11 +192,62 @@ class Select extends TSelect, AstNode {
override string getAPrimaryQlClass() { result = "Select" }
}
class PredicateOrBuiltin extends TPredOrBuiltin, AstNode {
string getName() { none() }
Type getDeclaringType() { none() }
Type getParameterType(int i) { none() }
Type getReturnType() { none() }
int getArity() { result = count(getParameterType(_)) }
predicate isPrivate() { none() }
}
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin {
override string toString() { result = getName() }
override string getAPrimaryQlClass() { result = "BuiltinPredicate" }
}
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
string name;
string ret;
string args;
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
}
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
string name;
string qual;
string ret;
string args;
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
override PrimitiveType getDeclaringType() { result.getName() = qual }
}
/**
* A QL predicate.
* Either a classless predicate, a class predicate, or a characteristic predicate.
*/
class Predicate extends TPredicate, AstNode, Declaration {
class Predicate extends TPredicate, AstNode, PredicateOrBuiltin, Declaration {
/**
* Gets the body of the predicate.
*/
@@ -200,7 +266,7 @@ class Predicate extends TPredicate, AstNode, Declaration {
/**
* Gets the number of parameters.
*/
int getArity() {
override int getArity() {
not this.(ClasslessPredicate).getAlias() instanceof PredicateExpr and
result = count(getParameter(_))
or
@@ -209,12 +275,19 @@ class Predicate extends TPredicate, AstNode, Declaration {
)
}
/**
* Holds if this predicate is private.
*/
override predicate isPrivate() { hasAnnotation("private") }
/**
* Gets the return type (if any) of the predicate.
*/
TypeExpr getReturnTypeExpr() { none() }
Type getReturnType() { result = this.getReturnTypeExpr().getResolvedType() }
override Type getReturnType() { result = this.getReturnTypeExpr().getResolvedType() }
override Type getParameterType(int i) { result = this.getParameter(i).getType() }
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
@@ -376,6 +449,8 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati
or
pred_name = directMember("getReturnTypeExpr") and result = this.getReturnTypeExpr()
}
override predicate isPrivate() { Predicate.super.isPrivate() }
}
/**
@@ -394,11 +469,6 @@ class ClassPredicate extends TClassPredicate, Predicate {
override Class getParent() { result.getAClassPredicate() = this }
/**
* Holds if this predicate is private.
*/
predicate isPrivate() { hasAnnotation("private") }
/**
* Holds if this predicate is annotated as overriding another predicate.
*/
@@ -416,7 +486,7 @@ class ClassPredicate extends TClassPredicate, Predicate {
/**
* Gets the type representing this class.
*/
ClassType getDeclaringType() { result.getDeclaration() = getParent() }
override ClassType getDeclaringType() { result.getDeclaration() = getParent() }
predicate overrides(ClassPredicate other) { predOverrides(this, other) }
@@ -453,7 +523,7 @@ class CharPred extends TCharPred, Predicate {
pred_name = directMember("getBody") and result = this.getBody()
}
ClassType getDeclaringType() { result.getDeclaration() = getParent() }
override ClassType getDeclaringType() { result.getDeclaration() = getParent() }
}
/**
@@ -764,7 +834,7 @@ class NewType extends TNewType, TypeDeclaration, ModuleDeclaration {
* A branch in a `newtype`.
* E.g. `Bar()` or `Baz()` in `newtype Foo = Bar() or Baz()`.
*/
class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
class NewTypeBranch extends TNewTypeBranch, PredicateOrBuiltin, TypeDeclaration {
Generated::DatatypeBranch branch;
NewTypeBranch() { this = TNewTypeBranch(branch) }
@@ -786,6 +856,16 @@ class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
/** Gets the body of this branch. */
Formula getBody() { toGenerated(result) = branch.getChild(_).(Generated::Body).getChild() }
override NewTypeBranchType getReturnType() { result.getDeclaration() = this }
override Type getParameterType(int i) { result = this.getField(i).getType() }
override int getArity() { result = count(this.getField(_)) }
override Type getDeclaringType() { none() }
override predicate isPrivate() { this.getNewType().isPrivate() }
override QLDoc getQLDoc() { toGenerated(result) = branch.getChild(_) }
NewType getNewType() { result.getABranch() = this }

View File

@@ -1,5 +1,6 @@
import codeql_ql.ast.Ast as AST
import TreeSitter
private import Builtins
cached
newtype TAstNode =
@@ -65,7 +66,11 @@ newtype TAstNode =
TYamlEntry(Generated::YamlEntry ye) or
TYamlKey(Generated::YamlKey yk) or
TYamlListitem(Generated::YamlListitem yli) or
TYamlValue(Generated::YamlValue yv)
TYamlValue(Generated::YamlValue yv) or
TBuiltinClassless(string ret, string name, string args) { isBuiltinClassless(ret, name, args) } or
TBuiltinMember(string qual, string ret, string name, string args) {
isBuiltinMember(qual, ret, name, args)
}
class TFormula =
TDisjunction or TConjunction or TComparisonFormula or TQuantifier or TNegation or TIfFormula or
@@ -194,6 +199,10 @@ Generated::AstNode toGenerated(AST::AstNode n) {
class TPredicate = TCharPred or TClasslessPredicate or TClassPredicate or TDBRelation;
class TPredOrBuiltin = TPredicate or TNewTypeBranch or TBuiltin;
class TBuiltin = TBuiltinClassless or TBuiltinMember;
class TModuleMember = TModuleDeclaration or TImport or TSelect or TQLDoc;
class TDeclaration = TTypeDeclaration or TModuleDeclaration or TPredicate or TVarDecl;

View File

@@ -1,12 +1,11 @@
import ql
private import Builtins
private import codeql_ql.ast.internal.Module
private import codeql_ql.ast.internal.AstNodes as AstNodes
private import codeql_ql.ast.internal.AstNodes
private class TClasslessPredicateOrNewTypeBranch =
AstNodes::TClasslessPredicate or AstNodes::TNewTypeBranch;
private class TClasslessPredicateOrNewTypeBranch = TClasslessPredicate or TNewTypeBranch;
string getPredicateName(TClasslessPredicateOrNewTypeBranch p) {
private string getPredicateName(TClasslessPredicateOrNewTypeBranch p) {
result = p.(ClasslessPredicate).getName() or
result = p.(NewTypeBranch).getName()
}
@@ -69,8 +68,7 @@ private module Cached {
m = pc.getQualifier().getResolvedModule() and
public = true
|
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p.getDeclaration(),
public)
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p, public)
)
}
@@ -93,8 +91,8 @@ private module Cached {
rel.getName() = pc.getPredicateName()
}
private predicate resolveDBRelation(PredicateCall pc, DefinedPredicate p) {
exists(Relation rel | p = TPred(rel) |
private predicate resolveDBRelation(PredicateCall pc, Predicate p) {
exists(Relation rel | p = rel |
candidate(rel, pc) and
rel.getArity() = pc.getNumberOfArguments() and
(
@@ -120,142 +118,9 @@ private module Cached {
not resolvePredicateCall(c, _) and
resolveDBRelation(c, p)
}
cached
module NewTypeDef {
cached
newtype TPredOrBuiltin =
TPred(Predicate p) or
TNewTypeBranch(NewTypeBranch b) or
TBuiltinClassless(string ret, string name, string args) {
isBuiltinClassless(ret, name, args)
} or
TBuiltinMember(string qual, string ret, string name, string args) {
isBuiltinMember(qual, ret, name, args)
}
}
}
import Cached
private import NewTypeDef
class PredicateOrBuiltin extends TPredOrBuiltin {
string getName() { none() }
string toString() { result = getName() }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
if exists(getDeclaration())
then
getDeclaration()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
else (
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
)
}
AstNode getDeclaration() { none() }
Type getDeclaringType() { none() }
Type getParameterType(int i) { none() }
Type getReturnType() { none() }
int getArity() { result = count(getParameterType(_)) }
predicate isPrivate() { none() }
}
private class DefinedPredicate extends PredicateOrBuiltin, TPred {
Predicate decl;
DefinedPredicate() { this = TPred(decl) }
override Predicate getDeclaration() { result = decl }
override string getName() { result = decl.getName() }
override Type getReturnType() { result = decl.getReturnType() }
override Type getParameterType(int i) { result = decl.getParameter(i).getType() }
// Can be removed when all types can be resolved
override int getArity() { result = decl.getArity() }
override Type getDeclaringType() {
result = decl.(ClassPredicate).getDeclaringType()
or
result = decl.(CharPred).getDeclaringType()
}
override predicate isPrivate() {
decl.(ClassPredicate).isPrivate() or decl.(ClassPredicate).isPrivate()
}
}
private class DefinedNewTypeBranch extends PredicateOrBuiltin, TNewTypeBranch {
NewTypeBranch b;
DefinedNewTypeBranch() { this = TNewTypeBranch(b) }
override NewTypeBranch getDeclaration() { result = b }
override string getName() { result = b.getName() }
override NewTypeBranchType getReturnType() { result.getDeclaration() = b }
override Type getParameterType(int i) { result = b.getField(i).getType() }
// Can be removed when all types can be resolved
override int getArity() { result = count(b.getField(_)) }
override Type getDeclaringType() { none() }
override predicate isPrivate() { b.getNewType().isPrivate() }
}
private class TBuiltin = TBuiltinClassless or TBuiltinMember;
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin { }
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
string name;
string ret;
string args;
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
}
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
string name;
string qual;
string ret;
string args;
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
override PrimitiveType getDeclaringType() { result.getName() = qual }
}
module PredConsistency {
query predicate noResolvePredicateExpr(PredicateExpr pe) {
@@ -287,7 +152,7 @@ module PredConsistency {
strictcount(PredicateOrBuiltin p0 |
resolveCall(call, p0) and
// aliases are expected to resolve to multiple.
not exists(p0.getDeclaration().(ClasslessPredicate).getAlias())
not exists(p0.(ClasslessPredicate).getAlias())
) and
c > 1 and
resolveCall(call, p)

View File

@@ -114,6 +114,7 @@ private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) {
result.getArity() = arity
}
pragma[nomagic]
private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity) {
result = declaredPred(ty, name, arity)
or
@@ -127,8 +128,7 @@ private PredicateOrBuiltin inherClassPredCandidate(Type ty, string name, int ari
}
predicate predOverrides(ClassPredicate sub, ClassPredicate sup) {
sup =
inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity()).getDeclaration()
sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity())
}
private VarDecl declaredField(ClassType ty, string name) {
@@ -283,6 +283,7 @@ private predicate qualifier(TypeExpr te, FileOrModule m, boolean public, string
)
}
pragma[nomagic]
private predicate defines(FileOrModule m, string name, Type t, boolean public) {
exists(Class ty | t = TClass(ty) |
getEnclosingModule(ty) = m and

View File

@@ -54,7 +54,7 @@ private predicate resolveField(FieldAccess va, VarDecl decl, string kind) {
}
private predicate resolveCall(Call c, Predicate p, string kind) {
p = c.getTarget().getDeclaration() and
p = c.getTarget() and
kind = "call"
}

View File

@@ -19,7 +19,7 @@ predicate usesThis(ClassPredicate pred) {
or
// implicit this
exists(PredicateCall pc | pc.getEnclosingPredicate() = pred |
pc.getTarget().getDeclaration() instanceof ClassPredicate
pc.getTarget() instanceof ClassPredicate
)
}
@@ -39,7 +39,7 @@ predicate isLiteralComparison(ComparisonFormula eq) {
rhs instanceof Literal
or
exists(NewTypeBranch nt |
rhs.(Call).getTarget().getDeclaration() = nt and
rhs.(Call).getTarget() = nt and
count(nt.getField(_)) = 0
)
)

View File

@@ -1,3 +1,3 @@
import ql
query AstNode getTarget(Call call) { result = call.getTarget().getDeclaration() }
query AstNode getTarget(Call call) { result = call.getTarget() }

View File

@@ -171,6 +171,84 @@ nodes
| Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 85 |
| Foo.qll:26:10:26:14 | Boolean | semmle.label | [Boolean] Boolean |
| Foo.qll:26:10:26:14 | Boolean | semmle.order | 86 |
| file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs |
| file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs |
| file://:0:0:0:0 | acos | semmle.label | [BuiltinPredicate] acos |
| file://:0:0:0:0 | any | semmle.label | [BuiltinPredicate] any |
| file://:0:0:0:0 | atan | semmle.label | [BuiltinPredicate] atan |
| file://:0:0:0:0 | bitAnd | semmle.label | [BuiltinPredicate] bitAnd |
| file://:0:0:0:0 | bitNot | semmle.label | [BuiltinPredicate] bitNot |
| file://:0:0:0:0 | bitOr | semmle.label | [BuiltinPredicate] bitOr |
| file://:0:0:0:0 | bitShiftLeft | semmle.label | [BuiltinPredicate] bitShiftLeft |
| file://:0:0:0:0 | bitShiftRight | semmle.label | [BuiltinPredicate] bitShiftRight |
| file://:0:0:0:0 | bitShiftRightSigned | semmle.label | [BuiltinPredicate] bitShiftRightSigned |
| file://:0:0:0:0 | bitXor | semmle.label | [BuiltinPredicate] bitXor |
| file://:0:0:0:0 | booleanAnd | semmle.label | [BuiltinPredicate] booleanAnd |
| file://:0:0:0:0 | booleanNot | semmle.label | [BuiltinPredicate] booleanNot |
| file://:0:0:0:0 | booleanOr | semmle.label | [BuiltinPredicate] booleanOr |
| file://:0:0:0:0 | booleanXor | semmle.label | [BuiltinPredicate] booleanXor |
| file://:0:0:0:0 | ceil | semmle.label | [BuiltinPredicate] ceil |
| file://:0:0:0:0 | charAt | semmle.label | [BuiltinPredicate] charAt |
| file://:0:0:0:0 | copySign | semmle.label | [BuiltinPredicate] copySign |
| file://:0:0:0:0 | cos | semmle.label | [BuiltinPredicate] cos |
| file://:0:0:0:0 | cosh | semmle.label | [BuiltinPredicate] cosh |
| file://:0:0:0:0 | daysTo | semmle.label | [BuiltinPredicate] daysTo |
| file://:0:0:0:0 | exp | semmle.label | [BuiltinPredicate] exp |
| file://:0:0:0:0 | floor | semmle.label | [BuiltinPredicate] floor |
| file://:0:0:0:0 | gcd | semmle.label | [BuiltinPredicate] gcd |
| file://:0:0:0:0 | getDay | semmle.label | [BuiltinPredicate] getDay |
| file://:0:0:0:0 | getHours | semmle.label | [BuiltinPredicate] getHours |
| file://:0:0:0:0 | getMinutes | semmle.label | [BuiltinPredicate] getMinutes |
| file://:0:0:0:0 | getMonth | semmle.label | [BuiltinPredicate] getMonth |
| file://:0:0:0:0 | getSeconds | semmle.label | [BuiltinPredicate] getSeconds |
| file://:0:0:0:0 | getYear | semmle.label | [BuiltinPredicate] getYear |
| file://:0:0:0:0 | indexOf | semmle.label | [BuiltinPredicate] indexOf |
| file://:0:0:0:0 | indexOf | semmle.label | [BuiltinPredicate] indexOf |
| file://:0:0:0:0 | isLowercase | semmle.label | [BuiltinPredicate] isLowercase |
| file://:0:0:0:0 | isUppercase | semmle.label | [BuiltinPredicate] isUppercase |
| file://:0:0:0:0 | length | semmle.label | [BuiltinPredicate] length |
| file://:0:0:0:0 | log | semmle.label | [BuiltinPredicate] log |
| file://:0:0:0:0 | log | semmle.label | [BuiltinPredicate] log |
| file://:0:0:0:0 | log2 | semmle.label | [BuiltinPredicate] log2 |
| file://:0:0:0:0 | log10 | semmle.label | [BuiltinPredicate] log10 |
| file://:0:0:0:0 | matches | semmle.label | [BuiltinPredicate] matches |
| file://:0:0:0:0 | maximum | semmle.label | [BuiltinPredicate] maximum |
| file://:0:0:0:0 | minimum | semmle.label | [BuiltinPredicate] minimum |
| file://:0:0:0:0 | nextAfter | semmle.label | [BuiltinPredicate] nextAfter |
| file://:0:0:0:0 | nextDown | semmle.label | [BuiltinPredicate] nextDown |
| file://:0:0:0:0 | nextUp | semmle.label | [BuiltinPredicate] nextUp |
| file://:0:0:0:0 | none | semmle.label | [BuiltinPredicate] none |
| file://:0:0:0:0 | pow | semmle.label | [BuiltinPredicate] pow |
| file://:0:0:0:0 | prefix | semmle.label | [BuiltinPredicate] prefix |
| file://:0:0:0:0 | regexpMatch | semmle.label | [BuiltinPredicate] regexpMatch |
| file://:0:0:0:0 | regexpReplaceAll | semmle.label | [BuiltinPredicate] regexpReplaceAll |
| file://:0:0:0:0 | replaceAll | semmle.label | [BuiltinPredicate] replaceAll |
| file://:0:0:0:0 | signum | semmle.label | [BuiltinPredicate] signum |
| file://:0:0:0:0 | sin | semmle.label | [BuiltinPredicate] sin |
| file://:0:0:0:0 | sinh | semmle.label | [BuiltinPredicate] sinh |
| file://:0:0:0:0 | splitAt | semmle.label | [BuiltinPredicate] splitAt |
| file://:0:0:0:0 | splitAt | semmle.label | [BuiltinPredicate] splitAt |
| file://:0:0:0:0 | sqrt | semmle.label | [BuiltinPredicate] sqrt |
| file://:0:0:0:0 | substring | semmle.label | [BuiltinPredicate] substring |
| file://:0:0:0:0 | suffix | semmle.label | [BuiltinPredicate] suffix |
| file://:0:0:0:0 | tan | semmle.label | [BuiltinPredicate] tan |
| file://:0:0:0:0 | tanh | semmle.label | [BuiltinPredicate] tanh |
| file://:0:0:0:0 | toDate | semmle.label | [BuiltinPredicate] toDate |
| file://:0:0:0:0 | toFloat | semmle.label | [BuiltinPredicate] toFloat |
| file://:0:0:0:0 | toISO | semmle.label | [BuiltinPredicate] toISO |
| file://:0:0:0:0 | toInt | semmle.label | [BuiltinPredicate] toInt |
| file://:0:0:0:0 | toLowerCase | semmle.label | [BuiltinPredicate] toLowerCase |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toUnicode | semmle.label | [BuiltinPredicate] toUnicode |
| file://:0:0:0:0 | toUpperCase | semmle.label | [BuiltinPredicate] toUpperCase |
| file://:0:0:0:0 | toUrl | semmle.label | [BuiltinPredicate] toUrl |
| file://:0:0:0:0 | toUrl | semmle.label | [BuiltinPredicate] toUrl |
| file://:0:0:0:0 | trim | semmle.label | [BuiltinPredicate] trim |
| file://:0:0:0:0 | ulp | semmle.label | [BuiltinPredicate] ulp |
| printAst.ql:1:1:1:28 | Import | semmle.label | [Import] Import |
| printAst.ql:1:1:1:28 | Import | semmle.order | 87 |
| printAst.ql:1:1:1:29 | TopLevel | semmle.label | [TopLevel] TopLevel |