mirror of
https://github.com/github/codeql.git
synced 2026-05-03 04:39:29 +02:00
Merge pull request #12103 from michaelnebel/csharp/scopedmodfier
C# 11: Scoped parameters and local variables.
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 a relation for scoped annotations.
|
||||
compatibility: backwards
|
||||
scoped_annotation.rel: delete
|
||||
@@ -59,6 +59,19 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
protected void PopulateScopedKind(TextWriter trapFile, ScopedKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case ScopedKind.ScopedRef:
|
||||
trapFile.scoped_annotation(this, Kinds.ScopedAnnotation.ScopedRef);
|
||||
break;
|
||||
case ScopedKind.ScopedValue:
|
||||
trapFile.scoped_annotation(this, Kinds.ScopedAnnotation.ScopedValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void ExtractCompilerGenerated(TextWriter trapFile)
|
||||
{
|
||||
if (Symbol.IsImplicitlyDeclared)
|
||||
|
||||
@@ -33,7 +33,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PopulateRefKind(trapFile, Symbol.RefKind);
|
||||
|
||||
var unboundFieldKey = Field.Create(Context, Symbol.OriginalDefinition);
|
||||
trapFile.fields(this, (Symbol.IsConst ? 2 : 1), Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey);
|
||||
var kind = Symbol.IsConst ? VariableKind.Const : VariableKind.None;
|
||||
trapFile.fields(this, kind, Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey);
|
||||
|
||||
PopulateModifiers(trapFile);
|
||||
|
||||
|
||||
@@ -23,17 +23,23 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
public void PopulateManual(Expression parent, bool isVar)
|
||||
{
|
||||
var trapFile = Context.TrapWriter.Writer;
|
||||
var (kind, type) = Symbol is ILocalSymbol l
|
||||
? (l.IsRef ? 3 : l.IsConst ? 2 : 1, l.GetAnnotatedType())
|
||||
: (1, parent.Type);
|
||||
trapFile.localvars(this, kind, Symbol.Name, isVar ? 1 : 0, Type.Create(Context, type).TypeRef, parent);
|
||||
var @var = isVar ? 1 : 0;
|
||||
|
||||
if (Symbol is ILocalSymbol local)
|
||||
{
|
||||
var kind = local.IsRef ? Kinds.VariableKind.Ref : local.IsConst ? Kinds.VariableKind.Const : Kinds.VariableKind.None;
|
||||
var type = local.GetAnnotatedType();
|
||||
trapFile.localvars(this, kind, Symbol.Name, @var, Type.Create(Context, type).TypeRef, parent);
|
||||
|
||||
PopulateNullability(trapFile, local.GetAnnotatedType());
|
||||
PopulateScopedKind(trapFile, local.ScopedKind);
|
||||
if (local.IsRef)
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.localvars(this, Kinds.VariableKind.None, Symbol.Name, @var, Type.Create(Context, parent.Type).TypeRef, parent);
|
||||
}
|
||||
|
||||
trapFile.localvar_location(this, Location);
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PopulateAttributes();
|
||||
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
|
||||
PopulateRefKind(trapFile, Symbol.RefKind);
|
||||
PopulateScopedKind(trapFile, Symbol.ScopedKind);
|
||||
|
||||
if (Symbol.Name != Original.Symbol.Name)
|
||||
Context.ModelError(Symbol, "Inconsistent parameter declaration");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Semmle.Extraction.Kinds;
|
||||
|
||||
public enum ScopedAnnotation
|
||||
{
|
||||
None = 0,
|
||||
ScopedRef = 1,
|
||||
ScopedValue = 2
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Semmle.Extraction.Kinds;
|
||||
|
||||
public enum VariableKind
|
||||
{
|
||||
None = 1,
|
||||
Const = 2,
|
||||
Ref = 3
|
||||
}
|
||||
@@ -191,8 +191,8 @@ namespace Semmle.Extraction.CSharp
|
||||
internal static void field_location(this TextWriter trapFile, Field field, Location location) =>
|
||||
trapFile.WriteTuple("field_location", field, location);
|
||||
|
||||
internal static void fields(this TextWriter trapFile, Field field, int @const, string name, Type declaringType, Type fieldType, Field unboundKey) =>
|
||||
trapFile.WriteTuple("fields", field, @const, name, declaringType, fieldType, unboundKey);
|
||||
internal static void fields(this TextWriter trapFile, Field field, VariableKind kind, string name, Type declaringType, Type fieldType, Field unboundKey) =>
|
||||
trapFile.WriteTuple("fields", field, (int)kind, name, declaringType, fieldType, unboundKey);
|
||||
|
||||
internal static void general_type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, int hasKind) =>
|
||||
trapFile.WriteTuple("general_type_parameter_constraints", constraints, hasKind);
|
||||
@@ -227,8 +227,8 @@ namespace Semmle.Extraction.CSharp
|
||||
internal static void localvar_location(this TextWriter trapFile, LocalVariable var, Location location) =>
|
||||
trapFile.WriteTuple("localvar_location", var, location);
|
||||
|
||||
internal static void localvars(this TextWriter trapFile, LocalVariable key, int @const, string name, int @var, Type type, Expression expr) =>
|
||||
trapFile.WriteTuple("localvars", key, @const, name, @var, type, expr);
|
||||
internal static void localvars(this TextWriter trapFile, LocalVariable key, VariableKind kind, string name, int @var, Type type, Expression expr) =>
|
||||
trapFile.WriteTuple("localvars", key, (int)kind, name, @var, type, expr);
|
||||
|
||||
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) =>
|
||||
trapFile.WriteTuple("metadata_handle", entity, assembly, handleValue);
|
||||
@@ -462,5 +462,8 @@ namespace Semmle.Extraction.CSharp
|
||||
|
||||
internal static void file_extraction_mode(this System.IO.TextWriter trapFile, Entities.File file, ExtractorMode mode) =>
|
||||
trapFile.WriteTuple("file_extraction_mode", file, mode);
|
||||
|
||||
internal static void scoped_annotation(this TextWriter trapFile, IEntity element, ScopedAnnotation @scoped) =>
|
||||
trapFile.WriteTuple("scoped_annotation", element, (int)@scoped);
|
||||
}
|
||||
}
|
||||
|
||||
4
csharp/ql/lib/change-notes/2023-02-07-scoped-modifier.md
Normal file
4
csharp/ql/lib/change-notes/2023-02-07-scoped-modifier.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||
@@ -71,6 +71,11 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
|
||||
*/
|
||||
predicate isRef() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this local variable or parameter is `scoped`.
|
||||
*/
|
||||
predicate isScoped() { scoped_annotation(this, _) }
|
||||
|
||||
override predicate hasQualifiedName(string qualifier, string name) { none() }
|
||||
}
|
||||
|
||||
|
||||
@@ -878,6 +878,13 @@ param_location(
|
||||
int id: @parameter ref,
|
||||
int loc: @location ref);
|
||||
|
||||
@has_scoped_annotation = @local_scope_variable
|
||||
|
||||
scoped_annotation(
|
||||
int id: @has_scoped_annotation ref,
|
||||
int kind: int ref // scoped ref = 1, scoped value = 2
|
||||
);
|
||||
|
||||
/** STATEMENTS **/
|
||||
|
||||
@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
|
||||
|
||||
@@ -26228,6 +26228,59 @@
|
||||
</dep>
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>scoped_annotation</name>
|
||||
<cardinality>43498</cardinality>
|
||||
<columnsizes>
|
||||
<e>
|
||||
<k>id</k>
|
||||
<v>43498</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>kind</k>
|
||||
<v>18</v>
|
||||
</e>
|
||||
</columnsizes>
|
||||
<dependencies>
|
||||
<dep>
|
||||
<src>id</src>
|
||||
<trg>kind</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>43498</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>kind</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>11</a>
|
||||
<b>12</b>
|
||||
<v>9</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>4599</a>
|
||||
<b>4600</b>
|
||||
<v>9</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
<name>statements</name>
|
||||
<cardinality>2458000</cardinality>
|
||||
|
||||
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 a relation for scoped annotations.
|
||||
compatibility: backwards
|
||||
@@ -343,6 +343,87 @@ PatternMatchSpan.cs:
|
||||
# 16| 2: [DefaultCase] default:
|
||||
# 16| 3: [BlockStmt] {...}
|
||||
# 16| 0: [BreakStmt] break;
|
||||
Scoped.cs:
|
||||
# 1| [Struct] S1
|
||||
# 2| [Struct] S2
|
||||
# 7| [Class] ScopedModifierTest
|
||||
# 9| 5: [Method] M1
|
||||
# 9| -1: [TypeMention] int
|
||||
#-----| 2: (Parameters)
|
||||
# 9| 0: [Parameter] x1
|
||||
# 9| -1: [TypeMention] int
|
||||
# 9| 1: [Parameter] y1
|
||||
# 9| -1: [TypeMention] int
|
||||
# 10| 4: [BlockStmt] {...}
|
||||
# 13| 0: [ReturnStmt] return ...;
|
||||
# 13| 0: [RefExpr] ref ...
|
||||
# 13| 0: [ParameterAccess] access to parameter y1
|
||||
# 16| 6: [Method] M2
|
||||
# 16| -1: [TypeMention] int
|
||||
#-----| 2: (Parameters)
|
||||
# 16| 0: [Parameter] x2
|
||||
# 16| -1: [TypeMention] int
|
||||
# 16| 1: [Parameter] y2
|
||||
# 16| -1: [TypeMention] int
|
||||
# 17| 4: [BlockStmt] {...}
|
||||
# 18| 0: [ExprStmt] ...;
|
||||
# 18| 0: [AssignExpr] ... = ...
|
||||
# 18| 0: [ParameterAccess] access to parameter x2
|
||||
# 18| 1: [IntLiteral] 0
|
||||
# 21| 1: [ReturnStmt] return ...;
|
||||
# 21| 0: [RefExpr] ref ...
|
||||
# 21| 0: [ParameterAccess] access to parameter y2
|
||||
# 24| 7: [Method] M3
|
||||
# 24| -1: [TypeMention] int
|
||||
#-----| 2: (Parameters)
|
||||
# 24| 0: [Parameter] x3
|
||||
# 24| -1: [TypeMention] int
|
||||
# 25| 4: [BlockStmt] {...}
|
||||
# 27| 0: [ReturnStmt] return ...;
|
||||
# 27| 0: [ParameterAccess] access to parameter x3
|
||||
# 30| 8: [Method] M4
|
||||
# 30| -1: [TypeMention] S1
|
||||
#-----| 2: (Parameters)
|
||||
# 30| 0: [Parameter] x4
|
||||
# 30| -1: [TypeMention] S1
|
||||
# 31| 4: [BlockStmt] {...}
|
||||
# 33| 0: [ReturnStmt] return ...;
|
||||
# 33| 0: [ParameterAccess] access to parameter x4
|
||||
# 36| 9: [Method] M5
|
||||
# 36| -1: [TypeMention] S2
|
||||
#-----| 2: (Parameters)
|
||||
# 36| 0: [Parameter] x5
|
||||
# 36| -1: [TypeMention] S2
|
||||
# 37| 4: [BlockStmt] {...}
|
||||
# 40| 0: [ReturnStmt] return ...;
|
||||
# 40| 0: [ObjectCreation] object creation of type S2
|
||||
# 40| 0: [TypeMention] S2
|
||||
# 43| 10: [Method] M6
|
||||
# 43| -1: [TypeMention] S2
|
||||
#-----| 2: (Parameters)
|
||||
# 43| 0: [Parameter] x6
|
||||
# 43| -1: [TypeMention] S2
|
||||
# 44| 4: [BlockStmt] {...}
|
||||
# 47| 0: [ReturnStmt] return ...;
|
||||
# 47| 0: [ObjectCreation] object creation of type S2
|
||||
# 47| 0: [TypeMention] S2
|
||||
# 50| 11: [Method] Locals
|
||||
# 50| -1: [TypeMention] S2
|
||||
# 51| 4: [BlockStmt] {...}
|
||||
# 52| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 52| 0: [LocalVariableDeclAndInitExpr] S2 x7 = ...
|
||||
# 52| -1: [TypeMention] null
|
||||
# 52| 0: [LocalVariableAccess] access to local variable x7
|
||||
# 52| 1: [ObjectCreation] object creation of type S2
|
||||
# 52| 0: [TypeMention] S2
|
||||
# 55| 1: [LocalVariableDeclStmt] ... ...;
|
||||
# 55| 0: [LocalVariableDeclAndInitExpr] S2 y7 = ...
|
||||
# 55| -1: [TypeMention] S2
|
||||
# 55| 0: [LocalVariableAccess] access to local variable y7
|
||||
# 55| 1: [ObjectCreation] object creation of type S2
|
||||
# 55| 0: [TypeMention] S2
|
||||
# 56| 2: [ReturnStmt] return ...;
|
||||
# 56| 0: [LocalVariableAccess] access to local variable y7
|
||||
SignAnalysis.cs:
|
||||
# 1| [Class] MySignAnalysis
|
||||
# 4| 5: [Method] UnsignedRightShiftSign
|
||||
|
||||
59
csharp/ql/test/library-tests/csharp11/Scoped.cs
Normal file
59
csharp/ql/test/library-tests/csharp11/Scoped.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
public struct S1 { }
|
||||
public ref struct S2 { }
|
||||
|
||||
// The `scoped` modifier can be applied to parameters
|
||||
// or local variables. The type of the parameter or
|
||||
// local variable must be either a `ref` value or `ref struct` value.
|
||||
public class ScopedModifierTest
|
||||
{
|
||||
public ref int M1(scoped ref int x1, ref int y1)
|
||||
{
|
||||
// Not allowed.
|
||||
// return ref x1;
|
||||
return ref y1;
|
||||
}
|
||||
|
||||
public ref int M2(scoped out int x2, ref int y2)
|
||||
{
|
||||
x2 = 0;
|
||||
// Not allowed.
|
||||
// return ref x;
|
||||
return ref y2;
|
||||
}
|
||||
|
||||
public int M3(scoped ref int x3)
|
||||
{
|
||||
// Allowed is it is not returned by reference.
|
||||
return x3;
|
||||
}
|
||||
|
||||
public S1 M4(scoped ref S1 x4)
|
||||
{
|
||||
// Allowed as it is not returned by reference.
|
||||
return x4;
|
||||
}
|
||||
|
||||
public S2 M5(scoped S2 x5)
|
||||
{
|
||||
// Not allowed.
|
||||
// return x5;
|
||||
return new S2();
|
||||
}
|
||||
|
||||
public S2 M6(scoped ref S2 x6)
|
||||
{
|
||||
// Not allowed.
|
||||
// return x6;
|
||||
return new S2();
|
||||
}
|
||||
|
||||
public S2 Locals()
|
||||
{
|
||||
scoped S2 x7 = new S2();
|
||||
// Not allowed.
|
||||
// return x7;
|
||||
S2 y7 = new S2();
|
||||
return y7;
|
||||
}
|
||||
|
||||
}
|
||||
7
csharp/ql/test/library-tests/csharp11/scoped.expected
Normal file
7
csharp/ql/test/library-tests/csharp11/scoped.expected
Normal file
@@ -0,0 +1,7 @@
|
||||
| Scoped.cs:9:38:9:39 | x1 | Parameter |
|
||||
| Scoped.cs:16:38:16:39 | x2 | Parameter |
|
||||
| Scoped.cs:24:34:24:35 | x3 | Parameter |
|
||||
| Scoped.cs:30:32:30:33 | x4 | Parameter |
|
||||
| Scoped.cs:36:28:36:29 | x5 | Parameter |
|
||||
| Scoped.cs:43:32:43:33 | x6 | Parameter |
|
||||
| Scoped.cs:52:19:52:20 | x7 | LocalVariable |
|
||||
5
csharp/ql/test/library-tests/csharp11/scoped.ql
Normal file
5
csharp/ql/test/library-tests/csharp11/scoped.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import csharp
|
||||
|
||||
from LocalScopeVariable v
|
||||
where v.getFile().getStem() = "Scoped" and v.isScoped()
|
||||
select v, v.getAPrimaryQlClass()
|
||||
Reference in New Issue
Block a user