diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
index 4ab90def2c16..aa9408693197 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
@@ -234,9 +234,9 @@ type.SpecialType is SpecialType.System_IntPtr ||
///
/// The expression syntax node.
/// Returns the target method symbol, or null if it cannot be resolved.
- protected IMethodSymbol? GetTargetSymbol(ExpressionSyntax node)
+ protected static IMethodSymbol? GetTargetSymbol(Context cx, ExpressionSyntax node)
{
- var si = Context.GetSymbolInfo(node);
+ var si = cx.GetSymbolInfo(node);
if (si.Symbol is ISymbol symbol)
{
var method = symbol as IMethodSymbol;
@@ -255,7 +255,7 @@ type.SpecialType is SpecialType.System_IntPtr ||
.Where(method => method.Parameters.Length >= syntax.ArgumentList.Arguments.Count)
.Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= syntax.ArgumentList.Arguments.Count);
- return Context.ExtractionContext.IsStandalone ?
+ return cx.ExtractionContext.IsStandalone ?
candidates.FirstOrDefault() :
candidates.SingleOrDefault();
}
@@ -263,16 +263,6 @@ type.SpecialType is SpecialType.System_IntPtr ||
return si.Symbol as IMethodSymbol;
}
- ///
- /// Adapt the operator kind depending on whether it's a dynamic call or a user-operator call.
- ///
- ///
- ///
- ///
- ///
- public static ExprKind UnaryOperatorKind(Context cx, ExprKind originalKind, ExpressionSyntax node) =>
- GetCallType(cx, node).AdjustKind(originalKind);
-
///
/// If the expression calls an operator, add an expr_call()
/// to show the target of the call. Also note the dynamic method
@@ -281,7 +271,7 @@ public static ExprKind UnaryOperatorKind(Context cx, ExprKind originalKind, Expr
/// The expression.
public void AddOperatorCall(TextWriter trapFile, ExpressionSyntax node)
{
- var @operator = GetTargetSymbol(node);
+ var @operator = GetTargetSymbol(Context, node);
if (@operator is IMethodSymbol method)
{
var callType = GetCallType(Context, node);
@@ -312,9 +302,9 @@ public enum CallType
/// The call type.
public static CallType GetCallType(Context cx, ExpressionSyntax node)
{
- var @operator = cx.GetSymbolInfo(node);
+ var @operator = GetTargetSymbol(cx, node);
- if (@operator.Symbol is IMethodSymbol method)
+ if (@operator is IMethodSymbol method)
{
if (method.ContainingSymbol is ITypeSymbol containingSymbol && containingSymbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Dynamic)
{
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs
index c11711f30926..c24a7914c7c7 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs
@@ -10,7 +10,17 @@ internal class Cast : Expression
private const int ExpressionIndex = 0;
private const int TypeAccessIndex = 1;
- private Cast(ExpressionNodeInfo info) : base(info.SetKind(UnaryOperatorKind(info.Context, ExprKind.CAST, info.Node))) { }
+ private Cast(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info.Context, ExprKind.CAST, info.Node))) { }
+
+ ///
+ /// Adapt the operator kind depending on whether it's a dynamic call or a user-operator call.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ExprKind GetKind(Context cx, ExprKind originalKind, ExpressionSyntax node) =>
+ GetCallType(cx, node).AdjustKind(originalKind);
public static Expression Create(ExpressionNodeInfo info) => new Cast(info).TryPopulate();
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs
index ed8dae3738fc..8ef19df7ab5d 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs
@@ -58,10 +58,10 @@ internal static Expression Create(ExpressionNodeInfo info)
return Invocation.Create(info);
case SyntaxKind.PostIncrementExpression:
- return PostfixUnary.Create(info.SetKind(ExprKind.POST_INCR), ((PostfixUnaryExpressionSyntax)info.Node).Operand);
+ return PostfixUnary.Create(info.SetKind(ExprKind.POST_INCR));
case SyntaxKind.PostDecrementExpression:
- return PostfixUnary.Create(info.SetKind(ExprKind.POST_DECR), ((PostfixUnaryExpressionSyntax)info.Node).Operand);
+ return PostfixUnary.Create(info.SetKind(ExprKind.POST_DECR));
case SyntaxKind.AwaitExpression:
return Await.Create(info);
@@ -109,10 +109,10 @@ internal static Expression Create(ExpressionNodeInfo info)
return MemberAccess.Create(info, (MemberAccessExpressionSyntax)info.Node);
case SyntaxKind.UnaryMinusExpression:
- return Unary.Create(info.SetKind(ExprKind.MINUS));
+ return PrefixUnary.Create(info.SetKind(ExprKind.MINUS));
case SyntaxKind.UnaryPlusExpression:
- return Unary.Create(info.SetKind(ExprKind.PLUS));
+ return PrefixUnary.Create(info.SetKind(ExprKind.PLUS));
case SyntaxKind.SimpleLambdaExpression:
return Lambda.Create(info, (SimpleLambdaExpressionSyntax)info.Node);
@@ -146,16 +146,16 @@ internal static Expression Create(ExpressionNodeInfo info)
return Name.Create(info);
case SyntaxKind.LogicalNotExpression:
- return Unary.Create(info.SetKind(ExprKind.LOG_NOT));
+ return Not.Create(info);
case SyntaxKind.BitwiseNotExpression:
- return Unary.Create(info.SetKind(ExprKind.BIT_NOT));
+ return PrefixUnary.Create(info.SetKind(ExprKind.BIT_NOT));
case SyntaxKind.PreIncrementExpression:
- return Unary.Create(info.SetKind(ExprKind.PRE_INCR));
+ return PrefixUnary.Create(info.SetKind(ExprKind.PRE_INCR));
case SyntaxKind.PreDecrementExpression:
- return Unary.Create(info.SetKind(ExprKind.PRE_DECR));
+ return PrefixUnary.Create(info.SetKind(ExprKind.PRE_DECR));
case SyntaxKind.ThisExpression:
return This.CreateExplicit(info);
@@ -164,10 +164,10 @@ internal static Expression Create(ExpressionNodeInfo info)
return PropertyFieldAccess.Create(info);
case SyntaxKind.AddressOfExpression:
- return Unary.Create(info.SetKind(ExprKind.ADDRESS_OF));
+ return PrefixUnary.Create(info.SetKind(ExprKind.ADDRESS_OF));
case SyntaxKind.PointerIndirectionExpression:
- return Unary.Create(info.SetKind(ExprKind.POINTER_INDIRECTION));
+ return PrefixUnary.Create(info.SetKind(ExprKind.POINTER_INDIRECTION));
case SyntaxKind.DefaultExpression:
return Default.Create(info);
@@ -248,13 +248,13 @@ internal static Expression Create(ExpressionNodeInfo info)
return RangeExpression.Create(info);
case SyntaxKind.IndexExpression:
- return Unary.Create(info.SetKind(ExprKind.INDEX));
+ return PrefixUnary.Create(info.SetKind(ExprKind.INDEX));
case SyntaxKind.SwitchExpression:
return Switch.Create(info);
case SyntaxKind.SuppressNullableWarningExpression:
- return PostfixUnary.Create(info.SetKind(ExprKind.SUPPRESS_NULLABLE_WARNING), ((PostfixUnaryExpressionSyntax)info.Node).Operand);
+ return PostfixUnary.Create(info.SetKind(ExprKind.SUPPRESS_NULLABLE_WARNING));
case SyntaxKind.WithExpression:
return WithExpression.Create(info);
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs
index 343f288eeafe..5b25e53e8eef 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs
@@ -44,7 +44,7 @@ protected override void PopulateExpression(TextWriter trapFile)
var child = -1;
string? memberName = null;
- var target = GetTargetSymbol(Syntax);
+ var target = GetTargetSymbol(Context, Syntax);
switch (Syntax.Expression)
{
case MemberAccessExpressionSyntax memberAccess when IsValidMemberAccessKind():
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Not.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Not.cs
new file mode 100644
index 000000000000..785ac9990d81
--- /dev/null
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Not.cs
@@ -0,0 +1,19 @@
+using Microsoft.CodeAnalysis;
+using Semmle.Extraction.Kinds;
+
+namespace Semmle.Extraction.CSharp.Entities.Expressions
+{
+ internal static class Not
+ {
+ public static Expression Create(ExpressionNodeInfo info)
+ {
+ var cx = info.Context;
+ if (cx.GetSymbolInfo(info.Node).Symbol is IMethodSymbol @operator &&
+ @operator.MethodKind == MethodKind.BuiltinOperator)
+ {
+ return PrefixUnary.Create(info.SetKind(ExprKind.LOG_NOT));
+ }
+ return PrefixUnary.Create(info.SetKind(ExprKind.NOT));
+ }
+ }
+}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs
index 051a03e9f8c2..f8e0072eaf9c 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs
@@ -4,28 +4,22 @@
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
- internal class PostfixUnary : Expression
+ internal class PostfixUnary : Expression
{
- private PostfixUnary(ExpressionNodeInfo info, ExprKind kind, ExpressionSyntax operand)
- : base(info.SetKind(UnaryOperatorKind(info.Context, kind, info.Node)))
+ private PostfixUnary(ExpressionNodeInfo info)
+ : base(info)
{
- this.operand = operand;
- operatorKind = kind;
}
- private readonly ExpressionSyntax operand;
- private readonly ExprKind operatorKind;
-
- public static Expression Create(ExpressionNodeInfo info, ExpressionSyntax operand) => new PostfixUnary(info, info.Kind, operand).TryPopulate();
+ public static Expression Create(ExpressionNodeInfo info) => new PostfixUnary(info).TryPopulate();
protected override void PopulateExpression(TextWriter trapFile)
{
- Create(Context, operand, this, 0);
+ Create(Context, Syntax.Operand, this, 0);
+ AddOperatorCall(trapFile, Syntax);
- if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) &&
- Kind == ExprKind.OPERATOR_INVOCATION)
+ if (Kind == ExprKind.POST_INCR || Kind == ExprKind.POST_DECR)
{
- AddOperatorCall(trapFile, Syntax);
trapFile.mutator_invocation_mode(this, 2);
}
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PrefixUnary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PrefixUnary.cs
new file mode 100644
index 000000000000..155c8d2c5511
--- /dev/null
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PrefixUnary.cs
@@ -0,0 +1,27 @@
+using System.IO;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Semmle.Extraction.Kinds;
+
+namespace Semmle.Extraction.CSharp.Entities.Expressions
+{
+ internal class PrefixUnary : Expression
+ {
+ private PrefixUnary(ExpressionNodeInfo info)
+ : base(info)
+ {
+ }
+
+ public static Expression Create(ExpressionNodeInfo info) => new PrefixUnary(info).TryPopulate();
+
+ protected override void PopulateExpression(TextWriter trapFile)
+ {
+ Create(Context, Syntax.Operand, this, 0);
+ AddOperatorCall(trapFile, Syntax);
+
+ if (Kind == ExprKind.PRE_INCR || Kind == ExprKind.PRE_DECR)
+ {
+ trapFile.mutator_invocation_mode(this, 1);
+ }
+ }
+ }
+}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs
deleted file mode 100644
index 699c3810d116..000000000000
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.IO;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Semmle.Extraction.Kinds;
-
-namespace Semmle.Extraction.CSharp.Entities.Expressions
-{
- internal class Unary : Expression
- {
- private Unary(ExpressionNodeInfo info, ExprKind kind)
- : base(info.SetKind(UnaryOperatorKind(info.Context, info.Kind, info.Node)))
- {
- operatorKind = kind;
- }
-
- private readonly ExprKind operatorKind;
-
- public static Unary Create(ExpressionNodeInfo info)
- {
- var ret = new Unary(info, info.Kind);
- ret.TryPopulate();
- return ret;
- }
-
- protected override void PopulateExpression(TextWriter trapFile)
- {
- Create(Context, Syntax.Operand, this, 0);
- AddOperatorCall(trapFile, Syntax);
-
- if ((operatorKind == ExprKind.PRE_INCR || operatorKind == ExprKind.PRE_DECR) &&
- Kind == ExprKind.OPERATOR_INVOCATION)
- {
- trapFile.mutator_invocation_mode(this, 1);
- }
- }
- }
-}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs
index 46a694192842..ba2c53dadb6c 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs
@@ -133,6 +133,7 @@ public enum ExprKind
COLLECTION = 136,
SPREAD_ELEMENT = 137,
INTERPOLATED_STRING_INSERT = 138,
+ NOT = 139,
DEFINE_SYMBOL = 999,
}
}
diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
index c56d3dab420c..f5940d49f31d 100644
--- a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
+++ b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll
@@ -207,7 +207,11 @@ private module Input implements InputSig1, InputSig2 {
exists(QualifiableExpr qe | qe.isConditional() | n = getQualifier(qe))
}
- predicate postOrInOrder(Ast::AstNode n) { n instanceof YieldStmt or n instanceof Call }
+ predicate postOrInOrder(Ast::AstNode n) {
+ n instanceof YieldStmt
+ or
+ n instanceof Call and not n instanceof LogicalNotExpr
+ }
predicate beginAbruptCompletion(
Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll
index 193c48ed3a2b..67411ed5eff2 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/ArithmeticOperation.qll
@@ -20,7 +20,8 @@ class ArithmeticOperation extends Operation, @arith_op_expr {
* (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`),
* or a mutator operation (`MutatorOperation`).
*/
-class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_op_expr { }
+class UnaryArithmeticOperation extends ArithmeticOperation, UnaryCallOperation, @un_arith_op_expr {
+}
/**
* A unary minus operation, for example `-x`.
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
index 14bb3d74e2b2..2bc704f68093 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
@@ -16,7 +16,7 @@ class BitwiseOperation extends Operation, @bit_expr { }
* A unary bitwise operation, that is, a bitwise complement operation
* (`ComplementExpr`).
*/
-class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_op_expr { }
+class UnaryBitwiseOperation extends BitwiseOperation, UnaryCallOperation, @un_bit_op_expr { }
/**
* A bitwise complement operation, for example `~x`.
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
index 9dbf898e2864..42b69b77d038 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
@@ -545,7 +545,7 @@ class ExtensionOperatorCall extends OperatorCall {
}
/**
- * A call to a user-defined mutator operator, for example `a++` on
+ * A call to a mutator operator, for example `a++` on
* line 7 in
*
* ```csharp
@@ -560,7 +560,7 @@ class ExtensionOperatorCall extends OperatorCall {
* }
* ```
*/
-class MutatorOperatorCall extends OperatorCall {
+class MutatorOperatorCall extends MutatorOperation {
MutatorOperatorCall() { mutator_invocation_mode(this, _) }
/** Holds if the operator is in prefix position. */
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
index a26afb004901..867b40eefa2c 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
@@ -234,6 +234,33 @@ class UnaryOperation extends Operation, @un_op {
override string toString() { result = this.getOperator() + "..." }
}
+/**
+ * A unary operator call. Either a unary arithmetic operator call (`UnaryArithmeticOperatorCall`),
+ * a unary bitwise operator call (`UnaryBitwiseOperatorCall`), or a
+ * unary logical operator call (`UnaryLogicalOperatorCall`).
+ */
+class UnaryCallOperation extends OperatorCall, UnaryOperation, @un_op_call_expr {
+ override string toString() { result = UnaryOperation.super.toString() }
+}
+
+/**
+ * A logical 'not', for example `!String.IsNullOrEmpty(s)` or a call to a user-defined
+ * not operator such as `!x` in:
+ * ```csharp
+ * class Negatable {
+ * public static Negatable operator !(Negatable n) => { ...};
+ * }
+ *
+ * var x = new Negatable();
+ * var y = !x;
+ * ```
+ */
+class UnaryNotOperation extends UnaryCallOperation, @un_not_op_expr {
+ override string getOperator() { result = "!" }
+
+ override string getAPrimaryQlClass() { result = "UnaryNotOperation" }
+}
+
/**
* A binary operation. Either a binary arithmetic operation
* (`BinaryArithmeticOperation`), a binary bitwise operation
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll
index 4161f734c9b7..ad2af29555ba 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll
@@ -18,13 +18,13 @@ class LogicalOperation extends Operation, @log_expr {
/**
* A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`).
*/
-class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_op_expr { }
+class UnaryLogicalOperation extends LogicalOperation, UnaryCallOperation, @un_log_op_expr { }
/**
* A logical 'not', for example `!String.IsNullOrEmpty(s)`.
*/
-class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr {
- override string getOperator() { result = "!" }
+class LogicalNotExpr extends UnaryLogicalOperation, UnaryNotOperation, @log_not_expr {
+ override string getOperator() { result = UnaryNotOperation.super.getOperator() }
override string getAPrimaryQlClass() { result = "LogicalNotExpr" }
}
diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme
index 3cabc77473cb..a1a00aeec45e 100644
--- a/csharp/ql/lib/semmlecode.csharp.dbscheme
+++ b/csharp/ql/lib/semmlecode.csharp.dbscheme
@@ -1198,6 +1198,7 @@ case @expr.kind of
| 136 = @collection_expr
| 137 = @spread_element_expr
| 138 = @interpolated_string_insert_expr
+| 139 = @not_expr
/* Preprocessor */
| 999 = @define_symbol_expr
;
@@ -1216,7 +1217,7 @@ case @expr.kind of
| @string_literal_expr | @null_literal_expr;
@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
-@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr
+@assign_op_call_expr = @assign_arith_expr | @assign_bitwise_expr;
@assign_op_expr = @assign_op_call_expr | @assign_event_expr | @assign_coalesce_expr;
@assign_event_expr = @add_event_expr | @remove_event_expr;
@@ -1263,6 +1264,7 @@ case @expr.kind of
@ternary_log_op_expr = @conditional_expr;
@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_not_op_expr = @log_not_expr | @not_expr;
@un_log_op_expr = @log_not_expr;
@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
@@ -1279,12 +1281,13 @@ case @expr.kind of
@ternary_op = @ternary_log_op_expr;
@bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
-@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+@un_op_call_expr = @un_arith_op_expr | @un_not_op_expr | @un_bit_op_expr;
+@un_op = @un_op_call_expr | @sizeof_expr
| @pointer_indirection_expr | @address_of_expr;
@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
-@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr
+@op_invoke_expr = @operator_invocation_expr | @assign_op_call_expr | @un_op_call_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;
@@ -1311,7 +1314,7 @@ implicitly_typed_object_creation(
unique int id: @implicitly_typeable_object_creation_expr ref);
mutator_invocation_mode(
- unique int id: @operator_invocation_expr ref,
+ unique int id: @mut_op_expr ref,
int mode: int ref /* prefix = 1, postfix = 2*/);
expr_value(