mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge pull request #7749 from michaelnebel/csharp/lambda-improvements
C# 10 - Lambda improvements.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Remove 'lambda_expr_return_type' relation.
|
||||
compatibility: backwards
|
||||
lambda_expr_return_type.rel: delete
|
||||
@@ -22,12 +22,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
Parameter.Create(Context, symbol, this);
|
||||
}
|
||||
|
||||
private Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable<ParameterSyntax> @params)
|
||||
private Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable<ParameterSyntax> @params, TypeSyntax? @return)
|
||||
: base(info)
|
||||
{
|
||||
if (Context.GetModel(info.Node).GetSymbolInfo(info.Node).Symbol is IMethodSymbol symbol)
|
||||
{
|
||||
Modifier.ExtractModifiers(Context, info.Context.TrapWriter.Writer, this, symbol);
|
||||
Attribute.ExtractAttributes(Context, symbol, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -40,6 +41,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
foreach (var param in @params)
|
||||
VisitParameter(param);
|
||||
|
||||
if (@return is not null)
|
||||
{
|
||||
var symbol = Context.GetType(@return);
|
||||
var type = Entities.Type.Create(Context, symbol);
|
||||
var trapFile = Context.TrapWriter.Writer;
|
||||
trapFile.lambda_expr_return_type(this, type.TypeRef);
|
||||
}
|
||||
if (body is ExpressionSyntax exprBody)
|
||||
Create(Context, exprBody, this, 0);
|
||||
else if (body is BlockSyntax blockBody)
|
||||
@@ -50,17 +58,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
}
|
||||
|
||||
private Lambda(ExpressionNodeInfo info, ParenthesizedLambdaExpressionSyntax node)
|
||||
: this(info.SetKind(ExprKind.LAMBDA), node.Body, node.ParameterList.Parameters) { }
|
||||
: this(info.SetKind(ExprKind.LAMBDA), node.Body, node.ParameterList.Parameters, node.ReturnType) { }
|
||||
|
||||
public static Lambda Create(ExpressionNodeInfo info, ParenthesizedLambdaExpressionSyntax node) => new Lambda(info, node);
|
||||
|
||||
private Lambda(ExpressionNodeInfo info, SimpleLambdaExpressionSyntax node)
|
||||
: this(info.SetKind(ExprKind.LAMBDA), node.Body, Enumerators.Singleton(node.Parameter)) { }
|
||||
: this(info.SetKind(ExprKind.LAMBDA), node.Body, Enumerators.Singleton(node.Parameter), null) { }
|
||||
|
||||
public static Lambda Create(ExpressionNodeInfo info, SimpleLambdaExpressionSyntax node) => new Lambda(info, node);
|
||||
|
||||
private Lambda(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) :
|
||||
this(info.SetKind(ExprKind.ANONYMOUS_METHOD), node.Body, node.ParameterList is null ? Enumerable.Empty<ParameterSyntax>() : node.ParameterList.Parameters)
|
||||
this(info.SetKind(ExprKind.ANONYMOUS_METHOD), node.Body, node.ParameterList is null ? Enumerable.Empty<ParameterSyntax>() : node.ParameterList.Parameters, null)
|
||||
{ }
|
||||
|
||||
public static Lambda Create(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) => new Lambda(info, node);
|
||||
|
||||
@@ -215,6 +215,9 @@ namespace Semmle.Extraction.CSharp
|
||||
internal static void indexers(this TextWriter trapFile, Indexer propKey, string name, Type declaringType, Type memberType, Indexer unboundProperty) =>
|
||||
trapFile.WriteTuple("indexers", propKey, name, declaringType, memberType, unboundProperty);
|
||||
|
||||
internal static void lambda_expr_return_type(this TextWriter trapFile, Lambda expr, Type returnType) =>
|
||||
trapFile.WriteTuple("lambda_expr_return_type", expr, returnType);
|
||||
|
||||
internal static void local_function_stmts(this TextWriter trapFile, Entities.Statements.LocalFunction fnStmt, LocalFunction fn) =>
|
||||
trapFile.WriteTuple("local_function_stmts", fnStmt, fn);
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
Added support for C# 10 lambda improvements
|
||||
* Explicit return types on lambda expressions.
|
||||
* Lambda expression can be tagged with method and return value attributes.
|
||||
@@ -10,8 +10,8 @@ private import TypeRef
|
||||
* An element that can have attributes. Either an assembly (`Assembly`), a field (`Field`),
|
||||
* a parameter (`Parameter`), an operator (`Operator`), a method (`Method`), a constructor (`Constructor`),
|
||||
* a destructor (`Destructor`), a callable accessor (`CallableAccessor`), a value or reference type
|
||||
* (`ValueOrRefType`), a declaration with accessors (`DeclarationWithAccessors`), or a local function
|
||||
* (`LocalFunction`).
|
||||
* (`ValueOrRefType`), a declaration with accessors (`DeclarationWithAccessors`), a local function
|
||||
* (`LocalFunction`) or a lambda expression (`LambdaExp`).
|
||||
*/
|
||||
class Attributable extends @attributable {
|
||||
/** Gets an attribute attached to this element, if any. */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import Expr
|
||||
import semmle.code.csharp.Callable
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
private import semmle.code.csharp.TypeRef
|
||||
|
||||
/**
|
||||
* Either an object initializer (`ObjectInitializer`) or a collection
|
||||
@@ -434,6 +435,12 @@ class AnonymousFunctionExpr extends Expr, Callable, Modifiable, @anonymous_funct
|
||||
* A lambda expression, for example `(int x) => x + 1`.
|
||||
*/
|
||||
class LambdaExpr extends AnonymousFunctionExpr, @lambda_expr {
|
||||
/* Holds if this lambda expression has explicit return type. */
|
||||
predicate hasExplicitReturnType() { lambda_expr_return_type(this, _) }
|
||||
|
||||
/* Gets the explicit return type of this lambda expression, if any. */
|
||||
Type getExplicitReturnType() { lambda_expr_return_type(this, getTypeRef(result)) }
|
||||
|
||||
override string toString() { result = "(...) => ..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LambdaExpr" }
|
||||
|
||||
@@ -191,7 +191,7 @@ sourceLocationPrefix(
|
||||
|
||||
@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
|
||||
| @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
|
||||
| @local_function;
|
||||
| @local_function | @lambda_expr;
|
||||
|
||||
/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
|
||||
|
||||
@@ -1269,6 +1269,10 @@ expr_argument_name(
|
||||
unique int id: @expr ref,
|
||||
string name: string ref);
|
||||
|
||||
lambda_expr_return_type(
|
||||
unique int id: @lambda_expr ref,
|
||||
int type_id: @type_or_ref ref);
|
||||
|
||||
/** CONTROL/DATA FLOW **/
|
||||
|
||||
@control_flow_element = @stmt | @expr;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add relation 'lambda_expr_return_type' for lambdas with explicit return types.
|
||||
compatibility: backwards
|
||||
20
csharp/ql/test/library-tests/csharp10/Lambda.cs
Normal file
20
csharp/ql/test/library-tests/csharp10/Lambda.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
public class Lambda
|
||||
{
|
||||
public void M1()
|
||||
{
|
||||
// Examples need for implicitly typed lambdas.
|
||||
Func<int, string> f1 = (int x) => x.ToString();
|
||||
var f2 = (int x) => x.ToString();
|
||||
|
||||
// Examples need for explicit return type for implicitly and explicitly typed lambda.
|
||||
var f3 = object (bool b) => b ? "1" : 0;
|
||||
Func<bool, object> f4 = object (bool b) => b ? "1" : 0;
|
||||
|
||||
// Examples needed for explicit return type for downcast.
|
||||
var f5 = int (bool b) => b ? 1 : 0;
|
||||
var f6 = object (bool b) => b ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
18
csharp/ql/test/library-tests/csharp10/LambdaAttributes.cs
Normal file
18
csharp/ql/test/library-tests/csharp10/LambdaAttributes.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
public class Example : Attribute
|
||||
{
|
||||
public Example(int x) { }
|
||||
}
|
||||
|
||||
public class LambdaAttributes
|
||||
{
|
||||
|
||||
public void M1()
|
||||
{
|
||||
// Examples needed for attributes.
|
||||
var f7 = ([Example(1)] int x) => x.ToString(); // Parameter attribute
|
||||
var f8 =[Example(2)] (int x) => x.ToString(); // Lambda attribute
|
||||
var f9 =[return: Example(3)] (int x) => x.ToString(); // Return value attribute
|
||||
}
|
||||
}
|
||||
23
csharp/ql/test/library-tests/csharp10/lambda.expected
Normal file
23
csharp/ql/test/library-tests/csharp10/lambda.expected
Normal file
@@ -0,0 +1,23 @@
|
||||
lambdaDeclaration
|
||||
| Func<bool, int> | Lambda.cs:16:13:16:14 | f5 | Lambda.cs:16:18:16:42 | (...) => ... |
|
||||
| Func<bool, object> | Lambda.cs:12:13:12:14 | f3 | Lambda.cs:12:18:12:47 | (...) => ... |
|
||||
| Func<bool, object> | Lambda.cs:13:28:13:29 | f4 | Lambda.cs:13:33:13:62 | (...) => ... |
|
||||
| Func<bool, object> | Lambda.cs:17:13:17:14 | f6 | Lambda.cs:17:18:17:45 | (...) => ... |
|
||||
| Func<int, string> | Lambda.cs:8:27:8:28 | f1 | Lambda.cs:8:32:8:54 | (...) => ... |
|
||||
| Func<int, string> | Lambda.cs:9:13:9:14 | f2 | Lambda.cs:9:18:9:40 | (...) => ... |
|
||||
| Func<int, string> | LambdaAttributes.cs:14:13:14:14 | f7 | LambdaAttributes.cs:14:18:14:53 | (...) => ... |
|
||||
| Func<int, string> | LambdaAttributes.cs:15:13:15:14 | f8 | LambdaAttributes.cs:15:17:15:52 | (...) => ... |
|
||||
| Func<int, string> | LambdaAttributes.cs:16:13:16:14 | f9 | LambdaAttributes.cs:16:17:16:60 | (...) => ... |
|
||||
lambdaDeclarationNatural
|
||||
| Func<bool, int> | Lambda.cs:16:13:16:14 | f5 | Lambda.cs:16:18:16:42 | (...) => ... |
|
||||
| Func<bool, object> | Lambda.cs:12:13:12:14 | f3 | Lambda.cs:12:18:12:47 | (...) => ... |
|
||||
| Func<bool, object> | Lambda.cs:17:13:17:14 | f6 | Lambda.cs:17:18:17:45 | (...) => ... |
|
||||
| Func<int, string> | Lambda.cs:9:13:9:14 | f2 | Lambda.cs:9:18:9:40 | (...) => ... |
|
||||
| Func<int, string> | LambdaAttributes.cs:14:13:14:14 | f7 | LambdaAttributes.cs:14:18:14:53 | (...) => ... |
|
||||
| Func<int, string> | LambdaAttributes.cs:15:13:15:14 | f8 | LambdaAttributes.cs:15:17:15:52 | (...) => ... |
|
||||
| Func<int, string> | LambdaAttributes.cs:16:13:16:14 | f9 | LambdaAttributes.cs:16:17:16:60 | (...) => ... |
|
||||
lambdaDeclarationExplicitReturnType
|
||||
| Func<bool, int> | int | int | Lambda.cs:16:13:16:14 | f5 | Lambda.cs:16:18:16:42 | (...) => ... |
|
||||
| Func<bool, object> | object | object | Lambda.cs:12:13:12:14 | f3 | Lambda.cs:12:18:12:47 | (...) => ... |
|
||||
| Func<bool, object> | object | object | Lambda.cs:13:28:13:29 | f4 | Lambda.cs:13:33:13:62 | (...) => ... |
|
||||
| Func<bool, object> | object | object | Lambda.cs:17:13:17:14 | f6 | Lambda.cs:17:18:17:45 | (...) => ... |
|
||||
25
csharp/ql/test/library-tests/csharp10/lambda.ql
Normal file
25
csharp/ql/test/library-tests/csharp10/lambda.ql
Normal file
@@ -0,0 +1,25 @@
|
||||
import csharp
|
||||
|
||||
private predicate getLambda(
|
||||
LocalVariableDeclAndInitExpr e, string type, LocalVariable v, LambdaExpr lexp
|
||||
) {
|
||||
lexp = e.getRValue() and
|
||||
v = e.getTargetVariable() and
|
||||
type = e.getType().toStringWithTypes()
|
||||
}
|
||||
|
||||
query predicate lambdaDeclaration(string type, LocalVariable v, LambdaExpr lexp) {
|
||||
getLambda(_, type, v, lexp)
|
||||
}
|
||||
|
||||
query predicate lambdaDeclarationNatural(string type, LocalVariable v, LambdaExpr lexp) {
|
||||
exists(LocalVariableDeclAndInitExpr e | getLambda(e, type, v, lexp) and e.isImplicitlyTyped())
|
||||
}
|
||||
|
||||
query predicate lambdaDeclarationExplicitReturnType(
|
||||
string type, string explicit, string actual, LocalVariable v, LambdaExpr lexp
|
||||
) {
|
||||
getLambda(_, type, v, lexp) and
|
||||
explicit = lexp.getExplicitReturnType().toStringWithTypes() and
|
||||
actual = lexp.getReturnType().toStringWithTypes()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
allAttributes
|
||||
| LambdaAttributes.cs:14:20:14:26 | [Example(...)] | LambdaAttributes.cs:14:28:14:28 | 1 | Parameter |
|
||||
| LambdaAttributes.cs:15:18:15:24 | [Example(...)] | LambdaAttributes.cs:15:26:15:26 | 2 | LambdaExpr |
|
||||
| LambdaAttributes.cs:16:26:16:32 | [return: Example(...)] | LambdaAttributes.cs:16:34:16:34 | 3 | LambdaExpr |
|
||||
lambdaAttributes
|
||||
| LambdaAttributes.cs:15:18:15:24 | [Example(...)] | LambdaAttributes.cs:15:26:15:26 | 2 | LambdaAttributes.cs:15:17:15:52 | (...) => ... |
|
||||
| LambdaAttributes.cs:16:26:16:32 | [return: Example(...)] | LambdaAttributes.cs:16:34:16:34 | 3 | LambdaAttributes.cs:16:17:16:60 | (...) => ... |
|
||||
11
csharp/ql/test/library-tests/csharp10/lambdaAttributes.ql
Normal file
11
csharp/ql/test/library-tests/csharp10/lambdaAttributes.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
import csharp
|
||||
|
||||
query predicate allAttributes(Attribute a, Expr arg, string c) {
|
||||
a.fromSource() and
|
||||
arg = a.getArgument(0) and
|
||||
c = a.getTarget().(Element).getAPrimaryQlClass()
|
||||
}
|
||||
|
||||
query predicate lambdaAttributes(Attribute a, Expr arg, LambdaExpr l) {
|
||||
allAttributes(a, arg, _) and a.getTarget() = l
|
||||
}
|
||||
Reference in New Issue
Block a user