diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
index f3e2e510cd64..995b0a1a9f6a 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
@@ -22,26 +22,12 @@ public static Assignment Create(ExpressionNodeInfo info)
protected override void PopulateExpression(TextWriter trapFile)
{
- var operatorKind = OperatorKind;
- if (operatorKind.HasValue)
- {
- // Convert assignment such as `a += b` into `a = a + b`.
- var simpleAssignExpr = new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.SIMPLE_ASSIGN, this, 2, isCompilerGenerated: true, null));
- Create(Context, Syntax.Left, simpleAssignExpr, 1);
- var opexpr = new Expression(new ExpressionInfo(Context, Type, Location, operatorKind.Value, simpleAssignExpr, 0, isCompilerGenerated: true, null));
- Create(Context, Syntax.Left, opexpr, 0, isCompilerGenerated: true);
- Create(Context, Syntax.Right, opexpr, 1);
- opexpr.OperatorCall(trapFile, Syntax);
- }
- else
- {
- Create(Context, Syntax.Left, this, 1);
- Create(Context, Syntax.Right, this, 0);
+ Create(Context, Syntax.Left, this, 0);
+ Create(Context, Syntax.Right, this, 1);
- if (Kind == ExprKind.ADD_EVENT || Kind == ExprKind.REMOVE_EVENT)
- {
- OperatorCall(trapFile, Syntax);
- }
+ if (Kind != ExprKind.SIMPLE_ASSIGN)
+ {
+ OperatorCall(trapFile, Syntax);
}
}
@@ -108,56 +94,5 @@ private static ExprKind GetKind(Context cx, AssignmentExpressionSyntax syntax)
return kind;
}
-
- ///
- /// Gets the kind of this assignment operator (null if the
- /// assignment is not an assignment operator). For example, the operator
- /// kind of `*=` is `*`.
- ///
- private ExprKind? OperatorKind
- {
- get
- {
- var kind = Kind;
- if (kind == ExprKind.REMOVE_EVENT || kind == ExprKind.ADD_EVENT || kind == ExprKind.SIMPLE_ASSIGN)
- return null;
-
- if (CallType.AdjustKind(kind) == ExprKind.OPERATOR_INVOCATION)
- return ExprKind.OPERATOR_INVOCATION;
-
- switch (kind)
- {
- case ExprKind.ASSIGN_ADD:
- return ExprKind.ADD;
- case ExprKind.ASSIGN_AND:
- return ExprKind.BIT_AND;
- case ExprKind.ASSIGN_DIV:
- return ExprKind.DIV;
- case ExprKind.ASSIGN_LSHIFT:
- return ExprKind.LSHIFT;
- case ExprKind.ASSIGN_MUL:
- return ExprKind.MUL;
- case ExprKind.ASSIGN_OR:
- return ExprKind.BIT_OR;
- case ExprKind.ASSIGN_REM:
- return ExprKind.REM;
- case ExprKind.ASSIGN_RSHIFT:
- return ExprKind.RSHIFT;
- case ExprKind.ASSIGN_URSHIFT:
- return ExprKind.URSHIFT;
- case ExprKind.ASSIGN_SUB:
- return ExprKind.SUB;
- case ExprKind.ASSIGN_XOR:
- return ExprKind.BIT_XOR;
- case ExprKind.ASSIGN_COALESCE:
- return ExprKind.NULL_COALESCING;
- default:
- Context.ModelError(Syntax, $"Couldn't unfold assignment of type {kind}");
- return ExprKind.UNKNOWN;
- }
- }
- }
-
- public new CallType CallType => GetCallType(Context, Syntax);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs
index 92e2b910f992..63024cd47fcb 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs
@@ -83,30 +83,31 @@ protected override void PopulateExpression(TextWriter trapFile)
{
var assignmentInfo = new ExpressionNodeInfo(Context, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN);
var assignmentEntity = new Expression(assignmentInfo);
- var typeInfoRight = Context.GetTypeInfo(assignment.Right);
- if (typeInfoRight.Type is null)
- // The type may be null for nested initializers such as
- // ```csharp
- // new ClassWithArrayField() { As = { [0] = a } }
- // ```
- // In this case we take the type from the assignment
- // `As = { [0] = a }` instead
- typeInfoRight = assignmentInfo.TypeInfo;
- CreateFromNode(new ExpressionNodeInfo(Context, assignment.Right, assignmentEntity, 0, typeInfoRight));
-
var target = Context.GetSymbolInfo(assignment.Left);
// If the target is null, then assume that this is an array initializer (of the form `[...] = ...`)
-
var access = target.Symbol is null ?
- new Expression(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) :
- Access.Create(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 1), target.Symbol, false, Context.CreateEntity(target.Symbol));
+ new Expression(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 0).SetKind(ExprKind.ARRAY_ACCESS)) :
+ Access.Create(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 0), target.Symbol, false, Context.CreateEntity(target.Symbol));
if (assignment.Left is ImplicitElementAccessSyntax iea)
{
// An array/indexer initializer of the form `[...] = ...`
access.PopulateArguments(trapFile, iea.ArgumentList.Arguments, 0);
}
+
+ var typeInfoRight = Context.GetTypeInfo(assignment.Right);
+ if (typeInfoRight.Type is null)
+ {
+ // The type may be null for nested initializers such as
+ // ```csharp
+ // new ClassWithArrayField() { As = { [0] = a } }
+ // ```
+ // In this case we take the type from the assignment
+ // `As = { [0] = a }` instead
+ typeInfoRight = assignmentInfo.TypeInfo;
+ }
+ CreateFromNode(new ExpressionNodeInfo(Context, assignment.Right, assignmentEntity, 1, typeInfoRight));
}
else
{
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs
index a6f94f533387..1fdf03171b9f 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs
@@ -41,11 +41,11 @@ protected override void PopulateExpression(TextWriter trapFile)
var loc = Context.CreateLocation(init.GetLocation());
var assignment = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, isCompilerGenerated: false, null));
- Create(Context, init.Expression, assignment, 0);
Property.Create(Context, property);
-
- var access = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, isCompilerGenerated: false, null));
+ var access = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 0, isCompilerGenerated: false, null));
trapFile.expr_access(access, propEntity);
+
+ Create(Context, init.Expression, assignment, 1);
}
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs
index 85a1ceda47ca..aadf06f2dee6 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs
@@ -94,12 +94,12 @@ protected Expression DeclareRangeVariable(Context cx, IExpressionParentEntity pa
child
);
- Expression.Create(cx, Expr, decl, 0);
-
var nameLoc = cx.CreateLocation(name.GetLocation());
- var access = new Expression(new ExpressionInfo(cx, type, nameLoc, ExprKind.LOCAL_VARIABLE_ACCESS, decl, 1, isCompilerGenerated: false, null));
+ var access = new Expression(new ExpressionInfo(cx, type, nameLoc, ExprKind.LOCAL_VARIABLE_ACCESS, decl, 0, isCompilerGenerated: false, null));
cx.TrapWriter.Writer.expr_access(access, LocalVariable.Create(cx, variableSymbol));
+ Expression.Create(cx, Expr, decl, 1);
+
return decl;
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs
index c44f9e2b9468..47ecee3e037e 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs
@@ -176,11 +176,11 @@ public static VariableDeclaration CreateDeclarator(Context cx, VariableDeclarato
if (d.Initializer is not null)
{
- Create(cx, d.Initializer.Value, ret, 0);
-
// Create an access
- var access = new Expression(new ExpressionInfo(cx, type, localVar.Location, ExprKind.LOCAL_VARIABLE_ACCESS, ret, 1, isCompilerGenerated: false, null));
+ var access = new Expression(new ExpressionInfo(cx, type, localVar.Location, ExprKind.LOCAL_VARIABLE_ACCESS, ret, 0, isCompilerGenerated: false, null));
cx.TrapWriter.Writer.expr_access(access, localVar);
+
+ Create(cx, d.Initializer.Value, ret, 1);
}
if (d.Parent is VariableDeclarationSyntax decl)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs
index 329115f11c7a..708c00d2f736 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs
@@ -116,9 +116,9 @@ private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSynta
{
var type = Symbol.GetAnnotatedType();
var simpleAssignExpr = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.SIMPLE_ASSIGN, this, child++, isCompilerGenerated: true, constValue));
- Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer, simpleAssignExpr, 0));
- var access = new Expression(new ExpressionInfo(Context, type, Location, ExprKind.FIELD_ACCESS, simpleAssignExpr, 1, isCompilerGenerated: true, constValue));
+ var access = new Expression(new ExpressionInfo(Context, type, Location, ExprKind.FIELD_ACCESS, simpleAssignExpr, 0, isCompilerGenerated: true, constValue));
trapFile.expr_access(access, this);
+ Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer, simpleAssignExpr, 1));
return access;
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs
index 57eb5efc0070..988ca843927e 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs
@@ -94,9 +94,9 @@ public override void Populate(TextWriter trapFile)
var loc = Context.CreateLocation(initializer!.GetLocation());
var annotatedType = AnnotatedTypeSymbol.CreateNotAnnotated(Symbol.Type);
var simpleAssignExpr = new Expression(new ExpressionInfo(Context, annotatedType, loc, ExprKind.SIMPLE_ASSIGN, this, child++, isCompilerGenerated: true, null));
- Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Value, simpleAssignExpr, 0));
- var access = new Expression(new ExpressionInfo(Context, annotatedType, Location, ExprKind.PROPERTY_ACCESS, simpleAssignExpr, 1, isCompilerGenerated: true, null));
+ var access = new Expression(new ExpressionInfo(Context, annotatedType, Location, ExprKind.PROPERTY_ACCESS, simpleAssignExpr, 0, isCompilerGenerated: true, null));
trapFile.expr_access(access, this);
+ Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Value, simpleAssignExpr, 1));
if (!Symbol.IsStatic)
{
This.CreateImplicit(Context, Symbol.ContainingType, Location, access, -1);
diff --git a/csharp/ql/lib/semmle/code/csharp/Assignable.qll b/csharp/ql/lib/semmle/code/csharp/Assignable.qll
index 3c7170a6f846..98278cc19ded 100644
--- a/csharp/ql/lib/semmle/code/csharp/Assignable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Assignable.qll
@@ -78,6 +78,8 @@ class AssignableRead extends AssignableAccess {
this.isRefArgument()
or
this = any(AssignableDefinitions::AddressOfDefinition def).getTargetAccess()
+ or
+ this = any(AssignableDefinitions::AssignOperationDefinition def).getTargetAccess()
) and
not nameOfChild(_, this)
}
@@ -271,6 +273,8 @@ module AssignableInternal {
def = TAddressOfDefinition(result)
or
def = TPatternDefinition(result)
+ or
+ def = TAssignOperationDefinition(result)
}
/** A local variable declaration at the top-level of a pattern. */
@@ -286,7 +290,10 @@ module AssignableInternal {
private module Cached {
cached
newtype TAssignableDefinition =
- TAssignmentDefinition(Assignment a) { not a.getLValue() instanceof TupleExpr } or
+ TAssignmentDefinition(Assignment a) {
+ not a.getLValue() instanceof TupleExpr and
+ not a instanceof AssignOperation
+ } or
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or
TOutRefDefinition(AssignableAccess aa) {
aa.isOutArgument()
@@ -309,7 +316,8 @@ module AssignableInternal {
)
} or
TAddressOfDefinition(AddressOfExpr aoe) or
- TPatternDefinition(TopLevelPatternDecl tlpd)
+ TPatternDefinition(TopLevelPatternDecl tlpd) or
+ TAssignOperationDefinition(AssignOperation ao)
/**
* Gets the source expression assigned in tuple definition `def`, if any.
@@ -355,6 +363,8 @@ module AssignableInternal {
def = TMutationDefinition(any(MutatorOperation mo | mo.getOperand() = result))
or
def = TAddressOfDefinition(any(AddressOfExpr aoe | aoe.getOperand() = result))
+ or
+ def = TAssignOperationDefinition(any(AssignOperation ao | ao.getLeftOperand() = result))
}
/**
@@ -369,8 +379,10 @@ module AssignableInternal {
or
exists(Assignment ass | ac = ass.getLValue() |
result = ass.getRValue() and
- not ass.(AssignOperation).hasExpandedAssignment()
+ not ass instanceof AssignOperation
)
+ or
+ exists(AssignOperation ao | ac = ao.getLeftOperand() | result = ao)
}
}
@@ -388,8 +400,9 @@ private import AssignableInternal
* a mutation update (`AssignableDefinitions::MutationDefinition`), a local variable
* declaration without an initializer (`AssignableDefinitions::LocalVariableDefinition`),
* an implicit parameter definition (`AssignableDefinitions::ImplicitParameterDefinition`),
- * an address-of definition (`AssignableDefinitions::AddressOfDefinition`), or a pattern
- * definition (`AssignableDefinitions::PatternDefinition`).
+ * an address-of definition (`AssignableDefinitions::AddressOfDefinition`), a pattern
+ * definition (`AssignableDefinitions::PatternDefinition`), or a compound assignment
+ * operation definition (`AssignableDefinitions::AssignOperationDefinition`)
*/
class AssignableDefinition extends TAssignableDefinition {
/**
@@ -511,7 +524,7 @@ module AssignableDefinitions {
override Expr getSource() {
result = a.getRValue() and
- not a instanceof AssignOperation
+ not a instanceof AddOrRemoveEventExpr
}
override string toString() { result = a.toString() }
@@ -735,4 +748,17 @@ module AssignableDefinitions {
/** Gets the assignable (field or property) being initialized. */
Assignable getAssignable() { result = fieldOrProp }
}
+
+ /**
+ * A definition by a compound assignment operation, for example `x += y`.
+ */
+ class AssignOperationDefinition extends AssignableDefinition, TAssignOperationDefinition {
+ AssignOperation ao;
+
+ AssignOperationDefinition() { this = TAssignOperationDefinition(ao) }
+
+ override Expr getSource() { result = ao }
+
+ override string toString() { result = ao.toString() }
+ }
}
diff --git a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll
index aa834ef91038..3ce937316a84 100644
--- a/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll
+++ b/csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll
@@ -20,7 +20,7 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
/** Gets the `i`th child expression of this element (zero-based). */
final Expr getChildExpr(int i) {
- expr_parent_adjusted(result, i, this) or
+ expr_parent(result, i, this) or
expr_parent_top_level_adjusted(result, i, this)
}
@@ -119,66 +119,14 @@ private module Cached {
}
/**
- * The `expr_parent()` relation adjusted for expandable assignments. For example,
- * the assignment `x += y` is extracted as
- *
- * ```
- * +=
- * |
- * 2
- * |
- * =
- * / \
- * 1 0
- * / \
- * x +
- * / \
- * 1 0
- * / \
- * x y
- * ```
- *
- * in order to be able to retrieve the expanded assignment `x = x + y` as the 2nd
- * child. This predicate changes the diagram above into
- *
- * ```
- * +=
- * / \
- * 1 0
- * / \
- * x y
- * ```
+ * Use `expr_parent` instead.
*/
cached
- predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement parent) {
- if parent instanceof AssignOperation
- then
- parent =
- any(AssignOperation ao |
- exists(AssignExpr ae | ae = ao.getExpandedAssignment() |
- i = 0 and
- exists(Expr right |
- // right = `x + y`
- expr_parent(right, 0, ae)
- |
- expr_parent(child, 1, right)
- )
- or
- i = 1 and
- expr_parent(child, 1, ae)
- )
- or
- not ao.hasExpandedAssignment() and
- expr_parent(child, i, parent)
- )
- else expr_parent(child, i, parent)
- }
+ deprecated predicate expr_parent_adjusted(Expr child, int i, ControlFlowElement parent) { none() }
private Expr getAChildExpr(ExprOrStmtParent parent) {
result = parent.getAChildExpr() and
not result = parent.(DeclarationWithGetSetAccessors).getExpressionBody()
- or
- result = parent.(AssignOperation).getExpandedAssignment()
}
private ControlFlowElement getAChild(ExprOrStmtParent parent) {
diff --git a/csharp/ql/lib/semmle/code/csharp/Property.qll b/csharp/ql/lib/semmle/code/csharp/Property.qll
index 88665280d5b9..bbd4fdd9d8ec 100644
--- a/csharp/ql/lib/semmle/code/csharp/Property.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Property.qll
@@ -226,7 +226,7 @@ class Property extends DeclarationWithGetSetAccessors, @property {
* }
* ```
*/
- Expr getInitializer() { result = this.getChildExpr(1).getChildExpr(0) }
+ Expr getInitializer() { result = this.getChildExpr(1).getChildExpr(1) }
/**
* Holds if this property has an initial value. For example, the initial
diff --git a/csharp/ql/lib/semmle/code/csharp/Variable.qll b/csharp/ql/lib/semmle/code/csharp/Variable.qll
index 746ea6acd2f6..6d59816373d2 100644
--- a/csharp/ql/lib/semmle/code/csharp/Variable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Variable.qll
@@ -408,7 +408,7 @@ class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent
* }
* ```
*/
- final override Expr getInitializer() { result = this.getChildExpr(0).getChildExpr(0) }
+ final override Expr getInitializer() { result = this.getChildExpr(0).getChildExpr(1) }
/**
* Holds if this field has an initial value. For example, the initial
diff --git a/csharp/ql/lib/semmle/code/csharp/commons/Strings.qll b/csharp/ql/lib/semmle/code/csharp/commons/Strings.qll
index bdf9e5585394..f2d39f9dcc7c 100644
--- a/csharp/ql/lib/semmle/code/csharp/commons/Strings.qll
+++ b/csharp/ql/lib/semmle/code/csharp/commons/Strings.qll
@@ -49,6 +49,16 @@ class ImplicitToStringExpr extends Expr {
this = add.getOtherOperand(o).stripImplicit()
)
or
+ // s1 += s2 for where the left hand side is a string, call an operator +(string, object)
+ exists(AssignAddExpr add, Operator o, Parameter p0, Parameter p1 |
+ o = add.getTarget() and
+ o.getName() = "+" and
+ p0 = o.getParameter(0) and
+ p1 = o.getParameter(1) and
+ p0.getType() instanceof StringType and
+ this = getAnAssignedArgumentOrParam(p1).stripImplicit()
+ )
+ or
this = any(InterpolatedStringExpr ise).getAnInsert().stripImplicit()
}
}
diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll
index 40ec3722edd2..0dc04f70f3b5 100644
--- a/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll
+++ b/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll
@@ -296,6 +296,10 @@ private module LogicInput implements GuardsImpl::LogicInputSig {
v1.isNullValue() and
v2 = v1
or
+ g2 = g1.(AssignCoalesceExpr).getAnOperand() and
+ v1.isNullValue() and
+ v2 = v1
+ or
exists(Assertion assert, AssertMethod target, int i |
assert.getAssertMethod() = target and
g1 = assert and
@@ -841,6 +845,8 @@ module Internal {
e1 = e2.(Cast).getExpr()
or
e2 = e1.(NullCoalescingExpr).getAnOperand()
+ or
+ e2 = e1.(AssignCoalesceExpr).getAnOperand()
}
/** Holds if expression `e3` is a `null` value whenever `e1` and `e2` are. */
@@ -848,6 +854,8 @@ module Internal {
e3 = any(ConditionalExpr ce | e1 = ce.getThen() and e2 = ce.getElse())
or
e3 = any(NullCoalescingExpr nce | e1 = nce.getLeftOperand() and e2 = nce.getRightOperand())
+ or
+ e3 = any(AssignCoalesceExpr ace | e1 = ace.getLeftOperand() and e2 = ace.getRightOperand())
}
predicate nullValueImplied(Expr e) {
@@ -922,11 +930,10 @@ module Internal {
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
predicate nonNullValueImpliedUnary(Expr e1, Expr e2) {
- e1 = e2.(CastExpr).getExpr()
- or
- e1 = e2.(AssignExpr).getRValue()
- or
- e1 = e2.(NullCoalescingExpr).getAnOperand()
+ e1 = e2.(CastExpr).getExpr() or
+ e1 = e2.(AssignExpr).getRValue() or
+ e1 = e2.(NullCoalescingExpr).getAnOperand() or
+ e1 = e2.(AssignCoalesceExpr).getAnOperand()
}
/**
@@ -953,10 +960,13 @@ module Internal {
)
or
// In C#, `null + 1` has type `int?` with value `null`
- exists(BinaryArithmeticOperation bao, Expr o |
- result = bao and
- bao.getAnOperand() = e and
- bao.getAnOperand() = o and
+ exists(BinaryOperation bo, Expr o |
+ bo instanceof BinaryArithmeticOperation or
+ bo instanceof AssignArithmeticOperation
+ |
+ result = bo and
+ bo.getAnOperand() = e and
+ bo.getAnOperand() = o and
// The other operand must be provably non-null in order
// for `only if` to hold
nonNullValueImplied(o) and
@@ -972,10 +982,10 @@ module Internal {
any(QualifiableExpr qe |
qe.isConditional() and
result = qe.getQualifier()
- )
- or
+ ) or
// In C#, `null + 1` has type `int?` with value `null`
- e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand())
+ e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) or
+ e = any(AssignArithmeticOperation aao | result = aao.getAnOperand())
}
deprecated predicate isGuard(Expr e, GuardValue val) {
diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll
index 1696869e5911..09b4443fabb4 100644
--- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll
+++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll
@@ -89,18 +89,13 @@ class CfgScope extends Element, @top_level_exprorstmt_parent {
private class TAstNode = @callable or @control_flow_element;
-private Element getAChild(Element p) {
- result = p.getAChild() or
- result = p.(AssignOperation).getExpandedAssignment()
-}
-
pragma[nomagic]
private predicate astNode(Element e) {
e = any(@top_level_exprorstmt_parent p | not p instanceof Attribute)
or
exists(Element parent |
astNode(parent) and
- e = getAChild(parent)
+ e = parent.getAChild()
)
}
@@ -474,7 +469,6 @@ module Expressions {
private AstNode getExprChild0(Expr e, int i) {
not e instanceof NameOfExpr and
not e instanceof QualifiableExpr and
- not e instanceof Assignment and
not e instanceof AnonymousFunctionExpr and
result = e.getChild(i)
or
@@ -485,14 +479,6 @@ module Expressions {
not qe instanceof ExtensionMethodCall and
result = qe.getChild(i)
)
- or
- e =
- any(Assignment a |
- // The left-hand side of an assignment is evaluated before the right-hand side
- i = 0 and result = a.getLValue()
- or
- i = 1 and result = a.getRValue()
- )
}
private AstNode getExprChild(Expr e, int i) {
@@ -520,7 +506,6 @@ module Expressions {
not this instanceof LogicalOrExpr and
not this instanceof NullCoalescingExpr and
not this instanceof ConditionalExpr and
- not this instanceof AssignOperationWithExpandedAssignment and
not this instanceof ConditionallyQualifiedExpr and
not this instanceof ThrowExpr and
not this instanceof ObjectCreation and
@@ -618,7 +603,7 @@ module Expressions {
def.getExpr() = this and
def.getTargetAccess().(WriteAccess) instanceof QualifiableExpr and
not def instanceof AssignableDefinitions::OutRefDefinition and
- not this instanceof AssignOperationWithExpandedAssignment
+ not def instanceof AssignableDefinitions::AssignOperationDefinition
}
/**
@@ -801,26 +786,6 @@ module Expressions {
}
}
- /**
- * An assignment operation that has an expanded version. We use the expanded
- * version in the control flow graph in order to get better data flow / taint
- * tracking.
- */
- private class AssignOperationWithExpandedAssignment extends ControlFlowTree instanceof AssignOperation
- {
- private Expr expanded;
-
- AssignOperationWithExpandedAssignment() { expanded = this.getExpandedAssignment() }
-
- final override predicate first(AstNode first) { first(expanded, first) }
-
- final override predicate last(AstNode last, Completion c) { last(expanded, last, c) }
-
- final override predicate propagatesAbnormal(AstNode child) { none() }
-
- final override predicate succ(AstNode pred, AstNode succ, Completion c) { none() }
- }
-
/** A conditionally qualified expression. */
private class ConditionallyQualifiedExpr extends PostOrderTree instanceof QualifiableExpr {
private Expr qualifier;
@@ -1578,7 +1543,7 @@ module Statements {
/** Gets a child of `cfe` that is in CFG scope `scope`. */
pragma[noinline]
private ControlFlowElement getAChildInScope(AstNode cfe, Callable scope) {
- result = getAChild(cfe) and
+ result = cfe.getAChild() and
scope = result.getEnclosingCallable()
}
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
index 99a50b36873e..930d0a1610e5 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll
@@ -49,6 +49,8 @@ private predicate localTaintExprStep(Expr e1, Expr e2) {
or
e1 = e2.(AddExpr).getAnOperand()
or
+ e1 = e2.(AssignAddExpr).getAnOperand()
+ or
// A comparison expression where taint can flow from one of the
// operands if the other operand is a constant value.
exists(ComparisonTest ct, Expr other |
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
index 71d177a48bb1..4b7d7506bdbf 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
@@ -33,7 +33,11 @@ private module Impl {
/** Holds if SSA definition `def` equals `e + delta`. */
predicate ssaUpdateStep(ExplicitDefinition def, ExprNode e, int delta) {
exists(ControlFlow::Node cfn | cfn = def.getControlFlowNode() |
- e = cfn.(ExprNode::Assignment).getRValue() and delta = 0
+ e = cfn.(ExprNode::Assignment).getRValue() and
+ delta = 0 and
+ not cfn instanceof ExprNode::AssignOperation
+ or
+ e = cfn.(ExprNode::AssignOperation) and delta = 0
or
e = cfn.(ExprNode::PostIncrExpr).getOperand() and delta = 1
or
@@ -230,6 +234,11 @@ module ExprNode {
override CS::AssignExpr e;
}
+ /** A compound assignment operation. */
+ class AssignOperation extends Assignment, BinaryOperation {
+ override CS::AssignOperation e;
+ }
+
/** A unary operation. */
class UnaryOperation extends ExprNode {
override CS::UnaryOperation e;
@@ -321,80 +330,168 @@ module ExprNode {
}
/** An addition operation. */
- class AddExpr extends BinaryOperation {
+ abstract private class AddExprImpl extends BinaryOperation {
+ override TAddOp getOp() { any() }
+ }
+
+ final class AddExpr = AddExprImpl;
+
+ private class AddAddExpr extends AddExprImpl {
override CS::AddExpr e;
+ }
- override TAddOp getOp() { any() }
+ private class AddAssignAddExpr extends AddExprImpl, AssignOperation {
+ override CS::AssignAddExpr e;
}
/** A subtraction operation. */
- class SubExpr extends BinaryOperation {
+ abstract private class SubExprImpl extends BinaryOperation {
+ override TSubOp getOp() { any() }
+ }
+
+ final class SubExpr = SubExprImpl;
+
+ private class AddSubExpr extends SubExprImpl {
override CS::SubExpr e;
+ }
- override TSubOp getOp() { any() }
+ private class AddAssignSubExpr extends SubExprImpl, AssignOperation {
+ override CS::AssignSubExpr e;
}
/** A multiplication operation. */
- class MulExpr extends BinaryOperation {
+ abstract private class MulExprImpl extends BinaryOperation {
+ override TMulOp getOp() { any() }
+ }
+
+ final class MulExpr = MulExprImpl;
+
+ private class AddMulExpr extends MulExprImpl {
override CS::MulExpr e;
+ }
- override TMulOp getOp() { any() }
+ private class AddAssignMulExpr extends MulExprImpl, AssignOperation {
+ override CS::AssignMulExpr e;
}
/** A division operation. */
- class DivExpr extends BinaryOperation {
+ abstract private class DivExprImpl extends BinaryOperation {
+ override TDivOp getOp() { any() }
+ }
+
+ final class DivExpr = DivExprImpl;
+
+ private class AddDivExpr extends DivExprImpl {
override CS::DivExpr e;
+ }
- override TDivOp getOp() { any() }
+ private class AddAssignDivExpr extends DivExprImpl, AssignOperation {
+ override CS::AssignDivExpr e;
}
/** A remainder operation. */
- class RemExpr extends BinaryOperation {
+ abstract private class RemExprImpl extends BinaryOperation {
+ override TRemOp getOp() { any() }
+ }
+
+ final class RemExpr = RemExprImpl;
+
+ private class AddRemExpr extends RemExprImpl {
override CS::RemExpr e;
+ }
- override TRemOp getOp() { any() }
+ private class AddAssignRemExpr extends RemExprImpl, AssignOperation {
+ override CS::AssignRemExpr e;
}
/** A bitwise-and operation. */
- class BitwiseAndExpr extends BinaryOperation {
+ abstract private class BitwiseAndExprImpl extends BinaryOperation {
+ override TBitAndOp getOp() { any() }
+ }
+
+ final class BitwiseAndExpr = BitwiseAndExprImpl;
+
+ private class AddBitwiseAndExpr extends BitwiseAndExprImpl {
override CS::BitwiseAndExpr e;
+ }
- override TBitAndOp getOp() { any() }
+ private class AddAssignAndExpr extends BitwiseAndExprImpl, AssignOperation {
+ override CS::AssignAndExpr e;
}
/** A bitwise-or operation. */
- class BitwiseOrExpr extends BinaryOperation {
+ abstract private class BitwiseOrExprImpl extends BinaryOperation {
+ override TBitOrOp getOp() { any() }
+ }
+
+ final class BitwiseOrExpr = BitwiseOrExprImpl;
+
+ private class AddBitwiseOrExpr extends BitwiseOrExprImpl {
override CS::BitwiseOrExpr e;
+ }
- override TBitOrOp getOp() { any() }
+ private class AddAssignOrExpr extends BitwiseOrExprImpl, AssignOperation {
+ override CS::AssignOrExpr e;
}
/** A bitwise-xor operation. */
- class BitwiseXorExpr extends BinaryOperation {
+ abstract private class BitwiseXorExprImpl extends BinaryOperation {
+ override TBitXorOp getOp() { any() }
+ }
+
+ final class BitwiseXorExpr = BitwiseXorExprImpl;
+
+ private class AddBitwiseXorExpr extends BitwiseXorExprImpl {
override CS::BitwiseXorExpr e;
+ }
- override TBitXorOp getOp() { any() }
+ private class AddAssignXorExpr extends BitwiseXorExprImpl, AssignOperation {
+ override CS::AssignXorExpr e;
}
/** A left-shift operation. */
- class LeftShiftExpr extends BinaryOperation {
+ abstract private class LeftShiftExprImpl extends BinaryOperation {
+ override TLeftShiftOp getOp() { any() }
+ }
+
+ final class LeftShiftExpr = LeftShiftExprImpl;
+
+ private class AddLeftShiftExpr extends LeftShiftExprImpl {
override CS::LeftShiftExpr e;
+ }
- override TLeftShiftOp getOp() { any() }
+ private class AddAssignLeftShiftExpr extends LeftShiftExprImpl, AssignOperation {
+ override CS::AssignLeftShiftExpr e;
}
/** A right-shift operation. */
- class RightShiftExpr extends BinaryOperation {
+ abstract private class RightShiftExprImpl extends BinaryOperation {
+ override TRightShiftOp getOp() { any() }
+ }
+
+ final class RightShiftExpr = RightShiftExprImpl;
+
+ private class AddRightShiftExpr extends RightShiftExprImpl {
override CS::RightShiftExpr e;
+ }
- override TRightShiftOp getOp() { any() }
+ private class AddAssignRightShiftExpr extends RightShiftExprImpl, AssignOperation {
+ override CS::AssignRightShiftExpr e;
}
/** An unsigned right-shift operation. */
- class UnsignedRightShiftExpr extends BinaryOperation {
+ abstract private class UnsignedRightShiftExprImpl extends BinaryOperation {
+ override TUnsignedRightShiftOp getOp() { any() }
+ }
+
+ final class UnsignedRightShiftExpr = UnsignedRightShiftExprImpl;
+
+ private class AddUnsignedRightShiftExpr extends UnsignedRightShiftExprImpl {
override CS::UnsignedRightShiftExpr e;
+ }
- override TUnsignedRightShiftOp getOp() { any() }
+ private class AddAssignUnsignedRightShiftExpr extends UnsignedRightShiftExprImpl, AssignOperation {
+ override CS::AssignUnsighedRightShiftExpr e;
}
/** A conditional expression. */
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
index 1bd86e19f34d..01511d348a47 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
@@ -130,6 +130,11 @@ private module Impl {
adef = def.getADefinition() and
hasChild(adef.getExpr(), adef.getSource(), def.getControlFlowNode(), result)
)
+ or
+ exists(AssignableDefinitions::AssignOperationDefinition adef |
+ adef = def.getADefinition() and
+ result.getExpr() = adef.getSource()
+ )
}
/** Holds if `def` can have any sign. */
diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll
index a83967441d74..f7f6c7a50be4 100644
--- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll
@@ -202,11 +202,9 @@ private module Internal {
private predicate isPotentialEventCall(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) {
- exists(DynamicOperatorCall doc, AssignExpr ae |
- ae = aao.getExpandedAssignment() and
- dma = ae.getLValue() and
- doc = ae.getRValue()
- |
+ aao instanceof DynamicOperatorCall and
+ dma = aao.getLeftOperand() and
+ (
aao instanceof AssignAddExpr and
name = "add_" + dma.getLateBoundTargetName()
or
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
index 9fa2a93724d4..d6b7538024ed 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
@@ -17,18 +17,14 @@ class Assignment extends BinaryOperation, @assign_expr {
implies
// Same as `this.(LocalVariableDeclExpr).hasInitializer()` but avoids
// negative recursion
- expr_parent(_, 0, this)
+ expr_parent(_, 1, this)
}
- override Expr getLeftOperand() { result = this.getChild(1) }
-
- override Expr getRightOperand() { result = this.getChild(0) }
-
/** Gets the left operand of this assignment. */
- Expr getLValue() { result = this.getChild(1) }
+ Expr getLValue() { result = this.getLeftOperand() }
/** Gets the right operand of this assignment. */
- Expr getRValue() { result = this.getChild(0) }
+ Expr getRValue() { result = this.getRightOperand() }
/** Gets the variable being assigned to, if any. */
Variable getTargetVariable() { result.getAnAccess() = this.getLValue() }
@@ -64,33 +60,21 @@ class AssignExpr extends Assignment, @simple_assign_expr {
/**
* An assignment operation. Either an arithmetic assignment operation
- * (`AssignArithmeticOperation`), a bitwise assignment operation
- * (`AssignBitwiseOperation`), or an event assignment (`AddOrRemoveEventExpr`).
+ * (`AssignArithmeticOperation`), a bitwise assignment operation or
+ * (`AssignBitwiseOperation`).
*/
-class AssignOperation extends Assignment, @assign_op_expr {
+class AssignOperation extends Assignment, OperatorCall, @assign_op_expr {
override string getOperator() { none() }
/**
- * Gets the expanded version of this assignment operation, if any.
- *
- * For example, if this assignment operation is `x += y` then
- * the expanded assignment is `x = x + y`.
- *
- * If an expanded version exists, then it is used in the control
- * flow graph.
+ * Expanded versions of compound assignments are no longer extracted.
*/
- AssignExpr getExpandedAssignment() { expr_parent(result, 2, this) }
+ deprecated AssignExpr getExpandedAssignment() { none() }
/**
- * Holds if this assignment operation has an expanded version.
- *
- * For example, if this assignment operation is `x += y` then
- * it has the expanded version `x = x + y`.
- *
- * If an expanded version exists, then it is used in the control
- * flow graph.
+ * Expanded versions of compound assignments are no longer extracted.
*/
- predicate hasExpandedAssignment() { exists(this.getExpandedAssignment()) }
+ deprecated predicate hasExpandedAssignment() { none() }
override string toString() { result = "... " + this.getOperator() + " ..." }
}
@@ -218,13 +202,17 @@ class AssignUnsighedRightShiftExpr extends AssignBitwiseOperation, @assign_urshi
* An event assignment. Either an event addition (`AddEventExpr`) or an event
* removal (`RemoveEventExpr`).
*/
-class AddOrRemoveEventExpr extends AssignOperation, @assign_event_expr {
+class AddOrRemoveEventExpr extends Assignment, @assign_event_expr {
+ override string getOperator() { none() }
+
/** Gets the event targeted by this event assignment. */
Event getTarget() { result = this.getLValue().getTarget() }
- override EventAccess getLValue() { result = this.getChild(1) }
+ override EventAccess getLValue() { result = this.getChild(0) }
+
+ override EventAccess getLeftOperand() { result = this.getChild(0) }
- override Expr getRValue() { result = this.getChild(0) }
+ override string toString() { result = "... " + this.getOperator() + " ..." }
}
/**
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
index f8b51a990ed1..912cb23e06b7 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
@@ -493,12 +493,16 @@ class ConstructorInitializer extends Call, @constructor_init_expr {
* }
* ```
*/
-class OperatorCall extends Call, LateBindableExpr, @operator_invocation_expr {
+class OperatorCall extends Call, LateBindableExpr, @op_invoke_expr {
override Operator getTarget() { expr_call(this, result) }
override Operator getARuntimeTarget() { result = Call.super.getARuntimeTarget() }
- override string toString() { result = "call to operator " + this.getTarget().getName() }
+ override string toString() {
+ if this instanceof DynamicOperatorCall
+ then result = "dynamic call to operator " + this.getLateBoundTargetName()
+ else result = "call to operator " + this.getTarget().getName()
+ }
override string getAPrimaryQlClass() { result = "OperatorCall" }
}
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll
index 04ea9f062a50..bfc5c36ff37c 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Dynamic.qll
@@ -96,13 +96,7 @@ class DynamicMethodCall extends DynamicExpr, MethodCall {
* Unlike an ordinary call to a user-defined operator (`OperatorCall`), the
* target operator may not be known at compile-time (as in the example above).
*/
-class DynamicOperatorCall extends DynamicExpr, OperatorCall {
- override string toString() {
- result = "dynamic call to operator " + this.getLateBoundTargetName()
- }
-
- override string getAPrimaryQlClass() { result = "DynamicOperatorCall" }
-}
+class DynamicOperatorCall extends DynamicExpr, OperatorCall { }
/**
* A call to a user-defined mutator operator where the operand is a `dynamic`
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
index c3b9bcc363b3..f1c0b3656111 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
@@ -65,25 +65,11 @@ class Expr extends ControlFlowElement, @expr {
/** Gets the enclosing callable of this expression, if any. */
override Callable getEnclosingCallable() { enclosingCallable(this, result) }
- pragma[nomagic]
- private predicate isExpandedAssignmentRValueDescendant() {
- this =
- any(AssignOperation op).getExpandedAssignment().getRValue().getChildExpr(0).getAChildExpr()
- or
- exists(Expr parent |
- parent.isExpandedAssignmentRValueDescendant() and
- this = parent.getAChildExpr()
- )
- }
-
/**
* Holds if this expression is generated by the compiler and does not appear
* explicitly in the source code.
*/
- final predicate isImplicit() {
- compiler_generated(this) or
- this.isExpandedAssignmentRValueDescendant()
- }
+ final predicate isImplicit() { compiler_generated(this) }
/**
* Gets an expression that is the result of stripping (recursively) all
@@ -168,7 +154,7 @@ class LocalVariableDeclExpr extends Expr, @local_var_decl_expr {
string getName() { result = this.getVariable().getName() }
/** Gets the initializer expression of this local variable declaration, if any. */
- Expr getInitializer() { result = this.getChild(0) }
+ Expr getInitializer() { result = this.getChild(1) }
/** Holds if this local variable declaration has an initializer. */
predicate hasInitializer() { exists(this.getInitializer()) }
diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme
index e73ca2c93df8..eadfb04c00fc 100644
--- a/csharp/ql/lib/semmlecode.csharp.dbscheme
+++ b/csharp/ql/lib/semmlecode.csharp.dbscheme
@@ -1215,8 +1215,8 @@ case @expr.kind of
@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
| @string_literal_expr | @null_literal_expr;
-@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
-@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr | @assign_event_expr;
+@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_coalesce_expr;
@assign_event_expr = @add_event_expr | @remove_event_expr;
@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
@@ -1270,14 +1270,15 @@ case @expr.kind of
@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
-@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr
+@op_invoke_expr = @operator_invocation_expr | @assign_op_expr
+@call = @method_invocation_expr | @constructor_init_expr | @op_invoke_expr
| @delegate_invocation_expr | @object_creation_expr | @call_access_expr
| @local_function_invocation_expr | @function_pointer_invocation_expr;
@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
- | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr;
+ | @object_creation_expr | @method_invocation_expr | @op_invoke_expr;
@throw_element = @throw_expr | @throw_stmt;
diff --git a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
index 0f6e6d11fb2c..59816a18b3fb 100644
--- a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
+++ b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql
@@ -84,6 +84,8 @@ class RelevantDefinition extends AssignableDefinition {
)
or
this instanceof AssignableDefinitions::PatternDefinition
+ or
+ this instanceof AssignableDefinitions::AssignOperationDefinition
}
/** Holds if this assignment may be live. */
diff --git a/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql b/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql
index b980bfba1aea..53bf2599a551 100644
--- a/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql
+++ b/csharp/ql/src/Likely Bugs/DangerousNonShortCircuitLogic.ql
@@ -18,14 +18,9 @@ import csharp
/** A use of `&` or `|` on operands of type boolean. */
class NonShortCircuit extends BinaryBitwiseOperation {
NonShortCircuit() {
- (
- this instanceof BitwiseAndExpr
- or
- this instanceof BitwiseOrExpr
- ) and
- not exists(AssignBitwiseOperation abo | abo.getExpandedAssignment().getRValue() = this) and
- this.getLeftOperand().getType() instanceof BoolType and
- this.getRightOperand().getType() instanceof BoolType
+ this instanceof BitwiseAndExpr
+ or
+ this instanceof BitwiseOrExpr
}
pragma[nomagic]
diff --git a/csharp/ql/src/Performance/StringConcatenationInLoop.ql b/csharp/ql/src/Performance/StringConcatenationInLoop.ql
index a015771610d5..3b3228588a4b 100644
--- a/csharp/ql/src/Performance/StringConcatenationInLoop.ql
+++ b/csharp/ql/src/Performance/StringConcatenationInLoop.ql
@@ -23,7 +23,6 @@ class StringCat extends AddExpr {
* where `v` is a simple variable (and not, for example, a property).
*/
predicate isSelfConcatAssignExpr(AssignExpr e, Variable v) {
- not e = any(AssignAddExpr a).getExpandedAssignment() and
exists(VariableAccess use |
stringCatContains(e.getRValue(), use) and
use.getTarget() = e.getTargetVariable() and
diff --git a/csharp/ql/src/Security Features/InsecureRandomness.ql b/csharp/ql/src/Security Features/InsecureRandomness.ql
index 2c2df7010c67..8237afdff130 100644
--- a/csharp/ql/src/Security Features/InsecureRandomness.ql
+++ b/csharp/ql/src/Security Features/InsecureRandomness.ql
@@ -89,11 +89,7 @@ module Random {
e = any(SensitiveLibraryParameter v).getAnAssignedArgument()
or
// Assignment operation, e.g. += or similar
- exists(AssignOperation ao |
- ao.getRValue() = e and
- // "expanded" assignments will be covered by simple assignment
- not ao.hasExpandedAssignment()
- |
+ exists(AssignOperation ao | ao.getRValue() = e |
ao.getLValue() = any(SensitiveVariable v).getAnAccess() or
ao.getLValue() = any(SensitiveProperty v).getAnAccess() or
ao.getLValue() = any(SensitiveLibraryParameter v).getAnAccess()
diff --git a/csharp/ql/test/library-tests/arguments/argumentByName.expected b/csharp/ql/test/library-tests/arguments/argumentByName.expected
index 6fcb9021d17d..065d70703120 100644
--- a/csharp/ql/test/library-tests/arguments/argumentByName.expected
+++ b/csharp/ql/test/library-tests/arguments/argumentByName.expected
@@ -33,14 +33,16 @@
| arguments.cs:59:16:59:25 | access to indexer | arguments.cs:59:21:59:21 | 3 | a |
| arguments.cs:59:16:59:25 | access to indexer | arguments.cs:59:24:59:24 | 4 | b |
| arguments.cs:59:16:59:25 | access to indexer | arguments.cs:59:34:59:34 | 6 | value |
-| arguments.cs:61:9:61:12 | access to property Prop | arguments.cs:61:9:61:17 | ... + ... | value |
+| arguments.cs:61:9:61:12 | access to property Prop | arguments.cs:61:9:61:17 | ... += ... | value |
+| arguments.cs:61:9:61:17 | ... += ... | arguments.cs:61:9:61:12 | access to property Prop | left |
+| arguments.cs:61:9:61:17 | ... += ... | arguments.cs:61:17:61:17 | 7 | right |
| arguments.cs:62:9:62:18 | access to indexer | arguments.cs:62:14:62:14 | 8 | a |
| arguments.cs:62:9:62:18 | access to indexer | arguments.cs:62:17:62:17 | 9 | b |
-| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:9:63:26 | ... + ... | value |
+| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:9:63:26 | ... += ... | value |
| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:14:63:15 | 10 | a |
-| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:14:63:15 | 10 | a |
-| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:18:63:19 | 11 | b |
| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:18:63:19 | 11 | b |
+| arguments.cs:63:9:63:26 | ... += ... | arguments.cs:63:9:63:20 | access to indexer | left |
+| arguments.cs:63:9:63:26 | ... += ... | arguments.cs:63:25:63:26 | 12 | right |
| arguments.cs:65:16:65:27 | access to indexer | arguments.cs:65:21:65:22 | 15 | a |
| arguments.cs:65:16:65:27 | access to indexer | arguments.cs:65:25:65:26 | 16 | b |
| arguments.cs:76:9:76:31 | call to method f8`1 | arguments.cs:76:12:76:12 | 0 | o |
diff --git a/csharp/ql/test/library-tests/arguments/argumentByParameter.expected b/csharp/ql/test/library-tests/arguments/argumentByParameter.expected
index ac354d31e28e..c04658592532 100644
--- a/csharp/ql/test/library-tests/arguments/argumentByParameter.expected
+++ b/csharp/ql/test/library-tests/arguments/argumentByParameter.expected
@@ -33,12 +33,12 @@
| arguments.cs:59:16:59:25 | access to indexer | arguments.cs:59:21:59:21 | 3 | arguments.cs:53:18:53:18 | a |
| arguments.cs:59:16:59:25 | access to indexer | arguments.cs:59:24:59:24 | 4 | arguments.cs:53:25:53:25 | b |
| arguments.cs:59:16:59:25 | access to indexer | arguments.cs:59:34:59:34 | 6 | arguments.cs:53:44:53:46 | value |
-| arguments.cs:61:9:61:12 | access to property Prop | arguments.cs:61:9:61:17 | ... + ... | arguments.cs:51:21:51:23 | value |
+| arguments.cs:61:9:61:12 | access to property Prop | arguments.cs:61:9:61:17 | ... += ... | arguments.cs:51:21:51:23 | value |
| arguments.cs:62:9:62:18 | access to indexer | arguments.cs:62:14:62:14 | 8 | arguments.cs:53:18:53:18 | a |
| arguments.cs:62:9:62:18 | access to indexer | arguments.cs:62:14:62:14 | 8 | arguments.cs:53:18:53:18 | a |
| arguments.cs:62:9:62:18 | access to indexer | arguments.cs:62:17:62:17 | 9 | arguments.cs:53:25:53:25 | b |
| arguments.cs:62:9:62:18 | access to indexer | arguments.cs:62:17:62:17 | 9 | arguments.cs:53:25:53:25 | b |
-| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:9:63:26 | ... + ... | arguments.cs:53:44:53:46 | value |
+| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:9:63:26 | ... += ... | arguments.cs:53:44:53:46 | value |
| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:14:63:15 | 10 | arguments.cs:53:18:53:18 | a |
| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:14:63:15 | 10 | arguments.cs:53:18:53:18 | a |
| arguments.cs:63:9:63:20 | access to indexer | arguments.cs:63:18:63:19 | 11 | arguments.cs:53:25:53:25 | b |
diff --git a/csharp/ql/test/library-tests/arguments/argumentType.expected b/csharp/ql/test/library-tests/arguments/argumentType.expected
index 0dac70193453..fa148e657b44 100644
--- a/csharp/ql/test/library-tests/arguments/argumentType.expected
+++ b/csharp/ql/test/library-tests/arguments/argumentType.expected
@@ -36,8 +36,6 @@
| arguments.cs:62:14:62:14 | 8 | 0 |
| arguments.cs:62:17:62:17 | 9 | 0 |
| arguments.cs:63:14:63:15 | 10 | 0 |
-| arguments.cs:63:14:63:15 | 10 | 0 |
-| arguments.cs:63:18:63:19 | 11 | 0 |
| arguments.cs:63:18:63:19 | 11 | 0 |
| arguments.cs:64:22:64:23 | 13 | 0 |
| arguments.cs:64:26:64:27 | 14 | 0 |
diff --git a/csharp/ql/test/library-tests/arguments/parameterGetArguments.expected b/csharp/ql/test/library-tests/arguments/parameterGetArguments.expected
index 6f25b07e2e5a..9f830954efb8 100644
--- a/csharp/ql/test/library-tests/arguments/parameterGetArguments.expected
+++ b/csharp/ql/test/library-tests/arguments/parameterGetArguments.expected
@@ -28,7 +28,7 @@
| arguments.cs:51:21:51:23 | value | arguments.cs:57:16:57:16 | 0 |
| arguments.cs:51:21:51:23 | value | arguments.cs:58:16:58:25 | access to indexer |
| arguments.cs:51:21:51:23 | value | arguments.cs:59:31:59:31 | 5 |
-| arguments.cs:51:21:51:23 | value | arguments.cs:61:9:61:17 | ... + ... |
+| arguments.cs:51:21:51:23 | value | arguments.cs:61:9:61:17 | ... += ... |
| arguments.cs:53:18:53:18 | a | arguments.cs:58:21:58:21 | 1 |
| arguments.cs:53:18:53:18 | a | arguments.cs:59:21:59:21 | 3 |
| arguments.cs:53:18:53:18 | a | arguments.cs:62:14:62:14 | 8 |
@@ -44,7 +44,7 @@
| arguments.cs:53:25:53:25 | b | arguments.cs:63:18:63:19 | 11 |
| arguments.cs:53:25:53:25 | b | arguments.cs:65:25:65:26 | 16 |
| arguments.cs:53:44:53:46 | value | arguments.cs:59:34:59:34 | 6 |
-| arguments.cs:53:44:53:46 | value | arguments.cs:63:9:63:26 | ... + ... |
+| arguments.cs:53:44:53:46 | value | arguments.cs:63:9:63:26 | ... += ... |
| arguments.cs:74:20:74:20 | o | arguments.cs:76:12:76:12 | 0 |
| arguments.cs:74:20:74:20 | o | arguments.cs:77:12:77:12 | 0 |
| arguments.cs:74:20:74:20 | o | arguments.cs:78:12:78:12 | 0 |
diff --git a/csharp/ql/test/library-tests/assignments/AssignOperation.expected b/csharp/ql/test/library-tests/assignments/AssignOperation.expected
index f6f03fd050c6..0315bbe1c906 100644
--- a/csharp/ql/test/library-tests/assignments/AssignOperation.expected
+++ b/csharp/ql/test/library-tests/assignments/AssignOperation.expected
@@ -1,4 +1,3 @@
| Assignments.cs:6:9:6:14 | ... += ... | Assignments.cs:6:9:6:9 | access to local variable x | Assignments.cs:6:14:6:14 | 1 |
| Assignments.cs:9:9:9:14 | ... -= ... | Assignments.cs:9:9:9:9 | access to local variable d | Assignments.cs:9:14:9:14 | 2 |
| Assignments.cs:12:9:12:17 | ... += ... | Assignments.cs:12:9:12:9 | access to local variable a | Assignments.cs:12:14:12:17 | this access |
-| Assignments.cs:14:9:14:35 | ... += ... | Assignments.cs:14:9:14:13 | access to event Event | Assignments.cs:14:18:14:35 | (...) => ... |
diff --git a/csharp/ql/test/library-tests/assignments/AssignOperationExpanded.expected b/csharp/ql/test/library-tests/assignments/AssignOperationExpanded.expected
deleted file mode 100644
index bcc9d11c42f5..000000000000
--- a/csharp/ql/test/library-tests/assignments/AssignOperationExpanded.expected
+++ /dev/null
@@ -1,3 +0,0 @@
-| Assignments.cs:6:9:6:14 | ... += ... | Assignments.cs:6:9:6:14 | ... = ... | Assignments.cs:6:9:6:9 | access to local variable x | Assignments.cs:6:9:6:14 | ... + ... | Assignments.cs:6:9:6:9 | access to local variable x | Assignments.cs:6:14:6:14 | 1 |
-| Assignments.cs:9:9:9:14 | ... -= ... | Assignments.cs:9:9:9:14 | ... = ... | Assignments.cs:9:9:9:9 | access to local variable d | Assignments.cs:9:9:9:14 | dynamic call to operator - | Assignments.cs:9:9:9:9 | access to local variable d | Assignments.cs:9:14:9:14 | 2 |
-| Assignments.cs:12:9:12:17 | ... += ... | Assignments.cs:12:9:12:17 | ... = ... | Assignments.cs:12:9:12:9 | access to local variable a | Assignments.cs:12:9:12:17 | call to operator + | Assignments.cs:12:9:12:9 | access to local variable a | Assignments.cs:12:14:12:17 | this access |
diff --git a/csharp/ql/test/library-tests/assignments/AssignOperationExpanded.ql b/csharp/ql/test/library-tests/assignments/AssignOperationExpanded.ql
deleted file mode 100644
index bd67776520fb..000000000000
--- a/csharp/ql/test/library-tests/assignments/AssignOperationExpanded.ql
+++ /dev/null
@@ -1,22 +0,0 @@
-import csharp
-
-predicate getExpandedOperatorArgs(Expr e, Expr left, Expr right) {
- e =
- any(BinaryArithmeticOperation bo |
- bo.getLeftOperand() = left and
- bo.getRightOperand() = right
- )
- or
- e =
- any(OperatorCall oc |
- oc.getArgument(0) = left and
- oc.getArgument(1) = right
- )
-}
-
-from AssignOperation ao, AssignExpr ae, Expr op, Expr left, Expr right
-where
- ae = ao.getExpandedAssignment() and
- op = ae.getRValue() and
- getExpandedOperatorArgs(op, left, right)
-select ao, ae, ae.getLValue(), op, left, right
diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected
index 30f2b1051551..9802f2b01955 100644
--- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected
+++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected
@@ -7,11 +7,11 @@
| AccessorCalls.cs:19:10:19:11 | enter M2 | AccessorCalls.cs:19:10:19:11 | exit M2 | 42 |
| AccessorCalls.cs:28:10:28:11 | enter M3 | AccessorCalls.cs:28:10:28:11 | exit M3 | 17 |
| AccessorCalls.cs:35:10:35:11 | enter M4 | AccessorCalls.cs:35:10:35:11 | exit M4 | 20 |
-| AccessorCalls.cs:42:10:42:11 | enter M5 | AccessorCalls.cs:42:10:42:11 | exit M5 | 34 |
-| AccessorCalls.cs:49:10:49:11 | enter M6 | AccessorCalls.cs:49:10:49:11 | exit M6 | 43 |
+| AccessorCalls.cs:42:10:42:11 | enter M5 | AccessorCalls.cs:42:10:42:11 | exit M5 | 24 |
+| AccessorCalls.cs:49:10:49:11 | enter M6 | AccessorCalls.cs:49:10:49:11 | exit M6 | 30 |
| AccessorCalls.cs:56:10:56:11 | enter M7 | AccessorCalls.cs:56:10:56:11 | exit M7 | 25 |
| AccessorCalls.cs:61:10:61:11 | enter M8 | AccessorCalls.cs:61:10:61:11 | exit M8 | 31 |
-| AccessorCalls.cs:66:10:66:11 | enter M9 | AccessorCalls.cs:66:10:66:11 | exit M9 | 58 |
+| AccessorCalls.cs:66:10:66:11 | enter M9 | AccessorCalls.cs:66:10:66:11 | exit M9 | 51 |
| ArrayCreation.cs:1:7:1:19 | enter ArrayCreation | ArrayCreation.cs:1:7:1:19 | exit ArrayCreation | 7 |
| ArrayCreation.cs:3:11:3:12 | enter M1 | ArrayCreation.cs:3:11:3:12 | exit M1 | 5 |
| ArrayCreation.cs:5:12:5:13 | enter M2 | ArrayCreation.cs:5:12:5:13 | exit M2 | 6 |
@@ -164,7 +164,7 @@
| Assert.cs:138:10:138:12 | exit M13 (abnormal) | Assert.cs:138:10:138:12 | exit M13 (abnormal) | 1 |
| Assert.cs:141:9:141:15 | return ...; | Assert.cs:138:10:138:12 | exit M13 (normal) | 2 |
| Assignments.cs:1:7:1:17 | enter Assignments | Assignments.cs:1:7:1:17 | exit Assignments | 7 |
-| Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | exit M | 34 |
+| Assignments.cs:3:10:3:10 | enter M | Assignments.cs:3:10:3:10 | exit M | 31 |
| Assignments.cs:14:18:14:35 | enter (...) => ... | Assignments.cs:14:18:14:35 | exit (...) => ... | 4 |
| Assignments.cs:17:40:17:40 | enter + | Assignments.cs:17:40:17:40 | exit + | 6 |
| Assignments.cs:27:10:27:23 | enter SetParamSingle | Assignments.cs:27:10:27:23 | exit SetParamSingle | 7 |
@@ -250,7 +250,6 @@
| ConditionalAccess.cs:42:9:42:11 | enter get_Item | ConditionalAccess.cs:42:9:42:11 | exit get_Item | 6 |
| ConditionalAccess.cs:43:9:43:11 | enter set_Item | ConditionalAccess.cs:43:9:43:11 | exit set_Item | 4 |
| ConditionalAccess.cs:46:10:46:11 | enter M9 | ConditionalAccess.cs:48:9:48:10 | access to parameter ca | 4 |
-| ConditionalAccess.cs:46:10:46:11 | exit M9 (normal) | ConditionalAccess.cs:46:10:46:11 | exit M9 | 2 |
| ConditionalAccess.cs:48:24:48:25 | 42 | ConditionalAccess.cs:48:12:48:25 | ... = ... | 3 |
| ConditionalAccess.cs:49:9:49:33 | ...; | ConditionalAccess.cs:49:9:49:10 | access to parameter ca | 2 |
| ConditionalAccess.cs:49:26:49:32 | "Hello" | ConditionalAccess.cs:49:12:49:32 | ... = ... | 3 |
@@ -262,14 +261,11 @@
| ConditionalAccess.cs:52:9:52:16 | access to property Prop | ConditionalAccess.cs:52:9:52:16 | access to property Prop | 1 |
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:9:52:10 | access to parameter ca | 2 |
| ConditionalAccess.cs:52:32:52:38 | "World" | ConditionalAccess.cs:52:18:52:38 | ... = ... | 3 |
-| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:9:53:10 | access to parameter ca | 1 |
| ConditionalAccess.cs:53:9:53:20 | access to field IntField | ConditionalAccess.cs:53:9:53:20 | access to field IntField | 1 |
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:10 | access to parameter ca | 2 |
-| ConditionalAccess.cs:53:25:53:25 | 1 | ConditionalAccess.cs:53:12:53:25 | ... = ... | 4 |
-| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | 1 |
+| ConditionalAccess.cs:53:25:53:25 | 1 | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | 4 |
| ConditionalAccess.cs:54:9:54:22 | access to property StringProp | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | 1 |
-| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | 2 |
-| ConditionalAccess.cs:54:27:54:29 | "!" | ConditionalAccess.cs:54:12:54:29 | ... = ... | 4 |
+| ConditionalAccess.cs:54:27:54:29 | "!" | ConditionalAccess.cs:46:10:46:11 | exit M9 | 4 |
| ConditionalAccess.cs:60:26:60:38 | enter CommaJoinWith | ConditionalAccess.cs:60:26:60:38 | exit CommaJoinWith | 8 |
| Conditions.cs:1:7:1:16 | enter Conditions | Conditions.cs:1:7:1:16 | exit Conditions | 7 |
| Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:5:13:5:15 | access to parameter inc | 4 |
@@ -331,12 +327,12 @@
| Conditions.cs:97:17:97:20 | ...; | Conditions.cs:97:17:97:19 | ...++ | 3 |
| Conditions.cs:99:16:99:16 | access to local variable x | Conditions.cs:86:9:86:10 | exit M7 | 4 |
| Conditions.cs:102:12:102:13 | enter M8 | Conditions.cs:105:13:105:13 | access to parameter b | 8 |
-| Conditions.cs:106:13:106:20 | ...; | Conditions.cs:106:13:106:19 | ... = ... | 5 |
+| Conditions.cs:106:13:106:20 | ...; | Conditions.cs:106:13:106:19 | ... += ... | 4 |
| Conditions.cs:107:9:109:24 | if (...) ... | Conditions.cs:107:13:107:24 | ... > ... | 5 |
| Conditions.cs:108:13:109:24 | if (...) ... | Conditions.cs:108:18:108:18 | access to parameter b | 2 |
| Conditions.cs:108:17:108:18 | [false] !... | Conditions.cs:108:17:108:18 | [false] !... | 1 |
| Conditions.cs:108:17:108:18 | [true] !... | Conditions.cs:108:17:108:18 | [true] !... | 1 |
-| Conditions.cs:109:17:109:24 | ...; | Conditions.cs:109:17:109:23 | ... = ... | 5 |
+| Conditions.cs:109:17:109:24 | ...; | Conditions.cs:109:17:109:23 | ... += ... | 4 |
| Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:102:12:102:13 | exit M8 | 4 |
| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:116:18:116:22 | Int32 i = ... | 8 |
| Conditions.cs:113:10:113:11 | exit M9 (normal) | Conditions.cs:113:10:113:11 | exit M9 | 2 |
@@ -533,7 +529,7 @@
| Finally.cs:254:13:254:45 | ...; | Finally.cs:254:13:254:44 | call to method WriteLine | 3 |
| Finally.cs:257:9:259:9 | {...} | Finally.cs:258:13:258:46 | call to method WriteLine | 4 |
| Finally.cs:260:9:260:34 | ...; | Finally.cs:233:10:233:12 | exit M12 (normal) | 4 |
-| Finally.cs:263:10:263:12 | enter M13 | Finally.cs:272:13:272:18 | ... = ... | 16 |
+| Finally.cs:263:10:263:12 | enter M13 | Finally.cs:272:13:272:18 | ... += ... | 15 |
| Finally.cs:263:10:263:12 | exit M13 | Finally.cs:263:10:263:12 | exit M13 | 1 |
| Finally.cs:263:10:263:12 | exit M13 (abnormal) | Finally.cs:263:10:263:12 | exit M13 (abnormal) | 1 |
| Finally.cs:263:10:263:12 | exit M13 (normal) | Finally.cs:263:10:263:12 | exit M13 (normal) | 1 |
@@ -1130,7 +1126,7 @@
| cflow.cs:201:9:205:9 | {...} | cflow.cs:193:10:193:17 | exit Booleans (abnormal) | 5 |
| cflow.cs:208:10:208:11 | enter Do | cflow.cs:210:9:221:36 | do ... while (...); | 3 |
| cflow.cs:208:10:208:11 | exit Do (normal) | cflow.cs:208:10:208:11 | exit Do | 2 |
-| cflow.cs:211:9:221:9 | {...} | cflow.cs:213:17:213:32 | ... > ... | 15 |
+| cflow.cs:211:9:221:9 | {...} | cflow.cs:213:17:213:32 | ... > ... | 12 |
| cflow.cs:214:13:216:13 | {...} | cflow.cs:215:17:215:25 | continue; | 2 |
| cflow.cs:217:13:220:13 | if (...) ... | cflow.cs:217:17:217:32 | ... < ... | 6 |
| cflow.cs:218:13:220:13 | {...} | cflow.cs:219:17:219:22 | break; | 2 |
@@ -1138,7 +1134,7 @@
| cflow.cs:224:10:224:16 | enter Foreach | cflow.cs:226:27:226:64 | call to method Repeat | 5 |
| cflow.cs:224:10:224:16 | exit Foreach (normal) | cflow.cs:224:10:224:16 | exit Foreach | 2 |
| cflow.cs:226:9:237:9 | foreach (... ... in ...) ... | cflow.cs:226:9:237:9 | foreach (... ... in ...) ... | 1 |
-| cflow.cs:226:22:226:22 | String x | cflow.cs:229:17:229:32 | ... > ... | 16 |
+| cflow.cs:226:22:226:22 | String x | cflow.cs:229:17:229:32 | ... > ... | 13 |
| cflow.cs:230:13:232:13 | {...} | cflow.cs:231:17:231:25 | continue; | 2 |
| cflow.cs:233:13:236:13 | if (...) ... | cflow.cs:233:17:233:32 | ... < ... | 6 |
| cflow.cs:234:13:236:13 | {...} | cflow.cs:235:17:235:22 | break; | 2 |
diff --git a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected
index 3ef1d481abe8..cda25b6abd12 100644
--- a/csharp/ql/test/library-tests/controlflow/graph/Condition.expected
+++ b/csharp/ql/test/library-tests/controlflow/graph/Condition.expected
@@ -100,14 +100,8 @@ conditionBlock
| ConditionalAccess.cs:52:9:52:16 | access to property Prop | ConditionalAccess.cs:52:32:52:38 | "World" | false |
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:9:52:16 | access to property Prop | false |
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:32:52:38 | "World" | false |
-| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:9:53:20 | access to field IntField | false |
-| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:10 | access to parameter ca | false |
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:20 | access to field IntField | false |
-| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:25:53:25 | 1 | false |
-| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | false |
-| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:10 | access to parameter ca | false |
-| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | false |
-| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:27:54:29 | "!" | false |
+| ConditionalAccess.cs:53:25:53:25 | 1 | ConditionalAccess.cs:54:9:54:22 | access to property StringProp | false |
| Conditions.cs:3:10:3:19 | enter IncrOrDecr | Conditions.cs:6:13:6:16 | ...; | true |
| Conditions.cs:7:9:8:16 | if (...) ... | Conditions.cs:7:13:7:16 | [false] !... | true |
| Conditions.cs:7:9:8:16 | if (...) ... | Conditions.cs:7:13:7:16 | [true] !... | false |
diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected
index 204092c6df23..072d874d8d4f 100644
--- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected
+++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected
@@ -129,77 +129,54 @@ dominance
| AccessorCalls.cs:42:10:42:11 | enter M5 | AccessorCalls.cs:43:5:47:5 | {...} |
| AccessorCalls.cs:42:10:42:11 | exit M5 (normal) | AccessorCalls.cs:42:10:42:11 | exit M5 |
| AccessorCalls.cs:43:5:47:5 | {...} | AccessorCalls.cs:44:9:44:33 | ...; |
-| AccessorCalls.cs:44:9:44:12 | this access | AccessorCalls.cs:44:9:44:12 | this access |
| AccessorCalls.cs:44:9:44:12 | this access | AccessorCalls.cs:44:9:44:18 | access to field Field |
-| AccessorCalls.cs:44:9:44:18 | access to field Field | AccessorCalls.cs:44:9:44:32 | ... = ... |
| AccessorCalls.cs:44:9:44:18 | access to field Field | AccessorCalls.cs:44:23:44:26 | this access |
-| AccessorCalls.cs:44:9:44:32 | ... + ... | AccessorCalls.cs:44:9:44:18 | access to field Field |
-| AccessorCalls.cs:44:9:44:32 | ... = ... | AccessorCalls.cs:45:9:45:31 | ...; |
+| AccessorCalls.cs:44:9:44:32 | ... += ... | AccessorCalls.cs:45:9:45:31 | ...; |
| AccessorCalls.cs:44:9:44:33 | ...; | AccessorCalls.cs:44:9:44:12 | this access |
| AccessorCalls.cs:44:23:44:26 | this access | AccessorCalls.cs:44:23:44:32 | access to field Field |
-| AccessorCalls.cs:44:23:44:32 | access to field Field | AccessorCalls.cs:44:9:44:32 | ... + ... |
-| AccessorCalls.cs:45:9:45:12 | this access | AccessorCalls.cs:45:9:45:12 | this access |
+| AccessorCalls.cs:44:23:44:32 | access to field Field | AccessorCalls.cs:44:9:44:32 | ... += ... |
| AccessorCalls.cs:45:9:45:12 | this access | AccessorCalls.cs:45:9:45:17 | access to property Prop |
-| AccessorCalls.cs:45:9:45:17 | access to property Prop | AccessorCalls.cs:45:9:45:30 | ... = ... |
| AccessorCalls.cs:45:9:45:17 | access to property Prop | AccessorCalls.cs:45:22:45:25 | this access |
-| AccessorCalls.cs:45:9:45:30 | ... + ... | AccessorCalls.cs:45:9:45:17 | access to property Prop |
-| AccessorCalls.cs:45:9:45:30 | ... = ... | AccessorCalls.cs:46:9:46:27 | ...; |
+| AccessorCalls.cs:45:9:45:30 | ... += ... | AccessorCalls.cs:46:9:46:27 | ...; |
| AccessorCalls.cs:45:9:45:31 | ...; | AccessorCalls.cs:45:9:45:12 | this access |
| AccessorCalls.cs:45:22:45:25 | this access | AccessorCalls.cs:45:22:45:30 | access to property Prop |
-| AccessorCalls.cs:45:22:45:30 | access to property Prop | AccessorCalls.cs:45:9:45:30 | ... + ... |
+| AccessorCalls.cs:45:22:45:30 | access to property Prop | AccessorCalls.cs:45:9:45:30 | ... += ... |
| AccessorCalls.cs:46:9:46:12 | this access | AccessorCalls.cs:46:14:46:14 | 0 |
-| AccessorCalls.cs:46:9:46:12 | this access | AccessorCalls.cs:46:14:46:14 | 0 |
-| AccessorCalls.cs:46:9:46:15 | access to indexer | AccessorCalls.cs:46:9:46:26 | ... = ... |
| AccessorCalls.cs:46:9:46:15 | access to indexer | AccessorCalls.cs:46:20:46:23 | this access |
-| AccessorCalls.cs:46:9:46:26 | ... + ... | AccessorCalls.cs:46:9:46:15 | access to indexer |
-| AccessorCalls.cs:46:9:46:26 | ... = ... | AccessorCalls.cs:42:10:42:11 | exit M5 (normal) |
+| AccessorCalls.cs:46:9:46:26 | ... += ... | AccessorCalls.cs:42:10:42:11 | exit M5 (normal) |
| AccessorCalls.cs:46:9:46:27 | ...; | AccessorCalls.cs:46:9:46:12 | this access |
-| AccessorCalls.cs:46:14:46:14 | 0 | AccessorCalls.cs:46:9:46:12 | this access |
| AccessorCalls.cs:46:14:46:14 | 0 | AccessorCalls.cs:46:9:46:15 | access to indexer |
| AccessorCalls.cs:46:20:46:23 | this access | AccessorCalls.cs:46:25:46:25 | 0 |
-| AccessorCalls.cs:46:20:46:26 | access to indexer | AccessorCalls.cs:46:9:46:26 | ... + ... |
+| AccessorCalls.cs:46:20:46:26 | access to indexer | AccessorCalls.cs:46:9:46:26 | ... += ... |
| AccessorCalls.cs:46:25:46:25 | 0 | AccessorCalls.cs:46:20:46:26 | access to indexer |
| AccessorCalls.cs:49:10:49:11 | enter M6 | AccessorCalls.cs:50:5:54:5 | {...} |
| AccessorCalls.cs:49:10:49:11 | exit M6 (normal) | AccessorCalls.cs:49:10:49:11 | exit M6 |
| AccessorCalls.cs:50:5:54:5 | {...} | AccessorCalls.cs:51:9:51:37 | ...; |
| AccessorCalls.cs:51:9:51:12 | this access | AccessorCalls.cs:51:9:51:14 | access to field x |
-| AccessorCalls.cs:51:9:51:12 | this access | AccessorCalls.cs:51:9:51:14 | access to field x |
-| AccessorCalls.cs:51:9:51:14 | access to field x | AccessorCalls.cs:51:9:51:12 | this access |
| AccessorCalls.cs:51:9:51:14 | access to field x | AccessorCalls.cs:51:9:51:20 | access to field Field |
-| AccessorCalls.cs:51:9:51:20 | access to field Field | AccessorCalls.cs:51:9:51:36 | ... = ... |
| AccessorCalls.cs:51:9:51:20 | access to field Field | AccessorCalls.cs:51:25:51:28 | this access |
-| AccessorCalls.cs:51:9:51:36 | ... + ... | AccessorCalls.cs:51:9:51:20 | access to field Field |
-| AccessorCalls.cs:51:9:51:36 | ... = ... | AccessorCalls.cs:52:9:52:35 | ...; |
+| AccessorCalls.cs:51:9:51:36 | ... += ... | AccessorCalls.cs:52:9:52:35 | ...; |
| AccessorCalls.cs:51:9:51:37 | ...; | AccessorCalls.cs:51:9:51:12 | this access |
| AccessorCalls.cs:51:25:51:28 | this access | AccessorCalls.cs:51:25:51:30 | access to field x |
| AccessorCalls.cs:51:25:51:30 | access to field x | AccessorCalls.cs:51:25:51:36 | access to field Field |
-| AccessorCalls.cs:51:25:51:36 | access to field Field | AccessorCalls.cs:51:9:51:36 | ... + ... |
+| AccessorCalls.cs:51:25:51:36 | access to field Field | AccessorCalls.cs:51:9:51:36 | ... += ... |
| AccessorCalls.cs:52:9:52:12 | this access | AccessorCalls.cs:52:9:52:14 | access to field x |
-| AccessorCalls.cs:52:9:52:12 | this access | AccessorCalls.cs:52:9:52:14 | access to field x |
-| AccessorCalls.cs:52:9:52:14 | access to field x | AccessorCalls.cs:52:9:52:12 | this access |
| AccessorCalls.cs:52:9:52:14 | access to field x | AccessorCalls.cs:52:9:52:19 | access to property Prop |
-| AccessorCalls.cs:52:9:52:19 | access to property Prop | AccessorCalls.cs:52:9:52:34 | ... = ... |
| AccessorCalls.cs:52:9:52:19 | access to property Prop | AccessorCalls.cs:52:24:52:27 | this access |
-| AccessorCalls.cs:52:9:52:34 | ... + ... | AccessorCalls.cs:52:9:52:19 | access to property Prop |
-| AccessorCalls.cs:52:9:52:34 | ... = ... | AccessorCalls.cs:53:9:53:31 | ...; |
+| AccessorCalls.cs:52:9:52:34 | ... += ... | AccessorCalls.cs:53:9:53:31 | ...; |
| AccessorCalls.cs:52:9:52:35 | ...; | AccessorCalls.cs:52:9:52:12 | this access |
| AccessorCalls.cs:52:24:52:27 | this access | AccessorCalls.cs:52:24:52:29 | access to field x |
| AccessorCalls.cs:52:24:52:29 | access to field x | AccessorCalls.cs:52:24:52:34 | access to property Prop |
-| AccessorCalls.cs:52:24:52:34 | access to property Prop | AccessorCalls.cs:52:9:52:34 | ... + ... |
-| AccessorCalls.cs:53:9:53:12 | this access | AccessorCalls.cs:53:9:53:14 | access to field x |
+| AccessorCalls.cs:52:24:52:34 | access to property Prop | AccessorCalls.cs:52:9:52:34 | ... += ... |
| AccessorCalls.cs:53:9:53:12 | this access | AccessorCalls.cs:53:9:53:14 | access to field x |
| AccessorCalls.cs:53:9:53:14 | access to field x | AccessorCalls.cs:53:16:53:16 | 0 |
-| AccessorCalls.cs:53:9:53:14 | access to field x | AccessorCalls.cs:53:16:53:16 | 0 |
-| AccessorCalls.cs:53:9:53:17 | access to indexer | AccessorCalls.cs:53:9:53:30 | ... = ... |
| AccessorCalls.cs:53:9:53:17 | access to indexer | AccessorCalls.cs:53:22:53:25 | this access |
-| AccessorCalls.cs:53:9:53:30 | ... + ... | AccessorCalls.cs:53:9:53:17 | access to indexer |
-| AccessorCalls.cs:53:9:53:30 | ... = ... | AccessorCalls.cs:49:10:49:11 | exit M6 (normal) |
+| AccessorCalls.cs:53:9:53:30 | ... += ... | AccessorCalls.cs:49:10:49:11 | exit M6 (normal) |
| AccessorCalls.cs:53:9:53:31 | ...; | AccessorCalls.cs:53:9:53:12 | this access |
-| AccessorCalls.cs:53:16:53:16 | 0 | AccessorCalls.cs:53:9:53:12 | this access |
| AccessorCalls.cs:53:16:53:16 | 0 | AccessorCalls.cs:53:9:53:17 | access to indexer |
| AccessorCalls.cs:53:22:53:25 | this access | AccessorCalls.cs:53:22:53:27 | access to field x |
| AccessorCalls.cs:53:22:53:27 | access to field x | AccessorCalls.cs:53:29:53:29 | 0 |
-| AccessorCalls.cs:53:22:53:30 | access to indexer | AccessorCalls.cs:53:9:53:30 | ... + ... |
+| AccessorCalls.cs:53:22:53:30 | access to indexer | AccessorCalls.cs:53:9:53:30 | ... += ... |
| AccessorCalls.cs:53:29:53:29 | 0 | AccessorCalls.cs:53:22:53:30 | access to indexer |
| AccessorCalls.cs:56:10:56:11 | enter M7 | AccessorCalls.cs:57:5:59:5 | {...} |
| AccessorCalls.cs:56:10:56:11 | exit M7 (normal) | AccessorCalls.cs:56:10:56:11 | exit M7 |
@@ -271,25 +248,18 @@ dominance
| AccessorCalls.cs:70:9:70:19 | dynamic access to member MaybeProp | AccessorCalls.cs:70:9:70:21 | dynamic call to operator ++ |
| AccessorCalls.cs:70:9:70:21 | dynamic call to operator ++ | AccessorCalls.cs:71:9:71:26 | ...; |
| AccessorCalls.cs:70:9:70:22 | ...; | AccessorCalls.cs:70:9:70:9 | access to local variable d |
-| AccessorCalls.cs:71:9:71:9 | access to local variable d | AccessorCalls.cs:71:9:71:9 | access to local variable d |
| AccessorCalls.cs:71:9:71:9 | access to local variable d | AccessorCalls.cs:71:9:71:20 | dynamic access to member MaybeEvent |
-| AccessorCalls.cs:71:9:71:20 | dynamic access to member MaybeEvent | AccessorCalls.cs:71:9:71:25 | ... = ... |
| AccessorCalls.cs:71:9:71:20 | dynamic access to member MaybeEvent | AccessorCalls.cs:71:25:71:25 | access to parameter e |
-| AccessorCalls.cs:71:9:71:25 | ... = ... | AccessorCalls.cs:72:9:72:21 | ...; |
-| AccessorCalls.cs:71:9:71:25 | dynamic call to operator + | AccessorCalls.cs:71:9:71:20 | dynamic access to member MaybeEvent |
+| AccessorCalls.cs:71:9:71:25 | ... += ... | AccessorCalls.cs:72:9:72:21 | ...; |
| AccessorCalls.cs:71:9:71:26 | ...; | AccessorCalls.cs:71:9:71:9 | access to local variable d |
-| AccessorCalls.cs:71:25:71:25 | access to parameter e | AccessorCalls.cs:71:9:71:25 | dynamic call to operator + |
-| AccessorCalls.cs:72:9:72:9 | access to local variable d | AccessorCalls.cs:72:11:72:11 | 0 |
+| AccessorCalls.cs:71:25:71:25 | access to parameter e | AccessorCalls.cs:71:9:71:25 | ... += ... |
| AccessorCalls.cs:72:9:72:9 | access to local variable d | AccessorCalls.cs:72:11:72:11 | 0 |
-| AccessorCalls.cs:72:9:72:12 | dynamic access to element | AccessorCalls.cs:72:9:72:20 | ... = ... |
| AccessorCalls.cs:72:9:72:12 | dynamic access to element | AccessorCalls.cs:72:17:72:17 | access to local variable d |
-| AccessorCalls.cs:72:9:72:20 | ... = ... | AccessorCalls.cs:73:9:73:84 | ...; |
-| AccessorCalls.cs:72:9:72:20 | dynamic call to operator + | AccessorCalls.cs:72:9:72:12 | dynamic access to element |
+| AccessorCalls.cs:72:9:72:20 | ... += ... | AccessorCalls.cs:73:9:73:84 | ...; |
| AccessorCalls.cs:72:9:72:21 | ...; | AccessorCalls.cs:72:9:72:9 | access to local variable d |
-| AccessorCalls.cs:72:11:72:11 | 0 | AccessorCalls.cs:72:9:72:9 | access to local variable d |
| AccessorCalls.cs:72:11:72:11 | 0 | AccessorCalls.cs:72:9:72:12 | dynamic access to element |
| AccessorCalls.cs:72:17:72:17 | access to local variable d | AccessorCalls.cs:72:19:72:19 | 1 |
-| AccessorCalls.cs:72:17:72:20 | dynamic access to element | AccessorCalls.cs:72:9:72:20 | dynamic call to operator + |
+| AccessorCalls.cs:72:17:72:20 | dynamic access to element | AccessorCalls.cs:72:9:72:20 | ... += ... |
| AccessorCalls.cs:72:19:72:19 | 1 | AccessorCalls.cs:72:17:72:20 | dynamic access to element |
| AccessorCalls.cs:73:9:73:44 | (..., ...) | AccessorCalls.cs:73:49:73:49 | access to local variable d |
| AccessorCalls.cs:73:9:73:83 | ... = ... | AccessorCalls.cs:66:10:66:11 | exit M9 (normal) |
@@ -732,27 +702,24 @@ dominance
| Assignments.cs:5:13:5:17 | Int32 x = ... | Assignments.cs:6:9:6:15 | ...; |
| Assignments.cs:5:17:5:17 | 0 | Assignments.cs:5:13:5:17 | Int32 x = ... |
| Assignments.cs:6:9:6:9 | access to local variable x | Assignments.cs:6:14:6:14 | 1 |
-| Assignments.cs:6:9:6:14 | ... + ... | Assignments.cs:6:9:6:14 | ... = ... |
-| Assignments.cs:6:9:6:14 | ... = ... | Assignments.cs:8:9:8:22 | ... ...; |
+| Assignments.cs:6:9:6:14 | ... += ... | Assignments.cs:8:9:8:22 | ... ...; |
| Assignments.cs:6:9:6:15 | ...; | Assignments.cs:6:9:6:9 | access to local variable x |
-| Assignments.cs:6:14:6:14 | 1 | Assignments.cs:6:9:6:14 | ... + ... |
+| Assignments.cs:6:14:6:14 | 1 | Assignments.cs:6:9:6:14 | ... += ... |
| Assignments.cs:8:9:8:22 | ... ...; | Assignments.cs:8:21:8:21 | 0 |
| Assignments.cs:8:17:8:21 | dynamic d = ... | Assignments.cs:9:9:9:15 | ...; |
| Assignments.cs:8:21:8:21 | 0 | Assignments.cs:8:21:8:21 | (...) ... |
| Assignments.cs:8:21:8:21 | (...) ... | Assignments.cs:8:17:8:21 | dynamic d = ... |
| Assignments.cs:9:9:9:9 | access to local variable d | Assignments.cs:9:14:9:14 | 2 |
-| Assignments.cs:9:9:9:14 | ... = ... | Assignments.cs:11:9:11:34 | ... ...; |
-| Assignments.cs:9:9:9:14 | dynamic call to operator - | Assignments.cs:9:9:9:14 | ... = ... |
+| Assignments.cs:9:9:9:14 | ... -= ... | Assignments.cs:11:9:11:34 | ... ...; |
| Assignments.cs:9:9:9:15 | ...; | Assignments.cs:9:9:9:9 | access to local variable d |
-| Assignments.cs:9:14:9:14 | 2 | Assignments.cs:9:9:9:14 | dynamic call to operator - |
+| Assignments.cs:9:14:9:14 | 2 | Assignments.cs:9:9:9:14 | ... -= ... |
| Assignments.cs:11:9:11:34 | ... ...; | Assignments.cs:11:17:11:33 | object creation of type Assignments |
| Assignments.cs:11:13:11:33 | Assignments a = ... | Assignments.cs:12:9:12:18 | ...; |
| Assignments.cs:11:17:11:33 | object creation of type Assignments | Assignments.cs:11:13:11:33 | Assignments a = ... |
| Assignments.cs:12:9:12:9 | access to local variable a | Assignments.cs:12:14:12:17 | this access |
-| Assignments.cs:12:9:12:17 | ... = ... | Assignments.cs:14:9:14:36 | ...; |
-| Assignments.cs:12:9:12:17 | call to operator + | Assignments.cs:12:9:12:17 | ... = ... |
+| Assignments.cs:12:9:12:17 | ... += ... | Assignments.cs:14:9:14:36 | ...; |
| Assignments.cs:12:9:12:18 | ...; | Assignments.cs:12:9:12:9 | access to local variable a |
-| Assignments.cs:12:14:12:17 | this access | Assignments.cs:12:9:12:17 | call to operator + |
+| Assignments.cs:12:14:12:17 | this access | Assignments.cs:12:9:12:17 | ... += ... |
| Assignments.cs:14:9:14:13 | access to event Event | Assignments.cs:14:9:14:35 | ... += ... |
| Assignments.cs:14:9:14:13 | this access | Assignments.cs:14:18:14:35 | (...) => ... |
| Assignments.cs:14:9:14:35 | ... += ... | Assignments.cs:3:10:3:10 | exit M (normal) |
@@ -1058,22 +1025,16 @@ dominance
| ConditionalAccess.cs:52:9:52:28 | access to property StringProp | ConditionalAccess.cs:52:18:52:38 | ... = ... |
| ConditionalAccess.cs:52:9:52:39 | ...; | ConditionalAccess.cs:52:9:52:10 | access to parameter ca |
| ConditionalAccess.cs:52:32:52:38 | "World" | ConditionalAccess.cs:52:9:52:28 | access to property StringProp |
-| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:9:53:10 | access to parameter ca |
| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:9:53:20 | access to field IntField |
| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:53:25:53:25 | 1 |
-| ConditionalAccess.cs:53:9:53:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:30 | ...; |
-| ConditionalAccess.cs:53:9:53:20 | access to field IntField | ConditionalAccess.cs:53:12:53:25 | ... = ... |
| ConditionalAccess.cs:53:9:53:26 | ...; | ConditionalAccess.cs:53:9:53:10 | access to parameter ca |
-| ConditionalAccess.cs:53:12:53:25 | ... - ... | ConditionalAccess.cs:53:9:53:20 | access to field IntField |
-| ConditionalAccess.cs:53:25:53:25 | 1 | ConditionalAccess.cs:53:12:53:25 | ... - ... |
-| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:46:10:46:11 | exit M9 (normal) |
-| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:10 | access to parameter ca |
+| ConditionalAccess.cs:53:12:53:25 | ... -= ... | ConditionalAccess.cs:54:9:54:30 | ...; |
+| ConditionalAccess.cs:53:25:53:25 | 1 | ConditionalAccess.cs:53:12:53:25 | ... -= ... |
| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:9:54:22 | access to property StringProp |
| ConditionalAccess.cs:54:9:54:10 | access to parameter ca | ConditionalAccess.cs:54:27:54:29 | "!" |
-| ConditionalAccess.cs:54:9:54:22 | access to property StringProp | ConditionalAccess.cs:54:12:54:29 | ... = ... |
| ConditionalAccess.cs:54:9:54:30 | ...; | ConditionalAccess.cs:54:9:54:10 | access to parameter ca |
-| ConditionalAccess.cs:54:12:54:29 | ... + ... | ConditionalAccess.cs:54:9:54:22 | access to property StringProp |
-| ConditionalAccess.cs:54:27:54:29 | "!" | ConditionalAccess.cs:54:12:54:29 | ... + ... |
+| ConditionalAccess.cs:54:12:54:29 | ... += ... | ConditionalAccess.cs:46:10:46:11 | exit M9 (normal) |
+| ConditionalAccess.cs:54:27:54:29 | "!" | ConditionalAccess.cs:54:12:54:29 | ... += ... |
| ConditionalAccess.cs:60:26:60:38 | enter CommaJoinWith | ConditionalAccess.cs:60:70:60:71 | access to parameter s1 |
| ConditionalAccess.cs:60:26:60:38 | exit CommaJoinWith (normal) | ConditionalAccess.cs:60:26:60:38 | exit CommaJoinWith |
| ConditionalAccess.cs:60:70:60:71 | access to parameter s1 | ConditionalAccess.cs:60:75:60:78 | ", " |
@@ -1295,9 +1256,8 @@ dominance
| Conditions.cs:105:13:105:13 | access to parameter b | Conditions.cs:106:13:106:20 | ...; |
| Conditions.cs:105:13:105:13 | access to parameter b | Conditions.cs:107:9:109:24 | if (...) ... |
| Conditions.cs:106:13:106:13 | access to local variable x | Conditions.cs:106:18:106:19 | "" |
-| Conditions.cs:106:13:106:19 | ... + ... | Conditions.cs:106:13:106:19 | ... = ... |
| Conditions.cs:106:13:106:20 | ...; | Conditions.cs:106:13:106:13 | access to local variable x |
-| Conditions.cs:106:18:106:19 | "" | Conditions.cs:106:13:106:19 | ... + ... |
+| Conditions.cs:106:18:106:19 | "" | Conditions.cs:106:13:106:19 | ... += ... |
| Conditions.cs:107:9:109:24 | if (...) ... | Conditions.cs:107:13:107:13 | access to local variable x |
| Conditions.cs:107:13:107:13 | access to local variable x | Conditions.cs:107:13:107:20 | access to property Length |
| Conditions.cs:107:13:107:20 | access to property Length | Conditions.cs:107:24:107:24 | 0 |
@@ -1309,9 +1269,8 @@ dominance
| Conditions.cs:108:18:108:18 | access to parameter b | Conditions.cs:108:17:108:18 | [false] !... |
| Conditions.cs:108:18:108:18 | access to parameter b | Conditions.cs:108:17:108:18 | [true] !... |
| Conditions.cs:109:17:109:17 | access to local variable x | Conditions.cs:109:22:109:23 | "" |
-| Conditions.cs:109:17:109:23 | ... + ... | Conditions.cs:109:17:109:23 | ... = ... |
| Conditions.cs:109:17:109:24 | ...; | Conditions.cs:109:17:109:17 | access to local variable x |
-| Conditions.cs:109:22:109:23 | "" | Conditions.cs:109:17:109:23 | ... + ... |
+| Conditions.cs:109:22:109:23 | "" | Conditions.cs:109:17:109:23 | ... += ... |
| Conditions.cs:110:9:110:17 | return ...; | Conditions.cs:102:12:102:13 | exit M8 (normal) |
| Conditions.cs:110:16:110:16 | access to local variable x | Conditions.cs:110:9:110:17 | return ...; |
| Conditions.cs:113:10:113:11 | enter M9 | Conditions.cs:114:5:124:5 | {...} |
@@ -1939,11 +1898,10 @@ dominance
| Finally.cs:271:13:271:35 | ...; | Finally.cs:271:31:271:33 | "3" |
| Finally.cs:271:31:271:33 | "3" | Finally.cs:271:13:271:34 | call to method WriteLine |
| Finally.cs:272:13:272:13 | access to parameter i | Finally.cs:272:18:272:18 | 3 |
-| Finally.cs:272:13:272:18 | ... + ... | Finally.cs:272:13:272:18 | ... = ... |
-| Finally.cs:272:13:272:18 | ... = ... | Finally.cs:263:10:263:12 | exit M13 (abnormal) |
-| Finally.cs:272:13:272:18 | ... = ... | Finally.cs:263:10:263:12 | exit M13 (normal) |
+| Finally.cs:272:13:272:18 | ... += ... | Finally.cs:263:10:263:12 | exit M13 (abnormal) |
+| Finally.cs:272:13:272:18 | ... += ... | Finally.cs:263:10:263:12 | exit M13 (normal) |
| Finally.cs:272:13:272:19 | ...; | Finally.cs:272:13:272:13 | access to parameter i |
-| Finally.cs:272:18:272:18 | 3 | Finally.cs:272:13:272:18 | ... + ... |
+| Finally.cs:272:18:272:18 | 3 | Finally.cs:272:13:272:18 | ... += ... |
| Foreach.cs:4:7:4:13 | call to constructor Object | Foreach.cs:4:7:4:13 | {...} |
| Foreach.cs:4:7:4:13 | call to method