C#: Add support for init only accessors

This commit is contained in:
Tamas Vajk
2020-11-06 14:18:36 +01:00
parent b649ccd880
commit 4318941009
9 changed files with 156 additions and 0 deletions

View File

@@ -76,6 +76,11 @@ namespace Semmle.Extraction.CSharp.Entities
{
trapFile.compiler_generated(this);
}
if (symbol.IsInitOnly)
{
trapFile.init_only_accessors(this);
}
}
public static new Accessor Create(Context cx, IMethodSymbol symbol) =>

View File

@@ -26,6 +26,11 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("accessors", accessorKey, kind, name, propKey, unboundAccessor);
}
internal static void init_only_accessors(this TextWriter trapFile, Accessor accessorKey)
{
trapFile.WriteTuple("init_only_accessors", accessorKey);
}
internal static void array_element_type(this TextWriter trapFile, ArrayType array, int dimension, int rank, Type elementType)
{
trapFile.WriteTuple("array_element_type", array, dimension, rank, elementType);

View File

@@ -472,6 +472,9 @@ class Setter extends Accessor, @setter {
result = Accessor.super.getDeclaration()
}
/** Holds if this setter is an `init`-only accessor. */
predicate isInitOnly() { init_only_accessors(this) }
override string getAPrimaryQlClass() { result = "Setter" }
}

View File

@@ -604,6 +604,9 @@ case @accessor.kind of
| 2 = @setter
;
init_only_accessors(
unique int id: @accessor ref);
accessor_location(
int id: @accessor ref,
int loc: @location ref);

View File

@@ -0,0 +1,44 @@
using System;
namespace System.Runtime.CompilerServices
{
public sealed class IsExternalInit
{
}
}
public class Base
{
public int Prop0 { get { return 1; } init { Prop1 = value; } }
public virtual int Prop1 { get; init; }
public virtual int Prop2 { get; set; }
}
public class Derived : Base
{
public override int Prop1 { get; init; }
public int Prop2
{
get { return 0; }
init
{
System.Console.WriteLine(value);
Prop1 = value;
Prop0 = value;
}
}
}
public class C1
{
public void M1()
{
var d = new Derived
{
Prop1 = 1,
Prop2 = 2,
Prop0 = 0
};
}
}

View File

@@ -47,6 +47,88 @@ Discard.cs:
# 10| 4: [BlockStmt] {...}
# 10| 0: [ReturnStmt] return ...;
# 10| 0: [IntLiteral] 0
InitOnlyProperty.cs:
# 3| [NamespaceDeclaration] namespace ... { ... }
# 5| 1: [Class] IsExternalInit
# 10| [Class] Base
# 12| 5: [Property] Prop0
# 12| -1: [TypeMention] int
# 12| 3: [Getter] get_Prop0
# 12| 4: [BlockStmt] {...}
# 12| 0: [ReturnStmt] return ...;
# 12| 0: [IntLiteral] 1
# 12| 4: [Setter] set_Prop0
#-----| 2: (Parameters)
# 12| 0: [Parameter] value
# 12| 4: [BlockStmt] {...}
# 12| 0: [ExprStmt] ...;
# 12| 0: [AssignExpr] ... = ...
# 12| 0: [PropertyCall] access to property Prop1
# 12| 1: [ParameterAccess] access to parameter value
# 13| 6: [Property] Prop1
# 13| -1: [TypeMention] int
# 13| 3: [Getter] get_Prop1
# 13| 4: [Setter] set_Prop1
#-----| 2: (Parameters)
# 13| 0: [Parameter] value
# 14| 7: [Property] Prop2
# 14| -1: [TypeMention] int
# 14| 3: [Getter] get_Prop2
# 14| 4: [Setter] set_Prop2
#-----| 2: (Parameters)
# 14| 0: [Parameter] value
# 18| [Class] Derived
#-----| 3: (Base types)
# 18| 0: [TypeMention] Base
# 20| 5: [Property] Prop1
# 20| -1: [TypeMention] int
# 20| 3: [Getter] get_Prop1
# 20| 4: [Setter] set_Prop1
#-----| 2: (Parameters)
# 20| 0: [Parameter] value
# 21| 6: [Property] Prop2
# 21| -1: [TypeMention] int
# 23| 3: [Getter] get_Prop2
# 23| 4: [BlockStmt] {...}
# 23| 0: [ReturnStmt] return ...;
# 23| 0: [IntLiteral] 0
# 24| 4: [Setter] set_Prop2
#-----| 2: (Parameters)
# 24| 0: [Parameter] value
# 25| 4: [BlockStmt] {...}
# 26| 0: [ExprStmt] ...;
# 26| 0: [MethodCall] call to method WriteLine
# 26| -1: [TypeAccess] access to type Console
# 26| 0: [TypeMention] Console
# 26| 0: [ParameterAccess] access to parameter value
# 27| 1: [ExprStmt] ...;
# 27| 0: [AssignExpr] ... = ...
# 27| 0: [PropertyCall] access to property Prop1
# 27| 1: [ParameterAccess] access to parameter value
# 28| 2: [ExprStmt] ...;
# 28| 0: [AssignExpr] ... = ...
# 28| 0: [PropertyCall] access to property Prop0
# 28| 1: [ParameterAccess] access to parameter value
# 33| [Class] C1
# 35| 5: [Method] M1
# 35| -1: [TypeMention] Void
# 36| 4: [BlockStmt] {...}
# 37| 0: [LocalVariableDeclStmt] ... ...;
# 37| 0: [LocalVariableDeclAndInitExpr] Derived d = ...
# 37| -1: [TypeMention] Derived
# 37| 0: [LocalVariableAccess] access to local variable d
# 37| 1: [ObjectCreation] object creation of type Derived
# 37| -2: [TypeMention] Derived
# 38| -1: [ObjectInitializer] { ..., ... }
# 39| 0: [MemberInitializer] ... = ...
# 39| 0: [PropertyCall] access to property Prop1
# 39| 1: [IntLiteral] 1
# 40| 1: [MemberInitializer] ... = ...
# 40| 0: [PropertyCall] access to property Prop2
# 40| 1: [IntLiteral] 2
# 41| 2: [MemberInitializer] ... = ...
# 41| 0: [PropertyCall] access to property Prop0
# 41| 1: [IntLiteral] 0
LambdaModifier.cs:
# 4| [Class] Class1
# 6| 5: [Method] M1

View File

@@ -0,0 +1,5 @@
| InitOnlyProperty.cs:12:42:12:45 | set_Prop0 | init |
| InitOnlyProperty.cs:13:37:13:40 | set_Prop1 | init |
| InitOnlyProperty.cs:14:37:14:39 | set_Prop2 | set |
| InitOnlyProperty.cs:20:38:20:41 | set_Prop1 | init |
| InitOnlyProperty.cs:24:9:24:12 | set_Prop2 | init |

View File

@@ -0,0 +1,7 @@
import csharp
private string getType(Setter s) { if s.isInitOnly() then result = "init" else result = "set" }
from Setter s
where s.fromSource()
select s, getType(s)

View File

@@ -0,0 +1,2 @@
description: Added 'init_only_accessors' relation.
compatibility: backwards