Skip to content

Commit 3b16d26

Browse files
authored
Merge pull request #4821 from tamasvajk/feature/csharp9-cil-init-prop
C#: Extract init only accessors from CIL
2 parents c193d9f + 74622cf commit 3b16d26

30 files changed

+6518
-2241
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
lgtm,codescanning
2+
* CIL extraction has been improved to store `modreq` and `modopt` custom modifiers.
3+
The extracted information is surfaced through the `CustomModifierReceiver` class. Additionally,
4+
the information is also used to evaluate the new `Setter::isInitOnly` predicate.

csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ public override IEnumerable<IExtractionProduct> Contents
7676

7777
var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
7878

79-
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
79+
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
80+
Parameters = parameters.OfType<Parameter>().ToArray();
8081

81-
foreach (var c in Parameters)
82+
foreach (var c in parameters)
8283
yield return c;
8384

8485
foreach (var c in PopulateFlags)
@@ -95,7 +96,12 @@ public override IEnumerable<IExtractionProduct> Contents
9596
}
9697

9798
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
98-
yield return Tuples.cil_method(this, Name, declaringType, typeSignature.ReturnType);
99+
100+
foreach (var m in GetMethodExtractionProducts(Name, declaringType, typeSignature.ReturnType))
101+
{
102+
yield return m;
103+
}
104+
99105
yield return Tuples.cil_method_source_declaration(this, this);
100106
yield return Tuples.cil_method_location(this, Cx.Assembly);
101107

csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities
88
/// <summary>
99
/// An entity representing a field.
1010
/// </summary>
11-
internal abstract class Field : GenericContext, IMember
11+
internal abstract class Field : GenericContext, IMember, ICustomModifierReceiver
1212
{
1313
protected Field(Context cx) : base(cx)
1414
{
@@ -45,7 +45,13 @@ public virtual IEnumerable<IExtractionProduct> Contents
4545
{
4646
get
4747
{
48-
yield return Tuples.cil_field(this, DeclaringType, Name, Type);
48+
var t = Type;
49+
if (t is ModifiedType mt)
50+
{
51+
t = mt.Unmodified;
52+
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
53+
}
54+
yield return Tuples.cil_field(this, DeclaringType, Name, t);
4955
}
5056
}
5157

csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,16 @@ public override IEnumerable<IExtractionProduct> Contents
7676

7777
var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
7878

79-
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
80-
foreach (var p in Parameters) yield return p;
79+
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
80+
Parameters = parameters.OfType<Parameter>().ToArray();
81+
foreach (var p in parameters) yield return p;
8182

8283
foreach (var f in PopulateFlags) yield return f;
8384

84-
yield return Tuples.cil_method(this, Name, DeclaringType, typeSignature.ReturnType);
85+
foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, typeSignature.ReturnType))
86+
{
87+
yield return m;
88+
}
8589

8690
if (SourceDeclaration != null)
8791
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);

csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.IO;
6-
using Semmle.Util;
76

87
namespace Semmle.Extraction.CIL.Entities
98
{
109
/// <summary>
1110
/// A method entity.
1211
/// </summary>
13-
internal abstract class Method : TypeContainer, IMember
12+
internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver
1413
{
1514
protected MethodTypeParameter[]? genericParams;
1615
protected GenericContext gc;
@@ -21,6 +20,8 @@ protected Method(GenericContext gc) : base(gc.Cx)
2120
this.gc = gc;
2221
}
2322

23+
public ITypeSignature ReturnType => signature.ReturnType;
24+
2425
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters);
2526

2627
public override IEnumerable<Type> MethodParameters =>
@@ -76,7 +77,7 @@ protected IEnumerable<IExtractionProduct> PopulateFlags
7677

7778
public abstract bool IsStatic { get; }
7879

79-
protected IEnumerable<Parameter> MakeParameters(IEnumerable<Type> parameterTypes)
80+
protected IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes)
8081
{
8182
var i = 0;
8283

@@ -86,7 +87,26 @@ protected IEnumerable<Parameter> MakeParameters(IEnumerable<Type> parameterTypes
8687
}
8788

8889
foreach (var p in parameterTypes)
89-
yield return Cx.Populate(new Parameter(Cx, this, i++, p));
90+
{
91+
var t = p;
92+
if (t is ModifiedType mt)
93+
{
94+
t = mt.Unmodified;
95+
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
96+
}
97+
yield return Cx.Populate(new Parameter(Cx, this, i++, t));
98+
}
99+
}
100+
101+
protected IEnumerable<IExtractionProduct> GetMethodExtractionProducts(string name, Type declaringType, Type returnType)
102+
{
103+
var t = returnType;
104+
if (t is ModifiedType mt)
105+
{
106+
t = mt.Unmodified;
107+
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
108+
}
109+
yield return Tuples.cil_method(this, name, declaringType, t);
90110
}
91111
}
92112
}

csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,19 @@ public override IEnumerable<IExtractionProduct> Contents
7777
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
7878
}
7979

80-
Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray();
81-
foreach (var p in Parameters)
80+
var parameters = GetParameterExtractionProducts(constructedTypeSignature.ParameterTypes).ToArray();
81+
Parameters = parameters.OfType<Parameter>().ToArray();
82+
foreach (var p in parameters)
8283
yield return p;
8384

8485
foreach (var f in PopulateFlags)
8586
yield return f;
8687

87-
yield return Tuples.cil_method(this, Name, DeclaringType, constructedTypeSignature.ReturnType);
88+
foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, constructedTypeSignature.ReturnType))
89+
{
90+
yield return m;
91+
}
92+
8893
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
8994

9095
if (typeParams.Length != unboundMethod.GenericParameterCount)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
5+
namespace Semmle.Extraction.CIL.Entities
6+
{
7+
/// <summary>
8+
/// Modified types are not written directly to trap files. Instead, the modifiers are stored
9+
/// on the modifiable entity (field type, property/method/function pointer parameter or return types).
10+
/// </summary>
11+
internal sealed class ModifiedType : Type
12+
{
13+
public ModifiedType(Context cx, Type unmodified, Type modifier, bool isRequired) : base(cx)
14+
{
15+
Unmodified = unmodified;
16+
Modifier = modifier;
17+
IsRequired = isRequired;
18+
}
19+
20+
public Type Unmodified { get; }
21+
public Type Modifier { get; }
22+
public bool IsRequired { get; }
23+
24+
public override CilTypeKind Kind => throw new NotImplementedException();
25+
26+
public override Namespace? ContainingNamespace => throw new NotImplementedException();
27+
28+
public override Type? ContainingType => throw new NotImplementedException();
29+
30+
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
31+
32+
public override int ThisTypeParameterCount => throw new NotImplementedException();
33+
34+
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
35+
36+
public override string Name => $"{Unmodified.Name} {(IsRequired ? "modreq" : "modopt")}({Modifier.Name})";
37+
38+
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
39+
40+
public override void WriteId(TextWriter trapFile, bool inContext) => throw new NotImplementedException();
41+
}
42+
}

csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities
88
/// <summary>
99
/// A property.
1010
/// </summary>
11-
internal sealed class Property : LabelledEntity
11+
internal sealed class Property : LabelledEntity, ICustomModifierReceiver
1212
{
1313
private readonly Handle handle;
1414
private readonly Type type;
@@ -54,7 +54,15 @@ public override IEnumerable<IExtractionProduct> Contents
5454
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
5555
var sig = pd.DecodeSignature(Cx.TypeSignatureDecoder, type);
5656

57-
yield return Tuples.cil_property(this, type, Cx.ShortName(pd.Name), sig.ReturnType);
57+
var name = Cx.ShortName(pd.Name);
58+
59+
var t = sig.ReturnType;
60+
if (t is ModifiedType mt)
61+
{
62+
t = mt.Unmodified;
63+
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
64+
}
65+
yield return Tuples.cil_property(this, type, name, t);
5866

5967
var accessors = pd.GetAccessors();
6068
if (!accessors.Getter.IsNil)

csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Reflection.Metadata;
22
using System.Collections.Immutable;
33
using System.IO;
4+
using System.Linq;
45

56
namespace Semmle.Extraction.CIL.Entities
67
{
@@ -138,21 +139,28 @@ ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericTypePara
138139
private class Modified : ITypeSignature
139140
{
140141
private readonly ITypeSignature unmodifiedType;
142+
private readonly ITypeSignature modifier;
143+
private readonly bool isRequired;
141144

142-
public Modified(ITypeSignature unmodifiedType)
145+
public Modified(ITypeSignature unmodifiedType, ITypeSignature modifier, bool isRequired)
143146
{
144147
this.unmodifiedType = unmodifiedType;
148+
this.modifier = modifier;
149+
this.isRequired = isRequired;
145150
}
146151

147152
public void WriteId(TextWriter trapFile, GenericContext gc)
148153
{
149154
unmodifiedType.WriteId(trapFile, gc);
155+
trapFile.Write(isRequired ? " modreq(" : " modopt(");
156+
modifier.WriteId(trapFile, gc);
157+
trapFile.Write(")");
150158
}
151159
}
152160

153161
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
154162
{
155-
return new Modified(unmodifiedType);
163+
return new Modified(unmodifiedType, modifier, isRequired);
156164
}
157165

158166
private class Pinned : ITypeSignature

csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Type ISignatureTypeProvider<Type, GenericContext>.GetGenericTypeParameter(Generi
3535
genericContext.GetGenericTypeParameter(index);
3636

3737
Type ISignatureTypeProvider<Type, GenericContext>.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) =>
38-
unmodifiedType; // !! Not implemented properly
38+
new ModifiedType(cx, unmodifiedType, modifier, isRequired);
3939

4040
Type ISignatureTypeProvider<Type, GenericContext>.GetPinnedType(Type elementType) =>
4141
cx.Populate(new PointerType(cx, elementType));

0 commit comments

Comments
 (0)