mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
C#: Compute enclosing callable as a transitive closure
This commit is contained in:
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides efficient cached predicates for finding enclosing statements and callables.
|
||||
*
|
||||
* There are a number of difficulties. There can be expressions without
|
||||
* enclosing statements (for example initialisers for fields and constructors)
|
||||
* or enclosing callables (even if we consider constructor initialisers
|
||||
* to be enclosed by constructors, field initialisers don't have callables).
|
||||
*
|
||||
* The only cases where a `Stmt` has an `Expr` parent are delegate and lambda
|
||||
* expressions, which are both callable.
|
||||
*/
|
||||
|
||||
import Stmt
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
module Internal {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `c` is the enclosing callable of statement `s`.
|
||||
*/
|
||||
cached
|
||||
predicate enclosingCallable(Stmt s, Callable c) {
|
||||
// Compute the enclosing callable for a statement. This walks up through
|
||||
// enclosing statements until it hits a callable. It's unambiguous, since
|
||||
// if a statement has no parent statement, it's either the method body
|
||||
// or the body of an anonymous function declaration, in each of which cases the
|
||||
// non-statement parent is in fact the enclosing callable.
|
||||
c.getAChildStmt+() = s
|
||||
}
|
||||
|
||||
private Expr getAChildExpr(ExprOrStmtParent p) {
|
||||
result = p.getAChildExpr() or
|
||||
result = p.(AssignOperation).getExpandedAssignment()
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `s` is the enclosing statement of expression `e`.
|
||||
*/
|
||||
cached
|
||||
predicate enclosingStmt(Expr e, Stmt s) {
|
||||
// Compute the enclosing statement for an expression. Note that this need
|
||||
// not exist, since expressions can occur in contexts where they have no
|
||||
// enclosing statement (examples include field initialisers, both inline
|
||||
// and explicit on constructor definitions, and annotation arguments).
|
||||
getAChildExpr+(s) = e
|
||||
}
|
||||
|
||||
private predicate childExprOfCallable(Callable parent, Expr child) {
|
||||
child = getAChildExpr(parent)
|
||||
or
|
||||
exists(Expr mid | childExprOfCallable(parent, mid) |
|
||||
not mid instanceof Callable and
|
||||
child = getAChildExpr(mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `c` is the enclosing callable of expression `e`.
|
||||
*/
|
||||
cached
|
||||
predicate exprEnclosingCallable(Expr e, Callable c) {
|
||||
// Compute the enclosing callable of an expression. Note that expressions in
|
||||
// lambda functions should have the lambdas as enclosing callables, and their
|
||||
// enclosing statement may be the same as the enclosing statement of the
|
||||
// lambda; thus, it is *not* safe to go up to the enclosing statement and
|
||||
// take its own enclosing callable.
|
||||
childExprOfCallable(c, e)
|
||||
or
|
||||
not childExprOfCallable(_, e) and
|
||||
exists(Stmt s | enclosingStmt(e, s) | enclosingCallable(s, c))
|
||||
}
|
||||
}
|
||||
@@ -138,6 +138,54 @@ private module Cached {
|
||||
)
|
||||
else expr_parent(child, i, parent)
|
||||
}
|
||||
|
||||
private Expr getAChildExpr(ExprOrStmtParent parent) {
|
||||
result = parent.getAChildExpr() or
|
||||
result = parent.(AssignOperation).getExpandedAssignment()
|
||||
}
|
||||
|
||||
private ControlFlowElement getAChild(ExprOrStmtParent parent) {
|
||||
result = getAChildExpr(parent)
|
||||
or
|
||||
result = parent.getAChildStmt()
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private ControlFlowElement enclosingStart(ControlFlowElement cfe) {
|
||||
result = cfe
|
||||
or
|
||||
getAChild(result).(AnonymousFunctionExpr) = cfe
|
||||
}
|
||||
|
||||
private predicate parent(ControlFlowElement child, ExprOrStmtParent parent) {
|
||||
child = getAChild(parent) and
|
||||
not child instanceof Callable
|
||||
}
|
||||
|
||||
/** Holds if the enclosing body of `cfe` is `body`. */
|
||||
cached
|
||||
predicate enclosingBody(ControlFlowElement cfe, ControlFlowElement body) {
|
||||
body = any(Callable c).getBody() and
|
||||
parent*(enclosingStart(cfe), body)
|
||||
}
|
||||
|
||||
/** Holds if the enclosing callable of `cfe` is `c`. */
|
||||
cached
|
||||
predicate enclosingCallable(ControlFlowElement cfe, Callable c) {
|
||||
enclosingBody(cfe, c.getBody())
|
||||
or
|
||||
parent*(enclosingStart(cfe), c.(Constructor).getInitializer())
|
||||
}
|
||||
|
||||
/** Holds if the enclosing statement of expression `e` is `s`. */
|
||||
cached
|
||||
predicate enclosingStmt(Expr e, Stmt s) {
|
||||
// Compute the enclosing statement for an expression. Note that this need
|
||||
// not exist, since expressions can occur in contexts where they have no
|
||||
// enclosing statement (examples include field initialisers, both inline
|
||||
// and explicit on constructor definitions, and annotation arguments).
|
||||
getAChildExpr+(s) = e
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
@@ -8,7 +8,7 @@ import Element
|
||||
import Location
|
||||
import Member
|
||||
import exprs.Expr
|
||||
private import semmle.code.csharp.Enclosing::Internal
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import TypeRef
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.Enclosing::Internal
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.TypeRef
|
||||
|
||||
@@ -55,7 +55,7 @@ class Expr extends DotNet::Expr, ControlFlowElement, @expr {
|
||||
final Stmt getEnclosingStmt() { enclosingStmt(this, result) }
|
||||
|
||||
/** Gets the enclosing callable of this expression, if any. */
|
||||
override Callable getEnclosingCallable() { exprEnclosingCallable(this, result) }
|
||||
override Callable getEnclosingCallable() { enclosingCallable(this, result) }
|
||||
|
||||
/**
|
||||
* Holds if this expression is generated by the compiler and does not appear
|
||||
|
||||
Reference in New Issue
Block a user