Merge branch 'main' into redsun82/rules_rust-update

This commit is contained in:
Paolo Tranquilli
2025-02-11 12:07:08 +01:00
25 changed files with 1292 additions and 1043 deletions

View File

@@ -10,7 +10,7 @@ toolchain go1.23.1
// bazel mod tidy // bazel mod tidy
require ( require (
golang.org/x/mod v0.23.0 golang.org/x/mod v0.23.0
golang.org/x/tools v0.29.0 golang.org/x/tools v0.30.0
) )
require golang.org/x/sync v0.10.0 // indirect require golang.org/x/sync v0.11.0 // indirect

View File

@@ -2,7 +2,7 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=

View File

@@ -463,6 +463,21 @@ private predicate interestingCond(SsaSourceVariable npecand, ConditionBlock cond
not cond.getCondition().(Expr).getAChildExpr*() = npecand.getAnAccess() not cond.getCondition().(Expr).getAChildExpr*() = npecand.getAnAccess()
} }
pragma[nomagic]
private ConditionBlock ssaIntegerGuard(SsaVariable v, boolean branch, int k, boolean is_k) {
result.getCondition() = integerGuard(v.getAUse(), branch, k, is_k)
}
pragma[nomagic]
private ConditionBlock ssaIntBoundGuard(SsaVariable v, boolean branch_with_lower_bound_k, int k) {
result.getCondition() = intBoundGuard(v.getAUse(), branch_with_lower_bound_k, k)
}
pragma[nomagic]
private ConditionBlock ssaEnumConstEquality(SsaVariable v, boolean polarity, EnumConstant c) {
result.getCondition() = enumConstEquality(v.getAUse(), polarity, c)
}
/** A pair of correlated conditions for a given NPE candidate. */ /** A pair of correlated conditions for a given NPE candidate. */
private predicate correlatedConditions( private predicate correlatedConditions(
SsaSourceVariable npecand, ConditionBlock cond1, ConditionBlock cond2, boolean inverted SsaSourceVariable npecand, ConditionBlock cond1, ConditionBlock cond2, boolean inverted
@@ -485,25 +500,23 @@ private predicate correlatedConditions(
inverted = branch1.booleanXor(branch2) inverted = branch1.booleanXor(branch2)
) )
or or
exists(SsaVariable v, VarRead rv1, VarRead rv2, int k, boolean branch1, boolean branch2 | exists(SsaVariable v, int k, boolean branch1, boolean branch2 |
rv1 = v.getAUse() and cond1 = ssaIntegerGuard(v, branch1, k, true) and
rv2 = v.getAUse() and cond1 = ssaIntegerGuard(v, branch1.booleanNot(), k, false) and
cond1.getCondition() = integerGuard(rv1, branch1, k, true) and cond2 = ssaIntegerGuard(v, branch2, k, true) and
cond1.getCondition() = integerGuard(rv1, branch1.booleanNot(), k, false) and cond2 = ssaIntegerGuard(v, branch2.booleanNot(), k, false) and
cond2.getCondition() = integerGuard(rv2, branch2, k, true) and
cond2.getCondition() = integerGuard(rv2, branch2.booleanNot(), k, false) and
inverted = branch1.booleanXor(branch2) inverted = branch1.booleanXor(branch2)
) )
or or
exists(SsaVariable v, int k, boolean branch1, boolean branch2 | exists(SsaVariable v, int k, boolean branch1, boolean branch2 |
cond1.getCondition() = intBoundGuard(v.getAUse(), branch1, k) and cond1 = ssaIntBoundGuard(v, branch1, k) and
cond2.getCondition() = intBoundGuard(v.getAUse(), branch2, k) and cond2 = ssaIntBoundGuard(v, branch2, k) and
inverted = branch1.booleanXor(branch2) inverted = branch1.booleanXor(branch2)
) )
or or
exists(SsaVariable v, EnumConstant c, boolean pol1, boolean pol2 | exists(SsaVariable v, EnumConstant c, boolean pol1, boolean pol2 |
cond1.getCondition() = enumConstEquality(v.getAUse(), pol1, c) and cond1 = ssaEnumConstEquality(v, pol1, c) and
cond2.getCondition() = enumConstEquality(v.getAUse(), pol2, c) and cond2 = ssaEnumConstEquality(v, pol2, c) and
inverted = pol1.booleanXor(pol2) inverted = pol1.booleanXor(pol2)
) )
or or

File diff suppressed because it is too large Load Diff

View File

@@ -57,7 +57,7 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable {
} }
cached cached
private module SsaImpl { private module BaseSsaImpl {
/** Gets the destination variable of an update of a tracked variable. */ /** Gets the destination variable of an update of a tracked variable. */
cached cached
BaseSsaSourceVariable getDestVar(VariableUpdate upd) { BaseSsaSourceVariable getDestVar(VariableUpdate upd) {
@@ -440,7 +440,7 @@ private module SsaImpl {
} }
} }
private import SsaImpl private import BaseSsaImpl
private import SsaDefReaches private import SsaDefReaches
import SsaPublic import SsaPublic

View File

@@ -10,6 +10,8 @@ private import FlowSummaryImpl as FlowSummaryImpl
private import DataFlowImplCommon as DataFlowImplCommon private import DataFlowImplCommon as DataFlowImplCommon
private import semmle.code.java.controlflow.Guards private import semmle.code.java.controlflow.Guards
private import semmle.code.java.dataflow.RangeUtils private import semmle.code.java.dataflow.RangeUtils
private import semmle.code.java.dataflow.SSA
private import SsaImpl as SsaImpl
/** Gets a string for approximating the name of a field. */ /** Gets a string for approximating the name of a field. */
string approximateFieldContent(FieldContent fc) { result = fc.getField().getName().prefix(1) } string approximateFieldContent(FieldContent fc) { result = fc.getField().getName().prefix(1) }
@@ -21,8 +23,34 @@ private predicate deadcode(Expr e) {
) )
} }
module SsaFlow {
module Impl = SsaImpl::DataFlowIntegration;
Impl::Node asNode(Node n) {
n = TSsaNode(result)
or
result.(Impl::ExprNode).getExpr() = n.asExpr()
or
result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
or
TExplicitParameterNode(result.(Impl::ParameterNode).getParameter()) = n
}
predicate localFlowStep(
SsaImpl::Impl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep
) {
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
}
predicate localMustFlowStep(SsaImpl::Impl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
}
}
cached cached
private module Cached { private module Cached {
private import semmle.code.java.controlflow.internal.GuardsLogic as GuardsLogic
cached cached
newtype TNode = newtype TNode =
TExprNode(Expr e) { TExprNode(Expr e) {
@@ -31,6 +59,7 @@ private module Cached {
not e.getType() instanceof VoidType and not e.getType() instanceof VoidType and
not e.getParent*() instanceof Annotation not e.getParent*() instanceof Annotation
} or } or
TSsaNode(SsaFlow::Impl::SsaNode node) or
TExplicitParameterNode(Parameter p) { exists(p.getCallable().getBody()) } or TExplicitParameterNode(Parameter p) { exists(p.getCallable().getBody()) } or
TImplicitVarargsArray(Call c) { TImplicitVarargsArray(Call c) {
c.getCallee().isVarargs() and c.getCallee().isVarargs() and
@@ -137,6 +166,8 @@ module Public {
result = this.(FieldValueNode).getField().getType() result = this.(FieldValueNode).getField().getType()
or or
result instanceof TypeObject and this instanceof AdditionalNode result instanceof TypeObject and this instanceof AdditionalNode
or
result = this.(SsaNode).getDefinitionExt().getSourceVariable().getType()
} }
/** Gets the callable in which this node occurs. */ /** Gets the callable in which this node occurs. */
@@ -358,6 +389,18 @@ module Public {
private import Public private import Public
class SsaNode extends Node, TSsaNode {
private SsaFlow::Impl::SsaNode node;
SsaNode() { this = TSsaNode(node) }
SsaImpl::Impl::DefinitionExt getDefinitionExt() { result = node.getDefinitionExt() }
override Location getLocation() { result = node.getLocation() }
override string toString() { result = node.toString() }
}
private class NewExpr extends PostUpdateNode, TExprNode { private class NewExpr extends PostUpdateNode, TExprNode {
NewExpr() { exists(ClassInstanceExpr cie | this = TExprNode(cie)) } NewExpr() { exists(ClassInstanceExpr cie | this = TExprNode(cie)) }
@@ -398,7 +441,8 @@ module Private {
result.asSummarizedCallable() = n.(FlowSummaryNode).getSummarizedCallable() or result.asSummarizedCallable() = n.(FlowSummaryNode).getSummarizedCallable() or
result.asCallable() = n.(CaptureNode).getSynthesizedCaptureNode().getEnclosingCallable() or result.asCallable() = n.(CaptureNode).getSynthesizedCaptureNode().getEnclosingCallable() or
result.asFieldScope() = n.(FieldValueNode).getField() or result.asFieldScope() = n.(FieldValueNode).getField() or
result.asCallable() = any(Expr e | n.(AdditionalNode).nodeAt(e, _)).getEnclosingCallable() result.asCallable() = any(Expr e | n.(AdditionalNode).nodeAt(e, _)).getEnclosingCallable() or
result.asCallable() = n.(SsaNode).getDefinitionExt().getBasicBlock().getEnclosingCallable()
} }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */ /** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */

View File

@@ -581,7 +581,11 @@ predicate forceHighPrecision(Content c) {
} }
/** Holds if `n` should be hidden from path explanations. */ /** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode } predicate nodeIsHidden(Node n) {
n instanceof FlowSummaryNode
or
n instanceof SsaNode
}
class LambdaCallKind = Method; // the "apply" method in the functional interface class LambdaCallKind = Method; // the "apply" method in the functional interface

View File

@@ -10,6 +10,7 @@ private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSteps private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.FlowSummary private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.InstanceAccess private import semmle.code.java.dataflow.InstanceAccess
private import semmle.code.java.dataflow.internal.SsaImpl as SsaImpl
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import TaintTrackingUtil as TaintTrackingUtil private import TaintTrackingUtil as TaintTrackingUtil
private import DataFlowNodes private import DataFlowNodes
@@ -101,6 +102,10 @@ predicate hasNonlocalValue(FieldRead fr) {
) )
} }
private predicate capturedVariableRead(Node n) {
n.asExpr().(VarRead).getVariable() instanceof CapturedVariable
}
cached cached
private module Cached { private module Cached {
/** /**
@@ -110,7 +115,7 @@ private module Cached {
predicate localFlowStep(Node node1, Node node2) { predicate localFlowStep(Node node1, Node node2) {
simpleLocalFlowStep0(node1, node2, _) simpleLocalFlowStep0(node1, node2, _)
or or
adjacentUseUse(node1.asExpr(), node2.asExpr()) SsaFlow::localFlowStep(_, node1, node2, _)
or or
// Simple flow through library code is included in the exposed local // Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural // step relation, even though flow is technically inter-procedural
@@ -127,6 +132,20 @@ private module Cached {
predicate simpleLocalFlowStep(Node node1, Node node2, string model) { predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
simpleLocalFlowStep0(node1, node2, model) simpleLocalFlowStep0(node1, node2, model)
or or
exists(boolean isUseStep |
SsaFlow::localFlowStep(_, node1, node2, isUseStep) and
not capturedVariableRead(node2) and
model = ""
|
isUseStep = false
or
isUseStep = true and
not exists(FieldRead fr |
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _)
)
or
any(AdditionalValueStep a).step(node1, node2) and any(AdditionalValueStep a).step(node1, node2) and
pragma[only_bind_out](node1.getEnclosingCallable()) = pragma[only_bind_out](node1.getEnclosingCallable()) =
pragma[only_bind_out](node2.getEnclosingCallable()) and pragma[only_bind_out](node2.getEnclosingCallable()) and
@@ -149,14 +168,7 @@ predicate localMustFlowStep(Node node1, Node node2) {
node2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable() node2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable()
) )
or or
exists(SsaImplicitInit init | SsaFlow::localMustFlowStep(_, node1, node2)
init.isParameterDefinition(node1.asParameter()) and init.getAUse() = node2.asExpr()
)
or
exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() and
upd.getAUse() = node2.asExpr()
)
or or
node2.asExpr().(CastingExpr).getExpr() = node1.asExpr() node2.asExpr().(CastingExpr).getExpr() = node1.asExpr()
or or
@@ -168,10 +180,6 @@ predicate localMustFlowStep(Node node1, Node node2) {
import Cached import Cached
private predicate capturedVariableRead(Node n) {
n.asExpr().(VarRead).getVariable() instanceof CapturedVariable
}
/** /**
* Holds if there is a data flow step from `e1` to `e2` that only steps from * Holds if there is a data flow step from `e1` to `e2` that only steps from
* child to parent in the AST. * child to parent in the AST.
@@ -213,34 +221,8 @@ predicate simpleAstFlowStep(Expr e1, Expr e2) {
private predicate simpleLocalFlowStep0(Node node1, Node node2, string model) { private predicate simpleLocalFlowStep0(Node node1, Node node2, string model) {
( (
TaintTrackingUtil::forceCachingInSameStage() and TaintTrackingUtil::forceCachingInSameStage() and
// Variable flow steps through adjacent def-use and use-use pairs.
exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
upd.getDefiningExpr().(AssignOp) = node1.asExpr() or
upd.getDefiningExpr().(RecordBindingVariableExpr) = node1.asExpr()
|
node2.asExpr() = upd.getAFirstUse() and
not capturedVariableRead(node2)
)
or
exists(SsaImplicitInit init |
init.isParameterDefinition(node1.asParameter()) and
node2.asExpr() = init.getAFirstUse() and
not capturedVariableRead(node2)
)
or
adjacentUseUse(node1.asExpr(), node2.asExpr()) and
not exists(FieldRead fr |
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _) and
not capturedVariableRead(node2)
or
ThisFlow::adjacentThisRefs(node1, node2) ThisFlow::adjacentThisRefs(node1, node2)
or or
adjacentUseUse(node1.(PostUpdateNode).getPreUpdateNode().asExpr(), node2.asExpr()) and
not capturedVariableRead(node2)
or
ThisFlow::adjacentThisRefs(node1.(PostUpdateNode).getPreUpdateNode(), node2) ThisFlow::adjacentThisRefs(node1.(PostUpdateNode).getPreUpdateNode(), node2)
or or
simpleAstFlowStep(node1.asExpr(), node2.asExpr()) simpleAstFlowStep(node1.asExpr(), node2.asExpr())
@@ -404,11 +386,7 @@ signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
module BarrierGuard<guardChecksSig/3 guardChecks> { module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */ /** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() { Node getABarrierNode() {
exists(Guard g, SsaVariable v, boolean branch, VarRead use | SsaFlow::asNode(result) =
guardChecks(g, v.getAUse(), branch) and SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
use = v.getAUse() and
g.controls(use.getBasicBlock(), branch) and
result.asExpr() = use
)
} }
} }

View File

@@ -0,0 +1,746 @@
import java
private import codeql.ssa.Ssa as SsaImplCommon
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.dispatch.VirtualDispatch
private import semmle.code.java.dispatch.WrappedInvocation
private import semmle.code.java.controlflow.Guards as Guards
predicate fieldAccessInCallable(FieldAccess fa, Field f, Callable c) {
f = fa.getField() and
c = fa.getEnclosingCallable()
}
cached
newtype TSsaSourceVariable =
TLocalVar(Callable c, LocalScopeVariable v) {
c = v.getCallable() or c = v.getAnAccess().getEnclosingCallable()
} or
TPlainField(Callable c, Field f) {
exists(FieldRead fr |
fieldAccessInCallable(fr, f, c) and
(fr.isOwnFieldAccess() or f.isStatic())
)
} or
TEnclosingField(Callable c, Field f, RefType t) {
exists(FieldRead fr | fieldAccessInCallable(fr, f, c) and fr.isEnclosingFieldAccess(t))
} or
TQualifiedField(Callable c, SsaSourceVariable q, InstanceField f) {
exists(FieldRead fr | fieldAccessInCallable(fr, f, c) and fr.getQualifier() = q.getAnAccess())
}
private module TrackedVariablesImpl {
/** Gets the number of accesses of `f`. */
private int numberOfAccesses(SsaSourceField f) {
result = strictcount(FieldAccess fa | fa = f.getAnAccess())
}
/** Holds if `f` is accessed inside a loop. */
private predicate loopAccessed(SsaSourceField f) {
exists(LoopStmt l, FieldRead fr | fr = f.getAnAccess() |
l.getBody() = fr.getEnclosingStmt().getEnclosingStmt*() or
l.getCondition() = fr.getParent*() or
l.(ForStmt).getAnUpdate() = fr.getParent*()
)
}
/** Holds if `f` is accessed more than once or inside a loop. */
private predicate multiAccessed(SsaSourceField f) { loopAccessed(f) or 1 < numberOfAccesses(f) }
/**
* Holds if `f` is a field that is interesting as a basis for SSA.
*
* - A field that is read twice is interesting as we want to know whether the
* reads refer to the same value.
* - A field that is both written and read is interesting as we want to know
* whether the read might get the written value.
* - A field that is read in a loop is interesting as we want to know whether
* the value is the same in different iterations (that is, whether the SSA
* definition can be placed outside the loop).
* - A volatile field is never interesting, since all reads must reread from
* memory and we are forced to assume that the value can change at any point.
*/
cached
predicate trackField(SsaSourceField f) { multiAccessed(f) and not f.isVolatile() }
/**
* The variables that form the basis of the non-trivial SSA construction.
* Fields that aren't tracked get a trivial SSA construction (a definition
* prior to every read).
*/
class TrackedVar extends SsaSourceVariable {
TrackedVar() {
this = TLocalVar(_, _) or
trackField(this)
}
}
class TrackedField extends TrackedVar, SsaSourceField { }
}
private import TrackedVariablesImpl
private predicate untrackedFieldWrite(BasicBlock bb, int i, SsaSourceVariable v) {
v =
any(SsaSourceField nf |
bb.getNode(i + 1) = nf.getAnAccess().(FieldRead).getControlFlowNode() and not trackField(nf)
)
}
/** Gets the definition point of a nested class in the parent scope. */
private ControlFlowNode parentDef(NestedClass nc) {
nc.(AnonymousClass).getClassInstanceExpr().getControlFlowNode() = result or
nc.(LocalClass).getLocalTypeDeclStmt().getControlFlowNode() = result
}
/**
* Gets the enclosing type of a nested class.
*
* Differs from `RefType.getEnclosingType()` by including anonymous classes defined by lambdas.
*/
private RefType desugaredGetEnclosingType(NestedClass inner) {
exists(ControlFlowNode node |
node = parentDef(inner) and
node.getEnclosingCallable().getDeclaringType() = result
)
}
/**
* Gets the control flow node at which the variable is read to get the value for
* a `VarAccess` inside a closure. `capturedvar` is the variable in its defining
* scope, and `closurevar` is the variable in the closure.
*/
private ControlFlowNode captureNode(TrackedVar capturedvar, TrackedVar closurevar) {
exists(
LocalScopeVariable v, Callable inner, Callable outer, NestedClass innerclass, VarAccess va
|
va.getVariable() = v and
inner = va.getEnclosingCallable() and
outer = v.getCallable() and
inner != outer and
inner.getDeclaringType() = innerclass and
result = parentDef(desugaredGetEnclosingType*(innerclass)) and
result.getEnclosingStmt().getEnclosingCallable() = outer and
capturedvar = TLocalVar(outer, v) and
closurevar = TLocalVar(inner, v)
)
}
/** Holds if the value of `v` is captured in `b` at index `i`. */
private predicate variableCapture(TrackedVar capturedvar, TrackedVar closurevar, BasicBlock b, int i) {
b.getNode(i) = captureNode(capturedvar, closurevar)
}
/** Holds if `n` must update the locally tracked variable `v`. */
pragma[nomagic]
private predicate certainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) {
exists(VariableUpdate a | a.getControlFlowNode() = n | getDestVar(a) = v) and
b.getNode(i) = n and
hasDominanceInformation(b)
or
certainVariableUpdate(v.getQualifier(), n, b, i)
}
/** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
pragma[nomagic]
private predicate hasEntryDef(TrackedVar v, BasicBlock b) {
exists(LocalScopeVariable l, Callable c |
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
|
l instanceof Parameter or
l.getCallable() != c
)
or
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getControlFlowNode() = b
}
/** Holds if `n` might update the locally tracked variable `v`. */
pragma[nomagic]
private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) {
exists(Call c | c = n.asCall() | updatesNamedField(c, v, _)) and
b.getNode(i) = n and
hasDominanceInformation(b)
or
uncertainVariableUpdate(v.getQualifier(), n, b, i)
}
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private import java as J
private import semmle.code.java.controlflow.Dominance as Dom
class BasicBlock = J::BasicBlock;
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
class SourceVariable = SsaSourceVariable;
/**
* Holds if the `i`th node of basic block `bb` is a (potential) write to source
* variable `v`. The Boolean `certain` indicates whether the write is certain.
*
* This includes implicit writes via calls.
*/
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
certainVariableUpdate(v, _, bb, i) and
certain = true
or
untrackedFieldWrite(bb, i, v) and
certain = true
or
hasEntryDef(v, bb) and
i = 0 and
certain = true
or
uncertainVariableUpdate(v, _, bb, i) and
certain = false
}
/**
* Holds if the `i`th of basic block `bb` reads source variable `v`.
*
* This includes implicit reads via calls.
*/
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(VarRead use |
v.getAnAccess() = use and bb.getNode(i) = use.getControlFlowNode() and certain = true
)
or
variableCapture(v, _, bb, i) and
certain = false
}
}
import SsaImplCommon::Make<Location, SsaInput> as Impl
final class Definition = Impl::Definition;
final class WriteDefinition = Impl::WriteDefinition;
final class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
final class PhiNode = Impl::PhiNode;
class UntrackedDef extends Definition {
private VarRead read;
UntrackedDef() { ssaUntrackedDef(this, read) }
string toString() { result = read.toString() }
Location getLocation() { result = read.getLocation() }
}
cached
private module Cached {
/** Gets the destination variable of an update of a tracked variable. */
cached
TrackedVar getDestVar(VariableUpdate upd) {
result.getAnAccess() = upd.(Assignment).getDest()
or
exists(LocalVariableDecl v | v = upd.(LocalVariableDeclExpr).getVariable() |
result = TLocalVar(v.getCallable(), v)
)
or
result.getAnAccess() = upd.(UnaryAssignExpr).getExpr()
}
cached
predicate ssaExplicitUpdate(SsaUpdate def, VariableUpdate upd) {
exists(SsaSourceVariable v, BasicBlock bb, int i |
def.definesAt(v, bb, i) and
certainVariableUpdate(v, upd.getControlFlowNode(), bb, i) and
getDestVar(upd) = def.getSourceVariable()
)
}
cached
predicate ssaUntrackedDef(Definition def, VarRead read) {
exists(SsaSourceVariable v, BasicBlock bb, int i |
def.definesAt(v, bb, i) and
untrackedFieldWrite(bb, i, v) and
read.getControlFlowNode() = bb.getNode(i + 1)
)
}
/*
* The SSA construction for a field `f` relies on implicit update nodes at
* every call site that conceivably could reach an update of the field.
*
* At a first approximation we need to find update paths of the form:
* Callable --(callEdge)-->* Callable(setter of f)
*
* This can be improved by excluding paths ending in:
* Constructor --(intraInstanceCallEdge)-->+ Method(setter of this.f)
* as these updates are guaranteed not to alias with the `f` under
* consideration.
*
* This set of paths can be expressed positively by noting that those
* that set `this.f` end in zero or more `intraInstanceCallEdge`s between
* methods, and before those is either the originating `Call` or a
* `crossInstanceCallEdge`.
*/
/**
* Holds if `fw` is a field write that is not relevant as an implicit SSA
* update, since it is an initialization and therefore cannot alias.
*/
private predicate init(FieldWrite fw) {
fw.getEnclosingCallable() instanceof InitializerMethod
or
fw.getEnclosingCallable() instanceof Constructor and fw.isOwnFieldAccess()
or
exists(LocalVariableDecl v |
v.getAnAccess() = fw.getQualifier() and
forex(VariableAssign va | va.getDestVar() = v and exists(va.getSource()) |
va.getSource() instanceof ClassInstanceExpr
)
)
}
/**
* Holds if `fw` is an update of `f` in `c` that is relevant for SSA construction.
*/
cached
predicate relevantFieldUpdate(Callable c, Field f, FieldWrite fw) {
fw = f.getAnAccess() and
not init(fw) and
fw.getEnclosingCallable() = c and
exists(TrackedField nf | nf.getField() = f)
}
/** Holds if `c` can change the value of `this.f` and is relevant for SSA construction. */
private predicate setsOwnField(Method c, Field f) {
exists(FieldWrite fw | relevantFieldUpdate(c, f, fw) and fw.isOwnFieldAccess())
}
/**
* Holds if `c` can change the value of `f` and is relevant for SSA
* construction excluding those cases covered by `setsOwnField`.
*/
private predicate setsOtherField(Callable c, Field f) {
exists(FieldWrite fw | relevantFieldUpdate(c, f, fw) and not fw.isOwnFieldAccess())
}
pragma[nomagic]
private predicate innerclassSupertypeStar(InnerClass t1, RefType t2) {
t1.getASourceSupertype*().getSourceDeclaration() = t2
}
/**
* Holds if `(c1,m2)` is a call edge to a method that does not change the value
* of `this`.
*
* Constructor-to-constructor calls can also be intra-instance, but are not
* included, as this does not affect whether a call chain ends in
*
* ```
* Constructor --(intraInstanceCallEdge)-->+ Method(setter of this.f)
* ```
*/
private predicate intraInstanceCallEdge(Callable c1, Method m2) {
exists(MethodCall ma, RefType t1 |
ma.getCaller() = c1 and
m2 = viableImpl_v2(ma) and
not m2.isStatic() and
(
not exists(ma.getQualifier()) or
ma.getQualifier() instanceof ThisAccess or
ma.getQualifier() instanceof SuperAccess
) and
c1.getDeclaringType() = t1 and
if t1 instanceof InnerClass
then
innerclassSupertypeStar(t1, ma.getCallee().getSourceDeclaration().getDeclaringType()) and
not exists(ma.getQualifier().(ThisAccess).getQualifier()) and
not exists(ma.getQualifier().(SuperAccess).getQualifier())
else any()
)
}
private Callable tgt(Call c) {
result = viableImpl_v2(c)
or
result = getRunnerTarget(c)
or
c instanceof ConstructorCall and result = c.getCallee().getSourceDeclaration()
}
/** Holds if `(c1,c2)` is an edge in the call graph. */
private predicate callEdge(Callable c1, Callable c2) {
exists(Call c | c.getCaller() = c1 and c2 = tgt(c))
}
/** Holds if `(c1,c2)` is an edge in the call graph excluding `intraInstanceCallEdge`. */
private predicate crossInstanceCallEdge(Callable c1, Callable c2) {
callEdge(c1, c2) and not intraInstanceCallEdge(c1, c2)
}
/**
* Holds if `call` is relevant as a potential update of `f`. This requires the
* existence of an update to `f` somewhere.
*/
private predicate relevantCall(Call call, TrackedField f) {
call.getEnclosingCallable() = f.getEnclosingCallable() and
relevantFieldUpdate(_, f.getField(), _)
}
private predicate source(Call call, TrackedField f, Field field, Callable c, boolean fresh) {
relevantCall(call, f) and
field = f.getField() and
c = tgt(call) and
if c instanceof Constructor then fresh = true else fresh = false
}
/**
* A callable in a potential call-chain between a source that cares about the
* value of some field `f` and a sink that may overwrite `f`. The boolean
* `fresh` indicates whether the instance `this` in `c` has been freshly
* allocated along the call-chain.
*/
private newtype TCallableNode =
MkCallableNode(Callable c, boolean fresh) { source(_, _, _, c, fresh) or edge(_, c, fresh) }
private predicate edge(TCallableNode n, Callable c2, boolean f2) {
exists(Callable c1, boolean f1 | n = MkCallableNode(c1, f1) |
intraInstanceCallEdge(c1, c2) and f2 = f1
or
crossInstanceCallEdge(c1, c2) and
if c2 instanceof Constructor then f2 = true else f2 = false
)
}
private predicate edge(TCallableNode n1, TCallableNode n2) {
exists(Callable c2, boolean f2 |
edge(n1, c2, f2) and
n2 = MkCallableNode(c2, f2)
)
}
pragma[noinline]
private predicate source(Call call, TrackedField f, Field field, TCallableNode n) {
exists(Callable c, boolean fresh |
source(call, f, field, c, fresh) and
n = MkCallableNode(c, fresh)
)
}
private predicate sink(Callable c, Field f, TCallableNode n) {
setsOwnField(c, f) and n = MkCallableNode(c, false)
or
setsOtherField(c, f) and n = MkCallableNode(c, _)
}
private predicate prunedNode(TCallableNode n) {
sink(_, _, n)
or
exists(TCallableNode mid | edge(n, mid) and prunedNode(mid))
}
private predicate prunedEdge(TCallableNode n1, TCallableNode n2) {
prunedNode(n1) and
prunedNode(n2) and
edge(n1, n2)
}
private predicate edgePlus(TCallableNode c1, TCallableNode c2) = fastTC(prunedEdge/2)(c1, c2)
/**
* Holds if there exists a call-chain originating in `call` that can update `f` on some instance
* where `f` and `call` share the same enclosing callable in which a
* `FieldRead` of `f` is reachable from `call`.
*/
pragma[noopt]
private predicate updatesNamedFieldImpl(Call call, TrackedField f, Callable setter) {
exists(TCallableNode src, TCallableNode sink, Field field |
source(call, f, field, src) and
sink(setter, field, sink) and
(src = sink or edgePlus(src, sink))
)
}
bindingset[call, f]
pragma[inline_late]
private predicate updatesNamedField0(Call call, TrackedField f, Callable setter) {
updatesNamedField(call, f, setter)
}
cached
predicate defUpdatesNamedField(SsaImplicitUpdate def, TrackedField f, Callable setter) {
f = def.getSourceVariable() and
updatesNamedField0(def.getCfgNode().asCall(), f, setter)
}
cached
predicate ssaUncertainImplicitUpdate(SsaImplicitUpdate def) {
exists(SsaSourceVariable v, BasicBlock bb, int i |
def.definesAt(v, bb, i) and
uncertainVariableUpdate(v, _, bb, i)
)
}
cached
predicate ssaImplicitInit(WriteDefinition def) {
exists(SsaSourceVariable v, BasicBlock bb, int i |
def.definesAt(v, bb, i) and
hasEntryDef(v, bb) and
i = 0
)
}
pragma[nomagic]
private predicate captureDefReaches(Definition def, SsaInput::BasicBlock bb2, int i2) {
variableCapture(def.getSourceVariable(), _, _, _) and
exists(SsaInput::BasicBlock bb1, int i1 |
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
def.definesAt(_, bb1, i1)
)
or
exists(SsaInput::BasicBlock bb3, int i3 |
captureDefReaches(def, bb3, i3) and
SsaInput::variableRead(bb3, i3, _, _) and
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
/** Holds if `init` is a closure variable that captures the value of `capturedvar`. */
cached
predicate captures(SsaImplicitInit init, SsaVariable capturedvar) {
exists(BasicBlock bb, int i |
captureDefReaches(capturedvar, bb, i) and
variableCapture(capturedvar.getSourceVariable(), init.getSourceVariable(), bb, i)
)
}
/**
* Holds if the SSA definition of `v` at `def` reaches `redef` without crossing another
* SSA definition of `v`.
*/
cached
predicate ssaDefReachesUncertainDef(TrackedSsaDef def, SsaUncertainImplicitUpdate redef) {
Impl::uncertainWriteDefinitionInput(redef, def)
}
pragma[nomagic]
private predicate defReaches(Definition def, DataFlowIntegration::Node node) {
exists(DataFlowIntegration::SsaDefinitionExtNode nodeFrom |
nodeFrom.getDefinitionExt() = def and
DataFlowIntegrationImpl::localFlowStep(_, nodeFrom, node, false)
)
or
exists(DataFlowIntegration::Node mid |
defReaches(def, mid) and
DataFlowIntegrationImpl::localFlowStep(_, mid, node, _)
|
// flow into phi input node
mid instanceof DataFlowIntegration::SsaInputNode
or
// flow into definition
mid instanceof DataFlowIntegration::SsaDefinitionExtNode
)
}
/**
* Holds if the value defined at `def` can reach `use` without passing through
* any other uses, but possibly through phi nodes and uncertain implicit updates.
*/
cached
predicate firstUse(Definition def, VarRead use) {
exists(DataFlowIntegration::ExprNode nodeTo |
nodeTo.getExpr() = use and
defReaches(def, nodeTo)
)
}
cached
VarRead getAUse(Definition def) {
exists(SsaSourceVariable v, BasicBlock bb, int i |
Impl::ssaDefReachesRead(v, def, bb, i) and
result.getControlFlowNode() = bb.getNode(i) and
result = v.getAnAccess()
)
}
cached
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def) {
Impl::ssaDefReachesEndOfBlock(bb, def, _)
}
cached
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
Impl::phiHasInputFromBlock(phi, inp, bb)
}
cached
module DataFlowIntegration {
import DataFlowIntegrationImpl
cached
predicate localFlowStep(Impl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
not def instanceof UntrackedDef and
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
}
cached
predicate localMustFlowStep(Impl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
not def instanceof UntrackedDef and
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
}
signature predicate guardChecksSig(Guards::Guard g, Expr e, boolean branch);
cached // nothing is actually cached
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecksAdjTypes(
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch
) {
guardChecks(g, e, branch)
}
private Node getABarrierNodeImpl() {
result = DataFlowIntegrationImpl::BarrierGuard<guardChecksAdjTypes/3>::getABarrierNode()
}
predicate getABarrierNode = getABarrierNodeImpl/0;
}
}
cached
module SsaPublic {
pragma[nomagic]
private predicate useReaches(VarRead use, DataFlowIntegration::Node node, boolean sameVar) {
exists(DataFlowIntegration::ExprNode nodeFrom |
nodeFrom.getExpr() = use and
DataFlowIntegration::localFlowStep(_, nodeFrom, node, true) and
sameVar = true
)
or
exists(DataFlowIntegration::Node mid, boolean sameVarMid |
useReaches(use, mid, sameVarMid) and
DataFlowIntegration::localFlowStep(_, mid, node, _)
|
exists(Impl::DefinitionExt def |
// flow into definition
def = mid.(DataFlowIntegration::SsaDefinitionExtNode).getDefinitionExt()
or
// flow into phi input node
def = mid.(DataFlowIntegration::SsaInputNode).getDefinitionExt()
|
if def instanceof Impl::PhiReadNode then sameVar = sameVarMid else sameVar = false
)
)
}
/**
* Holds if `use1` and `use2` form an adjacent use-use-pair of the same SSA
* variable, that is, the value read in `use1` can reach `use2` without passing
* through any other use or any SSA definition of the variable.
*/
cached
predicate adjacentUseUseSameVar(VarRead use1, VarRead use2) {
exists(DataFlowIntegration::ExprNode nodeTo |
nodeTo.getExpr() = use2 and
useReaches(use1, nodeTo, true)
)
}
/**
* Holds if `use1` and `use2` form an adjacent use-use-pair of the same
* `SsaSourceVariable`, that is, the value read in `use1` can reach `use2`
* without passing through any other use or any SSA definition of the variable
* except for phi nodes and uncertain implicit updates.
*/
cached
predicate adjacentUseUse(VarRead use1, VarRead use2) {
exists(DataFlowIntegration::ExprNode nodeTo |
nodeTo.getExpr() = use2 and
useReaches(use1, nodeTo, _)
)
}
}
/**
* Provides internal implementation predicates that are not cached and should not
* be used outside of this file.
*/
cached // needed to avoid compilation error; has no actual effect
module Internal {
predicate updatesNamedField = updatesNamedFieldImpl/3; // use alias to avoid caching
}
}
import Cached
private import Internal
/**
* An SSA definition excluding those variables that use a trivial SSA construction.
*/
private class TrackedSsaDef extends Definition {
TrackedSsaDef() { not this.getSourceVariable() = any(SsaSourceField f | not trackField(f)) }
/**
* Holds if this SSA definition occurs at the specified position.
* Phi nodes are placed at index -1.
*/
predicate definesAt(TrackedVar v, BasicBlock b, int i) { super.definesAt(v, b, i) }
}
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
private import java as J
class Expr instanceof J::Expr {
string toString() { result = super.toString() }
Location getLocation() { result = super.getLocation() }
predicate hasCfgNode(BasicBlock bb, int i) {
super.getControlFlowNode() = bb.(J::BasicBlock).getNode(i)
}
}
Expr getARead(Definition def) { result = getAUse(def) }
class Parameter = J::Parameter;
predicate ssaDefAssigns(Impl::WriteDefinition def, Expr value) {
exists(VariableUpdate upd | upd = def.(SsaExplicitUpdate).getDefiningExpr() |
value = upd.(VariableAssign).getSource() or
value = upd.(AssignOp) or
value = upd.(RecordBindingVariableExpr)
)
}
predicate ssaDefInitializesParam(Impl::WriteDefinition def, Parameter p) {
def.(SsaImplicitInit).getSourceVariable() =
any(SsaSourceVariable v |
v.getVariable() = p and
v.getEnclosingCallable() = p.getCallable()
)
}
predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) {
def instanceof SsaUncertainImplicitUpdate
}
class Guard extends Guards::Guard {
predicate hasCfgNode(BasicBlock bb, int i) {
this = bb.getNode(i).asExpr()
or
this = bb.getNode(i).asStmt()
}
}
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
predicate guardControlsBlock(Guard guard, BasicBlock bb, boolean branch) {
guard.controls(bb, branch)
}
/** Gets an immediate conditional successor of basic block `bb`, if any. */
BasicBlock getAConditionalBasicBlockSuccessor(BasicBlock bb, boolean branch) {
result = bb.(Guards::ConditionBlock).getTestSuccessor(branch)
}
}
private module DataFlowIntegrationImpl = Impl::DataFlowIntegration<DataFlowIntegrationInput>;

View File

@@ -6,46 +6,36 @@ import java
import semmle.code.java.dataflow.SSA import semmle.code.java.dataflow.SSA
private import semmle.code.java.frameworks.Assertions private import semmle.code.java.frameworks.Assertions
private predicate emptyDecl(SsaExplicitUpdate ssa) { private predicate emptyDecl(LocalVariableDeclExpr decl) {
exists(LocalVariableDeclExpr decl | not exists(decl.getInit()) and
decl = ssa.getDefiningExpr() and not exists(EnhancedForStmt for | for.getVariable() = decl)
not exists(decl.getInit()) and }
not exists(EnhancedForStmt for | for.getVariable() = decl)
) /** A dead variable update. */
predicate deadLocal(VariableUpdate upd) {
upd.getDestVar() instanceof LocalScopeVariable and
not exists(SsaExplicitUpdate ssa | upd = ssa.getDefiningExpr()) and
not emptyDecl(upd) and
not readImplicitly(upd, _)
} }
/** /**
* A dead SSA variable. Excludes parameters, and phi nodes are never dead, so only includes `VariableUpdate`s. * A dead variable update that is expected to be dead as indicated by an assertion.
*/ */
predicate deadLocal(SsaExplicitUpdate ssa) { predicate expectedDead(VariableUpdate upd) { assertFail(upd.getBasicBlock(), _) }
ssa.getSourceVariable().getVariable() instanceof LocalScopeVariable and
not exists(ssa.getAUse()) and
not exists(SsaPhiNode phi | phi.getAPhiInput() = ssa) and
not exists(SsaImplicitInit init | init.captures(ssa)) and
not emptyDecl(ssa) and
not readImplicitly(ssa, _)
}
/** /**
* A dead SSA variable that is expected to be dead as indicated by an assertion. * A dead update that is overwritten by a live update.
*/ */
predicate expectedDead(SsaExplicitUpdate ssa) { predicate overwritten(VariableUpdate upd) {
deadLocal(ssa) and deadLocal(upd) and
assertFail(ssa.getBasicBlock(), _) exists(VariableUpdate overwrite |
} overwrite.getDestVar() = upd.getDestVar() and
/**
* A dead SSA variable that is overwritten by a live SSA definition.
*/
predicate overwritten(SsaExplicitUpdate ssa) {
deadLocal(ssa) and
exists(SsaExplicitUpdate overwrite |
overwrite.getSourceVariable() = ssa.getSourceVariable() and
not deadLocal(overwrite) and not deadLocal(overwrite) and
not overwrite.getDefiningExpr() instanceof LocalVariableDeclExpr and not overwrite instanceof LocalVariableDeclExpr and
exists(BasicBlock bb1, BasicBlock bb2, int i, int j | exists(BasicBlock bb1, BasicBlock bb2, int i, int j |
bb1.getNode(i) = ssa.getCfgNode() and bb1.getNode(i) = upd.getControlFlowNode() and
bb2.getNode(j) = overwrite.getCfgNode() bb2.getNode(j) = overwrite.getControlFlowNode()
| |
bb1.getABBSuccessor+() = bb2 bb1.getABBSuccessor+() = bb2
or or
@@ -63,9 +53,9 @@ predicate read(LocalScopeVariable v) {
readImplicitly(_, v) readImplicitly(_, v)
} }
private predicate readImplicitly(SsaExplicitUpdate ssa, LocalScopeVariable v) { predicate readImplicitly(VariableUpdate upd, LocalScopeVariable v) {
v = ssa.getSourceVariable().getVariable() and v = upd.getDestVar() and
exists(TryStmt try | try.getAResourceVariable() = ssa.getDefiningExpr().getDestVar()) exists(TryStmt try | try.getAResourceVariable() = upd.getDestVar())
} }
/** /**

View File

@@ -40,13 +40,12 @@ predicate excludedInit(Type t, Expr decl) {
) )
} }
from VariableUpdate def, LocalScopeVariable v, SsaExplicitUpdate ssa from VariableUpdate def, LocalScopeVariable v
where where
def = ssa.getDefiningExpr() and def.getDestVar() = v and
v = ssa.getSourceVariable().getVariable() and deadLocal(def) and
deadLocal(ssa) and not expectedDead(def) and
not expectedDead(ssa) and overwritten(def) and
overwritten(ssa) and
not exists(LocalVariableDeclExpr decl | def = decl | not exists(LocalVariableDeclExpr decl | def = decl |
excludedInit(decl.getVariable().getType(), decl.getInit()) excludedInit(decl.getVariable().getType(), decl.getInit())
) )

View File

@@ -11,13 +11,12 @@
import java import java
import DeadLocals import DeadLocals
from VariableUpdate def, LocalScopeVariable v, SsaExplicitUpdate ssa from VariableUpdate def, LocalScopeVariable v
where where
def = ssa.getDefiningExpr() and def.getDestVar() = v and
v = ssa.getSourceVariable().getVariable() and deadLocal(def) and
deadLocal(ssa) and not expectedDead(def) and
not expectedDead(ssa) and not overwritten(def) and
not overwritten(ssa) and
read(v) and read(v) and
not def.(AssignExpr).getSource() instanceof NullLiteral and not def.(AssignExpr).getSource() instanceof NullLiteral and
(def instanceof Assignment or def.(UnaryAssignExpr).getParent() instanceof ExprStmt) (def instanceof Assignment or def.(UnaryAssignExpr).getParent() instanceof ExprStmt)

View File

@@ -1,7 +1,10 @@
| A.java:14:14:14:16 | "A" : String | A.java:14:7:14:20 | SSA def(a) : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [p] | | A.java:14:14:14:16 | "A" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:15:16:15:16 | a : new A(...) { ... } [p] | | A.java:14:14:14:16 | "A" : String | A.java:15:16:15:16 | a : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:15:16:15:22 | get(...) : String | | A.java:14:14:14:16 | "A" : String | A.java:15:16:15:22 | get(...) : String |
| A.java:14:14:14:16 | "A" : String | A.java:18:8:18:15 | p : String | | A.java:14:14:14:16 | "A" : String | A.java:18:8:18:15 | p : String |
| A.java:14:14:14:16 | "A" : String | A.java:18:25:40:3 | SSA def(p) : String |
| A.java:14:14:14:16 | "A" : String | A.java:28:7:38:5 | SSA def(a) : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [p] | | A.java:14:14:14:16 | "A" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:28:11:38:5 | p : String | | A.java:14:14:14:16 | "A" : String | A.java:28:11:38:5 | p : String |
| A.java:14:14:14:16 | "A" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [p] | | A.java:14:14:14:16 | "A" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [p] |
@@ -13,11 +16,16 @@
| A.java:14:14:14:16 | "A" : String | A.java:35:26:35:27 | this : new A(...) { ... } [p] | | A.java:14:14:14:16 | "A" : String | A.java:35:26:35:27 | this : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:39:12:39:12 | a : new A(...) { ... } [p] | | A.java:14:14:14:16 | "A" : String | A.java:39:12:39:12 | a : new A(...) { ... } [p] |
| A.java:14:14:14:16 | "A" : String | A.java:39:12:39:12 | p : String | | A.java:14:14:14:16 | "A" : String | A.java:39:12:39:12 | p : String |
| A.java:21:11:21:13 | "B" : String | A.java:14:7:14:20 | SSA def(a) : new A(...) { ... } [String s] |
| A.java:21:11:21:13 | "B" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] |
| A.java:21:11:21:13 | "B" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] |
| A.java:21:11:21:13 | "B" : String | A.java:15:16:15:22 | get(...) : String | | A.java:21:11:21:13 | "B" : String | A.java:15:16:15:22 | get(...) : String |
| A.java:21:11:21:13 | "B" : String | A.java:21:7:21:13 | ...=... : String | | A.java:21:11:21:13 | "B" : String | A.java:21:7:21:13 | ...=... : String |
| A.java:21:11:21:13 | "B" : String | A.java:21:7:21:13 | SSA def(s) : String |
| A.java:21:11:21:13 | "B" : String | A.java:21:7:21:13 | [input] SSA phi(s) : String |
| A.java:21:11:21:13 | "B" : String | A.java:25:5:25:26 | SSA phi(s) : String |
| A.java:21:11:21:13 | "B" : String | A.java:25:5:25:26 | phi(String s) : String | | A.java:21:11:21:13 | "B" : String | A.java:25:5:25:26 | phi(String s) : String |
| A.java:21:11:21:13 | "B" : String | A.java:28:7:38:5 | SSA def(a) : new A(...) { ... } [String s] |
| A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | String s : String | | A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | String s : String |
| A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] |
| A.java:21:11:21:13 | "B" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] |
@@ -29,11 +37,16 @@
| A.java:21:11:21:13 | "B" : String | A.java:35:26:35:27 | this : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:35:26:35:27 | this : new A(...) { ... } [String s] |
| A.java:21:11:21:13 | "B" : String | A.java:39:12:39:12 | String s : String | | A.java:21:11:21:13 | "B" : String | A.java:39:12:39:12 | String s : String |
| A.java:21:11:21:13 | "B" : String | A.java:39:12:39:12 | a : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:39:12:39:12 | a : new A(...) { ... } [String s] |
| A.java:23:11:23:13 | "C" : String | A.java:14:7:14:20 | SSA def(a) : new A(...) { ... } [String s] |
| A.java:23:11:23:13 | "C" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] |
| A.java:23:11:23:13 | "C" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] |
| A.java:23:11:23:13 | "C" : String | A.java:15:16:15:22 | get(...) : String | | A.java:23:11:23:13 | "C" : String | A.java:15:16:15:22 | get(...) : String |
| A.java:23:11:23:13 | "C" : String | A.java:23:7:23:13 | ...=... : String | | A.java:23:11:23:13 | "C" : String | A.java:23:7:23:13 | ...=... : String |
| A.java:23:11:23:13 | "C" : String | A.java:23:7:23:13 | SSA def(s) : String |
| A.java:23:11:23:13 | "C" : String | A.java:23:7:23:13 | [input] SSA phi(s) : String |
| A.java:23:11:23:13 | "C" : String | A.java:25:5:25:26 | SSA phi(s) : String |
| A.java:23:11:23:13 | "C" : String | A.java:25:5:25:26 | phi(String s) : String | | A.java:23:11:23:13 | "C" : String | A.java:25:5:25:26 | phi(String s) : String |
| A.java:23:11:23:13 | "C" : String | A.java:28:7:38:5 | SSA def(a) : new A(...) { ... } [String s] |
| A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | String s : String | | A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | String s : String |
| A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] |
| A.java:23:11:23:13 | "C" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] |
@@ -47,16 +60,20 @@
| A.java:23:11:23:13 | "C" : String | A.java:39:12:39:12 | a : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:39:12:39:12 | a : new A(...) { ... } [String s] |
| A.java:25:22:25:24 | "D" : String | A.java:4:5:4:7 | parameter this [Return] : Box [elem] | | A.java:25:22:25:24 | "D" : String | A.java:4:5:4:7 | parameter this [Return] : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:4:9:4:16 | e : String | | A.java:25:22:25:24 | "D" : String | A.java:4:9:4:16 | e : String |
| A.java:25:22:25:24 | "D" : String | A.java:4:19:4:31 | SSA def(e) : String |
| A.java:25:22:25:24 | "D" : String | A.java:4:21:4:24 | this <.field> [post update] : Box [elem] | | A.java:25:22:25:24 | "D" : String | A.java:4:21:4:24 | this <.field> [post update] : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:4:21:4:28 | ...=... : String | | A.java:25:22:25:24 | "D" : String | A.java:4:21:4:28 | ...=... : String |
| A.java:25:22:25:24 | "D" : String | A.java:4:28:4:28 | e : String | | A.java:25:22:25:24 | "D" : String | A.java:4:28:4:28 | e : String |
| A.java:25:22:25:24 | "D" : String | A.java:6:12:6:18 | parameter this : Box [elem] | | A.java:25:22:25:24 | "D" : String | A.java:6:12:6:18 | parameter this : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:6:31:6:34 | elem : String | | A.java:25:22:25:24 | "D" : String | A.java:6:31:6:34 | elem : String |
| A.java:25:22:25:24 | "D" : String | A.java:6:31:6:34 | this <.field> : Box [elem] | | A.java:25:22:25:24 | "D" : String | A.java:6:31:6:34 | this <.field> : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:14:7:14:20 | SSA def(a) : new A(...) { ... } [Box b1, ... (2)] |
| A.java:25:22:25:24 | "D" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [Box b1, ... (2)] | | A.java:25:22:25:24 | "D" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [Box b1, ... (2)] |
| A.java:25:22:25:24 | "D" : String | A.java:15:16:15:16 | a : new A(...) { ... } [Box b1, ... (2)] | | A.java:25:22:25:24 | "D" : String | A.java:15:16:15:16 | a : new A(...) { ... } [Box b1, ... (2)] |
| A.java:25:22:25:24 | "D" : String | A.java:15:16:15:22 | get(...) : String | | A.java:25:22:25:24 | "D" : String | A.java:15:16:15:22 | get(...) : String |
| A.java:25:22:25:24 | "D" : String | A.java:25:9:25:25 | SSA def(b1) : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:25:14:25:25 | new Box(...) : Box [elem] | | A.java:25:22:25:24 | "D" : String | A.java:25:14:25:25 | new Box(...) : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:28:7:38:5 | SSA def(a) : new A(...) { ... } [Box b1, ... (2)] |
| A.java:25:22:25:24 | "D" : String | A.java:28:11:38:5 | Box b1 : Box [elem] | | A.java:25:22:25:24 | "D" : String | A.java:28:11:38:5 | Box b1 : Box [elem] |
| A.java:25:22:25:24 | "D" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [Box b1, ... (2)] | | A.java:25:22:25:24 | "D" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [Box b1, ... (2)] |
| A.java:25:22:25:24 | "D" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [Box b1, ... (2)] | | A.java:25:22:25:24 | "D" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [Box b1, ... (2)] |
@@ -71,16 +88,19 @@
| A.java:25:22:25:24 | "D" : String | A.java:39:12:39:12 | a : new A(...) { ... } [Box b1, ... (2)] | | A.java:25:22:25:24 | "D" : String | A.java:39:12:39:12 | a : new A(...) { ... } [Box b1, ... (2)] |
| A.java:27:16:27:18 | "E" : String | A.java:5:10:5:16 | parameter this [Return] : Box [elem] | | A.java:27:16:27:18 | "E" : String | A.java:5:10:5:16 | parameter this [Return] : Box [elem] |
| A.java:27:16:27:18 | "E" : String | A.java:5:18:5:25 | e : String | | A.java:27:16:27:18 | "E" : String | A.java:5:18:5:25 | e : String |
| A.java:27:16:27:18 | "E" : String | A.java:5:28:5:40 | SSA def(e) : String |
| A.java:27:16:27:18 | "E" : String | A.java:5:30:5:33 | this <.field> [post update] : Box [elem] | | A.java:27:16:27:18 | "E" : String | A.java:5:30:5:33 | this <.field> [post update] : Box [elem] |
| A.java:27:16:27:18 | "E" : String | A.java:5:30:5:37 | ...=... : String | | A.java:27:16:27:18 | "E" : String | A.java:5:30:5:37 | ...=... : String |
| A.java:27:16:27:18 | "E" : String | A.java:5:37:5:37 | e : String | | A.java:27:16:27:18 | "E" : String | A.java:5:37:5:37 | e : String |
| A.java:27:16:27:18 | "E" : String | A.java:6:12:6:18 | parameter this : Box [elem] | | A.java:27:16:27:18 | "E" : String | A.java:6:12:6:18 | parameter this : Box [elem] |
| A.java:27:16:27:18 | "E" : String | A.java:6:31:6:34 | elem : String | | A.java:27:16:27:18 | "E" : String | A.java:6:31:6:34 | elem : String |
| A.java:27:16:27:18 | "E" : String | A.java:6:31:6:34 | this <.field> : Box [elem] | | A.java:27:16:27:18 | "E" : String | A.java:6:31:6:34 | this <.field> : Box [elem] |
| A.java:27:16:27:18 | "E" : String | A.java:14:7:14:20 | SSA def(a) : new A(...) { ... } [Box b2, ... (2)] |
| A.java:27:16:27:18 | "E" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [Box b2, ... (2)] | | A.java:27:16:27:18 | "E" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [Box b2, ... (2)] |
| A.java:27:16:27:18 | "E" : String | A.java:15:16:15:16 | a : new A(...) { ... } [Box b2, ... (2)] | | A.java:27:16:27:18 | "E" : String | A.java:15:16:15:16 | a : new A(...) { ... } [Box b2, ... (2)] |
| A.java:27:16:27:18 | "E" : String | A.java:15:16:15:22 | get(...) : String | | A.java:27:16:27:18 | "E" : String | A.java:15:16:15:22 | get(...) : String |
| A.java:27:16:27:18 | "E" : String | A.java:27:5:27:6 | b2 [post update] : Box [elem] | | A.java:27:16:27:18 | "E" : String | A.java:27:5:27:6 | b2 [post update] : Box [elem] |
| A.java:27:16:27:18 | "E" : String | A.java:28:7:38:5 | SSA def(a) : new A(...) { ... } [Box b2, ... (2)] |
| A.java:27:16:27:18 | "E" : String | A.java:28:11:38:5 | Box b2 : Box [elem] | | A.java:27:16:27:18 | "E" : String | A.java:28:11:38:5 | Box b2 : Box [elem] |
| A.java:27:16:27:18 | "E" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [Box b2, ... (2)] | | A.java:27:16:27:18 | "E" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [Box b2, ... (2)] |
| A.java:27:16:27:18 | "E" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [Box b2, ... (2)] | | A.java:27:16:27:18 | "E" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [Box b2, ... (2)] |

View File

@@ -1,4 +1,6 @@
| A.java:5:18:5:21 | null | A.java:2:13:2:20 | o | | A.java:5:18:5:21 | null | A.java:2:13:2:20 | o |
| A.java:5:18:5:21 | null | A.java:5:12:5:21 | SSA def(src) |
| A.java:5:18:5:21 | null | A.java:5:18:5:21 | null | | A.java:5:18:5:21 | null | A.java:5:18:5:21 | null |
| A.java:5:18:5:21 | null | A.java:6:12:6:18 | SSA def(x) |
| A.java:5:18:5:21 | null | A.java:6:16:6:18 | src | | A.java:5:18:5:21 | null | A.java:6:16:6:18 | src |
| A.java:5:18:5:21 | null | A.java:7:10:7:10 | x | | A.java:5:18:5:21 | null | A.java:7:10:7:10 | x |

View File

@@ -3,12 +3,14 @@ edges
| A.java:12:14:12:18 | src(...) : Object | A.java:12:5:12:5 | b [post update] : Box [elem] | | A.java:12:14:12:18 | src(...) : Object | A.java:12:5:12:5 | b [post update] : Box [elem] |
| A.java:12:14:12:18 | src(...) : Object | A.java:12:5:12:18 | ...=... : Object | | A.java:12:14:12:18 | src(...) : Object | A.java:12:5:12:18 | ...=... : Object |
| A.java:13:12:13:12 | b : Box [elem] | A.java:17:13:17:16 | f1(...) : Box [elem] | | A.java:13:12:13:12 | b : Box [elem] | A.java:17:13:17:16 | f1(...) : Box [elem] |
| A.java:17:13:17:16 | f1(...) : Box [elem] | A.java:18:8:18:8 | b : Box [elem] | | A.java:17:9:17:16 | SSA def(b) : Box [elem] | A.java:18:8:18:8 | b : Box [elem] |
| A.java:17:13:17:16 | f1(...) : Box [elem] | A.java:17:9:17:16 | SSA def(b) : Box [elem] |
| A.java:18:8:18:8 | b : Box [elem] | A.java:21:11:21:15 | b : Box [elem] | | A.java:18:8:18:8 | b : Box [elem] | A.java:21:11:21:15 | b : Box [elem] |
#select #select
| 0 | A.java:12:5:12:5 | b [post update] : Box [elem] | | 0 | A.java:12:5:12:5 | b [post update] : Box [elem] |
| 0 | A.java:12:5:12:18 | ...=... : Object | | 0 | A.java:12:5:12:18 | ...=... : Object |
| 0 | A.java:13:12:13:12 | b : Box [elem] | | 0 | A.java:13:12:13:12 | b : Box [elem] |
| 1 | A.java:17:9:17:16 | SSA def(b) : Box [elem] |
| 1 | A.java:17:13:17:16 | f1(...) : Box [elem] | | 1 | A.java:17:13:17:16 | f1(...) : Box [elem] |
| 1 | A.java:18:8:18:8 | b : Box [elem] | | 1 | A.java:18:8:18:8 | b : Box [elem] |
| 2 | A.java:21:11:21:15 | b : Box [elem] | | 2 | A.java:21:11:21:15 | b : Box [elem] |

View File

@@ -2,7 +2,8 @@ edges
| A.java:4:16:4:18 | parameter this [Return] [elem] | A.java:22:17:22:25 | new Box(...) [elem] | | A.java:4:16:4:18 | parameter this [Return] [elem] | A.java:22:17:22:25 | new Box(...) [elem] |
| A.java:4:16:4:18 | this <constr(this)> [post update] [elem] | A.java:4:16:4:18 | parameter this [Return] [elem] | | A.java:4:16:4:18 | this <constr(this)> [post update] [elem] | A.java:4:16:4:18 | parameter this [Return] [elem] |
| A.java:5:19:5:22 | elem | A.java:24:10:24:19 | other.elem | | A.java:5:19:5:22 | elem | A.java:24:10:24:19 | other.elem |
| A.java:22:17:22:25 | new Box(...) [elem] | A.java:23:13:23:17 | other [elem] | | A.java:22:9:22:25 | SSA def(other) [elem] | A.java:23:13:23:17 | other [elem] |
| A.java:22:17:22:25 | new Box(...) [elem] | A.java:22:9:22:25 | SSA def(other) [elem] |
| A.java:23:13:23:17 | other [elem] | A.java:24:10:24:14 | other [elem] | | A.java:23:13:23:17 | other [elem] | A.java:24:10:24:14 | other [elem] |
| A.java:23:13:23:17 | other [post update] [elem] | A.java:24:10:24:14 | other [elem] | | A.java:23:13:23:17 | other [post update] [elem] | A.java:24:10:24:14 | other [elem] |
| A.java:24:10:24:14 | other [elem] | A.java:24:10:24:19 | other.elem | | A.java:24:10:24:14 | other [elem] | A.java:24:10:24:19 | other.elem |
@@ -10,6 +11,7 @@ edges
| A.java:28:5:28:5 | b [post update] [elem] | A.java:27:16:27:20 | b [Return] [elem] | | A.java:28:5:28:5 | b [post update] [elem] | A.java:27:16:27:20 | b [Return] [elem] |
| A.java:28:14:28:25 | new Object(...) | A.java:28:5:28:5 | b [post update] [elem] | | A.java:28:14:28:25 | new Object(...) | A.java:28:5:28:5 | b [post update] [elem] |
#select #select
| 0 | A.java:22:9:22:25 | SSA def(other) [elem] |
| 0 | A.java:22:17:22:25 | new Box(...) [elem] | | 0 | A.java:22:17:22:25 | new Box(...) [elem] |
| 0 | A.java:23:13:23:17 | other [elem] | | 0 | A.java:23:13:23:17 | other [elem] |
| 0 | A.java:23:13:23:17 | other [post update] [elem] | | 0 | A.java:23:13:23:17 | other [post update] [elem] |

View File

@@ -1,9 +1,13 @@
| TestSwitchExpr.java:4:15:4:22 | o | | TestSwitchExpr.java:4:15:4:22 | o |
| TestSwitchExpr.java:7:16:7:28 | SSA def(x1) |
| TestSwitchExpr.java:7:21:7:28 | source(...) | | TestSwitchExpr.java:7:21:7:28 | source(...) |
| TestSwitchExpr.java:8:16:8:30 | SSA def(x2) |
| TestSwitchExpr.java:8:21:8:30 | switch (...) | | TestSwitchExpr.java:8:21:8:30 | switch (...) |
| TestSwitchExpr.java:10:24:10:25 | x1 | | TestSwitchExpr.java:10:24:10:25 | x1 |
| TestSwitchExpr.java:12:16:12:30 | SSA def(x3) |
| TestSwitchExpr.java:12:21:12:30 | switch (...) | | TestSwitchExpr.java:12:21:12:30 | switch (...) |
| TestSwitchExpr.java:13:38:13:39 | x2 | | TestSwitchExpr.java:13:38:13:39 | x2 |
| TestSwitchExpr.java:16:16:16:30 | SSA def(x4) |
| TestSwitchExpr.java:16:21:16:30 | switch (...) | | TestSwitchExpr.java:16:21:16:30 | switch (...) |
| TestSwitchExpr.java:19:23:19:24 | x3 | | TestSwitchExpr.java:19:23:19:24 | x3 |
| TestSwitchExpr.java:23:14:23:15 | x4 | | TestSwitchExpr.java:23:14:23:15 | x4 |

View File

@@ -1,19 +1,24 @@
| Test.java:12:15:12:47 | SSA def(inp) |
| Test.java:12:21:12:47 | new FileInputStream(...) | | Test.java:12:21:12:47 | new FileInputStream(...) |
| Test.java:14:21:14:39 | buffer(...) | | Test.java:14:21:14:39 | buffer(...) |
| Test.java:14:36:14:38 | inp | | Test.java:14:36:14:38 | inp |
| Test.java:15:16:15:54 | SSA def(lines) |
| Test.java:15:24:15:54 | readLines(...) | | Test.java:15:24:15:54 | readLines(...) |
| Test.java:15:42:15:44 | inp | | Test.java:15:42:15:44 | inp |
| Test.java:16:18:16:45 | readFully(...) | | Test.java:16:18:16:45 | readFully(...) |
| Test.java:16:36:16:38 | inp | | Test.java:16:36:16:38 | inp |
| Test.java:17:22:17:55 | toBufferedInputStream(...) | | Test.java:17:22:17:55 | toBufferedInputStream(...) |
| Test.java:17:52:17:54 | inp | | Test.java:17:52:17:54 | inp |
| Test.java:18:10:18:71 | SSA def(bufread) |
| Test.java:18:20:18:71 | toBufferedReader(...) | | Test.java:18:20:18:71 | toBufferedReader(...) |
| Test.java:18:45:18:70 | new InputStreamReader(...) | | Test.java:18:45:18:70 | new InputStreamReader(...) |
| Test.java:18:67:18:69 | inp | | Test.java:18:67:18:69 | inp |
| Test.java:19:19:19:48 | toByteArray(...) | | Test.java:19:19:19:48 | toByteArray(...) |
| Test.java:19:39:19:41 | inp | | Test.java:19:39:19:41 | inp |
| Test.java:20:10:20:50 | SSA def(chars) |
| Test.java:20:18:20:50 | toCharArray(...) | | Test.java:20:18:20:50 | toCharArray(...) |
| Test.java:20:38:20:40 | inp | | Test.java:20:38:20:40 | inp |
| Test.java:21:10:21:43 | SSA def(s) |
| Test.java:21:14:21:43 | toString(...) | | Test.java:21:14:21:43 | toString(...) |
| Test.java:21:31:21:33 | inp | | Test.java:21:31:21:33 | inp |
| Test.java:22:20:22:52 | toInputStream(...) | | Test.java:22:20:22:52 | toInputStream(...) |

View File

@@ -10,11 +10,13 @@
| A.java:20:16:20:16 | this <.field> | | A.java:20:16:20:16 | this <.field> |
| A.java:21:12:21:20 | getThis(...) | | A.java:21:12:21:20 | getThis(...) |
| A.java:21:12:21:20 | this <.method> | | A.java:21:12:21:20 | this <.method> |
| A.java:25:7:25:17 | SSA def(a) |
| A.java:25:11:25:17 | new A(...) | | A.java:25:11:25:17 | new A(...) |
| A.java:25:11:25:17 | new A(...) [pre constructor] | | A.java:25:11:25:17 | new A(...) [pre constructor] |
| A.java:26:12:26:12 | a | | A.java:26:12:26:12 | a |
| A.java:26:12:26:22 | getThis(...) | | A.java:26:12:26:22 | getThis(...) |
| A.java:26:12:26:36 | getThisWrap(...) | | A.java:26:12:26:36 | getThisWrap(...) |
| A.java:27:7:27:17 | SSA def(c) |
| A.java:27:11:27:17 | new C(...) | | A.java:27:11:27:17 | new C(...) |
| A.java:27:11:27:17 | new C(...) [pre constructor] | | A.java:27:11:27:17 | new C(...) [pre constructor] |
| A.java:28:5:28:5 | c | | A.java:28:5:28:5 | c |

View File

@@ -25,6 +25,12 @@ public class GuardTest {
} }
String s2 = "string";
if (!isSafe(s2)) {
s2 = null;
}
sink(s2);
} }
} }

View File

@@ -1,7 +1,4 @@
| Fields.java:13:5:13:17 | x | Fields.java:13:11:13:16 | x | SSA def(x) |
| Fields.java:13:5:13:17 | x | Fields.java:15:5:15:10 | ...=... | SSA def(x) | | Fields.java:13:5:13:17 | x | Fields.java:15:5:15:10 | ...=... | SSA def(x) |
| Fields.java:13:5:13:17 | x | Fields.java:18:5:18:15 | ...=... | SSA def(x) |
| Fields.java:13:5:13:17 | x | Fields.java:20:5:20:10 | ...=... | SSA def(x) |
| Fields.java:13:15:13:16 | this.xs | Fields.java:12:19:21:3 | { ... } | SSA init(this.xs) | | Fields.java:13:15:13:16 | this.xs | Fields.java:12:19:21:3 | { ... } | SSA init(this.xs) |
| Fields.java:13:15:13:16 | this.xs | Fields.java:14:5:14:9 | upd(...) | SSA impl upd[nonlocal](this.xs) | | Fields.java:13:15:13:16 | this.xs | Fields.java:14:5:14:9 | upd(...) | SSA impl upd[nonlocal](this.xs) |
| Fields.java:13:15:13:16 | this.xs | Fields.java:17:7:17:11 | upd(...) | SSA impl upd[nonlocal](this.xs) | | Fields.java:13:15:13:16 | this.xs | Fields.java:17:7:17:11 | upd(...) | SSA impl upd[nonlocal](this.xs) |
@@ -10,33 +7,17 @@
| Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) |
| Fields.java:24:5:24:28 | f | Fields.java:43:7:43:22 | ...=... | SSA def(f) | | Fields.java:24:5:24:28 | f | Fields.java:43:7:43:22 | ...=... | SSA def(f) |
| Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | <Expr>; | SSA phi(f) | | Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | <Expr>; | SSA phi(f) |
| Fields.java:25:5:25:19 | y | Fields.java:25:11:25:18 | y | SSA def(y) |
| Fields.java:25:5:25:19 | y | Fields.java:29:5:29:12 | ...=... | SSA def(y) |
| Fields.java:25:5:25:19 | y | Fields.java:33:5:33:12 | ...=... | SSA def(y) |
| Fields.java:25:5:25:19 | y | Fields.java:37:5:37:12 | ...=... | SSA def(y) |
| Fields.java:25:5:25:19 | y | Fields.java:40:5:40:12 | ...=... | SSA def(y) |
| Fields.java:25:5:25:19 | y | Fields.java:44:5:44:12 | ...=... | SSA def(y) |
| Fields.java:25:5:25:19 | y | Fields.java:46:5:46:12 | ...=... | SSA def(y) |
| Fields.java:25:15:25:18 | f.xs | Fields.java:24:12:24:27 | f | SSA impl upd[explicit qualifier](f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:24:12:24:27 | f | SSA impl upd[explicit qualifier](f.xs) |
| Fields.java:25:15:25:18 | f.xs | Fields.java:28:5:28:12 | f(...) | SSA impl upd[nonlocal](f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:28:5:28:12 | f(...) | SSA impl upd[nonlocal](f.xs) |
| Fields.java:25:15:25:18 | f.xs | Fields.java:32:5:32:9 | f(...) | SSA impl upd[nonlocal](f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:32:5:32:9 | f(...) | SSA impl upd[nonlocal](f.xs) |
| Fields.java:25:15:25:18 | f.xs | Fields.java:39:5:39:21 | ...=... | SSA def(f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:39:5:39:21 | ...=... | SSA def(f.xs) |
| Fields.java:25:15:25:18 | f.xs | Fields.java:43:7:43:22 | ...=... | SSA impl upd[explicit qualifier](f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:43:7:43:22 | ...=... | SSA impl upd[explicit qualifier](f.xs) |
| Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | <Expr>; | SSA phi(f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | <Expr>; | SSA phi(f.xs) |
| Fields.java:26:5:26:17 | z | Fields.java:26:11:26:16 | z | SSA def(z) |
| Fields.java:26:5:26:17 | z | Fields.java:30:5:30:10 | ...=... | SSA def(z) |
| Fields.java:26:5:26:17 | z | Fields.java:34:5:34:10 | ...=... | SSA def(z) |
| Fields.java:26:5:26:17 | z | Fields.java:38:5:38:10 | ...=... | SSA def(z) |
| Fields.java:26:5:26:17 | z | Fields.java:41:5:41:10 | ...=... | SSA def(z) | | Fields.java:26:5:26:17 | z | Fields.java:41:5:41:10 | ...=... | SSA def(z) |
| Fields.java:26:5:26:17 | z | Fields.java:47:5:47:10 | ...=... | SSA def(z) |
| Fields.java:26:15:26:16 | this.xs | Fields.java:23:19:49:3 | { ... } | SSA init(this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:23:19:49:3 | { ... } | SSA init(this.xs) |
| Fields.java:26:15:26:16 | this.xs | Fields.java:28:5:28:12 | f(...) | SSA impl upd[nonlocal](this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:28:5:28:12 | f(...) | SSA impl upd[nonlocal](this.xs) |
| Fields.java:26:15:26:16 | this.xs | Fields.java:32:5:32:9 | f(...) | SSA impl upd[nonlocal](this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:32:5:32:9 | f(...) | SSA impl upd[nonlocal](this.xs) |
| Fields.java:26:15:26:16 | this.xs | Fields.java:36:5:36:19 | ...=... | SSA def(this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:36:5:36:19 | ...=... | SSA def(this.xs) |
| Fields.java:27:5:27:19 | w | Fields.java:27:11:27:18 | w | SSA def(w) |
| Fields.java:27:5:27:19 | w | Fields.java:31:5:31:12 | ...=... | SSA def(w) |
| Fields.java:27:5:27:19 | w | Fields.java:35:5:35:12 | ...=... | SSA def(w) |
| Fields.java:27:5:27:19 | w | Fields.java:48:5:48:12 | ...=... | SSA def(w) |
| Fields.java:27:15:27:18 | Fields.stat | Fields.java:23:19:49:3 | { ... } | SSA init(Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:23:19:49:3 | { ... } | SSA init(Fields.stat) |
| Fields.java:27:15:27:18 | Fields.stat | Fields.java:24:16:24:27 | new Fields(...) | SSA impl upd[nonlocal](Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:24:16:24:27 | new Fields(...) | SSA impl upd[nonlocal](Fields.stat) |
| Fields.java:27:15:27:18 | Fields.stat | Fields.java:28:5:28:12 | f(...) | SSA impl upd[nonlocal](Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:28:5:28:12 | f(...) | SSA impl upd[nonlocal](Fields.stat) |
@@ -58,15 +39,12 @@
| Nested.java:18:5:23:6 | h2 | Nested.java:18:15:23:5 | h2 | SSA def(h2) | | Nested.java:18:5:23:6 | h2 | Nested.java:18:15:23:5 | h2 | SSA def(h2) |
| Nested.java:20:9:20:40 | hnest | Nested.java:20:19:20:39 | hnest | SSA def(hnest) | | Nested.java:20:9:20:40 | hnest | Nested.java:20:19:20:39 | hnest | SSA def(hnest) |
| Nested.java:24:5:24:31 | getInt(..).obj2 | Nested.java:30:23:30:36 | { ... } | SSA init(getInt(..).obj2) | | Nested.java:24:5:24:31 | getInt(..).obj2 | Nested.java:30:23:30:36 | { ... } | SSA init(getInt(..).obj2) |
| Nested.java:24:5:24:31 | obj2 | Nested.java:24:12:24:30 | obj2 | SSA def(obj2) |
| Nested.java:24:5:24:31 | obj2 | Nested.java:26:7:26:25 | ...=... | SSA def(obj2) | | Nested.java:24:5:24:31 | obj2 | Nested.java:26:7:26:25 | ...=... | SSA def(obj2) |
| Nested.java:24:5:24:31 | obj2 | Nested.java:28:7:28:25 | ...=... | SSA def(obj2) | | Nested.java:24:5:24:31 | obj2 | Nested.java:28:7:28:25 | ...=... | SSA def(obj2) |
| Nested.java:24:5:24:31 | obj2 | Nested.java:30:5:30:37 | var ...; | SSA phi(obj2) | | Nested.java:24:5:24:31 | obj2 | Nested.java:30:5:30:37 | var ...; | SSA phi(obj2) |
| Nested.java:30:5:30:37 | hash2 | Nested.java:30:15:30:36 | hash2 | SSA def(hash2) |
| Nested.java:33:21:33:26 | p3 | Nested.java:33:29:42:3 | { ... } | SSA init(p3) | | Nested.java:33:21:33:26 | p3 | Nested.java:33:29:42:3 | { ... } | SSA init(p3) |
| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:37:20:37:25 | { ... } | SSA init(getInt(..).x3) | | Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:37:20:37:25 | { ... } | SSA init(getInt(..).x3) |
| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:40:20:40:25 | { ... } | SSA init(getInt(..).x3) | | Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:40:20:40:25 | { ... } | SSA init(getInt(..).x3) |
| Nested.java:34:5:34:11 | x3 | Nested.java:34:9:34:10 | x3 | SSA def(x3) |
| Nested.java:34:5:34:11 | x3 | Nested.java:36:7:36:12 | ...=... | SSA def(x3) | | Nested.java:34:5:34:11 | x3 | Nested.java:36:7:36:12 | ...=... | SSA def(x3) |
| Nested.java:34:5:34:11 | x3 | Nested.java:39:7:39:12 | ...=... | SSA def(x3) | | Nested.java:34:5:34:11 | x3 | Nested.java:39:7:39:12 | ...=... | SSA def(x3) |
| Test.java:4:8:4:16 | param | Test.java:4:19:32:2 | { ... } | SSA init(param) | | Test.java:4:8:4:16 | param | Test.java:4:19:32:2 | { ... } | SSA init(param) |
@@ -78,16 +56,12 @@
| Test.java:6:3:6:12 | x | Test.java:19:3:19:3 | ; | SSA phi(x) | | Test.java:6:3:6:12 | x | Test.java:19:3:19:3 | ; | SSA phi(x) |
| Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | SSA phi(x) | | Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | SSA phi(x) |
| Test.java:6:3:6:12 | x | Test.java:28:4:28:9 | ...+=... | SSA def(x) | | Test.java:6:3:6:12 | x | Test.java:28:4:28:9 | ...+=... | SSA def(x) |
| Test.java:7:3:7:8 | y | Test.java:7:7:7:7 | y | SSA def(y) |
| Test.java:7:3:7:8 | y | Test.java:11:4:11:10 | ...=... | SSA def(y) | | Test.java:7:3:7:8 | y | Test.java:11:4:11:10 | ...=... | SSA def(y) |
| Test.java:7:3:7:8 | y | Test.java:14:4:14:8 | ...=... | SSA def(y) | | Test.java:7:3:7:8 | y | Test.java:14:4:14:8 | ...=... | SSA def(y) |
| Test.java:7:3:7:8 | y | Test.java:15:4:15:9 | ...+=... | SSA def(y) | | Test.java:7:3:7:8 | y | Test.java:15:4:15:9 | ...+=... | SSA def(y) |
| Test.java:7:3:7:8 | y | Test.java:19:3:19:3 | ; | SSA phi(y) | | Test.java:7:3:7:8 | y | Test.java:19:3:19:3 | ; | SSA phi(y) |
| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | SSA phi(y) | | Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | SSA phi(y) |
| Test.java:7:3:7:8 | y | Test.java:24:4:24:9 | ...-=... | SSA def(y) | | Test.java:7:3:7:8 | y | Test.java:24:4:24:9 | ...-=... | SSA def(y) |
| Test.java:8:3:8:8 | z | Test.java:8:7:8:7 | z | SSA def(z) |
| Test.java:8:3:8:8 | z | Test.java:12:4:12:8 | ...=... | SSA def(z) |
| Test.java:8:3:8:8 | z | Test.java:17:4:17:8 | ...=... | SSA def(z) |
| Test.java:27:8:27:16 | i | Test.java:27:12:27:16 | i | SSA def(i) | | Test.java:27:8:27:16 | i | Test.java:27:12:27:16 | i | SSA def(i) |
| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) |
| Test.java:27:8:27:16 | i | Test.java:27:25:27:27 | ...++ | SSA def(i) | | Test.java:27:8:27:16 | i | Test.java:27:25:27:27 | ...++ | SSA def(i) |
@@ -101,5 +75,4 @@
| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | | TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) |
| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | | TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) |
| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA init(obj) | | TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA init(obj) |
| TestInstanceOfPattern.java:25:22:25:29 | s | TestInstanceOfPattern.java:25:29:25:29 | s | SSA def(s) |
| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA init(this.s) | | TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA init(this.s) |

View File

@@ -78,6 +78,12 @@ private import codeql.rust.elements.internal.PathResolution
/** Holds if `p` may resolve to multiple items including `i`. */ /** Holds if `p` may resolve to multiple items including `i`. */
query predicate multiplePathResolutions(Path p, ItemNode i) { query predicate multiplePathResolutions(Path p, ItemNode i) {
i = resolvePath(p) and i = resolvePath(p) and
// `use foo::bar` may use both a type `bar` and a value `bar`
not p =
any(UseTree use |
not use.isGlob() and
not use.hasUseTreeList()
).getPath() and
strictcount(resolvePath(p)) > 1 strictcount(resolvePath(p)) > 1
} }

View File

@@ -5,6 +5,31 @@
private import rust private import rust
private import codeql.rust.elements.internal.generated.ParentChild private import codeql.rust.elements.internal.generated.ParentChild
private newtype TNamespace =
TTypeNamespace() or
TValueNamespace()
/**
* A namespace.
*
* Either the _value_ namespace or the _type_ namespace, see
* https://doc.rust-lang.org/reference/names/namespaces.html.
*/
final class Namespace extends TNamespace {
/** Holds if this is the value namespace. */
predicate isValue() { this = TValueNamespace() }
/** Holds if this is the type namespace. */
predicate isType() { this = TTypeNamespace() }
/** Gets a textual representation of this namespace. */
string toString() {
this.isValue() and result = "value"
or
this.isType() and result = "type"
}
}
/** /**
* An item that may be referred to by a path, and which is a node in * An item that may be referred to by a path, and which is a node in
* the _item graph_. * the _item graph_.
@@ -46,11 +71,15 @@ private import codeql.rust.elements.internal.generated.ParentChild
* - https://doc.rust-lang.org/reference/names/scopes.html * - https://doc.rust-lang.org/reference/names/scopes.html
* - https://doc.rust-lang.org/reference/paths.html * - https://doc.rust-lang.org/reference/paths.html
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html * - https://doc.rust-lang.org/reference/visibility-and-privacy.html
* - https://doc.rust-lang.org/reference/names/namespaces.html
*/ */
abstract class ItemNode extends AstNode { abstract class ItemNode extends AstNode {
/** Gets the (original) name of this item. */ /** Gets the (original) name of this item. */
abstract string getName(); abstract string getName();
/** Gets the namespace that this item belongs to, if any. */
abstract Namespace getNamespace();
/** Gets the visibility of this item, if any. */ /** Gets the visibility of this item, if any. */
abstract Visibility getVisibility(); abstract Visibility getVisibility();
@@ -143,30 +172,44 @@ abstract private class ModuleLikeNode extends ItemNode {
private class SourceFileItemNode extends ModuleLikeNode, SourceFile { private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
override string getName() { result = "(source file)" } override string getName() { result = "(source file)" }
override Namespace getNamespace() {
result.isType() // can be referenced with `super`
}
override Visibility getVisibility() { none() } override Visibility getVisibility() { none() }
} }
private class ConstItemNode extends ItemNode instanceof Const { private class ConstItemNode extends ItemNode instanceof Const {
override string getName() { result = Const.super.getName().getText() } override string getName() { result = Const.super.getName().getText() }
override Namespace getNamespace() { result.isValue() }
override Visibility getVisibility() { result = Const.super.getVisibility() } override Visibility getVisibility() { result = Const.super.getVisibility() }
} }
private class EnumItemNode extends ItemNode instanceof Enum { private class EnumItemNode extends ItemNode instanceof Enum {
override string getName() { result = Enum.super.getName().getText() } override string getName() { result = Enum.super.getName().getText() }
override Namespace getNamespace() { result.isType() }
override Visibility getVisibility() { result = Enum.super.getVisibility() } override Visibility getVisibility() { result = Enum.super.getVisibility() }
} }
private class VariantItemNode extends ItemNode instanceof Variant { private class VariantItemNode extends ItemNode instanceof Variant {
override string getName() { result = Variant.super.getName().getText() } override string getName() { result = Variant.super.getName().getText() }
override Namespace getNamespace() {
if super.getFieldList() instanceof RecordFieldList then result.isType() else result.isValue()
}
override Visibility getVisibility() { result = Variant.super.getVisibility() } override Visibility getVisibility() { result = Variant.super.getVisibility() }
} }
private class FunctionItemNode extends ItemNode instanceof Function { private class FunctionItemNode extends ItemNode instanceof Function {
override string getName() { result = Function.super.getName().getText() } override string getName() { result = Function.super.getName().getText() }
override Namespace getNamespace() { result.isValue() }
override Visibility getVisibility() { result = Function.super.getVisibility() } override Visibility getVisibility() { result = Function.super.getVisibility() }
} }
@@ -184,57 +227,92 @@ abstract private class ImplOrTraitItemNode extends ItemNode {
} }
} }
private class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
ItemNode resolveSelfTy() { result = resolvePath(super.getSelfTy().(PathTypeRepr).getPath()) }
override string getName() { result = "(impl)" } override string getName() { result = "(impl)" }
override Namespace getNamespace() {
result.isType() // can be referenced with `Self`
}
override Visibility getVisibility() { result = Impl.super.getVisibility() } override Visibility getVisibility() { result = Impl.super.getVisibility() }
} }
private class MacroCallItemNode extends ItemNode instanceof MacroCall { private class MacroCallItemNode extends ItemNode instanceof MacroCall {
override string getName() { result = "(macro call)" } override string getName() { result = "(macro call)" }
override Namespace getNamespace() { none() }
override Visibility getVisibility() { none() } override Visibility getVisibility() { none() }
} }
private class ModuleItemNode extends ModuleLikeNode instanceof Module { private class ModuleItemNode extends ModuleLikeNode instanceof Module {
override string getName() { result = Module.super.getName().getText() } override string getName() { result = Module.super.getName().getText() }
override Namespace getNamespace() { result.isType() }
override Visibility getVisibility() { result = Module.super.getVisibility() } override Visibility getVisibility() { result = Module.super.getVisibility() }
} }
private class StructItemNode extends ItemNode instanceof Struct { private class StructItemNode extends ItemNode instanceof Struct {
override string getName() { result = Struct.super.getName().getText() } override string getName() { result = Struct.super.getName().getText() }
override Namespace getNamespace() {
result.isType() // the struct itself
or
not super.getFieldList() instanceof RecordFieldList and
result.isValue() // the constructor
}
override Visibility getVisibility() { result = Struct.super.getVisibility() } override Visibility getVisibility() { result = Struct.super.getVisibility() }
} }
private class TraitItemNode extends ImplOrTraitItemNode instanceof Trait { class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
override string getName() { result = Trait.super.getName().getText() } override string getName() { result = Trait.super.getName().getText() }
override Namespace getNamespace() { result.isType() }
override Visibility getVisibility() { result = Trait.super.getVisibility() } override Visibility getVisibility() { result = Trait.super.getVisibility() }
} }
class TypeAliasItemNode extends ItemNode instanceof TypeAlias {
override string getName() { result = TypeAlias.super.getName().getText() }
override Namespace getNamespace() { result.isType() }
override Visibility getVisibility() { result = TypeAlias.super.getVisibility() }
}
private class UnionItemNode extends ItemNode instanceof Union { private class UnionItemNode extends ItemNode instanceof Union {
override string getName() { result = Union.super.getName().getText() } override string getName() { result = Union.super.getName().getText() }
override Namespace getNamespace() { result.isType() }
override Visibility getVisibility() { result = Union.super.getVisibility() } override Visibility getVisibility() { result = Union.super.getVisibility() }
} }
private class UseItemNode extends ItemNode instanceof Use { private class UseItemNode extends ItemNode instanceof Use {
override string getName() { result = "(use)" } override string getName() { result = "(use)" }
override Namespace getNamespace() { none() }
override Visibility getVisibility() { none() } override Visibility getVisibility() { none() }
} }
private class BlockExprItemNode extends ItemNode instanceof BlockExpr { private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
override string getName() { result = "(block expr)" } override string getName() { result = "(block expr)" }
override Namespace getNamespace() { none() }
override Visibility getVisibility() { none() } override Visibility getVisibility() { none() }
} }
private class TypeParamItemNode extends ItemNode instanceof TypeParam { private class TypeParamItemNode extends ItemNode instanceof TypeParam {
override string getName() { result = TypeParam.super.getName().getText() } override string getName() { result = TypeParam.super.getName().getText() }
override Namespace getNamespace() { result.isType() }
override Visibility getVisibility() { none() } override Visibility getVisibility() { none() }
} }
@@ -320,19 +398,22 @@ private predicate useTreeDeclares(UseTree tree, string name) {
} }
/** /**
* Holds if `item` explicitly declares a sub item named `name`. This includes * Holds if `item` explicitly declares a sub item named `name` in the
* items declared by `use` statements, except for glob imports. * namespace `ns`. This includes items declared by `use` statements,
* except for glob imports.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate declares(ItemNode item, string name) { private predicate declares(ItemNode item, Namespace ns, string name) {
exists(ItemNode child | child.getImmediateParent() = item | exists(ItemNode child | child.getImmediateParent() = item |
child.getName() = name child.getName() = name and
child.getNamespace() = ns
or or
useTreeDeclares(child.(Use).getUseTree(), name) useTreeDeclares(child.(Use).getUseTree(), name) and
exists(ns) // `use foo::bar` can refer to both a value and a type
) )
or or
exists(MacroCallItemNode call | exists(MacroCallItemNode call |
declares(call, name) and declares(call, ns, name) and
call.getImmediateParent() = item call.getImmediateParent() = item
) )
} }
@@ -351,19 +432,20 @@ private class RelevantPath extends Path {
/** /**
* Holds if the unqualified path `p` references an item named `name`, and `name` * Holds if the unqualified path `p` references an item named `name`, and `name`
* may be looked up inside enclosing item `encl`. * may be looked up in the `ns` namespace inside enclosing item `encl`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate unqualifiedPathLookup(RelevantPath p, string name, ItemNode encl) { private predicate unqualifiedPathLookup(RelevantPath p, string name, Namespace ns, ItemNode encl) {
exists(ItemNode encl0 | exists(ItemNode encl0 |
// lookup in the immediately enclosing item // lookup in the immediately enclosing item
p.isUnqualified(name) and p.isUnqualified(name) and
encl0.getADescendant() = p encl0.getADescendant() = p and
exists(ns)
or or
// lookup in an outer scope, but only if the item is not declared in inner scope // lookup in an outer scope, but only if the item is not declared in inner scope
exists(ItemNode mid | exists(ItemNode mid |
unqualifiedPathLookup(p, name, mid) and unqualifiedPathLookup(p, name, ns, mid) and
not declares(mid, name) not declares(mid, ns, name)
| |
// nested modules do not have unqualified access to items from outer modules, // nested modules do not have unqualified access to items from outer modules,
// except for items declared at top-level in the source file // except for items declared at top-level in the source file
@@ -374,16 +456,30 @@ private predicate unqualifiedPathLookup(RelevantPath p, string name, ItemNode en
| |
// functions in `impl` blocks need to use explicit `Self::` to access other // functions in `impl` blocks need to use explicit `Self::` to access other
// functions in the `impl` block // functions in the `impl` block
if encl0 instanceof ImplOrTraitItemNode then encl = encl0.getImmediateParent() else encl = encl0 if encl0 instanceof ImplOrTraitItemNode and ns.isValue()
then encl = encl0.getImmediateParent()
else encl = encl0
) )
} }
/** Gets the item that `path` resolves to, if any. */ pragma[nomagic]
cached private ItemNode getASuccessor(ItemNode pred, string name, Namespace ns) {
ItemNode resolvePath(RelevantPath path) { result = pred.getASuccessor(name) and
exists(ItemNode encl, string name | ns = result.getNamespace()
unqualifiedPathLookup(path, name, encl) and }
result = encl.getASuccessor(name)
pragma[nomagic]
private ItemNode resolvePath0(RelevantPath path) {
exists(ItemNode encl, Namespace ns, string name, ItemNode res |
unqualifiedPathLookup(path, name, ns, encl) and
res = getASuccessor(encl, name, ns)
|
if
not any(RelevantPath parent).getQualifier() = path and
name = "Self" and
res instanceof ImplItemNode
then result = res.(ImplItemNode).resolveSelfTy()
else result = res
) )
or or
exists(ItemNode q, string name | exists(ItemNode q, string name |
@@ -394,6 +490,47 @@ ItemNode resolvePath(RelevantPath path) {
result = resolveUseTreeListItem(_, _, path) result = resolveUseTreeListItem(_, _, path)
} }
/** Holds if path `p` must be looked up in namespace `n`. */
private predicate pathUsesNamespace(Path p, Namespace n) {
n.isValue() and
(
p = any(PathExpr pe).getPath()
or
p = any(TupleStructPat tsp).getPath()
)
or
n.isType() and
(
p = any(Visibility v).getPath()
or
p = any(RecordExpr re).getPath()
or
p = any(PathTypeRepr ptr).getPath()
or
p = any(RecordPat rp).getPath()
or
p =
any(UseTree use |
use.isGlob()
or
use.hasUseTreeList()
).getPath()
or
p = any(Path parent).getQualifier()
)
}
/** Gets the item that `path` resolves to, if any. */
cached
ItemNode resolvePath(RelevantPath path) {
result = resolvePath0(path) and
(
pathUsesNamespace(path, result.getNamespace())
or
not pathUsesNamespace(path, _)
)
}
pragma[nomagic] pragma[nomagic]
private ItemNode resolvePathQualifier(RelevantPath path, string name) { private ItemNode resolvePathQualifier(RelevantPath path, string name) {
result = resolvePath(path.getQualifier()) and result = resolvePath(path.getQualifier()) and
@@ -452,14 +589,14 @@ pragma[nomagic]
private predicate useImportEdge(Use use, string name, ItemNode item) { private predicate useImportEdge(Use use, string name, ItemNode item) {
exists(UseTree tree, ItemNode used | exists(UseTree tree, ItemNode used |
used = resolveUseTreeListItem(use, tree) and used = resolveUseTreeListItem(use, tree) and
not exists(tree.getUseTreeList()) and not tree.hasUseTreeList() and
if tree.isGlob() if tree.isGlob()
then then
exists(ItemNode encl | exists(ItemNode encl, Namespace ns |
encl.getADescendant() = use and encl.getADescendant() = use and
item = used.getASuccessor(name) and item = getASuccessor(used, name, ns) and
// glob imports can be shadowed // glob imports can be shadowed
not declares(encl, name) not declares(encl, ns, name)
) )
else item = used else item = used
| |

View File

@@ -212,6 +212,74 @@ mod m10 {
} }
} }
mod m11 {
pub struct Foo {} // I61
fn Foo() {} // I62
pub fn f() {
let _ = Foo {}; // $ item=I61
Foo(); // $ item=I62
} // I63
mod f {} // I66
pub enum Bar {
FooBar {}, // I64
} // I65
use Bar::FooBar; // $ item=I64
fn FooBar() {} // I65
#[rustfmt::skip]
fn g(x: Foo) { // $ item=I61
let _ = FooBar {}; // $ item=I64
let _ = FooBar(); // $ item=I65
}
struct S; // I67
enum E {
C, // I68
}
use E::C; // $ item=I68
fn h() {
let _ = S; // $ item=I67
let _ = C; // $ item=I68
}
}
mod m12 {
#[rustfmt::skip]
trait MyParamTrait<
T // I69
> {
type AssociatedType; // I70
fn f(
&self,
x: T // $ item=I69
) -> Self::AssociatedType; // $ item=I70
}
}
mod m13 {
pub fn f() {} // I71
pub struct f {} // I72
mod m14 {
use crate::m13::f; // $ item=I71 item=I72
#[rustfmt::skip]
fn g(x: f) { // $ item=I72
let _ = f {}; // $ item=I72
f(); // $ item=I71
}
}
}
fn main() { fn main() {
my::nested::nested1::nested2::f(); // $ item=I4 my::nested::nested1::nested2::f(); // $ item=I4
my::f(); // $ item=I38 my::f(); // $ item=I38
@@ -230,4 +298,5 @@ fn main() {
m7::f(); // $ item=I45 m7::f(); // $ item=I45
m8::g(); // $ item=I55 m8::g(); // $ item=I55
m9::f(); // $ item=I57 m9::f(); // $ item=I57
m11::f(); // $ item=I63
} }

View File

@@ -13,6 +13,11 @@ mod
| main.rs:139:1:182:1 | mod m8 | | main.rs:139:1:182:1 | mod m8 |
| main.rs:184:1:192:1 | mod m9 | | main.rs:184:1:192:1 | mod m9 |
| main.rs:194:1:213:1 | mod m10 | | main.rs:194:1:213:1 | mod m10 |
| main.rs:215:1:252:1 | mod m11 |
| main.rs:225:5:225:12 | mod f |
| main.rs:254:1:266:1 | mod m12 |
| main.rs:268:1:281:1 | mod m13 |
| main.rs:272:5:280:5 | mod m14 |
| my2/mod.rs:1:1:1:16 | mod nested2 | | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/nested2.rs:1:1:11:1 | mod nested3 | | my2/nested2.rs:1:1:11:1 | mod nested3 |
| my2/nested2.rs:2:5:10:5 | mod nested4 | | my2/nested2.rs:2:5:10:5 | mod nested4 |
@@ -38,7 +43,7 @@ resolvePath
| main.rs:30:17:30:21 | super | main.rs:18:5:36:5 | mod m2 | | main.rs:30:17:30:21 | super | main.rs:18:5:36:5 | mod m2 |
| main.rs:30:17:30:24 | ...::f | main.rs:19:9:21:9 | fn f | | main.rs:30:17:30:24 | ...::f | main.rs:19:9:21:9 | fn f |
| main.rs:33:17:33:17 | f | main.rs:19:9:21:9 | fn f | | main.rs:33:17:33:17 | f | main.rs:19:9:21:9 | fn f |
| main.rs:40:9:40:13 | super | main.rs:1:1:233:2 | SourceFile | | main.rs:40:9:40:13 | super | main.rs:1:1:302:2 | SourceFile |
| main.rs:40:9:40:17 | ...::m1 | main.rs:13:1:37:1 | mod m1 | | main.rs:40:9:40:17 | ...::m1 | main.rs:13:1:37:1 | mod m1 |
| main.rs:40:9:40:21 | ...::m2 | main.rs:18:5:36:5 | mod m2 | | main.rs:40:9:40:21 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
| main.rs:40:9:40:24 | ...::g | main.rs:23:9:27:9 | fn g | | main.rs:40:9:40:24 | ...::g | main.rs:23:9:27:9 | fn g |
@@ -50,7 +55,7 @@ resolvePath
| main.rs:61:17:61:19 | Foo | main.rs:59:9:59:21 | struct Foo | | main.rs:61:17:61:19 | Foo | main.rs:59:9:59:21 | struct Foo |
| main.rs:64:13:64:15 | Foo | main.rs:53:5:53:17 | struct Foo | | main.rs:64:13:64:15 | Foo | main.rs:53:5:53:17 | struct Foo |
| main.rs:66:5:66:5 | f | main.rs:55:5:62:5 | fn f | | main.rs:66:5:66:5 | f | main.rs:55:5:62:5 | fn f |
| main.rs:68:5:68:8 | self | main.rs:1:1:233:2 | SourceFile | | main.rs:68:5:68:8 | self | main.rs:1:1:302:2 | SourceFile |
| main.rs:68:5:68:11 | ...::i | main.rs:71:1:83:1 | fn i | | main.rs:68:5:68:11 | ...::i | main.rs:71:1:83:1 | fn i |
| main.rs:74:13:74:15 | Foo | main.rs:48:1:48:13 | struct Foo | | main.rs:74:13:74:15 | Foo | main.rs:48:1:48:13 | struct Foo |
| main.rs:81:17:81:19 | Foo | main.rs:77:9:79:9 | struct Foo | | main.rs:81:17:81:19 | Foo | main.rs:77:9:79:9 | struct Foo |
@@ -64,7 +69,7 @@ resolvePath
| main.rs:87:57:87:66 | ...::g | my2/nested2.rs:7:9:9:9 | fn g | | main.rs:87:57:87:66 | ...::g | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:87:80:87:86 | nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 | | main.rs:87:80:87:86 | nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
| main.rs:100:5:100:22 | f_defined_in_macro | main.rs:99:18:99:42 | fn f_defined_in_macro | | main.rs:100:5:100:22 | f_defined_in_macro | main.rs:99:18:99:42 | fn f_defined_in_macro |
| main.rs:117:13:117:17 | super | main.rs:1:1:233:2 | SourceFile | | main.rs:117:13:117:17 | super | main.rs:1:1:302:2 | SourceFile |
| main.rs:117:13:117:21 | ...::m5 | main.rs:103:1:107:1 | mod m5 | | main.rs:117:13:117:21 | ...::m5 | main.rs:103:1:107:1 | mod m5 |
| main.rs:118:9:118:9 | f | main.rs:104:5:106:5 | fn f | | main.rs:118:9:118:9 | f | main.rs:104:5:106:5 | fn f |
| main.rs:118:9:118:9 | f | main.rs:110:5:112:5 | fn f | | main.rs:118:9:118:9 | f | main.rs:110:5:112:5 | fn f |
@@ -99,42 +104,65 @@ resolvePath
| main.rs:207:7:209:7 | MyStruct::<...> | main.rs:195:5:201:5 | struct MyStruct | | main.rs:207:7:209:7 | MyStruct::<...> | main.rs:195:5:201:5 | struct MyStruct |
| main.rs:208:9:208:9 | T | main.rs:204:14:204:14 | TypeParam | | main.rs:208:9:208:9 | T | main.rs:204:14:204:14 | TypeParam |
| main.rs:211:9:211:16 | MyStruct | main.rs:195:5:201:5 | struct MyStruct | | main.rs:211:9:211:16 | MyStruct | main.rs:195:5:201:5 | struct MyStruct |
| main.rs:216:5:216:6 | my | main.rs:1:1:1:7 | mod my | | main.rs:221:17:221:19 | Foo | main.rs:216:5:216:21 | struct Foo |
| main.rs:216:5:216:14 | ...::nested | my.rs:1:1:1:15 | mod nested | | main.rs:222:9:222:11 | Foo | main.rs:218:5:218:15 | fn Foo |
| main.rs:216:5:216:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 | | main.rs:231:9:231:11 | Bar | main.rs:227:5:229:5 | enum Bar |
| main.rs:216:5:216:32 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 | | main.rs:231:9:231:19 | ...::FooBar | main.rs:228:9:228:17 | FooBar |
| main.rs:216:5:216:35 | ...::f | my/nested.rs:3:9:5:9 | fn f | | main.rs:236:13:236:15 | Foo | main.rs:216:5:216:21 | struct Foo |
| main.rs:217:5:217:6 | my | main.rs:1:1:1:7 | mod my | | main.rs:237:17:237:22 | FooBar | main.rs:228:9:228:17 | FooBar |
| main.rs:217:5:217:9 | ...::f | my.rs:5:1:7:1 | fn f | | main.rs:238:17:238:22 | FooBar | main.rs:233:5:233:18 | fn FooBar |
| main.rs:218:5:218:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 | | main.rs:246:9:246:9 | E | main.rs:241:15:244:5 | enum E |
| main.rs:218:5:218:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 | | main.rs:246:9:246:12 | ...::C | main.rs:243:9:243:9 | C |
| main.rs:218:5:218:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 | | main.rs:249:17:249:17 | S | main.rs:241:5:241:13 | struct S |
| main.rs:218:5:218:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f | | main.rs:250:17:250:17 | C | main.rs:243:9:243:9 | C |
| main.rs:219:5:219:5 | f | my2/nested2.rs:3:9:5:9 | fn f | | main.rs:263:16:263:16 | T | main.rs:257:7:257:7 | TypeParam |
| main.rs:220:5:220:5 | g | my2/nested2.rs:7:9:9:9 | fn g | | main.rs:264:14:264:17 | Self | main.rs:255:5:265:5 | trait MyParamTrait |
| main.rs:221:5:221:9 | crate | main.rs:1:1:233:2 | SourceFile | | main.rs:264:14:264:33 | ...::AssociatedType | main.rs:259:9:259:28 | TypeAlias |
| main.rs:221:5:221:12 | ...::h | main.rs:50:1:69:1 | fn h | | main.rs:273:13:273:17 | crate | main.rs:1:1:302:2 | SourceFile |
| main.rs:222:5:222:6 | m1 | main.rs:13:1:37:1 | mod m1 | | main.rs:273:13:273:22 | ...::m13 | main.rs:268:1:281:1 | mod m13 |
| main.rs:222:5:222:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 | | main.rs:273:13:273:25 | ...::f | main.rs:269:5:269:17 | fn f |
| main.rs:222:5:222:13 | ...::g | main.rs:23:9:27:9 | fn g | | main.rs:273:13:273:25 | ...::f | main.rs:269:19:270:19 | struct f |
| main.rs:223:5:223:6 | m1 | main.rs:13:1:37:1 | mod m1 | | main.rs:276:17:276:17 | f | main.rs:269:19:270:19 | struct f |
| main.rs:223:5:223:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 | | main.rs:277:21:277:21 | f | main.rs:269:19:270:19 | struct f |
| main.rs:223:5:223:14 | ...::m3 | main.rs:29:9:35:9 | mod m3 | | main.rs:278:13:278:13 | f | main.rs:269:5:269:17 | fn f |
| main.rs:223:5:223:17 | ...::h | main.rs:30:27:34:13 | fn h | | main.rs:284:5:284:6 | my | main.rs:1:1:1:7 | mod my |
| main.rs:224:5:224:6 | m4 | main.rs:39:1:46:1 | mod m4 | | main.rs:284:5:284:14 | ...::nested | my.rs:1:1:1:15 | mod nested |
| main.rs:224:5:224:9 | ...::i | main.rs:42:5:45:5 | fn i | | main.rs:284:5:284:23 | ...::nested1 | my/nested.rs:1:1:17:1 | mod nested1 |
| main.rs:225:5:225:5 | h | main.rs:50:1:69:1 | fn h | | main.rs:284:5:284:32 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
| main.rs:226:5:226:11 | f_alias | my2/nested2.rs:3:9:5:9 | fn f | | main.rs:284:5:284:35 | ...::f | my/nested.rs:3:9:5:9 | fn f |
| main.rs:227:5:227:11 | g_alias | my2/nested2.rs:7:9:9:9 | fn g | | main.rs:285:5:285:6 | my | main.rs:1:1:1:7 | mod my |
| main.rs:228:5:228:5 | j | main.rs:97:1:101:1 | fn j | | main.rs:285:5:285:9 | ...::f | my.rs:5:1:7:1 | fn f |
| main.rs:229:5:229:6 | m6 | main.rs:109:1:120:1 | mod m6 | | main.rs:286:5:286:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| main.rs:229:5:229:9 | ...::g | main.rs:114:5:119:5 | fn g | | main.rs:286:5:286:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
| main.rs:230:5:230:6 | m7 | main.rs:122:1:137:1 | mod m7 | | main.rs:286:5:286:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
| main.rs:230:5:230:9 | ...::f | main.rs:129:5:136:5 | fn f | | main.rs:286:5:286:32 | ...::f | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:231:5:231:6 | m8 | main.rs:139:1:182:1 | mod m8 | | main.rs:287:5:287:5 | f | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:231:5:231:9 | ...::g | main.rs:169:5:181:5 | fn g | | main.rs:288:5:288:5 | g | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:232:5:232:6 | m9 | main.rs:184:1:192:1 | mod m9 | | main.rs:289:5:289:9 | crate | main.rs:1:1:302:2 | SourceFile |
| main.rs:232:5:232:9 | ...::f | main.rs:187:5:191:5 | fn f | | main.rs:289:5:289:12 | ...::h | main.rs:50:1:69:1 | fn h |
| main.rs:290:5:290:6 | m1 | main.rs:13:1:37:1 | mod m1 |
| main.rs:290:5:290:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
| main.rs:290:5:290:13 | ...::g | main.rs:23:9:27:9 | fn g |
| main.rs:291:5:291:6 | m1 | main.rs:13:1:37:1 | mod m1 |
| main.rs:291:5:291:10 | ...::m2 | main.rs:18:5:36:5 | mod m2 |
| main.rs:291:5:291:14 | ...::m3 | main.rs:29:9:35:9 | mod m3 |
| main.rs:291:5:291:17 | ...::h | main.rs:30:27:34:13 | fn h |
| main.rs:292:5:292:6 | m4 | main.rs:39:1:46:1 | mod m4 |
| main.rs:292:5:292:9 | ...::i | main.rs:42:5:45:5 | fn i |
| main.rs:293:5:293:5 | h | main.rs:50:1:69:1 | fn h |
| main.rs:294:5:294:11 | f_alias | my2/nested2.rs:3:9:5:9 | fn f |
| main.rs:295:5:295:11 | g_alias | my2/nested2.rs:7:9:9:9 | fn g |
| main.rs:296:5:296:5 | j | main.rs:97:1:101:1 | fn j |
| main.rs:297:5:297:6 | m6 | main.rs:109:1:120:1 | mod m6 |
| main.rs:297:5:297:9 | ...::g | main.rs:114:5:119:5 | fn g |
| main.rs:298:5:298:6 | m7 | main.rs:122:1:137:1 | mod m7 |
| main.rs:298:5:298:9 | ...::f | main.rs:129:5:136:5 | fn f |
| main.rs:299:5:299:6 | m8 | main.rs:139:1:182:1 | mod m8 |
| main.rs:299:5:299:9 | ...::g | main.rs:169:5:181:5 | fn g |
| main.rs:300:5:300:6 | m9 | main.rs:184:1:192:1 | mod m9 |
| main.rs:300:5:300:9 | ...::f | main.rs:187:5:191:5 | fn f |
| main.rs:301:5:301:7 | m11 | main.rs:215:1:252:1 | mod m11 |
| main.rs:301:5:301:10 | ...::f | main.rs:220:5:223:5 | fn f |
| my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 | | my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
| my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 | | my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
| my2/mod.rs:5:5:5:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 | | my2/mod.rs:5:5:5:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |