mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge rc/1.18 into next.
This commit is contained in:
@@ -12,27 +12,63 @@
|
||||
|
||||
import csharp
|
||||
|
||||
/** A callable that is not an extension method. */
|
||||
private class NonExtensionMethod extends Callable {
|
||||
NonExtensionMethod() {
|
||||
not this instanceof ExtensionMethod
|
||||
/** A static callable. */
|
||||
class StaticCallable extends Callable {
|
||||
StaticCallable() {
|
||||
this.(Modifiable).isStatic()
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if non-extension callable `c` is a member of type `t` with name `name`. */
|
||||
/** An instance callable, that is, a non-static callable. */
|
||||
class InstanceCallable extends Callable {
|
||||
InstanceCallable() {
|
||||
not this instanceof StaticCallable
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to a static callable. */
|
||||
class StaticCall extends Call {
|
||||
StaticCall() {
|
||||
this.getTarget() instanceof StaticCallable and
|
||||
not this = any(ExtensionMethodCall emc | not emc.isOrdinaryStaticCall())
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds `t` has instance callable `c` as a member, with name `name`. */
|
||||
pragma [noinline]
|
||||
private predicate hasCallable(ValueOrRefType t, NonExtensionMethod c, string name) {
|
||||
predicate hasInstanceCallable(ValueOrRefType t, InstanceCallable c, string name) {
|
||||
t.hasMember(c) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
/** Holds if extension method `m` is a method on `t` with name `name`. */
|
||||
pragma [noinline]
|
||||
private predicate hasExtensionMethod(ValueOrRefType t, ExtensionMethod m, string name) {
|
||||
predicate hasExtensionMethod(ValueOrRefType t, ExtensionMethod m, string name) {
|
||||
t.isImplicitlyConvertibleTo(m.getExtendedType()) and
|
||||
name = m.getName()
|
||||
}
|
||||
|
||||
/** Holds `t` has static callable `c` as a member, with name `name`. */
|
||||
pragma [noinline]
|
||||
predicate hasStaticCallable(ValueOrRefType t, StaticCallable c, string name) {
|
||||
t.hasMember(c) and
|
||||
name = c.getName()
|
||||
}
|
||||
|
||||
/** Gets the minimum number of arguments required to call `c`. */
|
||||
int getMinimumArguments(Callable c) {
|
||||
result = count(Parameter p |
|
||||
p = c.getAParameter() and
|
||||
not p.hasDefaultValue()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the maximum number of arguments allowed to call `c`, if any. */
|
||||
int getMaximumArguments(Callable c) {
|
||||
not c.getAParameter().isParams() and
|
||||
result = c.getNumberOfParameters()
|
||||
}
|
||||
|
||||
/** An explicit upcast. */
|
||||
class ExplicitUpcast extends ExplicitCast {
|
||||
ValueOrRefType src;
|
||||
@@ -56,47 +92,70 @@ class ExplicitUpcast extends ExplicitCast {
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate isDisambiguatingNonExtensionMethod0(NonExtensionMethod target, ValueOrRefType t) {
|
||||
exists(Call c |
|
||||
/** Holds if this upcast may be used to disambiguate the target of an instance call. */
|
||||
pragma [nomagic]
|
||||
private predicate isDisambiguatingInstanceCall(InstanceCallable other, int args) {
|
||||
exists(Call c, InstanceCallable target, ValueOrRefType t |
|
||||
this.isArgument(c, target) |
|
||||
t = c.(QualifiableExpr).getQualifier().getType() and
|
||||
hasInstanceCallable(t, other, target.getName()) and
|
||||
args = c.getNumberOfArguments() and
|
||||
other != target
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this upcast may be used to disambiguate the target of an extension method call. */
|
||||
pragma [nomagic]
|
||||
private predicate isDisambiguatingExtensionCall(ExtensionMethod other, int args) {
|
||||
exists(ExtensionMethodCall c, ExtensionMethod target, ValueOrRefType t |
|
||||
this.isArgument(c, target) |
|
||||
not c.isOrdinaryStaticCall() and
|
||||
t = target.getParameter(0).getType() and
|
||||
hasExtensionMethod(t, other, target.getName()) and
|
||||
args = c.getNumberOfArguments() and
|
||||
other != target
|
||||
)
|
||||
}
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate isDisambiguatingStaticCall0(StaticCall c, StaticCallable target, ValueOrRefType t) {
|
||||
this.isArgument(c, target) and
|
||||
(
|
||||
t = c.(QualifiableExpr).getQualifier().getType()
|
||||
or
|
||||
not exists(c.(QualifiableExpr).getQualifier()) and
|
||||
not c.(QualifiableExpr).hasQualifier() and
|
||||
t = target.getDeclaringType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this upcast may be used to affect call resolution in a non-extension
|
||||
* method call.
|
||||
*/
|
||||
private predicate isDisambiguatingNonExtensionMethodCall() {
|
||||
exists(NonExtensionMethod target, NonExtensionMethod other, ValueOrRefType t |
|
||||
this.isDisambiguatingNonExtensionMethod0(target, t) |
|
||||
hasCallable(t, other, target.getName()) and
|
||||
/** Holds if this upcast may be used to disambiguate the target of a static call. */
|
||||
pragma [nomagic]
|
||||
private predicate isDisambiguatingStaticCall(StaticCallable other, int args) {
|
||||
exists(StaticCall c, StaticCallable target, ValueOrRefType t |
|
||||
this.isDisambiguatingStaticCall0(c, target, t) |
|
||||
hasStaticCallable(t, other, target.getName()) and
|
||||
args = c.getNumberOfArguments() and
|
||||
other != target
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this upcast may be used to affect call resolution in an extension
|
||||
* method call.
|
||||
*/
|
||||
private predicate isDisambiguatingExtensionMethodCall() {
|
||||
exists(Call c, ExtensionMethod target, ExtensionMethod other, ValueOrRefType t |
|
||||
this.isArgument(c, target) |
|
||||
t = c.getArgument(0).getType() and
|
||||
hasExtensionMethod(t, other, target.getName()) and
|
||||
other != target
|
||||
/** Holds if this upcast may be used to disambiguate the target of a call. */
|
||||
private predicate isDisambiguatingCall() {
|
||||
exists(Callable other, int args |
|
||||
this.isDisambiguatingInstanceCall(other, args)
|
||||
or
|
||||
this.isDisambiguatingExtensionCall(other, args)
|
||||
or
|
||||
this.isDisambiguatingStaticCall(other, args)
|
||||
|
|
||||
args >= getMinimumArguments(other) and
|
||||
not args > getMaximumArguments(other)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this is a useful upcast. */
|
||||
predicate isUseful() {
|
||||
this.isDisambiguatingNonExtensionMethodCall()
|
||||
or
|
||||
this.isDisambiguatingExtensionMethodCall()
|
||||
this.isDisambiguatingCall()
|
||||
or
|
||||
this = any(Call c).(QualifiableExpr).getQualifier() and
|
||||
dest instanceof Interface
|
||||
|
||||
@@ -1714,7 +1714,13 @@ module Internal {
|
||||
exists(TryStmt ts |
|
||||
ts = last.getTryStmt() and
|
||||
exists(lastTryStmtBlock(ts, c)) and
|
||||
not ts.definitelyHandles(c.getExceptionClass(), _) and
|
||||
not ts.getACatchClause() instanceof GeneralCatchClause and
|
||||
forall(SpecificCatchClause scc |
|
||||
scc = ts.getACatchClause() |
|
||||
scc.hasFilterClause()
|
||||
or
|
||||
not c.getExceptionClass().getABaseType*() = scc.getCaughtExceptionType()
|
||||
) and
|
||||
last.isLast()
|
||||
)
|
||||
}
|
||||
@@ -2967,6 +2973,11 @@ module Internal {
|
||||
|
||||
/** Provides logic for calculating reachable control flow nodes. */
|
||||
module Reachability {
|
||||
/**
|
||||
* Holds if `cfe` is a control flow element where the set of possible splits may
|
||||
* be different from the set of possible splits for one of `cfe`'s predecessors.
|
||||
* That is, `cfe` starts a new block of elements with the same set of splits.
|
||||
*/
|
||||
private predicate startsSplits(ControlFlowElement cfe) {
|
||||
cfe = succEntry(_)
|
||||
or
|
||||
|
||||
@@ -119,11 +119,11 @@ module Ssa {
|
||||
ad.getAControlFlowNode() = bb.getNode(i)
|
||||
and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition tdef, TupleAssignmentDefinition other |
|
||||
tdef = ad |
|
||||
other.getAssignment() = tdef.getAssignment() and
|
||||
other.getEvaluationOrder() > tdef.getEvaluationOrder() and
|
||||
other = v.getADefinition()
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second |
|
||||
first = ad |
|
||||
second.getAssignment() = first.getAssignment() and
|
||||
second.getEvaluationOrder() > first.getEvaluationOrder() and
|
||||
second = v.getADefinition()
|
||||
)
|
||||
and
|
||||
// In cases like `M(out x, out x)`, there is no inherent evaluation order, so we
|
||||
@@ -1094,7 +1094,7 @@ module Ssa {
|
||||
|
||||
private module SimpleDelegateAnalysis {
|
||||
private import semmle.code.csharp.dataflow.DelegateDataFlow
|
||||
private import semmle.code.csharp.dataflow.DataFlowInternal
|
||||
private import semmle.code.csharp.dataflow.internal.Steps
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
|
||||
/**
|
||||
@@ -1124,7 +1124,7 @@ module Ssa {
|
||||
}
|
||||
|
||||
private predicate delegateFlowStep(Expr pred, Expr succ) {
|
||||
DataFlowInternal::stepClosed(pred, succ)
|
||||
Steps::stepClosed(pred, succ)
|
||||
or
|
||||
exists(Call call, Callable callable |
|
||||
callable.getSourceDeclaration().canReturn(pred) and
|
||||
|
||||
127
csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll
Normal file
127
csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll
Normal file
@@ -0,0 +1,127 @@
|
||||
import csharp
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides a simple SSA implementation for local scope variables.
|
||||
*/
|
||||
module BaseSsa {
|
||||
private import ControlFlowGraph
|
||||
private import AssignableDefinitions
|
||||
|
||||
private class SimpleLocalScopeVariable extends LocalScopeVariable {
|
||||
SimpleLocalScopeVariable() {
|
||||
not exists(AssignableDefinition def1, AssignableDefinition def2 |
|
||||
def1.getTarget() = this and
|
||||
def2.getTarget() = this and
|
||||
def1.getEnclosingCallable() != def2.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is assignable definition `def`,
|
||||
* targeting local scope variable `v`.
|
||||
*/
|
||||
private predicate defAt(BasicBlock bb, int i, AssignableDefinition def, SimpleLocalScopeVariable v) {
|
||||
bb.getNode(i) = def.getAControlFlowNode() and
|
||||
v = def.getTarget() and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second |
|
||||
first = def |
|
||||
second.getAssignment() = first.getAssignment() and
|
||||
second.getEvaluationOrder() > first.getEvaluationOrder() and
|
||||
second.getTarget() = v
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` would need to start with a phi node for local scope
|
||||
* variable `v` in an SSA representation.
|
||||
*/
|
||||
private predicate needsPhiNode(BasicBlock bb, SimpleLocalScopeVariable v) {
|
||||
exists(BasicBlock def |
|
||||
def.inDominanceFrontier(bb) |
|
||||
defAt(def, _, _, v) or
|
||||
needsPhiNode(def, v)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype SsaRefKind = SsaRead() or SsaDef()
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or a write including phi nodes
|
||||
* (when `k` is `SsaDef()`).
|
||||
*/
|
||||
private predicate ssaRef(BasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) {
|
||||
bb.getNode(i).getElement() = v.getAnAccess().(VariableRead) and
|
||||
k = SsaRead()
|
||||
or
|
||||
defAt(bb, i, _, v) and
|
||||
k = SsaDef()
|
||||
or
|
||||
needsPhiNode(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
|
||||
* block `bb`, which has the given reference kind `k`.
|
||||
*/
|
||||
private int ssaRefRank(BasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) {
|
||||
i = rank[result](int j | ssaRef(bb, j, v, _)) and
|
||||
ssaRef(bb, i, v, k)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if definition `def` of local scope variable `v` inside basic block
|
||||
* `bb` reaches the reference at rank `rnk`, without passing through another
|
||||
* definition of `v`, including phi nodes.
|
||||
*/
|
||||
private predicate defReachesRank(BasicBlock bb, AssignableDefinition def, SimpleLocalScopeVariable v, int rnk) {
|
||||
exists(int i |
|
||||
rnk = ssaRefRank(bb, i, v, SsaDef()) |
|
||||
defAt(bb, i, def, v)
|
||||
)
|
||||
or
|
||||
defReachesRank(bb, def, v, rnk - 1) and
|
||||
rnk = ssaRefRank(bb, _, v, SsaRead())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if definition `def` of local scope variable `v` reaches the end of
|
||||
* basic block `bb` without passing through another definition of `v`, including
|
||||
* phi nodes.
|
||||
*/
|
||||
private predicate reachesEndOf(AssignableDefinition def, SimpleLocalScopeVariable v, BasicBlock bb) {
|
||||
exists(int rnk |
|
||||
defReachesRank(bb, def, v, rnk) and
|
||||
rnk = max(ssaRefRank(bb, _, v, _))
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
reachesEndOf(def, v, mid) and
|
||||
not exists(ssaRefRank(mid, _, v, SsaDef())) and
|
||||
bb = mid.getASuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a read of the SSA definition for variable `v` at definition `def`. That is,
|
||||
* a read that is guaranteed to read the value assigned at definition `def`.
|
||||
*/
|
||||
cached AssignableRead getARead(AssignableDefinition def, SimpleLocalScopeVariable v) {
|
||||
exists(BasicBlock bb, int i, int rnk |
|
||||
result.getTarget() = v and
|
||||
result.getAControlFlowNode() = bb.getNode(i) and
|
||||
rnk = ssaRefRank(bb, i, v, SsaRead())
|
||||
|
|
||||
defReachesRank(bb, def, v, rnk)
|
||||
or
|
||||
reachesEndOf(def, v, bb.getAPredecessor()) and
|
||||
not ssaRefRank(bb, _, v, SsaDef()) < rnk
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,108 +1,5 @@
|
||||
import csharp
|
||||
|
||||
private cached module MiniSsa {
|
||||
private import ControlFlowGraph
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is assignable definition `def`,
|
||||
* targeting local scope variable `v`.
|
||||
*/
|
||||
private predicate defAt(BasicBlock bb, int i, AssignableDefinition def, LocalScopeVariable v) {
|
||||
bb.getNode(i) = def.getAControlFlowNode() and
|
||||
v = def.getTarget()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `bb` would need to start with a phi node for local scope
|
||||
* variable `v` in an SSA representation.
|
||||
*/
|
||||
private predicate needsPhiNode(BasicBlock bb, LocalScopeVariable v) {
|
||||
exists(BasicBlock def |
|
||||
def.inDominanceFrontier(bb) |
|
||||
defAt(def, _, _, v) or
|
||||
needsPhiNode(def, v)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype SsaRefKind = SsaRead() or SsaDef()
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or a write including phi nodes
|
||||
* (when `k` is `SsaDef()`).
|
||||
*/
|
||||
private predicate ssaRef(BasicBlock bb, int i, LocalScopeVariable v, SsaRefKind k) {
|
||||
bb.getNode(i).getElement() = v.getAnAccess().(VariableRead) and
|
||||
k = SsaRead()
|
||||
or
|
||||
defAt(bb, i, _, v) and
|
||||
k = SsaDef()
|
||||
or
|
||||
needsPhiNode(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
|
||||
* block `bb`, which has the given reference kind `k`.
|
||||
*/
|
||||
private int ssaRefRank(BasicBlock bb, int i, LocalScopeVariable v, SsaRefKind k) {
|
||||
i = rank[result](int j | ssaRef(bb, j, v, _)) and
|
||||
ssaRef(bb, i, v, k)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if definition `def` of local scope variable `v` inside basic block
|
||||
* `bb` reaches the reference at rank `rnk`, without passing through another
|
||||
* definition of `v`, including phi nodes.
|
||||
*/
|
||||
private predicate defReachesRank(BasicBlock bb, AssignableDefinition def, LocalScopeVariable v, int rnk) {
|
||||
exists(int i |
|
||||
rnk = ssaRefRank(bb, i, v, SsaDef()) |
|
||||
defAt(bb, i, def, v)
|
||||
)
|
||||
or
|
||||
defReachesRank(bb, def, v, rnk - 1) and
|
||||
rnk = ssaRefRank(bb, _, v, SsaRead())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if definition `def` of local scope variable `v` reaches the end of
|
||||
* basic block `bb` without passing through another definition of `v`, including
|
||||
* phi nodes.
|
||||
*/
|
||||
private predicate reachesEndOf(AssignableDefinition def, LocalScopeVariable v, BasicBlock bb) {
|
||||
exists(int rnk |
|
||||
defReachesRank(bb, def, v, rnk) and
|
||||
rnk = max(ssaRefRank(bb, _, v, _))
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
reachesEndOf(def, v, mid) and
|
||||
not exists(ssaRefRank(mid, _, v, SsaDef())) and
|
||||
bb = mid.getASuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a read of the SSA definition for variable `v` at definition `def`. That is,
|
||||
* a read that is guaranteed to read the value assigned at definition `def`.
|
||||
*/
|
||||
cached AssignableRead getARead(AssignableDefinition def, LocalScopeVariable v) {
|
||||
exists(BasicBlock bb, int i, int rnk |
|
||||
result.getTarget() = v and
|
||||
result.getAControlFlowNode() = bb.getNode(i) and
|
||||
rnk = ssaRefRank(bb, i, v, SsaRead())
|
||||
|
|
||||
defReachesRank(bb, def, v, rnk)
|
||||
or
|
||||
reachesEndOf(def, v, bb.getAPredecessor()) and
|
||||
not ssaRefRank(bb, i, v, SsaDef()) < rnk
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
@@ -112,12 +9,14 @@ private cached module MiniSsa {
|
||||
* Instead, this library relies on a self-contained, minimalistic SSA-like
|
||||
* implementation.
|
||||
*/
|
||||
module DataFlowInternal {
|
||||
module Steps {
|
||||
private import semmle.code.csharp.dataflow.internal.BaseSSA
|
||||
|
||||
/**
|
||||
* Gets a read that is guaranteed to read the value assigned at definition `def`.
|
||||
*/
|
||||
private AssignableRead getARead(AssignableDefinition def) {
|
||||
result = MiniSsa::getARead(def, _)
|
||||
result = BaseSsa::getARead(def, _)
|
||||
or
|
||||
exists(LocalScopeVariable v |
|
||||
def.getTarget() = v |
|
||||
@@ -9,7 +9,7 @@ import csharp
|
||||
private import RuntimeCallable
|
||||
private import OverridableCallable
|
||||
private import semmle.code.csharp.Conversion
|
||||
private import semmle.code.csharp.dataflow.DataFlowInternal
|
||||
private import semmle.code.csharp.dataflow.internal.Steps
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.frameworks.system.Reflection
|
||||
|
||||
@@ -145,8 +145,8 @@ private module Internal {
|
||||
* using simple data flow.
|
||||
*/
|
||||
private Expr getAMethodCallArgSource(MethodCallArg e) {
|
||||
DataFlowInternal::stepOpen*(result, e) and
|
||||
not DataFlowInternal::stepOpen(_, result)
|
||||
Steps::stepOpen*(result, e) and
|
||||
not Steps::stepOpen(_, result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,7 +302,7 @@ private module Internal {
|
||||
}
|
||||
|
||||
private predicate stepExpr0(Expr succ, Expr pred) {
|
||||
DataFlowInternal::stepOpen(pred, succ)
|
||||
Steps::stepOpen(pred, succ)
|
||||
or
|
||||
exists(Assignable a |
|
||||
a instanceof Field or
|
||||
|
||||
@@ -357,7 +357,7 @@ class ExtensionMethodCall extends MethodCall {
|
||||
override Expr getArgument(int i) {
|
||||
exists(int j |
|
||||
result = this.getChildExpr(j) |
|
||||
if isOrdinaryCall() then
|
||||
if isOrdinaryStaticCall() then
|
||||
(j = i and j >= 0)
|
||||
else
|
||||
(j = i - 1 and j >= -1)
|
||||
@@ -381,7 +381,7 @@ class ExtensionMethodCall extends MethodCall {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
private predicate isOrdinaryCall() {
|
||||
predicate isOrdinaryStaticCall() {
|
||||
not exists(this.getChildExpr(-1)) // `Ext(i)` case above
|
||||
or
|
||||
exists(this.getQualifier()) // `Extensions.Ext(i)` case above
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.BaseSSA
|
||||
|
||||
from AssignableRead ar, AssignableDefinition def, LocalScopeVariable v
|
||||
where ar = BaseSsa::getARead(def, v)
|
||||
and not exists(Ssa::ExplicitDefinition edef |
|
||||
edef.getADefinition() = def and
|
||||
edef.getARead() = ar
|
||||
)
|
||||
select ar, def
|
||||
@@ -1,5 +1,6 @@
|
||||
| Capture.cs:6:16:6:16 | i | Capture.cs:8:17:8:17 | access to parameter i | Capture.cs:33:13:33:13 | access to parameter i |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:16:17:16:17 | access to local variable x | Capture.cs:17:21:17:21 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:45:13:45:13 | access to local variable x | Capture.cs:47:13:47:13 | access to local variable x |
|
||||
| Capture.cs:10:16:10:16 | a | Capture.cs:38:9:38:9 | access to local variable a | Capture.cs:46:12:46:12 | access to local variable a |
|
||||
| Capture.cs:65:45:65:51 | strings | Capture.cs:68:18:68:24 | access to parameter strings | Capture.cs:70:9:70:15 | access to parameter strings |
|
||||
| Consistency.cs:5:9:5:13 | Field | Consistency.cs:26:13:26:19 | access to field Field | Consistency.cs:27:13:27:19 | access to field Field |
|
||||
|
||||
@@ -17,7 +17,6 @@ WARNING: Predicate getAFirstUncertainRead has been deprecated and may be removed
|
||||
| Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:40:13:40:13 | access to local variable x |
|
||||
| Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:44:11:44:11 | access to local variable x |
|
||||
| Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:45:13:45:13 | access to local variable x |
|
||||
| Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:47:13:47:13 | access to local variable x |
|
||||
| Capture.cs:50:20:50:20 | SSA param(a) | Capture.cs:54:9:54:9 | access to parameter a |
|
||||
| Capture.cs:52:16:52:43 | SSA def(b) | Capture.cs:53:9:53:9 | access to local variable b |
|
||||
| Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:54:9:54:9 | access to parameter a |
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
| in | Capture.cs:6:16:6:16 | i | Capture.cs:6:16:6:16 | SSA param(i) | Capture.cs:10:20:27:9 | SSA capture def(i) | Capture.cs:38:9:38:11 | delegate call |
|
||||
| in | Capture.cs:6:16:6:16 | i | Capture.cs:6:16:6:16 | SSA param(i) | Capture.cs:10:20:27:9 | SSA capture def(i) | Capture.cs:44:9:44:12 | call to method M |
|
||||
| in | Capture.cs:6:16:6:16 | i | Capture.cs:6:16:6:16 | SSA param(i) | Capture.cs:10:20:27:9 | SSA capture def(i) | Capture.cs:46:9:46:13 | call to method M2 |
|
||||
| in | Capture.cs:8:13:8:13 | x | Capture.cs:8:13:8:17 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:38:9:38:11 | delegate call |
|
||||
| in | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:25:13:25:15 | delegate call |
|
||||
| in | Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:44:9:44:12 | call to method M |
|
||||
| in | Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:46:9:46:13 | call to method M2 |
|
||||
| in | Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:25:13:25:15 | delegate call |
|
||||
| in | Capture.cs:59:13:59:13 | i | Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:61:9:61:25 | call to method Select |
|
||||
| in | Capture.cs:67:13:67:13 | c | Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:18:68:50 | call to method Where |
|
||||
@@ -31,7 +29,6 @@
|
||||
| out | Capture.cs:6:16:6:16 | i | Capture.cs:13:13:13:17 | SSA def(i) | Capture.cs:38:9:38:11 | SSA call def(i) | Capture.cs:38:9:38:11 | delegate call |
|
||||
| out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:38:9:38:11 | delegate call |
|
||||
| out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:44:9:44:12 | call to method M |
|
||||
| out | Capture.cs:8:13:8:13 | x | Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:46:9:46:13 | call to method M2 |
|
||||
| out | Capture.cs:29:13:29:13 | z | Capture.cs:30:28:30:32 | SSA def(z) | Capture.cs:32:9:32:11 | SSA call def(z) | Capture.cs:32:9:32:11 | delegate call |
|
||||
| out | Capture.cs:50:20:50:20 | a | Capture.cs:52:28:52:40 | SSA def(a) | Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:53:9:53:11 | delegate call |
|
||||
| out | Capture.cs:59:13:59:13 | i | Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select |
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:38:9:38:11 | SSA call def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) |
|
||||
| Capture.cs:10:16:10:16 | a | Capture.cs:10:16:27:9 | SSA def(a) |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:19:24:23:13 | SSA capture def(y) |
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:21:21:21:21 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:40:13:40:13 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:44:11:44:11 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:45:13:45:13 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:47:13:47:13 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:47:13:47:13 | access to local variable x |
|
||||
| Capture.cs:10:16:10:16 | a | Capture.cs:10:16:27:9 | SSA def(a) | Capture.cs:46:12:46:12 | access to local variable a |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:26:17:26:17 | access to local variable y |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:22:21:22:21 | access to local variable y |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
| Capture.cs:6:16:6:16 | i | Capture.cs:38:9:38:11 | SSA call def(i) | Capture.cs:13:13:13:17 | ... = ... |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:15:13:15:17 | ... = ... |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:15:13:15:17 | ... = ... |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:15:13:15:17 | ... = ... |
|
||||
| Capture.cs:29:13:29:13 | z | Capture.cs:32:9:32:11 | SSA call def(z) | Capture.cs:30:28:30:32 | ... = ... |
|
||||
| Capture.cs:50:20:50:20 | a | Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:52:28:52:40 | ... = ... |
|
||||
| Capture.cs:59:13:59:13 | i | Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:60:36:60:38 | ...++ |
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:40:13:40:13 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:44:11:44:11 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:45:13:45:13 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:47:13:47:13 | access to local variable x |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:47:13:47:13 | access to local variable x |
|
||||
| Capture.cs:10:16:10:16 | a | Capture.cs:10:16:27:9 | SSA def(a) | Capture.cs:38:9:38:9 | access to local variable a |
|
||||
| Capture.cs:10:16:10:16 | a | Capture.cs:10:16:27:9 | SSA def(a) | Capture.cs:46:12:46:12 | access to local variable a |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:26:17:26:17 | access to local variable y |
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:43:9:43:13 | SSA def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:43:9:43:13 | SSA def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:44:9:44:12 | SSA call def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:43:9:43:13 | SSA def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:44:9:44:12 | SSA call def(x) |
|
||||
| Capture.cs:8:13:8:13 | x | Capture.cs:46:9:46:13 | SSA call def(x) | Capture.cs:46:9:46:13 | SSA call def(x) |
|
||||
| Capture.cs:10:16:10:16 | a | Capture.cs:10:16:27:9 | SSA def(a) | Capture.cs:10:16:27:9 | SSA def(a) |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:17:17:17:21 | SSA def(y) |
|
||||
| Capture.cs:17:17:17:17 | y | Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:19:24:23:13 | SSA capture def(y) |
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static StaticMethods;
|
||||
|
||||
interface I1 { int Foo(); }
|
||||
interface I2 { float Foo(); }
|
||||
interface I3 : I2 { }
|
||||
interface I4 : I3 { }
|
||||
|
||||
class A : I1, I2
|
||||
{
|
||||
@@ -42,7 +45,7 @@ class Tests
|
||||
void Fn(B a) { }
|
||||
void Fn2(A a) { }
|
||||
|
||||
void Fn(string[] args)
|
||||
void Test1(string[] args)
|
||||
{
|
||||
A a = new A();
|
||||
B b = new B();
|
||||
@@ -73,6 +76,59 @@ class Tests
|
||||
|
||||
var act = (Action) (() => { }); // GOOD
|
||||
|
||||
var objects = args.Select(s => (object)s); // GOOD
|
||||
var objects = args.Select(arg => (object)arg); // GOOD
|
||||
|
||||
M1((A)b); // GOOD: disambiguate targets from `StaticMethods`
|
||||
StaticMethods.M1((A)b); // GOOD: disambiguate targets from `StaticMethods`
|
||||
|
||||
void M2(A _) { }
|
||||
M2((A)b); // BAD: local functions cannot be overloaded
|
||||
}
|
||||
|
||||
static void M2(A _) { }
|
||||
|
||||
void Test2(B b)
|
||||
{
|
||||
// BAD: even though `StaticMethods` has an `M2`, only overloads in
|
||||
// `Tests` are taken into account
|
||||
M2((A)b);
|
||||
}
|
||||
|
||||
class Nested
|
||||
{
|
||||
static void M2(B _) { }
|
||||
|
||||
static void Test(C c)
|
||||
{
|
||||
// BAD: even though `StaticMethods` and `Tests` have `M2`s, only
|
||||
// overloads in `Nested` are taken into account
|
||||
M2((B)c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class IExtensions
|
||||
{
|
||||
public static void M1(this I2 i) { }
|
||||
|
||||
public static void M1(this I3 i) =>
|
||||
M1((I2)i); // GOOD
|
||||
|
||||
public static void M1(I4 i)
|
||||
{
|
||||
M1((I3)i); // GOOD
|
||||
((I3)i).M1(); // GOOD
|
||||
}
|
||||
|
||||
public static void M2(I2 i) { }
|
||||
|
||||
public static void M2(this I3 i) =>
|
||||
M2((I2)i); // GOOD
|
||||
}
|
||||
|
||||
static class StaticMethods
|
||||
{
|
||||
public static void M1(A _) { }
|
||||
public static void M1(B _) { }
|
||||
public static void M2(B _) { }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
| UselessUpcast.cs:51:13:51:16 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:17:7:17:7 | B | B | UselessUpcast.cs:10:7:10:7 | A | A |
|
||||
| UselessUpcast.cs:57:14:57:17 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:17:7:17:7 | B | B | UselessUpcast.cs:10:7:10:7 | A | A |
|
||||
| UselessUpcast.cs:66:13:66:16 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:17:7:17:7 | B | B | UselessUpcast.cs:10:7:10:7 | A | A |
|
||||
| UselessUpcast.cs:54:13:54:16 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:20:7:20:7 | B | B | UselessUpcast.cs:13:7:13:7 | A | A |
|
||||
| UselessUpcast.cs:60:14:60:17 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:20:7:20:7 | B | B | UselessUpcast.cs:13:7:13:7 | A | A |
|
||||
| UselessUpcast.cs:69:13:69:16 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:20:7:20:7 | B | B | UselessUpcast.cs:13:7:13:7 | A | A |
|
||||
| UselessUpcast.cs:85:12:85:15 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:20:7:20:7 | B | B | UselessUpcast.cs:13:7:13:7 | A | A |
|
||||
| UselessUpcast.cs:94:12:94:15 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:20:7:20:7 | B | B | UselessUpcast.cs:13:7:13:7 | A | A |
|
||||
| UselessUpcast.cs:105:16:105:19 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcast.cs:27:7:27:7 | C | C | UselessUpcast.cs:20:7:20:7 | B | B |
|
||||
| UselessUpcastBad.cs:9:23:9:32 | (...) ... | There is no need to upcast from $@ to $@ - the conversion can be done implicitly. | UselessUpcastBad.cs:4:11:4:13 | Sub | Sub | UselessUpcastBad.cs:3:11:3:15 | Super | Super |
|
||||
|
||||
Reference in New Issue
Block a user