Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b2b4c9e

Browse files
committed
C#: Extract 'with' expressions
1 parent 77af7ed commit b2b4c9e

18 files changed

Lines changed: 351 additions & 80 deletions

File tree

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ internal static Expression Create(ExpressionNodeInfo info)
250250
case SyntaxKind.SuppressNullableWarningExpression:
251251
return PostfixUnary.Create(info.SetKind(ExprKind.SUPPRESS_NULLABLE_WARNING), ((PostfixUnaryExpressionSyntax)info.Node).Operand);
252252

253+
case SyntaxKind.WithExpression:
254+
return WithExpression.Create(info);
255+
253256
default:
254257
info.Context.ModelError(info.Node, $"Unhandled expression '{info.Node}' of kind '{info.Node.Kind()}'");
255258
return new Unknown(info);

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal abstract class Initializer : Expression<InitializerExpressionSyntax>
1212
protected Initializer(ExpressionNodeInfo info) : base(info) { }
1313
}
1414

15-
internal class ArrayInitializer : Expression<InitializerExpressionSyntax>
15+
internal class ArrayInitializer : Initializer
1616
{
1717
private ArrayInitializer(ExpressionNodeInfo info) : base(info.SetType(null).SetKind(ExprKind.ARRAY_INIT)) { }
1818

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.CodeAnalysis.CSharp.Syntax;
2+
using Semmle.Extraction.Kinds;
3+
using System.IO;
4+
5+
namespace Semmle.Extraction.CSharp.Entities.Expressions
6+
{
7+
internal class WithExpression : Expression<WithExpressionSyntax>
8+
{
9+
private WithExpression(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.WITH)) { }
10+
11+
public static Expression Create(ExpressionNodeInfo info) => new WithExpression(info).TryPopulate();
12+
13+
protected override void PopulateExpression(TextWriter trapFile)
14+
{
15+
Create(cx, Syntax.Expression, this, 0);
16+
17+
ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, 1).SetType(Type));
18+
}
19+
}
20+
}

csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public enum ExprKind
124124
AND_PATTERN = 127,
125125
OR_PATTERN = 128,
126126
FUNCTION_POINTER_INVOCATION = 129,
127-
127+
WITH = 130,
128128
DEFINE_SYMBOL = 999
129129
}
130130
}

csharp/ql/src/semmle/code/csharp/Callable.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,15 @@ class Operator extends Callable, Member, Attributable, @operator {
461461
override Parameter getRawParameter(int i) { result = getParameter(i) }
462462
}
463463

464+
/** A clone method on a record. */
465+
class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
466+
override Constructor getConstructor() {
467+
result = DotNet::RecordCloneCallable.super.getConstructor()
468+
}
469+
470+
override string toString() { result = Method.super.toString() }
471+
}
472+
464473
/**
465474
* A user-defined unary operator - an operator taking one operand.
466475
*

csharp/ql/src/semmle/code/csharp/Type.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,9 @@ class Class extends RefType, @class_type {
748748
class Record extends Class {
749749
Record() { this.isRecord() }
750750

751+
/** Gets the clone method of this record. */
752+
RecordCloneMethod getCloneMethod() { result = this.getAMember() }
753+
751754
override string getAPrimaryQlClass() { result = "Record" }
752755
}
753756

csharp/ql/src/semmle/code/csharp/exprs/Expr.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,3 +1152,21 @@ class DefineSymbolExpr extends Expr, @define_symbol_expr {
11521152

11531153
override string getAPrimaryQlClass() { result = "DefineSymbolExpr" }
11541154
}
1155+
1156+
/**
1157+
* A `with` expression called on a record.
1158+
*/
1159+
class WithExpr extends Expr, @with_expr {
1160+
/** Gets the object initializer of this `with` expression. */
1161+
ObjectInitializer getInitializer() { result = this.getChild(1) }
1162+
1163+
/** Gets the expression on which this `with` is called. */
1164+
Expr getExpr() { result = this.getChild(0) }
1165+
1166+
/** Gets the clone method of the `record` that is targetted by this `with` expression. */
1167+
RecordCloneMethod getCloneMethod() { result = this.getExpr().getType().(Record).getCloneMethod() }
1168+
1169+
override string toString() { result = "... with { ... }" }
1170+
1171+
override string getAPrimaryQlClass() { result = "WithExpr" }
1172+
}

csharp/ql/src/semmle/code/dotnet/Callable.qll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,22 @@ abstract class Constructor extends Callable { }
9191

9292
/** A destructor/finalizer. */
9393
abstract class Destructor extends Callable { }
94+
95+
/** A clone method on a record. */
96+
class RecordCloneCallable extends Callable {
97+
RecordCloneCallable() {
98+
this.getDeclaringType() instanceof ValueOrRefType and
99+
this.hasName("<Clone>$") and
100+
this.getNumberOfParameters() = 0 and
101+
this.getReturnType() = this.getDeclaringType().(ValueOrRefType).getABaseType*() and
102+
this.(Member).isPublic() and
103+
not this.(Member).isStatic()
104+
}
105+
106+
/** Gets the constructor that this clone method calls. */
107+
Constructor getConstructor() {
108+
result.getDeclaringType() = this.getDeclaringType() and
109+
result.getNumberOfParameters() = 1 and
110+
result.getParameter(0).getType() = this.getDeclaringType()
111+
}
112+
}

csharp/ql/src/semmle/code/dotnet/Type.qll

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,7 @@ class ValueOrRefType extends Type, @dotnet_valueorreftype {
5151
ValueOrRefType getABaseType() { none() }
5252

5353
/** Holds if this type is a `record`. */
54-
predicate isRecord() {
55-
exists(Callable c |
56-
c.getDeclaringType() = this and
57-
c.hasName("<Clone>$") and
58-
c.getNumberOfParameters() = 0 and
59-
c.getReturnType() = this.getABaseType*() and
60-
c.(Member).isPublic() and
61-
not c.(Member).isStatic()
62-
)
63-
}
54+
predicate isRecord() { exists(RecordCloneCallable c | c.getDeclaringType() = this) }
6455
}
6556

6657
/**

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,7 @@ case @expr.kind of
11561156
| 127 = @and_pattern_expr
11571157
| 128 = @or_pattern_expr
11581158
| 129 = @function_pointer_invocation_expr
1159+
| 130 = @with_expr
11591160
/* Preprocessor */
11601161
| 999 = @define_symbol_expr
11611162
;

0 commit comments

Comments
 (0)