Skip to content

Commit 27aeb53

Browse files
authored
Merge pull request github#4615 from tamasvajk/feature/csharp9-lambda-modifiers
C#: Extract modifiers for lambdas (async, static)
2 parents 252692e + 864fce4 commit 27aeb53

File tree

13 files changed

+3892
-2
lines changed

13 files changed

+3892
-2
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* The `AnonymousFunctionExpr` class now extends `Modifiable`. This change allows storing the `async` modifier for lambdas, which was missing before, and the `static` modifier, which was added in C# 9.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ private void VisitParameter(ParameterSyntax p)
2424
private Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable<ParameterSyntax> @params)
2525
: base(info)
2626
{
27+
if (cx.GetModel(info.Node).GetSymbolInfo(info.Node).Symbol is IMethodSymbol symbol)
28+
{
29+
Modifier.ExtractModifiers(cx, info.Context.TrapWriter.Writer, this, symbol);
30+
}
31+
else
32+
{
33+
cx.ModelError(info.Node, "Unknown declared symbol");
34+
}
35+
2736
// No need to use `Populate` as the population happens later
2837
cx.PopulateLater(() =>
2938
{

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ class Stackalloc extends ArrayCreation {
407407
* An anonymous function. Either a lambda expression (`LambdaExpr`) or an
408408
* anonymous method expression (`AnonymousMethodExpr`).
409409
*/
410-
class AnonymousFunctionExpr extends Expr, Callable, @anonymous_function_expr {
410+
class AnonymousFunctionExpr extends Expr, Callable, Modifiable, @anonymous_function_expr {
411411
override string getName() { result = "<anonymous>" }
412412

413413
override Type getReturnType() {

csharp/ql/src/semmlecode.csharp.dbscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ specific_type_parameter_nullability(
541541

542542
@modifiable = @modifiable_direct | @event_accessor;
543543

544-
@modifiable_direct = @member | @accessor | @local_function;
544+
@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
545545

546546
modifiers(
547547
unique int id: @modifier,

csharp/ql/test/library-tests/csharp9/Discard.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
| Discard.cs:9:13:9:32 | (...) => ... | Discard.cs:9:25:9:25 | _`1 |
77
| Discard.cs:10:13:10:49 | delegate(...) { ... } | Discard.cs:10:27:10:27 | _ |
88
| Discard.cs:10:13:10:49 | delegate(...) { ... } | Discard.cs:10:34:10:34 | _`1 |
9+
| LambdaModifier.cs:11:11:11:27 | (...) => ... | LambdaModifier.cs:11:18:11:18 | x |
10+
| LambdaModifier.cs:12:11:12:20 | (...) => ... | LambdaModifier.cs:12:11:12:11 | x |
11+
| LambdaModifier.cs:13:11:13:51 | delegate(...) { ... } | LambdaModifier.cs:13:32:13:32 | x |
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
public class Class1
5+
{
6+
public async Task M1()
7+
{
8+
void m(Func<int, int> f) { }
9+
10+
const int z = 10;
11+
m(static x => x + z);
12+
m(x => x + z);
13+
m(static delegate (int x) { return x + z; });
14+
15+
await Task.Run(async () => { await Task.CompletedTask; });
16+
}
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
| Discard.cs:7:33:7:52 | (...) => ... | private |
2+
| Discard.cs:8:13:8:24 | (...) => ... | private |
3+
| Discard.cs:9:13:9:32 | (...) => ... | private |
4+
| Discard.cs:10:13:10:49 | delegate(...) { ... } | private |
5+
| LambdaModifier.cs:11:11:11:27 | (...) => ... | private |
6+
| LambdaModifier.cs:11:11:11:27 | (...) => ... | static |
7+
| LambdaModifier.cs:12:11:12:20 | (...) => ... | private |
8+
| LambdaModifier.cs:13:11:13:51 | delegate(...) { ... } | private |
9+
| LambdaModifier.cs:13:11:13:51 | delegate(...) { ... } | static |
10+
| LambdaModifier.cs:15:24:15:64 | (...) => ... | async |
11+
| LambdaModifier.cs:15:24:15:64 | (...) => ... | private |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import csharp
2+
3+
from AnonymousFunctionExpr anon, string modifier
4+
where anon.hasModifier(modifier)
5+
select anon, modifier

csharp/ql/test/library-tests/csharp9/LocalFunctions.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
noBody
22
| LocalFunction.cs:16:9:16:41 | localExtern |
33
localFunctionModifier
4+
| LambdaModifier.cs:8:9:8:36 | m | private |
45
| LocalFunction.cs:9:9:12:9 | mul | async |
56
| LocalFunction.cs:9:9:12:9 | mul | private |
67
| LocalFunction.cs:16:9:16:41 | localExtern | extern |

csharp/ql/test/library-tests/csharp9/PrintAst.expected

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,66 @@ Discard.cs:
4747
# 10| 4: [BlockStmt] {...}
4848
# 10| 0: [ReturnStmt] return ...;
4949
# 10| 0: [IntLiteral] 0
50+
LambdaModifier.cs:
51+
# 4| [Class] Class1
52+
# 6| 5: [Method] M1
53+
# 6| -1: [TypeMention] Task
54+
# 7| 4: [BlockStmt] {...}
55+
# 8| 0: [LocalFunctionStmt] m(...)
56+
# 8| 0: [LocalFunction] m
57+
#-----| 2: (Parameters)
58+
# 8| 0: [Parameter] f
59+
# 8| -1: [TypeMention] Func<Int32, Int32>
60+
# 8| 1: [TypeMention] int
61+
# 8| 2: [TypeMention] int
62+
# 8| 4: [BlockStmt] {...}
63+
# 10| 1: [LocalConstantDeclStmt] const ... ...;
64+
# 10| 0: [LocalVariableDeclAndInitExpr] Int32 z = ...
65+
# 10| -1: [TypeMention] int
66+
# 10| 0: [LocalVariableAccess] access to local variable z
67+
# 10| 1: [IntLiteral] 10
68+
# 11| 2: [ExprStmt] ...;
69+
# 11| 0: [LocalFunctionCall] call to local function m
70+
# 11| -1: [LocalFunctionAccess] access to local function m
71+
# 11| 0: [LambdaExpr] (...) => ...
72+
#-----| 2: (Parameters)
73+
# 11| 0: [Parameter] x
74+
# 11| 4: [AddExpr] ... + ...
75+
# 11| 0: [ParameterAccess] access to parameter x
76+
# 11| 1: [LocalVariableAccess] access to local variable z
77+
# 12| 3: [ExprStmt] ...;
78+
# 12| 0: [LocalFunctionCall] call to local function m
79+
# 12| -1: [LocalFunctionAccess] access to local function m
80+
# 12| 0: [LambdaExpr] (...) => ...
81+
#-----| 2: (Parameters)
82+
# 12| 0: [Parameter] x
83+
# 12| 4: [AddExpr] ... + ...
84+
# 12| 0: [ParameterAccess] access to parameter x
85+
# 12| 1: [LocalVariableAccess] access to local variable z
86+
# 13| 4: [ExprStmt] ...;
87+
# 13| 0: [LocalFunctionCall] call to local function m
88+
# 13| -1: [LocalFunctionAccess] access to local function m
89+
# 13| 0: [AnonymousMethodExpr] delegate(...) { ... }
90+
#-----| 2: (Parameters)
91+
# 13| 0: [Parameter] x
92+
# 13| -1: [TypeMention] int
93+
# 13| 4: [BlockStmt] {...}
94+
# 13| 0: [ReturnStmt] return ...;
95+
# 13| 0: [AddExpr] ... + ...
96+
# 13| 0: [ParameterAccess] access to parameter x
97+
# 13| 1: [LocalVariableAccess] access to local variable z
98+
# 15| 5: [ExprStmt] ...;
99+
# 15| 0: [AwaitExpr] await ...
100+
# 15| 0: [MethodCall] call to method Run
101+
# 15| -1: [TypeAccess] access to type Task
102+
# 15| 0: [TypeMention] Task
103+
# 15| 0: [LambdaExpr] (...) => ...
104+
# 15| 4: [BlockStmt] {...}
105+
# 15| 0: [ExprStmt] ...;
106+
# 15| 0: [AwaitExpr] await ...
107+
# 15| 0: [PropertyCall] access to property CompletedTask
108+
# 15| -1: [TypeAccess] access to type Task
109+
# 15| 0: [TypeMention] Task
50110
LocalFunction.cs:
51111
# 4| [Class] LocalFunction
52112
# 6| 5: [Method] M1

0 commit comments

Comments
 (0)