Merge pull request #1392 from calumgrant/cs/cs8/static-using-null

C#: More C# 8 features
This commit is contained in:
Tom Hvitved 2019-06-05 14:21:49 +02:00 коммит произвёл GitHub
Родитель a6da4996a7 c88359b9c7
Коммит 51d6858cd0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
39 изменённых файлов: 4087 добавлений и 51 удалений

Просмотреть файл

@ -13,6 +13,10 @@
* The following C# 8 features are now extracted: * The following C# 8 features are now extracted:
- Range expressions - Range expressions
- Recursive patterns - Recursive patterns
- Using declaration statements
- `static` modifiers on local functions
- Null-coalescing assignment expressions
* The `unmanaged` type parameter constraint is now extracted. * The `unmanaged` type parameter constraint is now extracted.
## Changes to QL libraries ## Changes to QL libraries
@ -20,6 +24,7 @@
* The class `Attribute` has two new predicates: `getConstructorArgument()` and `getNamedArgument()`. The first predicate returns arguments to the underlying constructor call and the latter returns named arguments for initializing fields and properties. * The class `Attribute` has two new predicates: `getConstructorArgument()` and `getNamedArgument()`. The first predicate returns arguments to the underlying constructor call and the latter returns named arguments for initializing fields and properties.
* The class `TypeParameterConstraints` has a new predicate `hasUnmanagedTypeConstraint()`, indicating that the type parameter has the `unmanaged` constraint. * The class `TypeParameterConstraints` has a new predicate `hasUnmanagedTypeConstraint()`, indicating that the type parameter has the `unmanaged` constraint.
* The following QL classes have been added to model C# 8 features: * The following QL classes have been added to model C# 8 features:
- Class `AssignCoalesceExpr` models null-coalescing assignment, for example `x ??= y`
- Class `IndexExpr` models from-end index expressions, for example `^1` - Class `IndexExpr` models from-end index expressions, for example `^1`
- Class `PatternExpr` is an `Expr` that appears in a pattern. It has the new subclasses `DiscardPatternExpr`, `LabeledPatternExpr`, `RecursivePatternExpr`, `TypeAccessPatternExpr`, `TypePatternExpr`, and `VariablePatternExpr`. - Class `PatternExpr` is an `Expr` that appears in a pattern. It has the new subclasses `DiscardPatternExpr`, `LabeledPatternExpr`, `RecursivePatternExpr`, `TypeAccessPatternExpr`, `TypePatternExpr`, and `VariablePatternExpr`.
- Class `PatternMatch` models a pattern being matched. It has the subclasses `Case` and `IsExpr`. - Class `PatternMatch` models a pattern being matched. It has the subclasses `Case` and `IsExpr`.
@ -31,5 +36,6 @@
- Classes `IsConstantExpr`, `IsTypeExpr` and `IsPatternExpr` are deprecated in favour of `IsExpr` - Classes `IsConstantExpr`, `IsTypeExpr` and `IsPatternExpr` are deprecated in favour of `IsExpr`
- Class `Switch` models both `SwitchExpr` and `SwitchStmt` - Class `Switch` models both `SwitchExpr` and `SwitchStmt`
- Class `Case` models both `CaseStmt` and `SwitchCaseExpr` - Class `Case` models both `CaseStmt` and `SwitchCaseExpr`
- Class `UsingStmt` models both `UsingBlockStmt` and `UsingDeclStmt`
## Changes to autobuilder ## Changes to autobuilder

Просмотреть файл

@ -71,6 +71,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.ASSIGN_LSHIFT; return ExprKind.ASSIGN_LSHIFT;
case SyntaxKind.GreaterThanGreaterThanEqualsToken: case SyntaxKind.GreaterThanGreaterThanEqualsToken:
return ExprKind.ASSIGN_RSHIFT; return ExprKind.ASSIGN_RSHIFT;
case SyntaxKind.QuestionQuestionEqualsToken:
return ExprKind.ASSIGN_COALESCE;
default: default:
cx.ModelError(syntax, "Unrecognised assignment type " + GetKind(cx, syntax)); cx.ModelError(syntax, "Unrecognised assignment type " + GetKind(cx, syntax));
return ExprKind.UNKNOWN; return ExprKind.UNKNOWN;
@ -142,6 +144,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.SUB; return ExprKind.SUB;
case ExprKind.ASSIGN_XOR: case ExprKind.ASSIGN_XOR:
return ExprKind.BIT_XOR; return ExprKind.BIT_XOR;
case ExprKind.ASSIGN_COALESCE:
return ExprKind.NULL_COALESCING;
default: default:
cx.ModelError(Syntax, "Couldn't unfold assignment of type " + kind); cx.ModelError(Syntax, "Couldn't unfold assignment of type " + kind);
return ExprKind.UNKNOWN; return ExprKind.UNKNOWN;

Просмотреть файл

@ -80,6 +80,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.RightShiftAssignmentExpression: case SyntaxKind.RightShiftAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.DivideAssignmentExpression:
case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression:
case SyntaxKind.CoalesceAssignmentExpression:
return Assignment.Create(info); return Assignment.Create(info);
case SyntaxKind.ObjectCreationExpression: case SyntaxKind.ObjectCreationExpression:

Просмотреть файл

@ -1,4 +1,6 @@
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Linq;
namespace Semmle.Extraction.CSharp.Entities namespace Semmle.Extraction.CSharp.Entities
{ {
@ -39,6 +41,18 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate() public override void Populate()
{ {
PopulateMethod(); PopulateMethod();
// There is a "bug" in Roslyn whereby the IMethodSymbol associated with the local function symbol
// is always static, so we need to go to the syntax reference of the local function to see whether
// the "static" modifier is present.
if (symbol.DeclaringSyntaxReferences.SingleOrDefault().GetSyntax() is LocalFunctionStatementSyntax fn)
{
foreach(var modifier in fn.Modifiers)
{
Modifier.HasModifier(Context, this, modifier.Text);
}
}
var originalDefinition = IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition); var originalDefinition = IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition);
var returnType = Type.Create(Context, symbol.ReturnType); var returnType = Type.Create(Context, symbol.ReturnType);
Context.Emit(Tuples.local_functions(this, symbol.Name, returnType, originalDefinition)); Context.Emit(Tuples.local_functions(this, symbol.Name, returnType, originalDefinition));

Просмотреть файл

@ -6,8 +6,19 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
{ {
class LocalDeclaration : Statement<LocalDeclarationStatementSyntax> class LocalDeclaration : Statement<LocalDeclarationStatementSyntax>
{ {
static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt)
{
if (declStmt.UsingKeyword.RawKind != 0)
return StmtKind.USING_DECL;
if (declStmt.IsConst)
return StmtKind.CONST_DECL;
return StmtKind.VAR_DECL;
}
LocalDeclaration(Context cx, LocalDeclarationStatementSyntax declStmt, IStatementParentEntity parent, int child) LocalDeclaration(Context cx, LocalDeclarationStatementSyntax declStmt, IStatementParentEntity parent, int child)
: base(cx, declStmt, declStmt.IsConst ? StmtKind.CONST_DECL : StmtKind.VAR_DECL, parent, child) { } : base(cx, declStmt, GetKind(declStmt), parent, child) { }
public static LocalDeclaration Create(Context cx, LocalDeclarationStatementSyntax node, IStatementParentEntity parent, int child) public static LocalDeclaration Create(Context cx, LocalDeclarationStatementSyntax node, IStatementParentEntity parent, int child)
{ {

Просмотреть файл

@ -112,6 +112,7 @@ namespace Semmle.Extraction.Kinds
RECURSIVE_PATTERN = 115, RECURSIVE_PATTERN = 115,
PROPERTY_PATTERN = 116, PROPERTY_PATTERN = 116,
POSITIONAL_PATTERN = 117, POSITIONAL_PATTERN = 117,
SWITCH_CASE = 118 SWITCH_CASE = 118,
ASSIGN_COALESCE = 119
} }
} }

Просмотреть файл

@ -34,6 +34,7 @@ namespace Semmle.Extraction.Kinds // lgtm[cs/similar-file]
LABEL = 27, LABEL = 27,
CATCH = 28, CATCH = 28,
CASE = 29, CASE = 29,
LOCAL_FUNCTION = 30 LOCAL_FUNCTION = 30,
USING_DECL = 31
} }
} }

Просмотреть файл

@ -903,7 +903,7 @@ class ExplicitConversionOperator extends ConversionOperator {
* } * }
* ``` * ```
*/ */
class LocalFunction extends Callable, @local_function { class LocalFunction extends Callable, Modifiable, @local_function {
override string getName() { local_functions(this, result, _, _) } override string getName() { local_functions(this, result, _, _) }
override LocalFunction getSourceDeclaration() { local_functions(this, _, _, result) } override LocalFunction getSourceDeclaration() { local_functions(this, _, _, result) }

Просмотреть файл

@ -1115,40 +1115,16 @@ class LockStmt extends Stmt, @lock_stmt {
} }
/** /**
* A `using` statement, for example * A using block or declaration. Either a using declaration (`UsingDeclStmt`) or
* * a using block (`UsingBlockStmt`).
* ```
* using (FileStream f = File.Open("settings.xml")) {
* ...
* }
* ```
*/ */
class UsingStmt extends Stmt, @using_stmt { class UsingStmt extends Stmt, @using_stmt {
/** Gets the `i`th local variable of this `using` statement. */
LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() }
/** Gets a local variable of this `using` statement. */
LocalVariable getAVariable() { result = this.getVariable(_) }
/** Gets the `i`th local variable declaration of this `using` statement. */ /** Gets the `i`th local variable declaration of this `using` statement. */
LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) } LocalVariableDeclExpr getVariableDeclExpr(int i) { none() }
/** Gets a local variable declaration of this `using` statement. */ /** Gets a local variable declaration of this `using` statement. */
LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) } LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) }
/**
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
Expr getExpr() { result = this.getChild(0) }
/** /**
* Gets an expression that is used in this `using` statement. Either an * Gets an expression that is used in this `using` statement. Either an
* expression assigned to a variable, for example `File.Open("settings.xml")` * expression assigned to a variable, for example `File.Open("settings.xml")`
@ -1169,14 +1145,69 @@ class UsingStmt extends Stmt, @using_stmt {
* } * }
* ``` * ```
*/ */
Expr getAnExpr() { Expr getAnExpr() { none() }
/**
* DEPRECATED: Use UsingBlockStmt.getExpr() instead.
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
deprecated Expr getExpr() { none() }
/**
* DEPRECATED: Use UsingBlockStmt.getBody() instead.
* Gets the body of this `using` statement.
*/
deprecated Stmt getBody() { none() }
}
/**
* A `using` block statement, for example
*
* ```
* using (FileStream f = File.Open("settings.xml")) {
* ...
* }
* ```
*/
class UsingBlockStmt extends UsingStmt, @using_block_stmt {
/** Gets the `i`th local variable of this `using` statement. */
LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() }
/** Gets a local variable of this `using` statement. */
LocalVariable getAVariable() { result = this.getVariable(_) }
/** Gets the `i`th local variable declaration of this `using` statement. */
override LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) }
/**
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
override Expr getExpr() { result = this.getChild(0) }
override Expr getAnExpr() {
result = this.getAVariableDeclExpr().getInitializer() result = this.getAVariableDeclExpr().getInitializer()
or or
result = this.getExpr() result = this.getExpr()
} }
/** Gets the body of this `using` statement. */ /** Gets the body of this `using` statement. */
Stmt getBody() { result.getParent() = this } override Stmt getBody() { result.getParent() = this }
override string toString() { result = "using (...) {...}" } override string toString() { result = "using (...) {...}" }
} }
@ -1254,6 +1285,29 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt {
override string toString() { result = "const ... ...;" } override string toString() { result = "const ... ...;" }
} }
/**
* A `using` declaration statement, for example
*
* ```
* using FileStream f = File.Open("settings.xml");
* ```
*/
class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt {
override string toString() { result = "using ... ...;" }
override LocalVariableDeclExpr getAVariableDeclExpr() {
result = LocalVariableDeclStmt.super.getAVariableDeclExpr()
}
override LocalVariableDeclExpr getVariableDeclExpr(int n) {
result = LocalVariableDeclStmt.super.getVariableDeclExpr(n)
}
override Expr getAnExpr() {
result = this.getAVariableDeclExpr().getInitializer()
}
}
/** /**
* An empty statement, for example line 2 in * An empty statement, for example line 2 in
* *

Просмотреть файл

@ -468,7 +468,7 @@ module ControlFlow {
override ControlFlowElement getChildElement(int i) { override ControlFlowElement getChildElement(int i) {
not this instanceof GeneralCatchClause and not this instanceof GeneralCatchClause and
not this instanceof FixedStmt and not this instanceof FixedStmt and
not this instanceof UsingStmt and not this instanceof UsingBlockStmt and
result = this.getChild(i) result = this.getChild(i)
or or
this = any(GeneralCatchClause gcc | i = 0 and result = gcc.getBlock()) this = any(GeneralCatchClause gcc | i = 0 and result = gcc.getBlock())
@ -480,7 +480,7 @@ module ControlFlow {
i = max(int j | exists(fs.getVariableDeclExpr(j))) + 1 i = max(int j | exists(fs.getVariableDeclExpr(j))) + 1
) )
or or
this = any(UsingStmt us | this = any(UsingBlockStmt us |
if exists(us.getExpr()) if exists(us.getExpr())
then ( then (
result = us.getExpr() and result = us.getExpr() and

Просмотреть файл

@ -230,3 +230,10 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr {
class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr { class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr {
override string toString() { result = "... -= ..." } override string toString() { result = "... -= ..." }
} }
/**
* A null-coalescing assignment operation, for example `x ??= y`.
*/
class AssignCoalesceExpr extends AssignOperation, @assign_coalesce_expr {
override string toString() { result = "... ??= ..." }
}

Просмотреть файл

@ -526,7 +526,7 @@ specific_type_parameter_constraints(
@modifiable = @modifiable_direct | @event_accessor; @modifiable = @modifiable_direct | @event_accessor;
@modifiable_direct = @member | @accessor; @modifiable_direct = @member | @accessor | @local_function;
modifiers( modifiers(
unique int id: @modifier, unique int id: @modifier,
@ -798,7 +798,7 @@ case @stmt.kind of
| 18 = @checked_stmt | 18 = @checked_stmt
| 19 = @unchecked_stmt | 19 = @unchecked_stmt
| 20 = @lock_stmt | 20 = @lock_stmt
| 21 = @using_stmt | 21 = @using_block_stmt
| 22 = @var_decl_stmt | 22 = @var_decl_stmt
| 23 = @const_decl_stmt | 23 = @const_decl_stmt
| 24 = @empty_stmt | 24 = @empty_stmt
@ -808,11 +808,14 @@ case @stmt.kind of
| 28 = @catch | 28 = @catch
| 29 = @case_stmt | 29 = @case_stmt
| 30 = @local_function_stmt | 30 = @local_function_stmt
| 31 = @using_decl_stmt
; ;
@using_stmt = @using_block_stmt | @using_decl_stmt;
@labeled_stmt = @label_stmt | @case; @labeled_stmt = @label_stmt | @case;
@decl_stmt = @var_decl_stmt | @const_decl_stmt; @decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
@cond_stmt = @if_stmt | @switch_stmt; @cond_stmt = @if_stmt | @switch_stmt;
@ -983,6 +986,7 @@ case @expr.kind of
| 116 = @property_pattern_expr | 116 = @property_pattern_expr
| 117 = @positional_pattern_expr | 117 = @positional_pattern_expr
| 118 = @switch_case_expr | 118 = @switch_case_expr
| 119 = @assign_coalesce_expr
; ;
@switch = @switch_stmt | @switch_expr; @switch = @switch_stmt | @switch_expr;
@ -995,7 +999,7 @@ case @expr.kind of
| @string_literal_expr | @null_literal_expr; | @string_literal_expr | @null_literal_expr;
@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; @assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr; @assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
@assign_event_expr = @add_event_expr | @remove_event_expr; @assign_event_expr = @add_event_expr | @remove_event_expr;
@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr @assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr

Просмотреть файл

@ -360,10 +360,14 @@
<v>1854</v> <v>1854</v>
</e> </e>
<e> <e>
<k>@using_stmt</k> <k>@using_block_stmt</k>
<v>5815</v> <v>5815</v>
</e> </e>
<e> <e>
<k>@using_decl_stmt</k>
<v>1000</v>
</e>
<e>
<k>@var_decl_stmt</k> <k>@var_decl_stmt</k>
<v>243866</v> <v>243866</v>
</e> </e>
@ -688,6 +692,10 @@
<v>116</v> <v>116</v>
</e> </e>
<e> <e>
<k>@assign_coalesce_expr</k>
<v>116</v>
</e>
<e>
<k>@object_init_expr</k> <k>@object_init_expr</k>
<v>5320</v> <v>5320</v>
</e> </e>

Просмотреть файл

@ -104,6 +104,7 @@
| Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | read | | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | read |
| Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | write | | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | write |
| Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | s | write | | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | s | write |
| Assignables.cs:138:19:138:19 | access to local variable x | Assignables.cs:138:19:138:19 | x | write |
| Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:5:30:5:30 | x | write | | Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:5:30:5:30 | x | write |
| Discards.cs:20:32:20:32 | Boolean z | Discards.cs:20:32:20:32 | z | write | | Discards.cs:20:32:20:32 | Boolean z | Discards.cs:20:32:20:32 | z | write |
| Discards.cs:25:27:25:30 | access to parameter args | Discards.cs:23:27:23:30 | args | read | | Discards.cs:25:27:25:30 | access to parameter args | Discards.cs:23:27:23:30 | args | read |

Просмотреть файл

@ -87,6 +87,7 @@
| Assignables.cs:132:13:132:13 | x | Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:13 | access to local variable x | Assignables.cs:132:17:132:17 | 0 | certain | | Assignables.cs:132:13:132:13 | x | Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:13 | access to local variable x | Assignables.cs:132:17:132:17 | 0 | certain |
| Assignables.cs:132:13:132:13 | x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | <none> | certain | | Assignables.cs:132:13:132:13 | x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | <none> | certain |
| Assignables.cs:133:29:133:29 | s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | <none> | certain | | Assignables.cs:133:29:133:29 | s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | <none> | certain |
| Assignables.cs:138:19:138:19 | x | Assignables.cs:138:19:138:50 | MemoryStream x = ... | Assignables.cs:138:19:138:19 | access to local variable x | Assignables.cs:138:23:138:50 | object creation of type MemoryStream | certain |
| Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | <none> | Discards.cs:5:30:5:30 | <none> | certain | | Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | <none> | Discards.cs:5:30:5:30 | <none> | certain |
| Discards.cs:5:30:5:30 | x | Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:7:13:7:17 | false | certain | | Discards.cs:5:30:5:30 | x | Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:7:13:7:17 | false | certain |
| Discards.cs:19:14:19:14 | x | Discards.cs:19:9:19:29 | ... = ... | Discards.cs:19:9:19:29 | <none> | Discards.cs:19:9:19:29 | <none> | certain | | Discards.cs:19:14:19:14 | x | Discards.cs:19:9:19:29 | ... = ... | Discards.cs:19:9:19:29 | <none> | Discards.cs:19:9:19:29 | <none> | certain |

Просмотреть файл

@ -86,6 +86,7 @@
| Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:17 | Int32 x = ... | | Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:17 | Int32 x = ... |
| Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:9:133:30 | delegate call | | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:9:133:30 | delegate call |
| Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:9:133:30 | delegate call | | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:9:133:30 | delegate call |
| Assignables.cs:138:19:138:50 | MemoryStream x = ... | Assignables.cs:138:19:138:50 | MemoryStream x = ... |
| Discards.cs:5:30:5:30 | x | Discards.cs:5:19:5:19 | enter f | | Discards.cs:5:30:5:30 | x | Discards.cs:5:19:5:19 | enter f |
| Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:17 | ... = ... | | Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:17 | ... = ... |
| Discards.cs:13:9:13:20 | ... = ... | Discards.cs:13:9:13:20 | ... = ... | | Discards.cs:13:9:13:20 | ... = ... | Discards.cs:13:9:13:20 | ... = ... |

Просмотреть файл

@ -132,4 +132,11 @@ class Assignables
var x = 0; var x = 0;
d(ref x, out string s); d(ref x, out string s);
} }
void UsingDeclarations()
{
using var x = new System.IO.MemoryStream();
}
} }
// semmle-extractor-options: /langversion:8.0

Просмотреть файл

@ -95,6 +95,7 @@
| Assignables.cs:130:31:130:31 | d | | Assignables.cs:130:31:130:31 | d |
| Assignables.cs:132:13:132:13 | x | | Assignables.cs:132:13:132:13 | x |
| Assignables.cs:133:29:133:29 | s | | Assignables.cs:133:29:133:29 | s |
| Assignables.cs:138:19:138:19 | x |
| Discards.cs:5:6:5:8 | Item1 | | Discards.cs:5:6:5:8 | Item1 |
| Discards.cs:5:11:5:16 | Item2 | | Discards.cs:5:11:5:16 | Item2 |
| Discards.cs:5:30:5:30 | x | | Discards.cs:5:30:5:30 | x |

Просмотреть файл

@ -37,6 +37,7 @@
| Assignables.cs:125:13:125:13 | s | Assignables.cs:125:17:125:25 | nameof(...) | | Assignables.cs:125:13:125:13 | s | Assignables.cs:125:17:125:25 | nameof(...) |
| Assignables.cs:125:13:125:13 | s | Assignables.cs:126:13:126:30 | nameof(...) | | Assignables.cs:125:13:125:13 | s | Assignables.cs:126:13:126:30 | nameof(...) |
| Assignables.cs:132:13:132:13 | x | Assignables.cs:132:17:132:17 | 0 | | Assignables.cs:132:13:132:13 | x | Assignables.cs:132:17:132:17 | 0 |
| Assignables.cs:138:19:138:19 | x | Assignables.cs:138:23:138:50 | object creation of type MemoryStream |
| Discards.cs:5:30:5:30 | x | Discards.cs:7:13:7:17 | false | | Discards.cs:5:30:5:30 | x | Discards.cs:7:13:7:17 | false |
| Finally.cs:7:13:7:13 | i | Finally.cs:7:17:7:17 | 0 | | Finally.cs:7:13:7:13 | i | Finally.cs:7:17:7:17 | 0 |
| Finally.cs:7:13:7:13 | i | Finally.cs:15:17:15:17 | 1 | | Finally.cs:7:13:7:13 | i | Finally.cs:15:17:15:17 | 1 |

Просмотреть файл

@ -0,0 +1,10 @@
using System;
class NullCoalescingAssignment
{
void NullCoalescing()
{
object o = null;
o ??= this;
}
}

Просмотреть файл

@ -0,0 +1,4 @@
nullcoalescing
| NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... |
assignments
| NullCoalescingAssignment.cs:8:9:8:18 | ... ??= ... | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... |

Просмотреть файл

@ -0,0 +1,7 @@
import csharp
query predicate nullcoalescing(NullCoalescingExpr expr) { any() }
query predicate assignments(AssignCoalesceExpr expr, Expr expanded) {
expanded = expr.getExpandedAssignment()
}

Просмотреть файл

@ -0,0 +1,11 @@
| NullCoalescingAssignment.cs:5:10:5:23 | enter NullCoalescing | NullCoalescingAssignment.cs:6:5:9:5 | {...} | semmle.label | successor |
| NullCoalescingAssignment.cs:6:5:9:5 | {...} | NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | semmle.label | successor |
| NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | NullCoalescingAssignment.cs:7:20:7:23 | null | semmle.label | successor |
| NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | NullCoalescingAssignment.cs:8:9:8:19 | ...; | semmle.label | successor |
| NullCoalescingAssignment.cs:7:20:7:23 | null | NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | semmle.label | successor |
| NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | semmle.label | non-null |
| NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | NullCoalescingAssignment.cs:8:15:8:18 | this access | semmle.label | null |
| NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | NullCoalescingAssignment.cs:5:10:5:23 | exit NullCoalescing | semmle.label | successor |
| NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | semmle.label | successor |
| NullCoalescingAssignment.cs:8:9:8:19 | ...; | NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | semmle.label | successor |
| NullCoalescingAssignment.cs:8:15:8:18 | this access | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | semmle.label | successor |

Просмотреть файл

@ -0,0 +1,10 @@
import csharp
import semmle.code.csharp.controlflow.ControlFlowGraph
query predicate edges(ControlFlow::Node node1, ControlFlow::Node node2, string label, string value) {
label = "semmle.label" and
exists(ControlFlow::SuccessorType t |
node2 = node1.getASuccessorByType(t) and value = t.toString()
)
and node1.getEnclosingCallable().hasName("NullCoalescing")
}

Просмотреть файл

@ -1,10 +0,0 @@
using System;
class StaticLocalFunction
{
int F()
{
static int G(int x) => x;
return G(12);
}
}

Просмотреть файл

@ -0,0 +1,13 @@
// semmle-extractor-options: /langversion:8.0
using System;
class StaticLocalFunctions
{
int Fn(int x)
{
static int I(int y) => y;
int J(int y) => x+y;
return I(x) + J(x);
}
}

Просмотреть файл

@ -0,0 +1 @@
| StaticLocalFunctions.cs:9:9:9:33 | I | static |

Просмотреть файл

@ -0,0 +1,5 @@
import csharp
from LocalFunction fn, string modifier
where fn.hasModifier(modifier)
select fn, modifier

Просмотреть файл

@ -0,0 +1,26 @@
| UsingDeclarations.cs:6:10:6:30 | enter TestUsingDeclarations | UsingDeclarations.cs:7:5:16:5 | {...} | semmle.label | successor |
| UsingDeclarations.cs:7:5:16:5 | {...} | UsingDeclarations.cs:8:9:8:116 | using ... ...; | semmle.label | successor |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:49:8:53 | "..." | semmle.label | successor |
| UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | UsingDeclarations.cs:8:95:8:99 | "..." | semmle.label | successor |
| UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | semmle.label | successor |
| UsingDeclarations.cs:8:49:8:53 | "..." | UsingDeclarations.cs:8:56:8:68 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:8:56:8:68 | access to constant Open | UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | semmle.label | successor |
| UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | semmle.label | successor |
| UsingDeclarations.cs:8:95:8:99 | "..." | UsingDeclarations.cs:8:102:8:114 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:8:102:8:114 | access to constant Open | UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:49:10:53 | "..." | semmle.label | successor |
| UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | UsingDeclarations.cs:10:95:10:99 | "..." | semmle.label | successor |
| UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | semmle.label | successor |
| UsingDeclarations.cs:10:49:10:53 | "..." | UsingDeclarations.cs:10:56:10:68 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:10:56:10:68 | access to constant Open | UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | UsingDeclarations.cs:11:9:12:9 | {...} | semmle.label | successor |
| UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | semmle.label | successor |
| UsingDeclarations.cs:10:95:10:99 | "..." | UsingDeclarations.cs:10:102:10:114 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:10:102:10:114 | access to constant Open | UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:11:9:12:9 | {...} | UsingDeclarations.cs:14:9:15:13 | using (...) {...} | semmle.label | successor |
| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | UsingDeclarations.cs:14:30:14:34 | "..." | semmle.label | successor |
| UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | UsingDeclarations.cs:15:13:15:13 | ; | semmle.label | successor |
| UsingDeclarations.cs:14:30:14:34 | "..." | UsingDeclarations.cs:14:37:14:49 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:14:37:14:49 | access to constant Open | UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:15:13:15:13 | ; | UsingDeclarations.cs:6:10:6:30 | exit TestUsingDeclarations | semmle.label | successor |

Просмотреть файл

@ -0,0 +1,10 @@
import csharp
import semmle.code.csharp.controlflow.ControlFlowGraph
query predicate edges(ControlFlow::Node node1, ControlFlow::Node node2, string label, string value) {
label = "semmle.label" and
exists(ControlFlow::SuccessorType t |
node2 = node1.getASuccessorByType(t) and value = t.toString()
)
and node1.getEnclosingCallable().hasName("TestUsingDeclarations")
}

Просмотреть файл

@ -0,0 +1,17 @@
using System;
using System.IO;
class UsingDeclarations
{
void TestUsingDeclarations()
{
using FileStream file1 = new FileStream("...", FileMode.Open), file2 = new FileStream("...", FileMode.Open);
using(FileStream file3 = new FileStream("...", FileMode.Open), file4 = new FileStream("...", FileMode.Open))
{
}
using(new FileStream("...", FileMode.Open))
;
}
}

Просмотреть файл

@ -0,0 +1,26 @@
localVars
| UsingDeclarations.cs:8:26:8:30 | file1 |
| UsingDeclarations.cs:8:72:8:76 | file2 |
| UsingDeclarations.cs:10:26:10:30 | file3 |
| UsingDeclarations.cs:10:72:10:76 | file4 |
localVariableDeclarations
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... |
usingStmts1
| UsingDeclarations.cs:8:9:8:116 | using ... ...; |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} |
| UsingDeclarations.cs:14:9:15:13 | using (...) {...} |
usingStmts
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 0 | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 1 | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... |
usingDecls
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... |
usingExprs
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream |
| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream |

Просмотреть файл

@ -0,0 +1,22 @@
import csharp
query predicate localVars(LocalVariable decl) {
decl.getEnclosingCallable().hasName("TestUsingDeclarations")
}
query predicate localVariableDeclarations(
LocalVariableDeclStmt stmt, int i, LocalVariableDeclExpr decl
) {
decl.getEnclosingCallable().hasName("TestUsingDeclarations") and
decl = stmt.getVariableDeclExpr(i)
}
query predicate usingStmts1(UsingStmt stmt) { any() }
query predicate usingStmts(UsingStmt stmt, int i, LocalVariableDeclExpr decl) {
decl = stmt.getVariableDeclExpr(i)
}
query predicate usingDecls(UsingDeclStmt stmt, int i, Expr e) { e = stmt.getChild(i) }
query predicate usingExprs(UsingStmt stmt, Expr e) { e = stmt.getAnExpr() }

Просмотреть файл

@ -5,7 +5,7 @@
import csharp import csharp
where where
forall(UsingStmt s | forall(UsingBlockStmt s |
exists(s.getAnExpr()) and exists(s.getAnExpr()) and
exists(s.getBody()) exists(s.getBody())
) )

Просмотреть файл

@ -58,6 +58,10 @@ class Test
SqlConnection c1f = new SqlConnection(); SqlConnection c1f = new SqlConnection();
Throw2(c1f); Throw2(c1f);
c1f.Dispose(); c1f.Dispose();
// GOOD: using declaration
using SqlConnection c2 = new SqlConnection("");
c2.Open();
} }
void Throw1(SqlConnection sc) void Throw1(SqlConnection sc)
@ -71,3 +75,5 @@ class Test
return sc == null ? throw new Exception() : sc; return sc == null ? throw new Exception() : sc;
} }
} }
// semmle-extractor-options: /langversion:8.0

Просмотреть файл

@ -78,6 +78,9 @@ class Test
// GOOD: Passed to a library. This is only detected in CIL. // GOOD: Passed to a library. This is only detected in CIL.
Console.SetOut(new StreamWriter("output.txt")); Console.SetOut(new StreamWriter("output.txt"));
// GOOD: Disposed automatically.
using var c2 = new Timer(TimerProc);
return null; return null;
} }
@ -88,3 +91,5 @@ class Test
{ {
} }
} }
// semmle-extractor-options: /langversion:8.0

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,2 @@
description: Support for null-coalescing assignment, static local functions, and using declarations.
compatibility: backwards