Merge pull request #8038 from michaelnebel/csharp/gvn-cfecomparison

C#: Refactor Structural Comparison for Control Flow Elements.
This commit is contained in:
Michael Nebel
2022-03-09 13:36:42 +01:00
committed by GitHub
4 changed files with 446 additions and 160 deletions

View File

@@ -5,6 +5,36 @@
import csharp
abstract private class GvnKind extends TGvnKind {
abstract string toString();
}
private class GvnKindExpr extends GvnKind, TGvnKindExpr {
private int kind;
GvnKindExpr() { this = TGvnKindExpr(kind) }
override string toString() { result = "Expr(" + kind + ")" }
}
private class GvnKindStmt extends GvnKind, TGvnKindStmt {
private int kind;
GvnKindStmt() { this = TGvnKindStmt(kind) }
override string toString() { result = "Stmt(" + kind + ")" }
}
private class GvnKindDeclaration extends GvnKind, TGvnKindDeclaration {
private int kind;
private boolean isTargetThis;
private Declaration d;
GvnKindDeclaration() { this = TGvnKindDeclaration(kind, isTargetThis, d) }
override string toString() { result = "Expr(" + kind + ")," + isTargetThis + "," + d }
}
/** Gets the declaration referenced by the expression `e`, if any. */
private Declaration referenceAttribute(Expr e) {
result = e.(MethodCall).getTarget()
@@ -14,17 +44,156 @@ private Declaration referenceAttribute(Expr e) {
result = e.(Access).getTarget()
}
/** Gets the AST node kind element `e`. */
private int elementKind(ControlFlowElement e) {
expressions(e, result, _)
/** Gets a Boolean indicating whether the target of the expression `e` is `this`. */
private boolean isTargetThis(Expr e) {
result = true and e.(MemberAccess).targetIsThisInstance()
or
exists(int k | statements(e, k) | result = -k)
result = false and not e.(MemberAccess).targetIsThisInstance()
}
private int getNumberOfActualChildren(ControlFlowElement e) {
if e.(MemberAccess).targetIsThisInstance()
then result = e.getNumberOfChildren() - 1
else result = e.getNumberOfChildren()
/**
* A global value number (GVN) for a control flow element.
*
* GVNs are used to map control flow elements to a representation that
* omits location information, that is, two elements that are structurally
* equal will be mapped to the same GVN.
*/
class Gvn extends TGvn {
/** Gets the string representation of this global value number. */
string toString() { none() }
}
private class ConstantGvn extends Gvn, TConstantGvn {
override string toString() { this = TConstantGvn(result) }
}
private class GvnNil extends Gvn, TGvnNil {
private GvnKind kind;
GvnNil() { this = TGvnNil(kind) }
override string toString() { result = "(kind:" + kind + ")" }
}
private class GvnCons extends Gvn, TGvnCons {
private Gvn head;
private Gvn tail;
GvnCons() { this = TGvnCons(head, tail) }
override string toString() { result = "(" + head + " :: " + tail + ")" }
}
pragma[noinline]
private predicate gvnKindDeclaration(Expr e, int kind, boolean isTargetThis, Declaration d) {
isTargetThis = isTargetThis(e) and
d = referenceAttribute(e) and
expressions(e, kind, _)
}
/**
* Gets the `GvnKind` of the element `cfe`.
*
* In case `cfe` is a reference attribute, we encode the entire declaration and whether
* the target is semantically equivalent to `this`.
*/
private GvnKind getGvnKind(ControlFlowElement cfe) {
exists(int kind, boolean isTargetThis, Declaration d |
gvnKindDeclaration(cfe, kind, isTargetThis, d) and
result = TGvnKindDeclaration(kind, isTargetThis, d)
)
or
exists(int kind |
not exists(referenceAttribute(cfe)) and
expressions(cfe, kind, _) and
result = TGvnKindExpr(kind)
or
statements(cfe, kind) and
result = TGvnKindStmt(kind)
)
}
private Gvn toGvn(ControlFlowElement cfe, GvnKind kind, int index) {
kind = getGvnKind(cfe) and
result = TGvnNil(kind) and
index = -1
or
exists(Gvn head, Gvn tail |
toGvnCons(cfe, kind, index, head, tail) and
result = TGvnCons(head, tail)
)
}
private int getNumberOfActualChildren(ControlFlowElement cfe) {
if cfe.(MemberAccess).targetIsThisInstance()
then result = cfe.getNumberOfChildren() - 1
else result = cfe.getNumberOfChildren()
}
private ControlFlowElement getRankedChild(ControlFlowElement cfe, int rnk) {
result =
rank[rnk + 1](ControlFlowElement child, int j |
child = cfe.getChild(j) and
(
j >= 0
or
j = -1 and not cfe.(MemberAccess).targetIsThisInstance()
)
|
child order by j
)
}
pragma[noinline]
private Gvn toGvnChild(ControlFlowElement cfe, int index) {
result = toGvn(getRankedChild(cfe, index))
}
pragma[noinline]
private predicate toGvnCons(ControlFlowElement cfe, GvnKind kind, int index, Gvn head, Gvn tail) {
tail = toGvn(cfe, kind, index - 1) and
head = toGvnChild(cfe, index)
}
cached
private module Cached {
cached
newtype TGvnKind =
TGvnKindExpr(int kind) { expressions(_, kind, _) } or
TGvnKindStmt(int kind) { statements(_, kind) } or
TGvnKindDeclaration(int kind, boolean thisTarget, Declaration d) {
exists(Expr e |
d = referenceAttribute(e) and thisTarget = isTargetThis(e) and expressions(e, kind, _)
)
}
cached
newtype TGvn =
TConstantGvn(string s) { s = any(Expr e).getValue() } or
TGvnNil(GvnKind gkind) or
TGvnCons(Gvn head, Gvn tail) { toGvnCons(_, _, _, head, tail) }
/** Gets the global value number of the element `cfe`. */
cached
Gvn toGvnCached(ControlFlowElement cfe) {
result = TConstantGvn(cfe.(Expr).getValue())
or
not exists(cfe.(Expr).getValue()) and
exists(GvnKind kind, int index |
result = toGvn(cfe, kind, index - 1) and
index = getNumberOfActualChildren(cfe)
)
}
}
private import Cached
predicate toGvn = toGvnCached/1;
pragma[inline]
private predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
pragma[only_bind_into](toGvn(pragma[only_bind_out](x))) =
pragma[only_bind_into](toGvn(pragma[only_bind_out](y)))
}
/**
@@ -57,87 +226,12 @@ abstract class StructuralComparisonConfiguration extends string {
*/
abstract predicate candidate(ControlFlowElement x, ControlFlowElement y);
private predicate candidateInternal(ControlFlowElement x, ControlFlowElement y) {
candidate(x, y)
or
exists(ControlFlowElement xParent, ControlFlowElement yParent, int i |
candidateInternalChild(xParent, i, x, yParent)
|
y = yParent.getChild(i)
)
}
pragma[noinline]
private predicate candidateInternalChild(
ControlFlowElement x, int i, ControlFlowElement xChild, ControlFlowElement y
) {
candidateInternal(x, y) and
xChild = x.getChild(i)
}
private predicate sameByValue(Expr x, Expr y) { sameByValueAux(x, y, y.getValue()) }
pragma[nomagic]
private predicate sameByValueAux(Expr x, Expr y, string value) {
candidateInternal(x, y) and
value = x.getValue()
}
private ControlFlowElement getRankedChild(ControlFlowElement cfe, int rnk, int i) {
(candidateInternal(cfe, _) or candidateInternal(_, cfe)) and
i =
rank[rnk](int j |
exists(ControlFlowElement child | child = cfe.getChild(j) |
not (j = -1 and cfe.(MemberAccess).targetIsThisInstance())
)
) and
result = cfe.getChild(i)
}
pragma[nomagic]
private predicate sameByStructure0(
ControlFlowElement x, ControlFlowElement y, int elementKind, int children
) {
candidateInternal(x, y) and
elementKind = elementKind(x) and
children = getNumberOfActualChildren(x) and
not (x.(Expr).hasValue() and y.(Expr).hasValue())
}
pragma[nomagic]
private predicate sameByStructure(ControlFlowElement x, ControlFlowElement y, int i) {
i = 0 and
// At least one of `x` and `y` must not have a value, they must have
// the same kind, and the same number of children
sameByStructure0(x, y, elementKind(y), getNumberOfActualChildren(y)) and
// If one of them has a reference attribute, they should both reference
// the same node
(exists(referenceAttribute(x)) implies referenceAttribute(x) = referenceAttribute(y)) and
// x is a member access on `this` iff y is
(x.(MemberAccess).targetIsThisInstance() implies y.(MemberAccess).targetIsThisInstance()) and
(y.(MemberAccess).targetIsThisInstance() implies x.(MemberAccess).targetIsThisInstance())
or
exists(int j | sameByStructure(x, y, i - 1) |
sameInternal(getRankedChild(x, i, j), getRankedChild(y, i, j))
)
}
pragma[nomagic]
private predicate sameInternal(ControlFlowElement x, ControlFlowElement y) {
sameByValue(x, y)
or
sameByStructure(x, y, getNumberOfActualChildren(x))
}
/**
* Holds if elements `x` and `y` structurally equal. `x` and `y` must be
* flagged as candidates for structural equality, that is,
* `candidate(x, y)` must hold.
*/
predicate same(ControlFlowElement x, ControlFlowElement y) {
candidate(x, y) and
sameInternal(x, y)
}
predicate same(ControlFlowElement x, ControlFlowElement y) { candidate(x, y) and sameGvn(x, y) }
}
/**
@@ -183,86 +277,11 @@ module Internal {
*/
abstract predicate candidate(ControlFlowElement x, ControlFlowElement y);
private predicate candidateInternal(ControlFlowElement x, ControlFlowElement y) {
candidate(x, y)
or
exists(ControlFlowElement xParent, ControlFlowElement yParent, int i |
candidateInternalChild(xParent, i, x, yParent)
|
y = yParent.getChild(i)
)
}
pragma[noinline]
private predicate candidateInternalChild(
ControlFlowElement x, int i, ControlFlowElement xChild, ControlFlowElement y
) {
candidateInternal(x, y) and
xChild = x.getChild(i)
}
private predicate sameByValue(Expr x, Expr y) { sameByValueAux(x, y, y.getValue()) }
pragma[nomagic]
private predicate sameByValueAux(Expr x, Expr y, string value) {
candidateInternal(x, y) and
value = x.getValue()
}
private ControlFlowElement getRankedChild(ControlFlowElement cfe, int rnk, int i) {
(candidateInternal(cfe, _) or candidateInternal(_, cfe)) and
i =
rank[rnk](int j |
exists(ControlFlowElement child | child = cfe.getChild(j) |
not (j = -1 and cfe.(MemberAccess).targetIsThisInstance())
)
) and
result = cfe.getChild(i)
}
pragma[nomagic]
private predicate sameByStructure0(
ControlFlowElement x, ControlFlowElement y, int elementKind, int children
) {
candidateInternal(x, y) and
elementKind = elementKind(x) and
children = getNumberOfActualChildren(x) and
not (x.(Expr).hasValue() and y.(Expr).hasValue())
}
pragma[nomagic]
private predicate sameByStructure(ControlFlowElement x, ControlFlowElement y, int i) {
i = 0 and
// At least one of `x` and `y` must not have a value, they must have
// the same kind, and the same number of children
sameByStructure0(x, y, elementKind(y), getNumberOfActualChildren(y)) and
// If one of them has a reference attribute, they should both reference
// the same node
(exists(referenceAttribute(x)) implies referenceAttribute(x) = referenceAttribute(y)) and
// x is a member access on `this` iff y is
(x.(MemberAccess).targetIsThisInstance() implies y.(MemberAccess).targetIsThisInstance()) and
(y.(MemberAccess).targetIsThisInstance() implies x.(MemberAccess).targetIsThisInstance())
or
exists(int j | sameByStructure(x, y, i - 1) |
sameInternal(getRankedChild(x, i, j), getRankedChild(y, i, j))
)
}
pragma[nomagic]
private predicate sameInternal(ControlFlowElement x, ControlFlowElement y) {
sameByValue(x, y)
or
sameByStructure(x, y, getNumberOfActualChildren(x))
}
/**
* Holds if elements `x` and `y` structurally equal. `x` and `y` must be
* flagged as candidates for structural equality, that is,
* `candidate(x, y)` must hold.
*/
predicate same(ControlFlowElement x, ControlFlowElement y) {
candidate(x, y) and
sameInternal(x, y)
}
predicate same(ControlFlowElement x, ControlFlowElement y) { candidate(x, y) and sameGvn(x, y) }
}
}

View File

@@ -0,0 +1,54 @@
using System;
public class Class
{
private readonly int x = 0;
private readonly int y = 1;
public int M0() => 0;
public int M1(int a) => a;
public int M2(int v1, int v2) => v1 + v2;
public void M3()
{
var z1 = x + y;
var z2 = x + y;
}
public void M4()
{
var z3 = M1(x);
var z4 = M1(x);
var z5 = M1(y);
var z6 = M0();
var z7 = M2(x, y) + M2(x, y);
M2(x, y);
M2(y, x);
M2(y, x);
}
}
public class BaseClass
{
public int Field;
public object Prop { get; set; }
}
public class DerivedClass : BaseClass
{
public void M4()
{
var x1 = base.Field;
var x2 = Field;
var x3 = this.Field;
}
public void M5()
{
var y1 = base.Prop;
var y2 = Prop;
var y3 = this.Prop;
}
}

View File

@@ -0,0 +1,179 @@
same
| StructuralComparison.cs:15:18:15:18 | access to field x | StructuralComparison.cs:16:18:16:18 | access to field x |
| StructuralComparison.cs:15:18:15:22 | ... + ... | StructuralComparison.cs:16:18:16:22 | ... + ... |
| StructuralComparison.cs:15:22:15:22 | access to field y | StructuralComparison.cs:16:22:16:22 | access to field y |
| StructuralComparison.cs:21:18:21:22 | call to method M1 | StructuralComparison.cs:22:18:22:22 | call to method M1 |
| StructuralComparison.cs:21:21:21:21 | access to field x | StructuralComparison.cs:22:21:22:21 | access to field x |
| StructuralComparison.cs:21:21:21:21 | access to field x | StructuralComparison.cs:25:21:25:21 | access to field x |
| StructuralComparison.cs:21:21:21:21 | access to field x | StructuralComparison.cs:25:32:25:32 | access to field x |
| StructuralComparison.cs:21:21:21:21 | access to field x | StructuralComparison.cs:26:12:26:12 | access to field x |
| StructuralComparison.cs:21:21:21:21 | access to field x | StructuralComparison.cs:27:15:27:15 | access to field x |
| StructuralComparison.cs:21:21:21:21 | access to field x | StructuralComparison.cs:28:15:28:15 | access to field x |
| StructuralComparison.cs:22:21:22:21 | access to field x | StructuralComparison.cs:25:21:25:21 | access to field x |
| StructuralComparison.cs:22:21:22:21 | access to field x | StructuralComparison.cs:25:32:25:32 | access to field x |
| StructuralComparison.cs:22:21:22:21 | access to field x | StructuralComparison.cs:26:12:26:12 | access to field x |
| StructuralComparison.cs:22:21:22:21 | access to field x | StructuralComparison.cs:27:15:27:15 | access to field x |
| StructuralComparison.cs:22:21:22:21 | access to field x | StructuralComparison.cs:28:15:28:15 | access to field x |
| StructuralComparison.cs:23:21:23:21 | access to field y | StructuralComparison.cs:25:24:25:24 | access to field y |
| StructuralComparison.cs:23:21:23:21 | access to field y | StructuralComparison.cs:25:35:25:35 | access to field y |
| StructuralComparison.cs:23:21:23:21 | access to field y | StructuralComparison.cs:26:15:26:15 | access to field y |
| StructuralComparison.cs:23:21:23:21 | access to field y | StructuralComparison.cs:27:12:27:12 | access to field y |
| StructuralComparison.cs:23:21:23:21 | access to field y | StructuralComparison.cs:28:12:28:12 | access to field y |
| StructuralComparison.cs:25:18:25:25 | call to method M2 | StructuralComparison.cs:25:29:25:36 | call to method M2 |
| StructuralComparison.cs:25:18:25:25 | call to method M2 | StructuralComparison.cs:26:9:26:16 | call to method M2 |
| StructuralComparison.cs:25:21:25:21 | access to field x | StructuralComparison.cs:25:32:25:32 | access to field x |
| StructuralComparison.cs:25:21:25:21 | access to field x | StructuralComparison.cs:26:12:26:12 | access to field x |
| StructuralComparison.cs:25:21:25:21 | access to field x | StructuralComparison.cs:27:15:27:15 | access to field x |
| StructuralComparison.cs:25:21:25:21 | access to field x | StructuralComparison.cs:28:15:28:15 | access to field x |
| StructuralComparison.cs:25:24:25:24 | access to field y | StructuralComparison.cs:25:35:25:35 | access to field y |
| StructuralComparison.cs:25:24:25:24 | access to field y | StructuralComparison.cs:26:15:26:15 | access to field y |
| StructuralComparison.cs:25:24:25:24 | access to field y | StructuralComparison.cs:27:12:27:12 | access to field y |
| StructuralComparison.cs:25:24:25:24 | access to field y | StructuralComparison.cs:28:12:28:12 | access to field y |
| StructuralComparison.cs:25:29:25:36 | call to method M2 | StructuralComparison.cs:26:9:26:16 | call to method M2 |
| StructuralComparison.cs:25:32:25:32 | access to field x | StructuralComparison.cs:26:12:26:12 | access to field x |
| StructuralComparison.cs:25:32:25:32 | access to field x | StructuralComparison.cs:27:15:27:15 | access to field x |
| StructuralComparison.cs:25:32:25:32 | access to field x | StructuralComparison.cs:28:15:28:15 | access to field x |
| StructuralComparison.cs:25:35:25:35 | access to field y | StructuralComparison.cs:26:15:26:15 | access to field y |
| StructuralComparison.cs:25:35:25:35 | access to field y | StructuralComparison.cs:27:12:27:12 | access to field y |
| StructuralComparison.cs:25:35:25:35 | access to field y | StructuralComparison.cs:28:12:28:12 | access to field y |
| StructuralComparison.cs:26:12:26:12 | access to field x | StructuralComparison.cs:27:15:27:15 | access to field x |
| StructuralComparison.cs:26:12:26:12 | access to field x | StructuralComparison.cs:28:15:28:15 | access to field x |
| StructuralComparison.cs:26:15:26:15 | access to field y | StructuralComparison.cs:27:12:27:12 | access to field y |
| StructuralComparison.cs:26:15:26:15 | access to field y | StructuralComparison.cs:28:12:28:12 | access to field y |
| StructuralComparison.cs:27:9:27:16 | call to method M2 | StructuralComparison.cs:28:9:28:16 | call to method M2 |
| StructuralComparison.cs:27:9:27:17 | ...; | StructuralComparison.cs:28:9:28:17 | ...; |
| StructuralComparison.cs:27:12:27:12 | access to field y | StructuralComparison.cs:28:12:28:12 | access to field y |
| StructuralComparison.cs:27:15:27:15 | access to field x | StructuralComparison.cs:28:15:28:15 | access to field x |
| StructuralComparison.cs:42:18:42:27 | access to field Field | StructuralComparison.cs:43:18:43:22 | access to field Field |
| StructuralComparison.cs:42:18:42:27 | access to field Field | StructuralComparison.cs:44:18:44:27 | access to field Field |
| StructuralComparison.cs:43:18:43:22 | access to field Field | StructuralComparison.cs:44:18:44:27 | access to field Field |
| StructuralComparison.cs:49:18:49:26 | access to property Prop | StructuralComparison.cs:50:18:50:21 | access to property Prop |
| StructuralComparison.cs:49:18:49:26 | access to property Prop | StructuralComparison.cs:51:18:51:26 | access to property Prop |
| StructuralComparison.cs:50:18:50:21 | access to property Prop | StructuralComparison.cs:51:18:51:26 | access to property Prop |
gvn
| StructuralComparison.cs:5:26:5:26 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:5:26:5:26 | this access | (kind:Expr(12)) |
| StructuralComparison.cs:5:26:5:30 | ... = ... | ((kind:Expr(16),true,x) :: (0 :: (kind:Expr(63)))) |
| StructuralComparison.cs:5:30:5:30 | 0 | 0 |
| StructuralComparison.cs:6:26:6:26 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:6:26:6:26 | this access | (kind:Expr(12)) |
| StructuralComparison.cs:6:26:6:30 | ... = ... | ((kind:Expr(16),true,y) :: (1 :: (kind:Expr(63)))) |
| StructuralComparison.cs:6:30:6:30 | 1 | 1 |
| StructuralComparison.cs:8:24:8:24 | 0 | 0 |
| StructuralComparison.cs:9:29:9:29 | access to parameter a | (kind:Expr(15),false,a) |
| StructuralComparison.cs:10:38:10:39 | access to parameter v1 | (kind:Expr(15),false,v1) |
| StructuralComparison.cs:10:38:10:44 | ... + ... | ((kind:Expr(15),false,v2) :: ((kind:Expr(15),false,v1) :: (kind:Expr(44)))) |
| StructuralComparison.cs:10:43:10:44 | access to parameter v2 | (kind:Expr(15),false,v2) |
| StructuralComparison.cs:14:5:17:5 | {...} | ((((kind:Expr(14),false,z2) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,z1) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: (kind:Stmt(1)))) |
| StructuralComparison.cs:15:9:15:23 | ... ...; | (((kind:Expr(14),false,z1) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:15:13:15:14 | access to local variable z1 | (kind:Expr(14),false,z1) |
| StructuralComparison.cs:15:13:15:22 | Int32 z1 = ... | ((kind:Expr(14),false,z1) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) :: (kind:Expr(83)))) |
| StructuralComparison.cs:15:18:15:18 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:15:18:15:18 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:15:18:15:22 | ... + ... | ((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) |
| StructuralComparison.cs:15:22:15:22 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:15:22:15:22 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:16:9:16:23 | ... ...; | (((kind:Expr(14),false,z2) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:16:13:16:14 | access to local variable z2 | (kind:Expr(14),false,z2) |
| StructuralComparison.cs:16:13:16:22 | Int32 z2 = ... | ((kind:Expr(14),false,z2) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) :: (kind:Expr(83)))) |
| StructuralComparison.cs:16:18:16:18 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:16:18:16:18 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:16:18:16:22 | ... + ... | ((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: (kind:Expr(44)))) |
| StructuralComparison.cs:16:22:16:22 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:16:22:16:22 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:20:5:29:5 | {...} | ((((kind:Expr(16),true,x) :: ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Stmt(2))) :: ((((kind:Expr(16),true,x) :: ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Stmt(2))) :: ((((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Stmt(2))) :: ((((kind:Expr(14),false,z7) :: ((((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Expr(44)))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,z6) :: (((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M0)) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,z5) :: (((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,z4) :: (((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,z3) :: (((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: (kind:Stmt(1)))))))))) |
| StructuralComparison.cs:21:9:21:23 | ... ...; | (((kind:Expr(14),false,z3) :: (((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:21:13:21:14 | access to local variable z3 | (kind:Expr(14),false,z3) |
| StructuralComparison.cs:21:13:21:22 | Int32 z3 = ... | ((kind:Expr(14),false,z3) :: (((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) |
| StructuralComparison.cs:21:18:21:22 | call to method M1 | ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) |
| StructuralComparison.cs:21:18:21:22 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:21:21:21:21 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:21:21:21:21 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:22:9:22:23 | ... ...; | (((kind:Expr(14),false,z4) :: (((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:22:13:22:14 | access to local variable z4 | (kind:Expr(14),false,z4) |
| StructuralComparison.cs:22:13:22:22 | Int32 z4 = ... | ((kind:Expr(14),false,z4) :: (((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) |
| StructuralComparison.cs:22:18:22:22 | call to method M1 | ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) |
| StructuralComparison.cs:22:18:22:22 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:22:21:22:21 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:22:21:22:21 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:23:9:23:23 | ... ...; | (((kind:Expr(14),false,z5) :: (((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:23:13:23:14 | access to local variable z5 | (kind:Expr(14),false,z5) |
| StructuralComparison.cs:23:13:23:22 | Int32 z5 = ... | ((kind:Expr(14),false,z5) :: (((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) :: (kind:Expr(83)))) |
| StructuralComparison.cs:23:18:23:22 | call to method M1 | ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M1))) |
| StructuralComparison.cs:23:18:23:22 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:23:21:23:21 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:23:21:23:21 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:24:9:24:22 | ... ...; | (((kind:Expr(14),false,z6) :: (((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M0)) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:24:13:24:14 | access to local variable z6 | (kind:Expr(14),false,z6) |
| StructuralComparison.cs:24:13:24:21 | Int32 z6 = ... | ((kind:Expr(14),false,z6) :: (((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M0)) :: (kind:Expr(83)))) |
| StructuralComparison.cs:24:18:24:21 | call to method M0 | ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M0)) |
| StructuralComparison.cs:24:18:24:21 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:25:9:25:37 | ... ...; | (((kind:Expr(14),false,z7) :: ((((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Expr(44)))) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:25:13:25:14 | access to local variable z7 | (kind:Expr(14),false,z7) |
| StructuralComparison.cs:25:13:25:36 | Int32 z7 = ... | ((kind:Expr(14),false,z7) :: ((((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Expr(44)))) :: (kind:Expr(83)))) |
| StructuralComparison.cs:25:18:25:25 | call to method M2 | ((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) |
| StructuralComparison.cs:25:18:25:25 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:25:18:25:36 | ... + ... | (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Expr(44)))) |
| StructuralComparison.cs:25:21:25:21 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:25:21:25:21 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:25:24:25:24 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:25:24:25:24 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:25:29:25:36 | call to method M2 | ((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) |
| StructuralComparison.cs:25:29:25:36 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:25:32:25:32 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:25:32:25:32 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:25:35:25:35 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:25:35:25:35 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:26:9:26:16 | call to method M2 | ((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) |
| StructuralComparison.cs:26:9:26:16 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:26:9:26:17 | ...; | (((kind:Expr(16),true,y) :: ((kind:Expr(16),true,x) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Stmt(2))) |
| StructuralComparison.cs:26:12:26:12 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:26:12:26:12 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:26:15:26:15 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:26:15:26:15 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:27:9:27:16 | call to method M2 | ((kind:Expr(16),true,x) :: ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) |
| StructuralComparison.cs:27:9:27:16 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:27:9:27:17 | ...; | (((kind:Expr(16),true,x) :: ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Stmt(2))) |
| StructuralComparison.cs:27:12:27:12 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:27:12:27:12 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:27:15:27:15 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:27:15:27:15 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:28:9:28:16 | call to method M2 | ((kind:Expr(16),true,x) :: ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) |
| StructuralComparison.cs:28:9:28:16 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:28:9:28:17 | ...; | (((kind:Expr(16),true,x) :: ((kind:Expr(16),true,y) :: ((kind:Expr(12),false,Class) :: (kind:Expr(24),false,M2)))) :: (kind:Stmt(2))) |
| StructuralComparison.cs:28:12:28:12 | access to field y | (kind:Expr(16),true,y) |
| StructuralComparison.cs:28:12:28:12 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:28:15:28:15 | access to field x | (kind:Expr(16),true,x) |
| StructuralComparison.cs:28:15:28:15 | this access | (kind:Expr(12),false,Class) |
| StructuralComparison.cs:41:5:45:5 | {...} | ((((kind:Expr(14),false,x3) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,x2) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,x1) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: (kind:Stmt(1))))) |
| StructuralComparison.cs:42:9:42:28 | ... ...; | (((kind:Expr(14),false,x1) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:42:13:42:14 | access to local variable x1 | (kind:Expr(14),false,x1) |
| StructuralComparison.cs:42:13:42:27 | Int32 x1 = ... | ((kind:Expr(14),false,x1) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) |
| StructuralComparison.cs:42:18:42:21 | base access | (kind:Expr(13),false,BaseClass) |
| StructuralComparison.cs:42:18:42:27 | access to field Field | (kind:Expr(16),true,Field) |
| StructuralComparison.cs:43:9:43:23 | ... ...; | (((kind:Expr(14),false,x2) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:43:13:43:14 | access to local variable x2 | (kind:Expr(14),false,x2) |
| StructuralComparison.cs:43:13:43:22 | Int32 x2 = ... | ((kind:Expr(14),false,x2) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) |
| StructuralComparison.cs:43:18:43:22 | access to field Field | (kind:Expr(16),true,Field) |
| StructuralComparison.cs:43:18:43:22 | this access | (kind:Expr(12),false,DerivedClass) |
| StructuralComparison.cs:44:9:44:28 | ... ...; | (((kind:Expr(14),false,x3) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:44:13:44:14 | access to local variable x3 | (kind:Expr(14),false,x3) |
| StructuralComparison.cs:44:13:44:27 | Int32 x3 = ... | ((kind:Expr(14),false,x3) :: ((kind:Expr(16),true,Field) :: (kind:Expr(83)))) |
| StructuralComparison.cs:44:18:44:21 | this access | (kind:Expr(12),false,DerivedClass) |
| StructuralComparison.cs:44:18:44:27 | access to field Field | (kind:Expr(16),true,Field) |
| StructuralComparison.cs:48:5:52:5 | {...} | ((((kind:Expr(14),false,y3) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,y2) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: ((((kind:Expr(14),false,y1) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) :: (kind:Stmt(22))) :: (kind:Stmt(1))))) |
| StructuralComparison.cs:49:9:49:27 | ... ...; | (((kind:Expr(14),false,y1) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:49:13:49:14 | access to local variable y1 | (kind:Expr(14),false,y1) |
| StructuralComparison.cs:49:13:49:26 | Object y1 = ... | ((kind:Expr(14),false,y1) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) |
| StructuralComparison.cs:49:18:49:21 | base access | (kind:Expr(13),false,BaseClass) |
| StructuralComparison.cs:49:18:49:26 | access to property Prop | (kind:Expr(17),true,Prop) |
| StructuralComparison.cs:50:9:50:22 | ... ...; | (((kind:Expr(14),false,y2) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:50:13:50:14 | access to local variable y2 | (kind:Expr(14),false,y2) |
| StructuralComparison.cs:50:13:50:21 | Object y2 = ... | ((kind:Expr(14),false,y2) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) |
| StructuralComparison.cs:50:18:50:21 | access to property Prop | (kind:Expr(17),true,Prop) |
| StructuralComparison.cs:50:18:50:21 | this access | (kind:Expr(12),false,DerivedClass) |
| StructuralComparison.cs:51:9:51:27 | ... ...; | (((kind:Expr(14),false,y3) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) :: (kind:Stmt(22))) |
| StructuralComparison.cs:51:13:51:14 | access to local variable y3 | (kind:Expr(14),false,y3) |
| StructuralComparison.cs:51:13:51:26 | Object y3 = ... | ((kind:Expr(14),false,y3) :: ((kind:Expr(17),true,Prop) :: (kind:Expr(83)))) |
| StructuralComparison.cs:51:18:51:21 | this access | (kind:Expr(12),false,DerivedClass) |
| StructuralComparison.cs:51:18:51:26 | access to property Prop | (kind:Expr(17),true,Prop) |

View File

@@ -0,0 +1,34 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
private class StructuralComparisonTest extends StructuralComparisonConfiguration {
StructuralComparisonTest() { this = "StructuralComparisonTest" }
/**
* All pairs of controls flow elements found in the source and within the same
* enclosing callable excluding all instances of `ThisAccess` to reduce the size
* of the output.
*/
override predicate candidate(ControlFlowElement e1, ControlFlowElement e2) {
e1.fromSource() and
e2.fromSource() and
e1 != e2 and
e1.getEnclosingCallable() = e2.getEnclosingCallable() and
not e1 instanceof ThisAccess
}
}
query predicate same(ControlFlowElement e1, ControlFlowElement e2) {
exists(StructuralComparisonTest sct, Location l1, Location l2 |
sct.same(e1, e2) and
l1 = e1.getLocation() and
l2 = e2.getLocation() and
(
l1.getStartLine() < l2.getStartLine()
or
l1.getStartLine() = l2.getStartLine() and l1.getStartColumn() < l2.getStartColumn()
)
)
}
query predicate gvn(ControlFlowElement e, Gvn gvn) { gvn = toGvn(e) and e.fromSource() }