mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
C#: Implement range operator
This commit is contained in:
@@ -719,3 +719,37 @@ class DiscardExpr extends Expr, @discard_expr {
|
||||
private class UnknownExpr extends Expr, @unknown_expr {
|
||||
override string toString() { result = "Expression" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A range expression, used to create a `System.Range`. For example
|
||||
* ```
|
||||
* 1..3
|
||||
* 1..^1
|
||||
* 3..
|
||||
* ..
|
||||
* ..5
|
||||
* ..^1
|
||||
* ```
|
||||
*/
|
||||
class RangeExpr extends Expr, @range_expr {
|
||||
override string toString() { result = "... .. ..." }
|
||||
|
||||
/** Gets the left hand operand of this range expression, if any. */
|
||||
Expr getStart() { result = this.getChild(0) }
|
||||
|
||||
/** Gets the right hand operand of this range expression, if any. */
|
||||
Expr getEnd() { result = this.getChild(1) }
|
||||
|
||||
/** Holds if this range expression has a left hand operand. */
|
||||
predicate hasStart() { exists(getStart()) }
|
||||
|
||||
/** Holds if this range expression has a right hand operand. */
|
||||
predicate hasEnd() { exists(getEnd()) }
|
||||
}
|
||||
|
||||
/** An index expression, for example `^1` meaning "1 from the end". */
|
||||
class IndexExpr extends Expr, @index_expr {
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
override string toString() { result = "^..." }
|
||||
}
|
||||
|
||||
@@ -975,6 +975,8 @@ case @expr.kind of
|
||||
| 109 = @local_function_invocation_expr
|
||||
| 110 = @ref_expr
|
||||
| 111 = @discard_expr
|
||||
| 112 = @range_expr
|
||||
| 113 = @index_expr
|
||||
;
|
||||
|
||||
@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
|
||||
|
||||
42
csharp/ql/test/library-tests/csharp8/ranges.cs
Normal file
42
csharp/ql/test/library-tests/csharp8/ranges.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
// semmle-extractor-options: /langversion:8.0
|
||||
|
||||
using System;
|
||||
|
||||
class Ranges
|
||||
{
|
||||
void F()
|
||||
{
|
||||
var array = new int[] { 1, 2, 3, 4 };
|
||||
var array2 = new int[2, 3];
|
||||
|
||||
var slice1 = array[1..3];
|
||||
var slice2 = array[0..^1];
|
||||
int x=2, y=3;
|
||||
var slice3 = array[x..y];
|
||||
var slice4 = array[..y];
|
||||
var slice5 = array[x..];
|
||||
var slice6 = array[..];
|
||||
var slice7 = array[^10..^5];
|
||||
var slice8 = array2[1..2, ..];
|
||||
}
|
||||
}
|
||||
|
||||
// These are temporary until qltest uses .NET Core 3.0.
|
||||
namespace System
|
||||
{
|
||||
public readonly struct Index
|
||||
{
|
||||
public Index(int value, bool fromEnd = false) { }
|
||||
public static implicit operator Index(int value) => default(Index);
|
||||
}
|
||||
|
||||
public readonly struct Range
|
||||
{
|
||||
public Range(Index start, Index end) => throw null;
|
||||
public static Range StartAt(System.Index start) => throw null;
|
||||
public static Range EndAt(System.Index end) => throw null;
|
||||
public static Range All => throw null;
|
||||
public static Range Create(Index start, Index end) => throw null;
|
||||
public static implicit operator int(Range r) => throw null;
|
||||
}
|
||||
}
|
||||
28
csharp/ql/test/library-tests/csharp8/ranges.expected
Normal file
28
csharp/ql/test/library-tests/csharp8/ranges.expected
Normal file
@@ -0,0 +1,28 @@
|
||||
indexes
|
||||
| ranges.cs:13:31:13:32 | ^... | ranges.cs:13:32:13:32 | 1 |
|
||||
| ranges.cs:19:28:19:30 | ^... | ranges.cs:19:29:19:30 | 10 |
|
||||
| ranges.cs:19:33:19:34 | ^... | ranges.cs:19:34:19:34 | 5 |
|
||||
ranges
|
||||
| ranges.cs:12:28:12:31 | ... .. ... |
|
||||
| ranges.cs:13:28:13:32 | ... .. ... |
|
||||
| ranges.cs:15:28:15:31 | ... .. ... |
|
||||
| ranges.cs:16:28:16:30 | ... .. ... |
|
||||
| ranges.cs:17:28:17:30 | ... .. ... |
|
||||
| ranges.cs:18:28:18:29 | ... .. ... |
|
||||
| ranges.cs:19:28:19:34 | ... .. ... |
|
||||
| ranges.cs:20:29:20:32 | ... .. ... |
|
||||
| ranges.cs:20:35:20:36 | ... .. ... |
|
||||
rangeStart
|
||||
| ranges.cs:12:28:12:31 | ... .. ... | ranges.cs:12:28:12:28 | 1 |
|
||||
| ranges.cs:13:28:13:32 | ... .. ... | ranges.cs:13:28:13:28 | 0 |
|
||||
| ranges.cs:15:28:15:31 | ... .. ... | ranges.cs:15:28:15:28 | access to local variable x |
|
||||
| ranges.cs:17:28:17:30 | ... .. ... | ranges.cs:17:28:17:28 | access to local variable x |
|
||||
| ranges.cs:19:28:19:34 | ... .. ... | ranges.cs:19:28:19:30 | ^... |
|
||||
| ranges.cs:20:29:20:32 | ... .. ... | ranges.cs:20:29:20:29 | 1 |
|
||||
rangeEnd
|
||||
| ranges.cs:12:28:12:31 | ... .. ... | ranges.cs:12:31:12:31 | 3 |
|
||||
| ranges.cs:13:28:13:32 | ... .. ... | ranges.cs:13:31:13:32 | ^... |
|
||||
| ranges.cs:15:28:15:31 | ... .. ... | ranges.cs:15:31:15:31 | access to local variable y |
|
||||
| ranges.cs:16:28:16:30 | ... .. ... | ranges.cs:16:30:16:30 | access to local variable y |
|
||||
| ranges.cs:19:28:19:34 | ... .. ... | ranges.cs:19:33:19:34 | ^... |
|
||||
| ranges.cs:20:29:20:32 | ... .. ... | ranges.cs:20:32:20:32 | 2 |
|
||||
20
csharp/ql/test/library-tests/csharp8/ranges.ql
Normal file
20
csharp/ql/test/library-tests/csharp8/ranges.ql
Normal file
@@ -0,0 +1,20 @@
|
||||
import csharp
|
||||
|
||||
predicate getConversion(Expr expr, Expr unconvertedExpr) {
|
||||
unconvertedExpr = expr.(Cast).getExpr()
|
||||
or
|
||||
unconvertedExpr = expr.(OperatorCall).getArgument(0) and
|
||||
expr.(OperatorCall).getTarget() instanceof ConversionOperator
|
||||
}
|
||||
|
||||
Expr stripConversions(Expr expr) {
|
||||
if getConversion(expr, _) then getConversion(expr, result) else result = expr
|
||||
}
|
||||
|
||||
query predicate indexes(IndexExpr e, Expr c) { c = e.getExpr() }
|
||||
|
||||
query predicate ranges(RangeExpr e) { any() }
|
||||
|
||||
query predicate rangeStart(RangeExpr e, Expr start) { start = stripConversions(e.getStart()) }
|
||||
|
||||
query predicate rangeEnd(RangeExpr e, Expr end) { end = stripConversions(e.getEnd()) }
|
||||
Reference in New Issue
Block a user