C#: Extract init only accessors and custom modifiers

This commit is contained in:
Tamas Vajk
2020-12-14 11:54:47 +01:00
parent 57c163f314
commit 7662b55ecc
14 changed files with 149 additions and 23 deletions

View File

@@ -76,9 +76,10 @@ namespace Semmle.Extraction.CIL.Entities
var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this); var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray(); var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
Parameters = parameters.OfType<Parameter>().ToArray();
foreach (var c in Parameters) foreach (var c in parameters)
yield return c; yield return c;
foreach (var c in PopulateFlags) foreach (var c in PopulateFlags)
@@ -95,7 +96,12 @@ namespace Semmle.Extraction.CIL.Entities
} }
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle)); yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
yield return Tuples.cil_method(this, Name, declaringType, typeSignature.ReturnType);
foreach (var m in GetMethodExtractionProducts(Name, declaringType, typeSignature.ReturnType))
{
yield return m;
}
yield return Tuples.cil_method_source_declaration(this, this); yield return Tuples.cil_method_source_declaration(this, this);
yield return Tuples.cil_method_location(this, Cx.Assembly); yield return Tuples.cil_method_location(this, Cx.Assembly);

View File

@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// An entity representing a field. /// An entity representing a field.
/// </summary> /// </summary>
internal abstract class Field : GenericContext, IMember internal abstract class Field : GenericContext, IMember, ICustomModifierReceiver
{ {
protected Field(Context cx) : base(cx) protected Field(Context cx) : base(cx)
{ {
@@ -45,7 +45,13 @@ namespace Semmle.Extraction.CIL.Entities
{ {
get get
{ {
yield return Tuples.cil_field(this, DeclaringType, Name, Type); var t = Type;
if (t is ModifiedType mt)
{
t = mt.Unmodified;
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
}
yield return Tuples.cil_field(this, DeclaringType, Name, t);
} }
} }

View File

@@ -76,12 +76,16 @@ namespace Semmle.Extraction.CIL.Entities
var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this); var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray(); var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
foreach (var p in Parameters) yield return p; Parameters = parameters.OfType<Parameter>().ToArray();
foreach (var p in parameters) yield return p;
foreach (var f in PopulateFlags) yield return f; foreach (var f in PopulateFlags) yield return f;
yield return Tuples.cil_method(this, Name, DeclaringType, typeSignature.ReturnType); foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, typeSignature.ReturnType))
{
yield return m;
}
if (SourceDeclaration != null) if (SourceDeclaration != null)
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration); yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);

View File

@@ -3,14 +3,13 @@ using System.Reflection.Metadata;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.IO; using System.IO;
using Semmle.Util;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
/// <summary> /// <summary>
/// A method entity. /// A method entity.
/// </summary> /// </summary>
internal abstract class Method : TypeContainer, IMember internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver
{ {
protected MethodTypeParameter[]? genericParams; protected MethodTypeParameter[]? genericParams;
protected GenericContext gc; protected GenericContext gc;
@@ -21,6 +20,8 @@ namespace Semmle.Extraction.CIL.Entities
this.gc = gc; this.gc = gc;
} }
public ITypeSignature ReturnType => signature.ReturnType;
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters); public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters);
public override IEnumerable<Type> MethodParameters => public override IEnumerable<Type> MethodParameters =>
@@ -76,7 +77,7 @@ namespace Semmle.Extraction.CIL.Entities
public abstract bool IsStatic { get; } public abstract bool IsStatic { get; }
protected IEnumerable<Parameter> MakeParameters(IEnumerable<Type> parameterTypes) protected IEnumerable<IExtractionProduct> GetParameterExtractionProducts(IEnumerable<Type> parameterTypes)
{ {
var i = 0; var i = 0;
@@ -86,7 +87,26 @@ namespace Semmle.Extraction.CIL.Entities
} }
foreach (var p in parameterTypes) foreach (var p in parameterTypes)
yield return Cx.Populate(new Parameter(Cx, this, i++, p)); {
var t = p;
if (t is ModifiedType mt)
{
t = mt.Unmodified;
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
}
yield return Cx.Populate(new Parameter(Cx, this, i++, t));
}
}
protected IEnumerable<IExtractionProduct> GetMethodExtractionProducts(string name, Type declaringType, Type returnType)
{
var t = returnType;
if (t is ModifiedType mt)
{
t = mt.Unmodified;
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
}
yield return Tuples.cil_method(this, name, declaringType, t);
} }
} }
} }

View File

@@ -77,14 +77,19 @@ namespace Semmle.Extraction.CIL.Entities
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}"); throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
} }
Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray(); var parameters = GetParameterExtractionProducts(constructedTypeSignature.ParameterTypes).ToArray();
foreach (var p in Parameters) Parameters = parameters.OfType<Parameter>().ToArray();
foreach (var p in parameters)
yield return p; yield return p;
foreach (var f in PopulateFlags) foreach (var f in PopulateFlags)
yield return f; yield return f;
yield return Tuples.cil_method(this, Name, DeclaringType, constructedTypeSignature.ReturnType); foreach (var m in GetMethodExtractionProducts(Name, DeclaringType, constructedTypeSignature.ReturnType))
{
yield return m;
}
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration); yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
if (typeParams.Length != unboundMethod.GenericParameterCount) if (typeParams.Length != unboundMethod.GenericParameterCount)

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// Modified types are not written directly to trap files. Instead, the modifiers are stored
/// on the modifiable entity (field type, property/method/function pointer parameter or return types).
/// </summary>
internal sealed class ModifiedType : Type
{
public ModifiedType(Context cx, Type unmodified, Type modifier, bool isRequired) : base(cx)
{
Unmodified = unmodified;
Modifier = modifier;
IsRequired = isRequired;
}
public Type Unmodified { get; }
public Type Modifier { get; }
public bool IsRequired { get; }
public override CilTypeKind Kind => throw new NotImplementedException();
public override Namespace? ContainingNamespace => throw new NotImplementedException();
public override Type? ContainingType => throw new NotImplementedException();
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override int ThisTypeParameterCount => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
public override string Name => Unmodified.Name + (IsRequired ? " modreq" : " modopt") + $"({Modifier.Name})";
public override void WriteAssemblyPrefix(TextWriter trapFile) => Unmodified.WriteAssemblyPrefix(trapFile);
public override void WriteId(TextWriter trapFile, bool inContext)
{
Unmodified.WriteId(trapFile, inContext);
trapFile.Write(IsRequired ? " modreq" : " modopt");
trapFile.Write("(");
Modifier.WriteId(trapFile, inContext);
trapFile.Write(")");
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities
/// <summary> /// <summary>
/// A property. /// A property.
/// </summary> /// </summary>
internal sealed class Property : LabelledEntity internal sealed class Property : LabelledEntity, ICustomModifierReceiver
{ {
private readonly Handle handle; private readonly Handle handle;
private readonly Type type; private readonly Type type;
@@ -54,7 +54,15 @@ namespace Semmle.Extraction.CIL.Entities
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle)); yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
var sig = pd.DecodeSignature(Cx.TypeSignatureDecoder, type); var sig = pd.DecodeSignature(Cx.TypeSignatureDecoder, type);
yield return Tuples.cil_property(this, type, Cx.ShortName(pd.Name), sig.ReturnType); var name = Cx.ShortName(pd.Name);
var t = sig.ReturnType;
if (t is ModifiedType mt)
{
t = mt.Unmodified;
yield return Tuples.cil_custom_modifiers(this, mt.Modifier, mt.IsRequired);
}
yield return Tuples.cil_property(this, type, name, t);
var accessors = pd.GetAccessors(); var accessors = pd.GetAccessors();
if (!accessors.Getter.IsNil) if (!accessors.Getter.IsNil)

View File

@@ -1,6 +1,7 @@
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq;
namespace Semmle.Extraction.CIL.Entities namespace Semmle.Extraction.CIL.Entities
{ {
@@ -138,21 +139,28 @@ namespace Semmle.Extraction.CIL.Entities
private class Modified : ITypeSignature private class Modified : ITypeSignature
{ {
private readonly ITypeSignature unmodifiedType; private readonly ITypeSignature unmodifiedType;
private readonly ITypeSignature modifier;
private readonly bool isRequired;
public Modified(ITypeSignature unmodifiedType) public Modified(ITypeSignature unmodifiedType, ITypeSignature modifier, bool isRequired)
{ {
this.unmodifiedType = unmodifiedType; this.unmodifiedType = unmodifiedType;
this.modifier = modifier;
this.isRequired = isRequired;
} }
public void WriteId(TextWriter trapFile, GenericContext gc) public void WriteId(TextWriter trapFile, GenericContext gc)
{ {
unmodifiedType.WriteId(trapFile, gc); unmodifiedType.WriteId(trapFile, gc);
trapFile.Write(isRequired ? " modreq(" : " modopt(");
modifier.WriteId(trapFile, gc);
trapFile.Write(")");
} }
} }
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired) ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
{ {
return new Modified(unmodifiedType); return new Modified(unmodifiedType, modifier, isRequired);
} }
private class Pinned : ITypeSignature private class Pinned : ITypeSignature

View File

@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CIL.Entities
genericContext.GetGenericTypeParameter(index); genericContext.GetGenericTypeParameter(index);
Type ISignatureTypeProvider<Type, GenericContext>.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => Type ISignatureTypeProvider<Type, GenericContext>.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) =>
unmodifiedType; // !! Not implemented properly new ModifiedType(cx, unmodifiedType, modifier, isRequired);
Type ISignatureTypeProvider<Type, GenericContext>.GetPinnedType(Type elementType) => Type ISignatureTypeProvider<Type, GenericContext>.GetPinnedType(Type elementType) =>
cx.Populate(new PointerType(cx, elementType)); cx.Populate(new PointerType(cx, elementType));

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL
{
internal interface ICustomModifierReceiver
{
}
}

View File

@@ -188,6 +188,9 @@ namespace Semmle.Extraction.CIL
internal static Tuple cil_virtual(Method method) => internal static Tuple cil_virtual(Method method) =>
new Tuple("cil_virtual", method); new Tuple("cil_virtual", method);
internal static Tuple cil_custom_modifiers(ICustomModifierReceiver receiver, Type modifier, bool isRequired) =>
new Tuple("cil_custom_modifiers", receiver, modifier, isRequired ? 1 : 0);
internal static Tuple containerparent(Folder parent, IFileOrFolder child) => internal static Tuple containerparent(Folder parent, IFileOrFolder child) =>
new Tuple("containerparent", parent, child); new Tuple("containerparent", parent, child);

View File

@@ -247,8 +247,12 @@ class Setter extends Accessor {
override Property getProperty() { cil_setter(result, this) } override Property getProperty() { cil_setter(result, this) }
/** Holds if this setter is an `init`-only accessor. */ /** Holds if this setter is an `init` accessor. */
predicate isInitOnly() { none() } predicate isInitOnly() {
exists(Type t | t.getQualifiedName() = "System.Runtime.CompilerServices.IsExternalInit" |
cil_custom_modifiers(this, t, 1)
)
}
} }
/** /**

View File

@@ -1712,6 +1712,7 @@ cil_field(
@cil_variable = @cil_field | @cil_stack_variable; @cil_variable = @cil_field | @cil_stack_variable;
@cil_stack_variable = @cil_local_variable | @cil_parameter; @cil_stack_variable = @cil_local_variable | @cil_parameter;
@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; @cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event;
@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field; // todo: add function pointer type
#keyset[method, index] #keyset[method, index]
cil_parameter( cil_parameter(
@@ -1726,6 +1727,12 @@ cil_parameter_out(unique int id: @cil_parameter ref);
cil_setter(unique int prop: @cil_property ref, cil_setter(unique int prop: @cil_property ref,
int method: @cil_method ref); int method: @cil_method ref);
#keyset[id, modifier]
cil_custom_modifiers(
int id: @cil_custom_modifier_receiver ref,
int modifier: @cil_type ref,
int kind: int ref); // modreq: 1, modopt: 0
cil_getter(unique int prop: @cil_property ref, cil_getter(unique int prop: @cil_property ref,
int method: @cil_method ref); int method: @cil_method ref);

View File

@@ -1,2 +1,2 @@
| cil-init-prop.dll:0:0:0:0 | set_Prop1 | set | | cil-init-prop.dll:0:0:0:0 | set_Prop1 | set |
| cil-init-prop.dll:0:0:0:0 | set_Prop2 | set | | cil-init-prop.dll:0:0:0:0 | set_Prop2 | init |