mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
QL: Resolve calls
This commit is contained in:
@@ -110,9 +110,10 @@ class Predicate extends TPredicate, AstNode {
|
||||
/**
|
||||
* Gets the return type (if any) of the predicate.
|
||||
*/
|
||||
TypeExpr getReturnType() { none() }
|
||||
TypeExpr getReturnTypeExpr() { none() }
|
||||
|
||||
Type getReturnType() { result = this.getReturnTypeExpr().getResolvedType() }
|
||||
|
||||
// TODO: ReturnType.
|
||||
override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
@@ -120,7 +121,7 @@ class Predicate extends TPredicate, AstNode {
|
||||
or
|
||||
exists(int i | pred = indexedMember("getParameter", i) and result = this.getParameter(i))
|
||||
or
|
||||
pred = directMember("getReturnType") and result = this.getReturnType()
|
||||
pred = directMember("getReturnTypeExpr") and result = this.getReturnTypeExpr()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Predicate" }
|
||||
@@ -199,7 +200,7 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati
|
||||
rank[i](Generated::VarDecl decl, int index | decl = pred.getChild(index) | decl order by index)
|
||||
}
|
||||
|
||||
override TypeExpr getReturnType() { toGenerated(result) = pred.getReturnType() }
|
||||
override TypeExpr getReturnTypeExpr() { toGenerated(result) = pred.getReturnType() }
|
||||
|
||||
override AstNode getAChild(string pred_name) {
|
||||
result = Predicate.super.getAChild(pred_name)
|
||||
@@ -210,7 +211,7 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati
|
||||
or
|
||||
exists(int i | pred_name = indexedMember("getParameter", i) and result = this.getParameter(i))
|
||||
or
|
||||
pred_name = directMember("getReturnType") and result = this.getReturnType()
|
||||
pred_name = directMember("getReturnTypeExpr") and result = this.getReturnTypeExpr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +245,7 @@ class ClassPredicate extends TClassPredicate, Predicate {
|
||||
|
||||
predicate overrides(ClassPredicate other) { predOverrides(this, other) }
|
||||
|
||||
override TypeExpr getReturnType() { toGenerated(result) = pred.getReturnType() }
|
||||
override TypeExpr getReturnTypeExpr() { toGenerated(result) = pred.getReturnType() }
|
||||
|
||||
override AstNode getAChild(string pred_name) {
|
||||
result = super.getAChild(pred_name)
|
||||
@@ -253,7 +254,7 @@ class ClassPredicate extends TClassPredicate, Predicate {
|
||||
or
|
||||
exists(int i | pred_name = indexedMember("getParameter", i) and result = this.getParameter(i))
|
||||
or
|
||||
pred_name = directMember("getReturnType") and result = this.getReturnType()
|
||||
pred_name = directMember("getReturnTypeExpr") and result = this.getReturnTypeExpr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,6 +287,8 @@ class VarDef extends TVarDef, AstNode {
|
||||
/** Gets the name of the declared variable. */
|
||||
string getName() { none() }
|
||||
|
||||
Type getType() { none() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VarDef" }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
@@ -301,9 +304,11 @@ class VarDecl extends TVarDecl, VarDef {
|
||||
|
||||
override string getName() { result = var.getChild(1).(Generated::VarName).getChild().getValue() }
|
||||
|
||||
override Type getType() { result = this.getTypeExpr().getResolvedType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VarDecl" }
|
||||
|
||||
TypeExpr getType() { toGenerated(result) = var.getChild(0) }
|
||||
TypeExpr getTypeExpr() { toGenerated(result) = var.getChild(0) }
|
||||
|
||||
predicate isPrivate() {
|
||||
exists(Generated::ClassMember member |
|
||||
@@ -320,7 +325,7 @@ class VarDecl extends TVarDecl, VarDef {
|
||||
override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = directMember("getType") and result = this.getType()
|
||||
pred = directMember("getTypeExpr") and result = this.getTypeExpr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,11 +589,17 @@ class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
|
||||
}
|
||||
}
|
||||
|
||||
class Call extends TCall, AstNode {
|
||||
class Call extends TCall, Expr {
|
||||
Expr getArgument(int i) {
|
||||
none() // overriden in sublcasses.
|
||||
}
|
||||
|
||||
Predicate getTarget() { resolveCall(this, result) }
|
||||
|
||||
override Type getType() { result = this.getTarget().getReturnType() }
|
||||
|
||||
final int getNumberOfArguments() { result = count(this.getArgument(_)) }
|
||||
|
||||
ModuleExpr getQualifier() { none() }
|
||||
}
|
||||
|
||||
@@ -673,6 +684,8 @@ class NoneCall extends TNoneCall, Call, Formula {
|
||||
NoneCall() { this = TNoneCall(call) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NoneCall" }
|
||||
|
||||
override AstNode getParent() { result = Call.super.getParent() }
|
||||
}
|
||||
|
||||
class AnyCall extends TAnyCall, Call {
|
||||
@@ -690,16 +703,18 @@ class InlineCast extends TInlineCast, Expr {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "InlineCast" }
|
||||
|
||||
TypeExpr getType() {
|
||||
TypeExpr getTypeExpr() {
|
||||
toGenerated(result) = expr.getChild(_).(Generated::QualifiedRhs).getChild(_)
|
||||
}
|
||||
|
||||
override Type getType() { result = this.getTypeExpr().getResolvedType() }
|
||||
|
||||
Expr getBase() { toGenerated(result) = expr.getChild(0) }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = directMember("getType") and result = this.getType()
|
||||
pred = directMember("getTypeExpr") and result = this.getTypeExpr()
|
||||
or
|
||||
pred = directMember("getBase") and result = this.getBase()
|
||||
}
|
||||
@@ -1181,6 +1196,14 @@ class Aggregate extends TAggregate, Expr {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Aggregate[" + kind + "]" }
|
||||
|
||||
override PrimitiveType getType() {
|
||||
kind.regexpMatch("(strict)?count|sum|min|max|rank") and
|
||||
result.getName() = "int"
|
||||
or
|
||||
kind.regexpMatch("(strict)?concat") and
|
||||
result.getName() = "string"
|
||||
}
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
@@ -1228,6 +1251,8 @@ class AsExpr extends TAsExpr, VarDef, Expr {
|
||||
|
||||
final override string getName() { result = this.getAsName() }
|
||||
|
||||
final override Type getType() { result = this.getInnerExpr().getType() }
|
||||
|
||||
/**
|
||||
* Gets the name the inner expression gets "saved" under.
|
||||
* For example this is `bar` in the expression `foo as bar`.
|
||||
@@ -1270,6 +1295,8 @@ class VarAccess extends Identifier {
|
||||
|
||||
override string getName() { result = id.getChild().(Generated::VarName).getChild().getValue() }
|
||||
|
||||
override Type getType() { result = this.getDeclaration().getType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "VarAccess" }
|
||||
}
|
||||
|
||||
@@ -1284,6 +1311,8 @@ class FieldAccess extends Identifier {
|
||||
|
||||
override string getName() { result = id.getChild().(Generated::VarName).getChild().getValue() }
|
||||
|
||||
override Type getType() { result = this.getDeclaration().getType() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FieldAccess" }
|
||||
}
|
||||
|
||||
@@ -1291,6 +1320,8 @@ class FieldAccess extends Identifier {
|
||||
class ThisAccess extends Identifier {
|
||||
ThisAccess() { any(Generated::This t).getParent() = id }
|
||||
|
||||
override Type getType() { result = this.getParent+().(Class).getType() }
|
||||
|
||||
override string getName() { result = "this" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ThisAccess" }
|
||||
@@ -1300,6 +1331,8 @@ class ThisAccess extends Identifier {
|
||||
class ResultAccess extends Identifier {
|
||||
ResultAccess() { any(Generated::Result r).getParent() = id }
|
||||
|
||||
override Type getType() { result = this.getParent+().(Predicate).getReturnType() }
|
||||
|
||||
override string getName() { result = "result" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ResultAccess" }
|
||||
@@ -1324,7 +1357,9 @@ class Negation extends TNegation, Formula {
|
||||
}
|
||||
|
||||
/** An expression, such as `x+4`. */
|
||||
class Expr extends TExpr, AstNode { }
|
||||
class Expr extends TExpr, AstNode {
|
||||
Type getType() { none() }
|
||||
}
|
||||
|
||||
class ExprAnnotation extends TExprAnnotation, Expr {
|
||||
Generated::ExprAnnotation expr_anno;
|
||||
|
||||
@@ -38,15 +38,59 @@ predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate resolvePredicateCall(PredicateCall pc, Predicate p) {
|
||||
exists(Class c, ClassType t |
|
||||
c = pc.getParent*() and
|
||||
t = c.getType() and
|
||||
p = t.getClassPredicate(pc.getPredicateName(), pc.getNumberOfArguments())
|
||||
)
|
||||
or
|
||||
exists(FileOrModule m, boolean public |
|
||||
not exists(pc.getQualifier()) and
|
||||
m = getEnclosingModule(pc).getEnclosing*() and
|
||||
public = [false, true]
|
||||
or
|
||||
m = pc.getQualifier().getResolvedModule() and
|
||||
public = true
|
||||
|
|
||||
definesPredicate(m, pc.getPredicateName(), p, public) and
|
||||
count(p.getParameter(_)) = pc.getNumberOfArguments()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate resolveMemberCall(MemberCall mc, Predicate p) {
|
||||
exists(ClassType t |
|
||||
t = mc.getBase().getType() and
|
||||
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
|
||||
)
|
||||
}
|
||||
|
||||
predicate resolveCall(Call c, Predicate p) {
|
||||
resolvePredicateCall(c, p)
|
||||
or
|
||||
resolveMemberCall(c, p)
|
||||
}
|
||||
|
||||
module PredConsistency {
|
||||
query predicate noResolvePredicateExpr(PredicateExpr pe) {
|
||||
not resolvePredicateExpr(pe, _) and
|
||||
not pe.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
|
||||
}
|
||||
|
||||
query predicate noResolveCall(Call c) {
|
||||
not resolveCall(c, _) and
|
||||
not c.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)
|
||||
}
|
||||
|
||||
query predicate multipleResolveCall(Call call, int c, Predicate p) {
|
||||
c = strictcount(Predicate p0 | resolveCall(call, p0)) and
|
||||
c > 1 and
|
||||
resolveCall(call, p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,4 +314,18 @@ module TyConsistency {
|
||||
c > 1 and
|
||||
resolveTypeExpr(te, t)
|
||||
}
|
||||
|
||||
query predicate varDefNoType(VarDef def) {
|
||||
not exists(def.getType()) and
|
||||
not def.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
|
||||
}
|
||||
|
||||
query predicate exprNoType(Expr e) {
|
||||
not exists(e.getType()) and
|
||||
not exists(Predicate p |
|
||||
p = e.(Call).getTarget() and
|
||||
not exists(p.getReturnType())
|
||||
) and
|
||||
not e.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,11 @@ private predicate resolveVar(VarAccess va, VarDecl decl, string kind) {
|
||||
kind = "variable"
|
||||
}
|
||||
|
||||
private predicate resolveCall(Call c, Predicate p, string kind) {
|
||||
p = c.getTarget() and
|
||||
kind = "call"
|
||||
}
|
||||
|
||||
cached
|
||||
predicate resolve(Loc ref, Loc target, string kind) {
|
||||
resolveModule(ref.asAst(), target.asMod(), kind)
|
||||
@@ -57,4 +62,6 @@ predicate resolve(Loc ref, Loc target, string kind) {
|
||||
resolvePredicate(ref.asAst(), target.asAst(), kind)
|
||||
or
|
||||
resolveVar(ref.asAst(), target.asAst(), kind)
|
||||
or
|
||||
resolveCall(ref.asAst(), target.asAst(), kind)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user