Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ type.SpecialType is SpecialType.System_IntPtr ||
/// </summary>
/// <param name="node">The expression syntax node.</param>
/// <returns>Returns the target method symbol, or null if it cannot be resolved.</returns>
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;
Expand All @@ -255,24 +255,14 @@ 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();
}

return si.Symbol as IMethodSymbol;
}

/// <summary>
/// Adapt the operator kind depending on whether it's a dynamic call or a user-operator call.
/// </summary>
/// <param name="cx"></param>
/// <param name="node"></param>
/// <param name="originalKind"></param>
/// <returns></returns>
public static ExprKind UnaryOperatorKind(Context cx, ExprKind originalKind, ExpressionSyntax node) =>
GetCallType(cx, node).AdjustKind(originalKind);

/// <summary>
/// If the expression calls an operator, add an expr_call()
/// to show the target of the call. Also note the dynamic method
Expand All @@ -281,7 +271,7 @@ public static ExprKind UnaryOperatorKind(Context cx, ExprKind originalKind, Expr
/// <param name="node">The expression.</param>
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);
Expand Down Expand Up @@ -312,9 +302,9 @@ public enum CallType
/// <returns>The call type.</returns>
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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,17 @@ internal class Cast : Expression<CastExpressionSyntax>
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))) { }

/// <summary>
/// Adapt the operator kind depending on whether it's a dynamic call or a user-operator call.
/// </summary>
/// <param name="cx"></param>
/// <param name="node"></param>
/// <param name="originalKind"></param>
/// <returns></returns>
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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
Original file line number Diff line number Diff line change
@@ -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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,22 @@

namespace Semmle.Extraction.CSharp.Entities.Expressions
{
internal class PostfixUnary : Expression<ExpressionSyntax>
internal class PostfixUnary : Expression<PostfixUnaryExpressionSyntax>
{
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);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<PrefixUnaryExpressionSyntax>
{
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);
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public enum ExprKind
COLLECTION = 136,
SPREAD_ELEMENT = 137,
INTERPOLATED_STRING_INSERT = 138,
NOT = 139,
DEFINE_SYMBOL = 999,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
4 changes: 2 additions & 2 deletions csharp/ql/lib/semmle/code/csharp/exprs/Call.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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. */
Expand Down
27 changes: 27 additions & 0 deletions csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions csharp/ql/lib/semmle/code/csharp/exprs/LogicalOperation.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
}
Expand Down
Loading
Loading