Merge rc/1.18 into next.

This commit is contained in:
Aditya Sharad
2018-09-05 14:09:06 +01:00
145 changed files with 598 additions and 365 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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
)
}
}

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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) |

View File

@@ -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 |

View File

@@ -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 | ...++ |

View File

@@ -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 |

View File

@@ -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) |

View File

@@ -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 _) { }
}

View File

@@ -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 |