Merge pull request #19246 from hvitved/rust/cache-tweaks

This commit is contained in:
Tom Hvitved
2025-04-10 19:02:25 +02:00
committed by GitHub
5 changed files with 69 additions and 33 deletions

View File

@@ -846,9 +846,11 @@ module RustDataFlow implements InputSig<Location> {
/** Provides logic related to captured variables. */
module VariableCapture {
private import codeql.rust.internal.CachedStages
private import codeql.dataflow.VariableCapture as SharedVariableCapture
private predicate closureFlowStep(ExprCfgNode e1, ExprCfgNode e2) {
Stages::DataFlowStage::ref() and
e1 = getALastEvalNode(e2)
or
exists(Ssa::Definition def |

View File

@@ -33,6 +33,7 @@ module Impl {
* Gets the nearest enclosing parent of this node, which is also an `AstNode`,
* if any.
*/
cached
AstNode getParentNode() { result = getParentOfAstStep*(getImmediateParent(this)) }
/** Gets the immediately enclosing callable of this node, if any. */

View File

@@ -68,36 +68,36 @@ module Impl {
* where `definingNode` is the entire `Either::Left(x) | Either::Right(x)`
* pattern.
*/
cached
private predicate variableDecl(AstNode definingNode, Name name, string text) {
(
exists(SelfParam sp |
name = sp.getName() and
definingNode = name and
text = name.getText() and
// exclude self parameters from functions without a body as these are
// trait method declarations without implementations
not exists(Function f | not f.hasBody() and f.getParamList().getSelfParam() = sp)
)
or
exists(IdentPat pat |
name = pat.getName() and
(
definingNode = getOutermostEnclosingOrPat(pat)
or
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
) and
text = name.getText() and
// exclude for now anything starting with an uppercase character, which may be a reference to
// an enum constant (e.g. `None`). This excludes static and constant variables (UPPERCASE),
// which we don't appear to recognize yet anyway. This also assumes programmers follow the
// naming guidelines, which they generally do, but they're not enforced.
not text.charAt(0).isUppercase() and
// exclude parameters from functions without a body as these are trait method declarations
// without implementations
not exists(Function f | not f.hasBody() and f.getParamList().getAParam().getPat() = pat) and
// exclude parameters from function pointer types (e.g. `x` in `fn(x: i32) -> i32`)
not exists(FnPtrTypeRepr fp | fp.getParamList().getParam(_).getPat() = pat)
)
Cached::ref() and
exists(SelfParam sp |
name = sp.getName() and
definingNode = name and
text = name.getText() and
// exclude self parameters from functions without a body as these are
// trait method declarations without implementations
not exists(Function f | not f.hasBody() and f.getParamList().getSelfParam() = sp)
)
or
exists(IdentPat pat |
name = pat.getName() and
(
definingNode = getOutermostEnclosingOrPat(pat)
or
not exists(getOutermostEnclosingOrPat(pat)) and definingNode = name
) and
text = name.getText() and
// exclude for now anything starting with an uppercase character, which may be a reference to
// an enum constant (e.g. `None`). This excludes static and constant variables (UPPERCASE),
// which we don't appear to recognize yet anyway. This also assumes programmers follow the
// naming guidelines, which they generally do, but they're not enforced.
not text.charAt(0).isUppercase() and
// exclude parameters from functions without a body as these are trait method declarations
// without implementations
not exists(Function f | not f.hasBody() and f.getParamList().getAParam().getPat() = pat) and
// exclude parameters from function pointer types (e.g. `x` in `fn(x: i32) -> i32`)
not exists(FnPtrTypeRepr fp | fp.getParamList().getParam(_).getPat() = pat)
)
}
@@ -156,8 +156,12 @@ module Impl {
predicate isCaptured() { this.getAnAccess().isCapture() }
/** Gets the parameter that introduces this variable, if any. */
cached
ParamBase getParameter() {
result = this.getSelfParam() or result.(Param).getPat() = getAVariablePatAncestor(this)
Cached::ref() and
result = this.getSelfParam()
or
result.(Param).getPat() = getAVariablePatAncestor(this)
}
/** Hold is this variable is mutable. */
@@ -614,12 +618,18 @@ module Impl {
/** A variable write. */
class VariableWriteAccess extends VariableAccess {
VariableWriteAccess() { assignmentExprDescendant(this) }
cached
VariableWriteAccess() {
Cached::ref() and
assignmentExprDescendant(this)
}
}
/** A variable read. */
class VariableReadAccess extends VariableAccess {
cached
VariableReadAccess() {
Cached::ref() and
not this instanceof VariableWriteAccess and
not this = any(RefExpr re).getExpr() and
not this = any(CompoundAssignmentExpr cae).getLhs()
@@ -638,6 +648,22 @@ module Impl {
cached
private module Cached {
cached
predicate ref() { 1 = 1 }
cached
predicate backref() {
1 = 1
or
variableDecl(_, _, _)
or
exists(VariableReadAccess a)
or
exists(VariableWriteAccess a)
or
exists(any(Variable v).getParameter())
}
cached
newtype TVariable =
MkVariable(AstNode definingNode, string name) { variableDecl(definingNode, _, name) }

View File

@@ -123,6 +123,10 @@ module Stages {
exists(any(ItemNode i).getASuccessor(_))
or
exists(any(ItemNode i).getASuccessorRec(_))
or
exists(any(ImplOrTraitItemNode i).getASelfPath())
or
any(TypeParamItemNode i).hasTraitBound()
}
}

View File

@@ -384,7 +384,9 @@ abstract class ImplOrTraitItemNode extends ItemNode {
}
/** Gets a `Self` path that refers to this item. */
cached
Path getASelfPath() {
Stages::PathResolutionStage::ref() and
isUnqualifiedSelfPath(result) and
this = unqualifiedPathLookup(result, _)
}
@@ -578,7 +580,7 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
override TypeParam getTypeParam(int i) { none() }
}
private class TypeParamItemNode extends ItemNode instanceof TypeParam {
class TypeParamItemNode extends ItemNode instanceof TypeParam {
pragma[nomagic]
Path getABoundPath() {
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
@@ -598,8 +600,9 @@ private class TypeParamItemNode extends ItemNode instanceof TypeParam {
* impl<T> Foo<T> where T: Trait { ... } // has trait bound
* ```
*/
pragma[nomagic]
cached
predicate hasTraitBound() {
Stages::PathResolutionStage::ref() and
exists(this.getABoundPath())
or
exists(ItemNode declaringItem, WherePred wp |