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:
- Range expressions
- Recursive patterns
- Using declaration statements
- `static` modifiers on local functions
- Null-coalescing assignment expressions
* The `unmanaged` type parameter constraint is now extracted.
## 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 `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:
- Class `AssignCoalesceExpr` models null-coalescing assignment, for example `x ??= y`
- 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 `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`
- Class `Switch` models both `SwitchExpr` and `SwitchStmt`
- Class `Case` models both `CaseStmt` and `SwitchCaseExpr`
- Class `UsingStmt` models both `UsingBlockStmt` and `UsingDeclStmt`
## Changes to autobuilder

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

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

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

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

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

@ -1,4 +1,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Linq;
namespace Semmle.Extraction.CSharp.Entities
{
@ -39,6 +41,18 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate()
{
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 returnType = Type.Create(Context, symbol.ReturnType);
Context.Emit(Tuples.local_functions(this, symbol.Name, returnType, originalDefinition));

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

@ -6,8 +6,19 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
{
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)
: 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)
{

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

@ -112,6 +112,7 @@ namespace Semmle.Extraction.Kinds
RECURSIVE_PATTERN = 115,
PROPERTY_PATTERN = 116,
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,
CATCH = 28,
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 LocalFunction getSourceDeclaration() { local_functions(this, _, _, result) }

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

@ -1115,40 +1115,16 @@ class LockStmt extends Stmt, @lock_stmt {
}
/**
* A `using` statement, for example
*
* ```
* using (FileStream f = File.Open("settings.xml")) {
* ...
* }
* ```
* A using block or declaration. Either a using declaration (`UsingDeclStmt`) or
* a using block (`UsingBlockStmt`).
*/
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. */
LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) }
LocalVariableDeclExpr getVariableDeclExpr(int i) { none() }
/** Gets a local variable declaration of this `using` statement. */
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
* 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()
or
result = this.getExpr()
}
/** Gets the body of this `using` statement. */
Stmt getBody() { result.getParent() = this }
override Stmt getBody() { result.getParent() = this }
override string toString() { result = "using (...) {...}" }
}
@ -1254,6 +1285,29 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt {
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
*

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

@ -468,7 +468,7 @@ module ControlFlow {
override ControlFlowElement getChildElement(int i) {
not this instanceof GeneralCatchClause and
not this instanceof FixedStmt and
not this instanceof UsingStmt and
not this instanceof UsingBlockStmt and
result = this.getChild(i)
or
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
)
or
this = any(UsingStmt us |
this = any(UsingBlockStmt us |
if exists(us.getExpr())
then (
result = us.getExpr() and

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

@ -230,3 +230,10 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr {
class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr {
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_direct = @member | @accessor;
@modifiable_direct = @member | @accessor | @local_function;
modifiers(
unique int id: @modifier,
@ -798,7 +798,7 @@ case @stmt.kind of
| 18 = @checked_stmt
| 19 = @unchecked_stmt
| 20 = @lock_stmt
| 21 = @using_stmt
| 21 = @using_block_stmt
| 22 = @var_decl_stmt
| 23 = @const_decl_stmt
| 24 = @empty_stmt
@ -808,11 +808,14 @@ case @stmt.kind of
| 28 = @catch
| 29 = @case_stmt
| 30 = @local_function_stmt
| 31 = @using_decl_stmt
;
@using_stmt = @using_block_stmt | @using_decl_stmt;
@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;
@ -983,6 +986,7 @@ case @expr.kind of
| 116 = @property_pattern_expr
| 117 = @positional_pattern_expr
| 118 = @switch_case_expr
| 119 = @assign_coalesce_expr
;
@switch = @switch_stmt | @switch_expr;
@ -995,7 +999,7 @@ case @expr.kind of
| @string_literal_expr | @null_literal_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_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr

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

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

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

@ -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: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: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: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 |

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

@ -86,6 +86,7 @@
| 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: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:7:9:7:17 | ... = ... | Discards.cs:7:9:7:17 | ... = ... |
| Discards.cs:13:9:13:20 | ... = ... | Discards.cs:13:9:13:20 | ... = ... |

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

@ -132,4 +132,11 @@ class Assignables
var x = 0;
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:132:13:132:13 | x |
| Assignables.cs:133:29:133:29 | s |
| Assignables.cs:138:19:138:19 | x |
| Discards.cs:5:6:5:8 | Item1 |
| Discards.cs:5:11:5:16 | Item2 |
| 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:126:13:126:30 | nameof(...) |
| 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 |
| 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 |

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

@ -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
where
forall(UsingStmt s |
forall(UsingBlockStmt s |
exists(s.getAnExpr()) and
exists(s.getBody())
)

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

@ -58,6 +58,10 @@ class Test
SqlConnection c1f = new SqlConnection();
Throw2(c1f);
c1f.Dispose();
// GOOD: using declaration
using SqlConnection c2 = new SqlConnection("");
c2.Open();
}
void Throw1(SqlConnection sc)
@ -71,3 +75,5 @@ class Test
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.
Console.SetOut(new StreamWriter("output.txt"));
// GOOD: Disposed automatically.
using var c2 = new Timer(TimerProc);
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