C#: Separate all classes to dedicated files in CIL extractor

This commit is contained in:
Tamas Vajk
2020-12-01 14:34:46 +01:00
parent df29a16365
commit df28544020
73 changed files with 2474 additions and 2256 deletions

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An array type.
/// </summary>
internal sealed class ArrayType : Type, IArrayType
{
private readonly Type elementType;
private readonly int rank;
public ArrayType(Context cx, Type elementType, int rank) : base(cx)
{
this.rank = rank;
this.elementType = elementType;
}
public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1)
{
}
public override bool Equals(object? obj)
{
return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank;
}
public override int GetHashCode()
{
return elementType.GetHashCode() * 5 + rank;
}
public override void WriteId(TextWriter trapFile, bool inContext)
{
elementType.GetId(trapFile, inContext);
trapFile.Write('[');
for (var i = 1; i < rank; ++i)
trapFile.Write(',');
trapFile.Write(']');
}
public override string Name => elementType.Name + "[]";
public override Namespace Namespace => Cx.SystemNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameters => elementType.ThisTypeParameters;
public override CilTypeKind Kind => CilTypeKind.Array;
public override Type Construct(IEnumerable<Type> typeArguments) => Cx.Populate(new ArrayType(Cx, elementType.Construct(typeArguments)));
public override Type SourceDeclaration => Cx.Populate(new ArrayType(Cx, elementType.SourceDeclaration));
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var c in base.Contents)
yield return c;
yield return Tuples.cil_array_type(this, elementType, rank);
}
}
public override void WriteAssemblyPrefix(TextWriter trapFile) => elementType.WriteAssemblyPrefix(trapFile);
public override IEnumerable<Type> GenericArguments => elementType.GenericArguments;
public override IEnumerable<Type> TypeParameters => elementType.TypeParameters;
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
}
}

View File

@@ -9,14 +9,6 @@ using Semmle.Util;
namespace Semmle.Extraction.CIL.Entities
{
public interface ILocation : IEntity
{
}
internal interface IAssembly : ILocation
{
}
/// <summary>
/// An assembly to extract.
/// </summary>

View File

@@ -4,13 +4,6 @@ using System.Reflection.Metadata;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A CIL attribute.
/// </summary>
internal interface IAttribute : IExtractedEntity
{
}
/// <summary>
/// Entity representing a CIL attribute.
/// </summary>
@@ -79,33 +72,4 @@ namespace Semmle.Extraction.CIL.Entities
}
}
}
/// <summary>
/// Helper class to decode the attribute structure.
/// Note that there are some unhandled cases that should be fixed in due course.
/// </summary>
internal class CustomAttributeDecoder : ICustomAttributeTypeProvider<Type>
{
private readonly Context cx;
public CustomAttributeDecoder(Context cx) { this.cx = cx; }
public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
public Type GetSystemType() => throw new NotImplementedException();
public Type GetSZArrayType(Type elementType) =>
cx.Populate(new ArrayType(cx, elementType));
public Type GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
(Type)cx.Create(handle);
public Type GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
(Type)cx.Create(handle);
public Type GetTypeFromSerializedName(string name) => throw new NotImplementedException();
public PrimitiveTypeCode GetUnderlyingEnumType(Type type) => throw new NotImplementedException();
public bool IsSystemType(Type type) => type is PrimitiveType; // ??
}
}

View File

@@ -0,0 +1,13 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// The CIL database type-kind.
/// </summary>
public enum CilTypeKind
{
ValueOrRefType,
TypeParameter,
Array,
Pointer
}
}

View File

@@ -0,0 +1,145 @@
using System;
using Microsoft.CodeAnalysis;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using Semmle.Util;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A constructed type.
/// </summary>
public sealed class ConstructedType : Type
{
private readonly Type unboundGenericType;
// Either null or notEmpty
private readonly Type[]? thisTypeArguments;
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments.EnumerateNull();
public override IEnumerable<Type> ThisGenericArguments => thisTypeArguments.EnumerateNull();
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var c in base.Contents)
yield return c;
var i = 0;
foreach (var type in ThisGenericArguments)
{
yield return type;
yield return Tuples.cil_type_argument(this, i++, type);
}
}
}
public override Type SourceDeclaration => unboundGenericType;
public ConstructedType(Context cx, Type unboundType, IEnumerable<Type> typeArguments) : base(cx)
{
var suppliedArgs = typeArguments.Count();
if (suppliedArgs != unboundType.TotalTypeParametersCheck)
throw new InternalError("Unexpected number of type arguments in ConstructedType");
unboundGenericType = unboundType;
var thisParams = unboundType.ThisTypeParameters;
if (typeArguments.Count() == thisParams)
{
containingType = unboundType.ContainingType;
thisTypeArguments = typeArguments.ToArray();
}
else if (thisParams == 0)
{
// all type arguments belong to containing type
containingType = unboundType.ContainingType!.Construct(typeArguments);
}
else
{
// some type arguments belong to containing type
var parentParams = suppliedArgs - thisParams;
containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams));
thisTypeArguments = typeArguments.Skip(parentParams).ToArray();
}
}
public override bool Equals(object? obj)
{
if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
{
if (thisTypeArguments is null)
return t.thisTypeArguments is null;
if (!(t.thisTypeArguments is null))
return thisTypeArguments.SequenceEqual(t.thisTypeArguments);
}
return false;
}
public override int GetHashCode()
{
var h = unboundGenericType.GetHashCode();
h = 13 * h + (containingType is null ? 0 : containingType.GetHashCode());
if (!(thisTypeArguments is null))
h = h * 13 + thisTypeArguments.SequenceHash();
return h;
}
private readonly Type? containingType;
public override Type? ContainingType => containingType;
public override string Name => unboundGenericType.Name;
public override Namespace Namespace => unboundGenericType.Namespace!;
public override int ThisTypeParameters => thisTypeArguments == null ? 0 : thisTypeArguments.Length;
public override CilTypeKind Kind => unboundGenericType.Kind;
public override Type Construct(IEnumerable<Type> typeArguments)
{
throw new NotImplementedException();
}
public override void WriteId(TextWriter trapFile, bool inContext)
{
if (ContainingType != null)
{
ContainingType.GetId(trapFile, inContext);
trapFile.Write('.');
}
else
{
WriteAssemblyPrefix(trapFile);
if (!Namespace.IsGlobalNamespace)
{
Namespace.WriteId(trapFile);
trapFile.Write('.');
}
}
trapFile.Write(unboundGenericType.Name);
if (thisTypeArguments != null && thisTypeArguments.Any())
{
trapFile.Write('<');
var index = 0;
foreach (var t in thisTypeArguments)
{
trapFile.WriteSeparator(",", ref index);
t.WriteId(trapFile);
}
trapFile.Write('>');
}
}
public override void WriteAssemblyPrefix(TextWriter trapFile) => unboundGenericType.WriteAssemblyPrefix(trapFile);
public override IEnumerable<Type> TypeParameters => GenericArguments;
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Reflection.Metadata;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// Helper class to decode the attribute structure.
/// Note that there are some unhandled cases that should be fixed in due course.
/// </summary>
internal class CustomAttributeDecoder : ICustomAttributeTypeProvider<Type>
{
private readonly Context cx;
public CustomAttributeDecoder(Context cx) { this.cx = cx; }
public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
public Type GetSystemType() => throw new NotImplementedException();
public Type GetSZArrayType(Type elementType) =>
cx.Populate(new ArrayType(cx, elementType));
public Type GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
(Type)cx.Create(handle);
public Type GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
(Type)cx.Create(handle);
public Type GetTypeFromSerializedName(string name) => throw new NotImplementedException();
public PrimitiveTypeCode GetUnderlyingEnumType(Type type) => throw new NotImplementedException();
public bool IsSystemType(Type type) => type is PrimitiveType; // ??
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class DefinitionField : Field
{
private readonly Handle handle;
private readonly FieldDefinition fd;
public DefinitionField(Context cx, FieldDefinitionHandle handle) : base(cx)
{
this.handle = handle;
fd = Cx.MdReader.GetFieldDefinition(handle);
}
public override bool Equals(object? obj)
{
return obj is DefinitionField field && handle.Equals(field.handle);
}
public override int GetHashCode() => handle.GetHashCode();
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
foreach (var c in base.Contents)
yield return c;
if (fd.Attributes.HasFlag(FieldAttributes.Private))
yield return Tuples.cil_private(this);
if (fd.Attributes.HasFlag(FieldAttributes.Public))
yield return Tuples.cil_public(this);
if (fd.Attributes.HasFlag(FieldAttributes.Family))
yield return Tuples.cil_protected(this);
if (fd.Attributes.HasFlag(FieldAttributes.Static))
yield return Tuples.cil_static(this);
if (fd.Attributes.HasFlag(FieldAttributes.Assembly))
yield return Tuples.cil_internal(this);
foreach (var c in Attribute.Populate(Cx, this, fd.GetCustomAttributes()))
yield return c;
}
}
public override string Name => Cx.GetString(fd.Name);
public override Type DeclaringType => (Type)Cx.Create(fd.GetDeclaringType());
public override Type Type => fd.DecodeSignature(Cx.TypeSignatureDecoder, DeclaringType);
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,266 @@
using System.Reflection.Metadata;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A definition method - a method defined in the current assembly.
/// </summary>
internal sealed class DefinitionMethod : Method, IMember
{
private readonly Handle handle;
private readonly MethodDefinition md;
private readonly PDB.IMethod? methodDebugInformation;
private readonly Type declaringType;
private readonly string name;
private LocalVariable[]? locals;
public MethodImplementation? Implementation { get; private set; }
public override IList<LocalVariable>? LocalVariables => locals;
public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc)
{
md = Cx.MdReader.GetMethodDefinition(handle);
this.gc = gc;
this.handle = handle;
name = Cx.GetString(md.Name);
declaringType = (Type)Cx.CreateGeneric(this, md.GetDeclaringType());
signature = md.DecodeSignature(new SignatureDecoder(), this);
methodDebugInformation = Cx.GetMethodDebugInformation(handle);
}
public override bool Equals(object? obj)
{
return obj is DefinitionMethod method && handle.Equals(method.handle);
}
public override int GetHashCode() => handle.GetHashCode();
public override bool IsStatic => !signature.Header.IsInstance;
public override Type DeclaringType => declaringType;
public override string Name => Cx.ShortName(md.Name);
public override string NameLabel => name;
/// <summary>
/// Holds if this method has bytecode.
/// </summary>
public bool HasBytecode => md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0;
public override IEnumerable<IExtractionProduct> Contents
{
get
{
if (md.GetGenericParameters().Any())
{
// We need to perform a 2-phase population because some type parameters can
// depend on other type parameters (as a constraint).
genericParams = new MethodTypeParameter[md.GetGenericParameters().Count];
for (var i = 0; i < genericParams.Length; ++i)
genericParams[i] = Cx.Populate(new MethodTypeParameter(this, this, i));
for (var i = 0; i < genericParams.Length; ++i)
genericParams[i].PopulateHandle(md.GetGenericParameters()[i]);
foreach (var p in genericParams)
yield return p;
}
var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
foreach (var c in Parameters)
yield return c;
foreach (var c in PopulateFlags)
yield return c;
foreach (var p in md.GetParameters().Select(h => Cx.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0))
{
var pe = Parameters[IsStatic ? p.SequenceNumber - 1 : p.SequenceNumber];
if (p.Attributes.HasFlag(ParameterAttributes.Out))
yield return Tuples.cil_parameter_out(pe);
if (p.Attributes.HasFlag(ParameterAttributes.In))
yield return Tuples.cil_parameter_in(pe);
Attribute.Populate(Cx, pe, p.GetCustomAttributes());
}
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
yield return Tuples.cil_method(this, Name, declaringType, typeSignature.ReturnType);
yield return Tuples.cil_method_source_declaration(this, this);
yield return Tuples.cil_method_location(this, Cx.Assembly);
if (HasBytecode)
{
Implementation = new MethodImplementation(this);
yield return Implementation;
var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress);
if (!body.LocalSignature.IsNil)
{
var locals = Cx.MdReader.GetStandaloneSignature(body.LocalSignature);
var localVariableTypes = locals.DecodeLocalSignature(Cx.TypeSignatureDecoder, this);
this.locals = new LocalVariable[localVariableTypes.Length];
for (var l = 0; l < this.locals.Length; ++l)
{
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, localVariableTypes[l]));
yield return this.locals[l];
}
}
var jump_table = new Dictionary<int, IInstruction>();
foreach (var c in Decode(body.GetILBytes(), jump_table))
yield return c;
var filter_index = 0;
foreach (var region in body.ExceptionRegions)
{
yield return new ExceptionRegion(this, Implementation, filter_index++, region, jump_table);
}
yield return Tuples.cil_method_stack_size(Implementation, body.MaxStack);
if (methodDebugInformation != null)
{
var sourceLocation = Cx.CreateSourceLocation(methodDebugInformation.Location);
yield return sourceLocation;
yield return Tuples.cil_method_location(this, sourceLocation);
}
}
// Flags
if (md.Attributes.HasFlag(MethodAttributes.Private))
yield return Tuples.cil_private(this);
if (md.Attributes.HasFlag(MethodAttributes.Public))
yield return Tuples.cil_public(this);
if (md.Attributes.HasFlag(MethodAttributes.Family))
yield return Tuples.cil_protected(this);
if (md.Attributes.HasFlag(MethodAttributes.Final))
yield return Tuples.cil_sealed(this);
if (md.Attributes.HasFlag(MethodAttributes.Virtual))
yield return Tuples.cil_virtual(this);
if (md.Attributes.HasFlag(MethodAttributes.Abstract))
yield return Tuples.cil_abstract(this);
if (md.Attributes.HasFlag(MethodAttributes.HasSecurity))
yield return Tuples.cil_security(this);
if (md.Attributes.HasFlag(MethodAttributes.RequireSecObject))
yield return Tuples.cil_requiresecobject(this);
if (md.Attributes.HasFlag(MethodAttributes.SpecialName))
yield return Tuples.cil_specialname(this);
if (md.Attributes.HasFlag(MethodAttributes.NewSlot))
yield return Tuples.cil_newslot(this);
// Populate attributes
Attribute.Populate(Cx, this, md.GetCustomAttributes());
}
}
private IEnumerable<IExtractionProduct> Decode(byte[] ilbytes, Dictionary<int, IInstruction> jump_table)
{
// Sequence points are stored in order of offset.
// We use an enumerator to locate the correct sequence point for each instruction.
// The sequence point gives the location of each instruction.
// The location of an instruction is given by the sequence point *after* the
// instruction.
IEnumerator<PDB.SequencePoint>? nextSequencePoint = null;
PdbSourceLocation? instructionLocation = null;
if (methodDebugInformation != null)
{
nextSequencePoint = methodDebugInformation.SequencePoints.GetEnumerator();
if (nextSequencePoint.MoveNext())
{
instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location);
yield return instructionLocation;
}
else
{
nextSequencePoint = null;
}
}
var child = 0;
for (var offset = 0; offset < ilbytes.Length;)
{
var instruction = new Instruction(Cx, this, ilbytes, offset, child++);
yield return instruction;
if (nextSequencePoint != null && offset >= nextSequencePoint.Current.Offset)
{
instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location);
yield return instructionLocation;
if (!nextSequencePoint.MoveNext())
nextSequencePoint = null;
}
if (instructionLocation != null)
yield return Tuples.cil_instruction_location(instruction, instructionLocation);
jump_table.Add(instruction.Offset, instruction);
offset += instruction.Width;
}
foreach (var i in jump_table)
{
foreach (var t in i.Value.JumpContents(jump_table))
yield return t;
}
}
/// <summary>
/// Display the instructions in the method in the debugger.
/// This is only used for debugging, not in the code itself.
/// </summary>
public IEnumerable<Instruction> DebugInstructions
{
get
{
if (md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0)
{
var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress);
var ilbytes = body.GetILBytes();
var child = 0;
for (var offset = 0; offset < ilbytes.Length;)
{
Instruction decoded;
try
{
decoded = new Instruction(Cx, this, ilbytes, offset, child++);
offset += decoded.Width;
}
catch // lgtm[cs/catch-of-all-exceptions]
{
yield break;
}
yield return decoded;
}
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class ErrorType : Type
{
public ErrorType(Context cx) : base(cx)
{
}
public override void WriteId(TextWriter trapFile, bool inContext) => trapFile.Write("<ErrorType>");
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
public override string Name => "!error";
public override Namespace Namespace => Cx.GlobalNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
}
}

View File

@@ -4,13 +4,6 @@ using System.Reflection.Metadata;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An event.
/// </summary>
internal interface IEvent : IExtractedEntity
{
}
/// <summary>
/// An event entity.
/// </summary>

View File

@@ -2,10 +2,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IExceptionRegion : IExtractedEntity
{
}
/// <summary>
/// An exception region entity.
/// </summary>

View File

@@ -1,29 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using System.Reflection.Metadata;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An entity represting a member.
/// Used to type tuples correctly.
/// </summary>
internal interface IMember : IExtractedEntity
{
}
/// <summary>
/// An entity representing a field.
/// </summary>
internal interface IField : IMember
{
}
/// <summary>
/// An entity representing a field.
/// </summary>
@@ -75,98 +56,4 @@ namespace Semmle.Extraction.CIL.Entities
TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
internal sealed class DefinitionField : Field
{
private readonly Handle handle;
private readonly FieldDefinition fd;
public DefinitionField(Context cx, FieldDefinitionHandle handle) : base(cx)
{
this.handle = handle;
fd = Cx.MdReader.GetFieldDefinition(handle);
}
public override bool Equals(object? obj)
{
return obj is DefinitionField field && handle.Equals(field.handle);
}
public override int GetHashCode() => handle.GetHashCode();
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
foreach (var c in base.Contents)
yield return c;
if (fd.Attributes.HasFlag(FieldAttributes.Private))
yield return Tuples.cil_private(this);
if (fd.Attributes.HasFlag(FieldAttributes.Public))
yield return Tuples.cil_public(this);
if (fd.Attributes.HasFlag(FieldAttributes.Family))
yield return Tuples.cil_protected(this);
if (fd.Attributes.HasFlag(FieldAttributes.Static))
yield return Tuples.cil_static(this);
if (fd.Attributes.HasFlag(FieldAttributes.Assembly))
yield return Tuples.cil_internal(this);
foreach (var c in Attribute.Populate(Cx, this, fd.GetCustomAttributes()))
yield return c;
}
}
public override string Name => Cx.GetString(fd.Name);
public override Type DeclaringType => (Type)Cx.Create(fd.GetDeclaringType());
public override Type Type => fd.DecodeSignature(Cx.TypeSignatureDecoder, DeclaringType);
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
}
internal sealed class MemberReferenceField : Field
{
private readonly MemberReferenceHandle handle;
private readonly MemberReference mr;
private readonly GenericContext gc;
private readonly Type declType;
public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.Cx)
{
this.handle = handle;
this.gc = gc;
mr = Cx.MdReader.GetMemberReference(handle);
declType = (Type)Cx.CreateGeneric(gc, mr.Parent);
}
public override bool Equals(object? obj)
{
return obj is MemberReferenceField field && handle.Equals(field.handle);
}
public override int GetHashCode()
{
return handle.GetHashCode();
}
public override string Name => Cx.GetString(mr.Name);
public override Type DeclaringType => declType;
public override Type Type => mr.DecodeFieldSignature(Cx.TypeSignatureDecoder, this);
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declType.TypeParameters);
public override IEnumerable<Type> MethodParameters => gc.MethodParameters.Concat(declType.MethodParameters);
}
}

View File

@@ -3,14 +3,6 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal interface IFileOrFolder : IEntity
{
}
internal interface IFile : IFileOrFolder
{
}
public class File : LabelledEntity, IFile
{
protected string OriginalPath { get; }
@@ -50,32 +42,4 @@ namespace Semmle.Extraction.CIL.Entities
public override string IdSuffix => ";sourcefile";
}
public class PdbSourceFile : File
{
private readonly PDB.ISourceFile file;
public PdbSourceFile(Context cx, PDB.ISourceFile file) : base(cx, file.Path)
{
this.file = file;
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var c in base.Contents)
yield return c;
var text = file.Contents;
if (text == null)
Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath));
else
Cx.Cx.TrapWriter.Archive(TransformedPath, text);
yield return Tuples.file_extraction_mode(this, 2);
}
}
}
}

View File

@@ -3,10 +3,6 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal interface IFolder : IFileOrFolder
{
}
public sealed class Folder : LabelledEntity, IFolder
{
private readonly PathTransformer.ITransformedPath transformedPath;

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An array type.
/// </summary>
internal interface IArrayType : IType
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IAssembly : ILocation
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A CIL attribute.
/// </summary>
internal interface IAttribute : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An event.
/// </summary>
internal interface IEvent : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IExceptionRegion : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An entity representing a field.
/// </summary>
internal interface IField : IMember
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IFile : IFileOrFolder
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IFileOrFolder : IEntity
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IFolder : IFileOrFolder
{
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A CIL instruction.
/// </summary>
internal interface IInstruction : IExtractedEntity
{
/// <summary>
/// Gets the extraction products for branches.
/// </summary>
/// <param name="jump_table">The map from offset to instruction.</param>
/// <returns>The extraction products.</returns>
IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, IInstruction> jump_table);
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface ILocal : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
public interface ILocation : IEntity
{
}
}

View File

@@ -0,0 +1,10 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// An entity represting a member.
/// Used to type tuples correctly.
/// </summary>
internal interface IMember : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A method entity.
/// </summary>
internal interface IMethod : IMember
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A method implementation entity.
/// </summary>
internal interface IMethodImplementation : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A namespace.
/// </summary>
internal interface INamespace : ITypeContainer
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A parameter entity.
/// </summary>
internal interface IParameter : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface IPointerType : IType
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A property.
/// </summary>
internal interface IProperty : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
public interface ISourceLocation : ILocation
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A type.
/// </summary>
internal interface IType : IEntity
{
}
}

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A type container (namespace/types/method).
/// </summary>
internal interface ITypeContainer : IExtractedEntity
{
}
}

View File

@@ -0,0 +1,6 @@
namespace Semmle.Extraction.CIL.Entities
{
internal interface ITypeParameter : IType
{
}
}

View File

@@ -0,0 +1,9 @@
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal interface ITypeSignature
{
void WriteId(TextWriter trapFile, GenericContext gc);
}
}

View File

@@ -5,19 +5,6 @@ using System.Reflection.Metadata.Ecma335;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A CIL instruction.
/// </summary>
internal interface IInstruction : IExtractedEntity
{
/// <summary>
/// Gets the extraction products for branches.
/// </summary>
/// <param name="jump_table">The map from offset to instruction.</param>
/// <returns>The extraction products.</returns>
IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, IInstruction> jump_table);
}
/// <summary>
/// A CIL instruction.
/// </summary>

View File

@@ -3,10 +3,6 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal interface ILocal : IExtractedEntity
{
}
internal class LocalVariable : LabelledEntity, ILocal
{
private readonly MethodImplementation method;

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class MemberReferenceField : Field
{
private readonly MemberReferenceHandle handle;
private readonly MemberReference mr;
private readonly GenericContext gc;
private readonly Type declType;
public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.Cx)
{
this.handle = handle;
this.gc = gc;
mr = Cx.MdReader.GetMemberReference(handle);
declType = (Type)Cx.CreateGeneric(gc, mr.Parent);
}
public override bool Equals(object? obj)
{
return obj is MemberReferenceField field && handle.Equals(field.handle);
}
public override int GetHashCode()
{
return handle.GetHashCode();
}
public override string Name => Cx.GetString(mr.Name);
public override Type DeclaringType => declType;
public override Type Type => mr.DecodeFieldSignature(Cx.TypeSignatureDecoder, this);
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declType.TypeParameters);
public override IEnumerable<Type> MethodParameters => gc.MethodParameters.Concat(declType.MethodParameters);
}
}

View File

@@ -0,0 +1,91 @@
using System.Reflection.Metadata;
using System.Collections.Generic;
using System.Linq;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// This is a late-bound reference to a method.
/// </summary>
internal sealed class MemberReferenceMethod : Method
{
private readonly MemberReferenceHandle handle;
private readonly MemberReference mr;
private readonly Type declaringType;
private readonly GenericContext parent;
private readonly Method? sourceDeclaration;
public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc)
{
this.handle = handle;
this.gc = gc;
mr = Cx.MdReader.GetMemberReference(handle);
signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc);
parent = (GenericContext)Cx.CreateGeneric(gc, mr.Parent);
var declType = parent is Method parentMethod
? parentMethod.DeclaringType
: parent as Type;
if (declType is null)
throw new InternalError("Parent context of method is not a type");
declaringType = declType;
nameLabel = Cx.GetString(mr.Name);
var typeSourceDeclaration = declaringType.SourceDeclaration;
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
}
private readonly string nameLabel;
public override string NameLabel => nameLabel;
public override bool Equals(object? obj)
{
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
}
public override int GetHashCode()
{
return handle.GetHashCode();
}
public override Method? SourceDeclaration => sourceDeclaration;
public override bool IsStatic => !signature.Header.IsInstance;
public override Type DeclaringType => declaringType;
public override string Name => Cx.ShortName(mr.Name);
public override IEnumerable<Type> TypeParameters => parent.TypeParameters.Concat(gc.TypeParameters);
public override IEnumerable<IExtractionProduct> Contents
{
get
{
genericParams = new MethodTypeParameter[signature.GenericParameterCount];
for (var p = 0; p < genericParams.Length; ++p)
genericParams[p] = Cx.Populate(new MethodTypeParameter(this, this, p));
foreach (var p in genericParams)
yield return p;
var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
foreach (var p in Parameters) yield return p;
foreach (var f in PopulateFlags) yield return f;
yield return Tuples.cil_method(this, Name, DeclaringType, typeSignature.ReturnType);
if (SourceDeclaration != null)
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
}
}
}
}

View File

@@ -1,22 +1,12 @@
using System;
using System.Collections.Immutable;
using System.Reflection.Metadata;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.IO;
using Semmle.Util;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A method entity.
/// </summary>
internal interface IMethod : IMember
{
}
/// <summary>
/// A method entity.
/// </summary>
@@ -99,467 +89,4 @@ namespace Semmle.Extraction.CIL.Entities
yield return Cx.Populate(new Parameter(Cx, this, i++, p));
}
}
/// <summary>
/// A method implementation entity.
/// </summary>
internal interface IMethodImplementation : IExtractedEntity
{
}
/// <summary>
/// A method implementation entity.
/// In the database, the same method could in principle have multiple implementations.
/// </summary>
internal class MethodImplementation : UnlabelledEntity, IMethodImplementation
{
private readonly Method m;
public MethodImplementation(Method m) : base(m.Cx)
{
this.m = m;
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.cil_method_implementation(this, m, Cx.Assembly);
}
}
}
/// <summary>
/// A definition method - a method defined in the current assembly.
/// </summary>
internal sealed class DefinitionMethod : Method, IMember
{
private readonly Handle handle;
private readonly MethodDefinition md;
private readonly PDB.IMethod? methodDebugInformation;
private readonly Type declaringType;
private readonly string name;
private LocalVariable[]? locals;
public MethodImplementation? Implementation { get; private set; }
public override IList<LocalVariable>? LocalVariables => locals;
public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc)
{
md = Cx.MdReader.GetMethodDefinition(handle);
this.gc = gc;
this.handle = handle;
name = Cx.GetString(md.Name);
declaringType = (Type)Cx.CreateGeneric(this, md.GetDeclaringType());
signature = md.DecodeSignature(new SignatureDecoder(), this);
methodDebugInformation = Cx.GetMethodDebugInformation(handle);
}
public override bool Equals(object? obj)
{
return obj is DefinitionMethod method && handle.Equals(method.handle);
}
public override int GetHashCode() => handle.GetHashCode();
public override bool IsStatic => !signature.Header.IsInstance;
public override Type DeclaringType => declaringType;
public override string Name => Cx.ShortName(md.Name);
public override string NameLabel => name;
/// <summary>
/// Holds if this method has bytecode.
/// </summary>
public bool HasBytecode => md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0;
public override IEnumerable<IExtractionProduct> Contents
{
get
{
if (md.GetGenericParameters().Any())
{
// We need to perform a 2-phase population because some type parameters can
// depend on other type parameters (as a constraint).
genericParams = new MethodTypeParameter[md.GetGenericParameters().Count];
for (var i = 0; i < genericParams.Length; ++i)
genericParams[i] = Cx.Populate(new MethodTypeParameter(this, this, i));
for (var i = 0; i < genericParams.Length; ++i)
genericParams[i].PopulateHandle(md.GetGenericParameters()[i]);
foreach (var p in genericParams)
yield return p;
}
var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
foreach (var c in Parameters)
yield return c;
foreach (var c in PopulateFlags)
yield return c;
foreach (var p in md.GetParameters().Select(h => Cx.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0))
{
var pe = Parameters[IsStatic ? p.SequenceNumber - 1 : p.SequenceNumber];
if (p.Attributes.HasFlag(ParameterAttributes.Out))
yield return Tuples.cil_parameter_out(pe);
if (p.Attributes.HasFlag(ParameterAttributes.In))
yield return Tuples.cil_parameter_in(pe);
Attribute.Populate(Cx, pe, p.GetCustomAttributes());
}
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
yield return Tuples.cil_method(this, Name, declaringType, typeSignature.ReturnType);
yield return Tuples.cil_method_source_declaration(this, this);
yield return Tuples.cil_method_location(this, Cx.Assembly);
if (HasBytecode)
{
Implementation = new MethodImplementation(this);
yield return Implementation;
var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress);
if (!body.LocalSignature.IsNil)
{
var locals = Cx.MdReader.GetStandaloneSignature(body.LocalSignature);
var localVariableTypes = locals.DecodeLocalSignature(Cx.TypeSignatureDecoder, this);
this.locals = new LocalVariable[localVariableTypes.Length];
for (var l = 0; l < this.locals.Length; ++l)
{
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, localVariableTypes[l]));
yield return this.locals[l];
}
}
var jump_table = new Dictionary<int, IInstruction>();
foreach (var c in Decode(body.GetILBytes(), jump_table))
yield return c;
var filter_index = 0;
foreach (var region in body.ExceptionRegions)
{
yield return new ExceptionRegion(this, Implementation, filter_index++, region, jump_table);
}
yield return Tuples.cil_method_stack_size(Implementation, body.MaxStack);
if (methodDebugInformation != null)
{
var sourceLocation = Cx.CreateSourceLocation(methodDebugInformation.Location);
yield return sourceLocation;
yield return Tuples.cil_method_location(this, sourceLocation);
}
}
// Flags
if (md.Attributes.HasFlag(MethodAttributes.Private))
yield return Tuples.cil_private(this);
if (md.Attributes.HasFlag(MethodAttributes.Public))
yield return Tuples.cil_public(this);
if (md.Attributes.HasFlag(MethodAttributes.Family))
yield return Tuples.cil_protected(this);
if (md.Attributes.HasFlag(MethodAttributes.Final))
yield return Tuples.cil_sealed(this);
if (md.Attributes.HasFlag(MethodAttributes.Virtual))
yield return Tuples.cil_virtual(this);
if (md.Attributes.HasFlag(MethodAttributes.Abstract))
yield return Tuples.cil_abstract(this);
if (md.Attributes.HasFlag(MethodAttributes.HasSecurity))
yield return Tuples.cil_security(this);
if (md.Attributes.HasFlag(MethodAttributes.RequireSecObject))
yield return Tuples.cil_requiresecobject(this);
if (md.Attributes.HasFlag(MethodAttributes.SpecialName))
yield return Tuples.cil_specialname(this);
if (md.Attributes.HasFlag(MethodAttributes.NewSlot))
yield return Tuples.cil_newslot(this);
// Populate attributes
Attribute.Populate(Cx, this, md.GetCustomAttributes());
}
}
private IEnumerable<IExtractionProduct> Decode(byte[] ilbytes, Dictionary<int, IInstruction> jump_table)
{
// Sequence points are stored in order of offset.
// We use an enumerator to locate the correct sequence point for each instruction.
// The sequence point gives the location of each instruction.
// The location of an instruction is given by the sequence point *after* the
// instruction.
IEnumerator<PDB.SequencePoint>? nextSequencePoint = null;
PdbSourceLocation? instructionLocation = null;
if (methodDebugInformation != null)
{
nextSequencePoint = methodDebugInformation.SequencePoints.GetEnumerator();
if (nextSequencePoint.MoveNext())
{
instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location);
yield return instructionLocation;
}
else
{
nextSequencePoint = null;
}
}
var child = 0;
for (var offset = 0; offset < ilbytes.Length;)
{
var instruction = new Instruction(Cx, this, ilbytes, offset, child++);
yield return instruction;
if (nextSequencePoint != null && offset >= nextSequencePoint.Current.Offset)
{
instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location);
yield return instructionLocation;
if (!nextSequencePoint.MoveNext())
nextSequencePoint = null;
}
if (instructionLocation != null)
yield return Tuples.cil_instruction_location(instruction, instructionLocation);
jump_table.Add(instruction.Offset, instruction);
offset += instruction.Width;
}
foreach (var i in jump_table)
{
foreach (var t in i.Value.JumpContents(jump_table))
yield return t;
}
}
/// <summary>
/// Display the instructions in the method in the debugger.
/// This is only used for debugging, not in the code itself.
/// </summary>
public IEnumerable<Instruction> DebugInstructions
{
get
{
if (md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0)
{
var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress);
var ilbytes = body.GetILBytes();
var child = 0;
for (var offset = 0; offset < ilbytes.Length;)
{
Instruction decoded;
try
{
decoded = new Instruction(Cx, this, ilbytes, offset, child++);
offset += decoded.Width;
}
catch // lgtm[cs/catch-of-all-exceptions]
{
yield break;
}
yield return decoded;
}
}
}
}
}
/// <summary>
/// This is a late-bound reference to a method.
/// </summary>
internal sealed class MemberReferenceMethod : Method
{
private readonly MemberReferenceHandle handle;
private readonly MemberReference mr;
private readonly Type declaringType;
private readonly GenericContext parent;
private readonly Method? sourceDeclaration;
public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc)
{
this.handle = handle;
this.gc = gc;
mr = Cx.MdReader.GetMemberReference(handle);
signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc);
parent = (GenericContext)Cx.CreateGeneric(gc, mr.Parent);
var declType = parent is Method parentMethod
? parentMethod.DeclaringType
: parent as Type;
if (declType is null)
throw new InternalError("Parent context of method is not a type");
declaringType = declType;
nameLabel = Cx.GetString(mr.Name);
var typeSourceDeclaration = declaringType.SourceDeclaration;
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
}
private readonly string nameLabel;
public override string NameLabel => nameLabel;
public override bool Equals(object? obj)
{
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
}
public override int GetHashCode()
{
return handle.GetHashCode();
}
public override Method? SourceDeclaration => sourceDeclaration;
public override bool IsStatic => !signature.Header.IsInstance;
public override Type DeclaringType => declaringType;
public override string Name => Cx.ShortName(mr.Name);
public override IEnumerable<Type> TypeParameters => parent.TypeParameters.Concat(gc.TypeParameters);
public override IEnumerable<IExtractionProduct> Contents
{
get
{
genericParams = new MethodTypeParameter[signature.GenericParameterCount];
for (var p = 0; p < genericParams.Length; ++p)
genericParams[p] = Cx.Populate(new MethodTypeParameter(this, this, p));
foreach (var p in genericParams)
yield return p;
var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
foreach (var p in Parameters) yield return p;
foreach (var f in PopulateFlags) yield return f;
yield return Tuples.cil_method(this, Name, DeclaringType, typeSignature.ReturnType);
if (SourceDeclaration != null)
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
}
}
}
/// <summary>
/// A constructed method.
/// </summary>
internal sealed class MethodSpecificationMethod : Method
{
private readonly MethodSpecificationHandle handle;
private readonly MethodSpecification ms;
private readonly Method unboundMethod;
private readonly ImmutableArray<Type> typeParams;
public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc)
{
this.handle = handle;
ms = Cx.MdReader.GetMethodSpecification(handle);
typeParams = ms.DecodeSignature(Cx.TypeSignatureDecoder, gc);
unboundMethod = (Method)Cx.CreateGeneric(gc, ms.Method);
}
public override void WriteId(TextWriter trapFile)
{
unboundMethod.WriteId(trapFile);
trapFile.Write('<');
var index = 0;
foreach (var param in typeParams)
{
trapFile.WriteSeparator(",", ref index);
trapFile.WriteSubId(param);
}
trapFile.Write('>');
}
public override string NameLabel => throw new NotImplementedException();
public override bool Equals(object? obj)
{
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
}
public override int GetHashCode() => handle.GetHashCode() * 11 + typeParams.SequenceHash();
public override Method SourceDeclaration => unboundMethod;
public override Type DeclaringType => unboundMethod.DeclaringType;
public override string Name => unboundMethod.Name;
public override bool IsStatic => unboundMethod.IsStatic;
public override IEnumerable<Type> MethodParameters => typeParams;
public override IEnumerable<IExtractionProduct> Contents
{
get
{
MethodSignature<Type> constructedTypeSignature;
switch (ms.Method.Kind)
{
case HandleKind.MemberReference:
var mr = Cx.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method);
constructedTypeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
break;
case HandleKind.MethodDefinition:
var md = Cx.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
constructedTypeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
break;
default:
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
}
Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray();
foreach (var p in Parameters)
yield return p;
foreach (var f in PopulateFlags)
yield return f;
yield return Tuples.cil_method(this, Name, DeclaringType, constructedTypeSignature.ReturnType);
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
if (typeParams.Length != unboundMethod.GenericParameterCount)
throw new InternalError("Method type parameter mismatch");
for (var p = 0; p < typeParams.Length; ++p)
{
yield return Tuples.cil_type_argument(this, p, typeParams[p]);
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A method implementation entity.
/// In the database, the same method could in principle have multiple implementations.
/// </summary>
internal class MethodImplementation : UnlabelledEntity, IMethodImplementation
{
private readonly Method m;
public MethodImplementation(Method m) : base(m.Cx)
{
this.m = m;
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.cil_method_implementation(this, m, Cx.Assembly);
}
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Immutable;
using System.Reflection.Metadata;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Semmle.Util;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A constructed method.
/// </summary>
internal sealed class MethodSpecificationMethod : Method
{
private readonly MethodSpecificationHandle handle;
private readonly MethodSpecification ms;
private readonly Method unboundMethod;
private readonly ImmutableArray<Type> typeParams;
public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc)
{
this.handle = handle;
ms = Cx.MdReader.GetMethodSpecification(handle);
typeParams = ms.DecodeSignature(Cx.TypeSignatureDecoder, gc);
unboundMethod = (Method)Cx.CreateGeneric(gc, ms.Method);
}
public override void WriteId(TextWriter trapFile)
{
unboundMethod.WriteId(trapFile);
trapFile.Write('<');
var index = 0;
foreach (var param in typeParams)
{
trapFile.WriteSeparator(",", ref index);
trapFile.WriteSubId(param);
}
trapFile.Write('>');
}
public override string NameLabel => throw new NotImplementedException();
public override bool Equals(object? obj)
{
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
}
public override int GetHashCode() => handle.GetHashCode() * 11 + typeParams.SequenceHash();
public override Method SourceDeclaration => unboundMethod;
public override Type DeclaringType => unboundMethod.DeclaringType;
public override string Name => unboundMethod.Name;
public override bool IsStatic => unboundMethod.IsStatic;
public override IEnumerable<Type> MethodParameters => typeParams;
public override IEnumerable<IExtractionProduct> Contents
{
get
{
MethodSignature<Type> constructedTypeSignature;
switch (ms.Method.Kind)
{
case HandleKind.MemberReference:
var mr = Cx.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method);
constructedTypeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
break;
case HandleKind.MethodDefinition:
var md = Cx.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
constructedTypeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
break;
default:
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
}
Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray();
foreach (var p in Parameters)
yield return p;
foreach (var f in PopulateFlags)
yield return f;
yield return Tuples.cil_method(this, Name, DeclaringType, constructedTypeSignature.ReturnType);
yield return Tuples.cil_method_source_declaration(this, SourceDeclaration);
if (typeParams.Length != unboundMethod.GenericParameterCount)
throw new InternalError("Method type parameter mismatch");
for (var p = 0; p < typeParams.Length; ++p)
{
yield return Tuples.cil_type_argument(this, p, typeParams[p]);
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class MethodTypeParameter : TypeParameter
{
private readonly Method method;
private readonly int index;
public override void WriteId(TextWriter trapFile, bool inContext)
{
if (!(inContext && method == gc))
{
trapFile.WriteSubId(method);
}
trapFile.Write("!");
trapFile.Write(index);
}
public override string Name => "!" + index;
public MethodTypeParameter(GenericContext gc, Method m, int index) : base(gc)
{
method = m;
this.index = index;
}
public override bool Equals(object? obj)
{
return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index;
}
public override int GetHashCode()
{
return method.GetHashCode() * 29 + index;
}
public override TypeContainer Parent => method;
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.cil_type(this, Name, Kind, method, SourceDeclaration);
yield return Tuples.cil_type_parameter(method, index, this);
}
}
}
}

View File

@@ -4,13 +4,6 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A namespace.
/// </summary>
internal interface INamespace : ITypeContainer
{
}
/// <summary>
/// A namespace.
/// </summary>

View File

@@ -3,13 +3,6 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A parameter entity.
/// </summary>
internal interface IParameter : IExtractedEntity
{
}
/// <summary>
/// A parameter entity.
/// </summary>

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
namespace Semmle.Extraction.CIL.Entities
{
public class PdbSourceFile : File
{
private readonly PDB.ISourceFile file;
public PdbSourceFile(Context cx, PDB.ISourceFile file) : base(cx, file.Path)
{
this.file = file;
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var c in base.Contents)
yield return c;
var text = file.Contents;
if (text == null)
Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath));
else
Cx.Cx.TrapWriter.Archive(TransformedPath, text);
yield return Tuples.file_extraction_mode(this, 2);
}
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class PointerType : Type, IPointerType
{
private readonly Type pointee;
public PointerType(Context cx, Type pointee) : base(cx)
{
this.pointee = pointee;
}
public override bool Equals(object? obj)
{
return obj is PointerType pt && pointee.Equals(pt.pointee);
}
public override int GetHashCode()
{
return pointee.GetHashCode() * 29;
}
public override void WriteId(TextWriter trapFile, bool inContext)
{
pointee.WriteId(trapFile, inContext);
trapFile.Write('*');
}
public override string Name => pointee.Name + "*";
public override Namespace? Namespace => pointee.Namespace;
public override Type? ContainingType => pointee.ContainingType;
public override TypeContainer Parent => pointee.Parent;
public override int ThisTypeParameters => 0;
public override CilTypeKind Kind => CilTypeKind.Pointer;
public override void WriteAssemblyPrefix(TextWriter trapFile) => pointee.WriteAssemblyPrefix(trapFile);
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var c in base.Contents) yield return c;
yield return Tuples.cil_pointer_type(this, pointee);
}
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Reflection.Metadata;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
public sealed class PrimitiveType : Type
{
private readonly PrimitiveTypeCode typeCode;
public PrimitiveType(Context cx, PrimitiveTypeCode tc) : base(cx)
{
typeCode = tc;
}
public override bool Equals(object? obj)
{
return obj is PrimitiveType pt && typeCode == pt.typeCode;
}
public override int GetHashCode()
{
return 1337 * (int)typeCode;
}
public override void WriteId(TextWriter trapFile, bool inContext)
{
trapFile.Write("builtin:");
trapFile.Write(Name);
}
public override string Name => typeCode.Id();
public override Namespace Namespace => Cx.SystemNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
public override void WriteAssemblyPrefix(TextWriter trapFile) { }
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
}
}

View File

@@ -5,13 +5,6 @@ using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A property.
/// </summary>
internal interface IProperty : IExtractedEntity
{
}
/// <summary>
/// A property.
/// </summary>

View File

@@ -0,0 +1,287 @@
using System.Reflection.Metadata;
using System.Collections.Immutable;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
public class SignatureDecoder : ISignatureTypeProvider<ITypeSignature, object>
{
private struct Array : ITypeSignature
{
private readonly ITypeSignature elementType;
private readonly ArrayShape shape;
public Array(ITypeSignature elementType, ArrayShape shape) : this()
{
this.elementType = elementType;
this.shape = shape;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
elementType.WriteId(trapFile, gc);
trapFile.Write('[');
for (var i = 1; i < shape.Rank; ++i)
trapFile.Write(',');
trapFile.Write(']');
}
}
private struct ByRef : ITypeSignature
{
private readonly ITypeSignature elementType;
public ByRef(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
trapFile.Write("ref ");
elementType.WriteId(trapFile, gc);
}
}
private struct FnPtr : ITypeSignature
{
public void WriteId(TextWriter trapFile, GenericContext gc)
{
trapFile.Write("<method signature>");
}
}
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetArrayType(ITypeSignature elementType, ArrayShape shape) =>
new Array(elementType, shape);
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetByReferenceType(ITypeSignature elementType) =>
new ByRef(elementType);
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetFunctionPointerType(MethodSignature<ITypeSignature> signature) =>
new FnPtr();
private class Instantiation : ITypeSignature
{
private readonly ITypeSignature genericType;
private readonly ImmutableArray<ITypeSignature> typeArguments;
public Instantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments)
{
this.genericType = genericType;
this.typeArguments = typeArguments;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
genericType.WriteId(trapFile, gc);
trapFile.Write('<');
var index = 0;
foreach (var arg in typeArguments)
{
trapFile.WriteSeparator(",", ref index);
arg.WriteId(trapFile, gc);
}
trapFile.Write('>');
}
}
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetGenericInstantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments) =>
new Instantiation(genericType, typeArguments);
private class GenericMethodParameter : ITypeSignature
{
private readonly object innerGc;
private readonly int index;
public GenericMethodParameter(object innerGc, int index)
{
this.innerGc = innerGc;
this.index = index;
}
public void WriteId(TextWriter trapFile, GenericContext outerGc)
{
if (!ReferenceEquals(innerGc, outerGc) && innerGc is Method method)
{
trapFile.WriteSubId(method);
}
trapFile.Write("M!");
trapFile.Write(index);
}
}
private class GenericTypeParameter : ITypeSignature
{
private readonly int index;
public GenericTypeParameter(int index)
{
this.index = index;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
trapFile.Write("T!");
trapFile.Write(index);
}
}
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericMethodParameter(object genericContext, int index) =>
new GenericMethodParameter(genericContext, index);
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericTypeParameter(object genericContext, int index) =>
new GenericTypeParameter(index);
private class Modified : ITypeSignature
{
private readonly ITypeSignature unmodifiedType;
public Modified(ITypeSignature unmodifiedType)
{
this.unmodifiedType = unmodifiedType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
unmodifiedType.WriteId(trapFile, gc);
}
}
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
{
return new Modified(unmodifiedType);
}
private class Pinned : ITypeSignature
{
private readonly ITypeSignature elementType;
public Pinned(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
trapFile.Write("pinned ");
elementType.WriteId(trapFile, gc);
}
}
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetPinnedType(ITypeSignature elementType)
{
return new Pinned(elementType);
}
private class PointerType : ITypeSignature
{
private readonly ITypeSignature elementType;
public PointerType(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
elementType.WriteId(trapFile, gc);
trapFile.Write('*');
}
}
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetPointerType(ITypeSignature elementType)
{
return new PointerType(elementType);
}
private class Primitive : ITypeSignature
{
private readonly PrimitiveTypeCode typeCode;
public Primitive(PrimitiveTypeCode typeCode)
{
this.typeCode = typeCode;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
trapFile.Write(typeCode.Id());
}
}
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetPrimitiveType(PrimitiveTypeCode typeCode)
{
return new Primitive(typeCode);
}
private class SzArrayType : ITypeSignature
{
private readonly ITypeSignature elementType;
public SzArrayType(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
elementType.WriteId(trapFile, gc);
trapFile.Write("[]");
}
}
ITypeSignature ISZArrayTypeProvider<ITypeSignature>.GetSZArrayType(ITypeSignature elementType)
{
return new SzArrayType(elementType);
}
private class TypeDefinition : ITypeSignature
{
private readonly TypeDefinitionHandle handle;
public TypeDefinition(TypeDefinitionHandle handle)
{
this.handle = handle;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
var type = (Type)gc.Cx.Create(handle);
type.WriteId(trapFile);
}
}
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
return new TypeDefinition(handle);
}
private class TypeReference : ITypeSignature
{
private readonly TypeReferenceHandle handle;
public TypeReference(TypeReferenceHandle handle)
{
this.handle = handle;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
var type = (Type)gc.Cx.Create(handle);
type.WriteId(trapFile);
}
}
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
return new TypeReference(handle);
}
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{
var ts = reader.GetTypeSpecification(handle);
return ts.DecodeSignature(this, genericContext);
}
}
}

View File

@@ -4,10 +4,6 @@ using Semmle.Extraction.PDB;
namespace Semmle.Extraction.CIL.Entities
{
public interface ISourceLocation : ILocation
{
}
public sealed class PdbSourceLocation : LabelledEntity, ISourceLocation
{
private readonly Location location;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
using System;
using Microsoft.CodeAnalysis;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// Base class for all type containers (namespaces, types, methods).
/// </summary>
public abstract class TypeContainer : GenericContext, ITypeContainer
{
protected TypeContainer(Context cx) : base(cx)
{
}
public virtual Label Label { get; set; }
public abstract void WriteId(TextWriter trapFile);
public void WriteQuotedId(TextWriter trapFile)
{
trapFile.Write("@\"");
WriteId(trapFile);
trapFile.Write(IdSuffix);
trapFile.Write('\"');
}
public abstract string IdSuffix { get; }
Location IEntity.ReportingLocation => throw new NotImplementedException();
public void Extract(Context cx2) { cx2.Populate(this); }
public abstract IEnumerable<IExtractionProduct> Contents { get; }
public override string ToString()
{
using var writer = new StringWriter();
WriteQuotedId(writer);
return writer.ToString();
}
TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

View File

@@ -0,0 +1,244 @@
using System;
using Microsoft.CodeAnalysis;
using System.Reflection.Metadata;
using System.Collections.Immutable;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A type defined in the current assembly.
/// </summary>
public sealed class TypeDefinitionType : Type
{
private readonly Handle handle;
private readonly TypeDefinition td;
public TypeDefinitionType(Context cx, TypeDefinitionHandle handle) : base(cx)
{
td = cx.MdReader.GetTypeDefinition(handle);
this.handle = handle;
declType =
td.GetDeclaringType().IsNil ? null :
(Type)cx.Create(td.GetDeclaringType());
// Lazy because should happen during population.
typeParams = new Lazy<IEnumerable<TypeTypeParameter>>(MakeTypeParameters);
}
public override bool Equals(object? obj)
{
return obj is TypeDefinitionType t && handle.Equals(t.handle);
}
public override int GetHashCode() => handle.GetHashCode();
public override void WriteId(TextWriter trapFile, bool inContext)
{
if (IsPrimitiveType)
{
PrimitiveTypeId(trapFile);
return;
}
var name = Cx.GetString(td.Name);
if (ContainingType != null)
{
ContainingType.GetId(trapFile, inContext);
trapFile.Write('.');
}
else
{
WriteAssemblyPrefix(trapFile);
var ns = Namespace;
if (!ns.IsGlobalNamespace)
{
ns.WriteId(trapFile);
trapFile.Write('.');
}
}
trapFile.Write(name);
}
public override string Name
{
get
{
var name = Cx.GetString(td.Name);
var tick = name.IndexOf('`');
return tick == -1 ? name : name.Substring(0, tick);
}
}
public override Namespace Namespace => Cx.Create(td.NamespaceDefinition);
private readonly Type? declType;
public override Type? ContainingType => declType;
public override int ThisTypeParameters
{
get
{
var containingType = td.GetDeclaringType();
var parentTypeParameters = containingType.IsNil ? 0 :
Cx.MdReader.GetTypeDefinition(containingType).GetGenericParameters().Count;
return td.GetGenericParameters().Count - parentTypeParameters;
}
}
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
public override Type Construct(IEnumerable<Type> typeArguments)
{
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));
}
public override void WriteAssemblyPrefix(TextWriter trapFile)
{
var ct = ContainingType;
if (ct is null)
Cx.WriteAssemblyPrefix(trapFile);
else if (IsPrimitiveType)
trapFile.Write("builtin:");
else
ct.WriteAssemblyPrefix(trapFile);
}
private IEnumerable<TypeTypeParameter> MakeTypeParameters()
{
if (ThisTypeParameters == 0)
return Enumerable.Empty<TypeTypeParameter>();
var newTypeParams = new TypeTypeParameter[ThisTypeParameters];
var genericParams = td.GetGenericParameters();
var toSkip = genericParams.Count - newTypeParams.Length;
// Two-phase population because type parameters can be mutually dependent
for (var i = 0; i < newTypeParams.Length; ++i)
newTypeParams[i] = Cx.Populate(new TypeTypeParameter(this, this, i));
for (var i = 0; i < newTypeParams.Length; ++i)
newTypeParams[i].PopulateHandle(genericParams[i + toSkip]);
return newTypeParams;
}
private readonly Lazy<IEnumerable<TypeTypeParameter>> typeParams;
public override IEnumerable<Type> MethodParameters => Enumerable.Empty<Type>();
public override IEnumerable<Type> TypeParameters
{
get
{
if (declType != null)
{
foreach (var t in declType.TypeParameters)
yield return t;
}
foreach (var t in typeParams.Value)
yield return t;
}
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.metadata_handle(this, Cx.Assembly, handle.GetHashCode());
foreach (var c in base.Contents) yield return c;
MakeTypeParameters();
foreach (var f in td.GetFields())
{
// Populate field if needed
yield return Cx.CreateGeneric(this, f);
}
foreach (var prop in td.GetProperties())
{
yield return new Property(this, this, prop);
}
foreach (var @event in td.GetEvents())
{
yield return new Event(Cx, this, @event);
}
foreach (var a in Attribute.Populate(Cx, this, td.GetCustomAttributes()))
yield return a;
foreach (var impl in td.GetMethodImplementations().Select(i => Cx.MdReader.GetMethodImplementation(i)))
{
var m = (Method)Cx.CreateGeneric(this, impl.MethodBody);
var decl = (Method)Cx.CreateGeneric(this, impl.MethodDeclaration);
yield return m;
yield return decl;
yield return Tuples.cil_implements(m, decl);
}
if (td.Attributes.HasFlag(TypeAttributes.Abstract))
yield return Tuples.cil_abstract(this);
if (td.Attributes.HasFlag(TypeAttributes.Interface))
yield return Tuples.cil_interface(this);
else
yield return Tuples.cil_class(this);
if (td.Attributes.HasFlag(TypeAttributes.Public))
yield return Tuples.cil_public(this);
if (td.Attributes.HasFlag(TypeAttributes.Sealed))
yield return Tuples.cil_sealed(this);
if (td.Attributes.HasFlag(TypeAttributes.HasSecurity))
yield return Tuples.cil_security(this);
// Base types
if (!td.BaseType.IsNil)
{
var @base = (Type)Cx.CreateGeneric(this, td.BaseType);
yield return @base;
yield return Tuples.cil_base_class(this, @base);
}
foreach (var @interface in td.GetInterfaceImplementations().Select(i => Cx.MdReader.GetInterfaceImplementation(i)))
{
var t = (Type)Cx.CreateGeneric(this, @interface.Interface);
yield return t;
yield return Tuples.cil_base_interface(this, t);
}
// Only type definitions have locations.
yield return Tuples.cil_type_location(this, Cx.Assembly);
}
}
internal override Method LookupMethod(StringHandle name, BlobHandle signature)
{
foreach (var h in td.GetMethods())
{
var md = Cx.MdReader.GetMethodDefinition(h);
if (md.Name == name && md.Signature == signature)
{
return (Method)Cx.Create(h);
}
}
throw new InternalError("Couldn't locate method in type");
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Reflection.Metadata;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal abstract class TypeParameter : Type, ITypeParameter
{
protected readonly GenericContext gc;
protected TypeParameter(GenericContext gc) : base(gc.Cx)
{
this.gc = gc;
}
public override Namespace? Namespace => null;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
public override CilTypeKind Kind => CilTypeKind.TypeParameter;
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new InternalError("Attempt to construct a type parameter");
public IEnumerable<IExtractionProduct> PopulateHandle(GenericParameterHandle parameterHandle)
{
if (!parameterHandle.IsNil)
{
var tp = Cx.MdReader.GetGenericParameter(parameterHandle);
if (tp.Attributes.HasFlag(GenericParameterAttributes.Contravariant))
yield return Tuples.cil_typeparam_contravariant(this);
if (tp.Attributes.HasFlag(GenericParameterAttributes.Covariant))
yield return Tuples.cil_typeparam_covariant(this);
if (tp.Attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
yield return Tuples.cil_typeparam_new(this);
if (tp.Attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
yield return Tuples.cil_typeparam_class(this);
if (tp.Attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
yield return Tuples.cil_typeparam_struct(this);
foreach (var constraint in tp.GetConstraints().Select(h => Cx.MdReader.GetGenericParameterConstraint(h)))
{
var t = (Type)Cx.CreateGeneric(this.gc, constraint.Type);
yield return t;
yield return Tuples.cil_typeparam_constraint(this, t);
}
}
}
}
}

View File

@@ -0,0 +1,165 @@
using System;
using Microsoft.CodeAnalysis;
using System.Reflection.Metadata;
using System.Collections.Immutable;
using System.Linq;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// A type reference, to a type in a referenced assembly.
/// </summary>
public sealed class TypeReferenceType : Type
{
private readonly TypeReferenceHandle handle;
private readonly TypeReference tr;
private readonly Lazy<TypeTypeParameter[]> typeParams;
public TypeReferenceType(Context cx, TypeReferenceHandle handle) : base(cx)
{
this.typeParams = new Lazy<TypeTypeParameter[]>(MakeTypeParameters);
this.handle = handle;
this.tr = cx.MdReader.GetTypeReference(handle);
}
public override bool Equals(object? obj)
{
return obj is TypeReferenceType t && handle.Equals(t.handle);
}
public override int GetHashCode()
{
return handle.GetHashCode();
}
private TypeTypeParameter[] MakeTypeParameters()
{
var newTypeParams = new TypeTypeParameter[ThisTypeParameters];
for (var i = 0; i < newTypeParams.Length; ++i)
{
newTypeParams[i] = new TypeTypeParameter(this, this, i);
}
return newTypeParams;
}
public override IEnumerable<IExtractionProduct> Contents
{
get
{
foreach (var tp in typeParams.Value)
yield return tp;
foreach (var c in base.Contents)
yield return c;
}
}
public override string Name
{
get
{
var name = Cx.GetString(tr.Name);
var tick = name.IndexOf('`');
return tick == -1 ? name : name.Substring(0, tick);
}
}
public override Namespace Namespace => Cx.CreateNamespace(tr.Namespace);
public override int ThisTypeParameters
{
get
{
// Parse the name
var name = Cx.GetString(tr.Name);
var tick = name.IndexOf('`');
return tick == -1 ? 0 : int.Parse(name.Substring(tick + 1));
}
}
public override IEnumerable<Type> ThisGenericArguments
{
get
{
foreach (var t in typeParams.Value)
yield return t;
}
}
public override Type? ContainingType
{
get
{
if (tr.ResolutionScope.Kind == HandleKind.TypeReference)
return (Type)Cx.Create((TypeReferenceHandle)tr.ResolutionScope);
return null;
}
}
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
public override void WriteAssemblyPrefix(TextWriter trapFile)
{
switch (tr.ResolutionScope.Kind)
{
case HandleKind.TypeReference:
ContainingType!.WriteAssemblyPrefix(trapFile);
break;
case HandleKind.AssemblyReference:
var assemblyDef = Cx.MdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
trapFile.Write(Cx.GetString(assemblyDef.Name));
trapFile.Write('_');
trapFile.Write(assemblyDef.Version.ToString());
trapFile.Write("::");
break;
default:
Cx.WriteAssemblyPrefix(trapFile);
break;
}
}
public override IEnumerable<Type> TypeParameters => typeParams.Value;
public override IEnumerable<Type> MethodParameters => throw new InternalError("This type does not have method parameters");
public override void WriteId(TextWriter trapFile, bool inContext)
{
if (IsPrimitiveType)
{
PrimitiveTypeId(trapFile);
return;
}
var ct = ContainingType;
if (ct != null)
{
ct.GetId(trapFile, inContext);
}
else
{
if (tr.ResolutionScope.Kind == HandleKind.AssemblyReference)
{
WriteAssemblyPrefix(trapFile);
}
if (!Namespace.IsGlobalNamespace)
{
Namespace.WriteId(trapFile);
}
}
trapFile.Write('.');
trapFile.Write(Cx.GetString(tr.Name));
}
public override Type Construct(IEnumerable<Type> typeArguments)
{
if (TotalTypeParametersCheck != typeArguments.Count())
throw new InternalError("Mismatched type arguments");
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Reflection.Metadata;
using System.Collections.Immutable;
namespace Semmle.Extraction.CIL.Entities
{
/// <summary>
/// Decodes a type signature and produces a Type, for use by DecodeSignature() and friends.
/// </summary>
public class TypeSignatureDecoder : ISignatureTypeProvider<Type, GenericContext>
{
private readonly Context cx;
public TypeSignatureDecoder(Context cx)
{
this.cx = cx;
}
Type IConstructedTypeProvider<Type>.GetArrayType(Type elementType, ArrayShape shape) =>
cx.Populate(new ArrayType(cx, elementType, shape.Rank));
Type IConstructedTypeProvider<Type>.GetByReferenceType(Type elementType) =>
elementType; // ??
Type ISignatureTypeProvider<Type, GenericContext>.GetFunctionPointerType(MethodSignature<Type> signature) =>
cx.ErrorType; // Don't know what to do !!
Type IConstructedTypeProvider<Type>.GetGenericInstantiation(Type genericType, ImmutableArray<Type> typeArguments) =>
genericType.Construct(typeArguments);
Type ISignatureTypeProvider<Type, GenericContext>.GetGenericMethodParameter(GenericContext genericContext, int index) =>
genericContext.GetGenericMethodParameter(index);
Type ISignatureTypeProvider<Type, GenericContext>.GetGenericTypeParameter(GenericContext genericContext, int index) =>
genericContext.GetGenericTypeParameter(index);
Type ISignatureTypeProvider<Type, GenericContext>.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) =>
unmodifiedType; // !! Not implemented properly
Type ISignatureTypeProvider<Type, GenericContext>.GetPinnedType(Type elementType) =>
cx.Populate(new PointerType(cx, elementType));
Type IConstructedTypeProvider<Type>.GetPointerType(Type elementType) =>
cx.Populate(new PointerType(cx, elementType));
Type ISimpleTypeProvider<Type>.GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
Type ISZArrayTypeProvider<Type>.GetSZArrayType(Type elementType) =>
cx.Populate(new ArrayType(cx, elementType));
Type ISimpleTypeProvider<Type>.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) =>
(Type)cx.Create(handle);
Type ISimpleTypeProvider<Type>.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) =>
(Type)cx.Create(handle);
Type ISignatureTypeProvider<Type, GenericContext>.GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) =>
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,51 @@
using System.Linq;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CIL.Entities
{
internal sealed class TypeTypeParameter : TypeParameter
{
private readonly Type type;
private readonly int index;
public TypeTypeParameter(GenericContext cx, Type t, int i) : base(cx)
{
index = i;
type = t;
}
public override bool Equals(object? obj)
{
return obj is TypeTypeParameter tp && type.Equals(tp.type) && index == tp.index;
}
public override int GetHashCode()
{
return type.GetHashCode() * 13 + index;
}
public override void WriteId(TextWriter trapFile, bool inContext)
{
type.WriteId(trapFile, inContext);
trapFile.Write('!');
trapFile.Write(index);
}
public override TypeContainer Parent => type;
public override string Name => "!" + index;
public override IEnumerable<Type> TypeParameters => Enumerable.Empty<Type>();
public override IEnumerable<Type> MethodParameters => Enumerable.Empty<Type>();
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return Tuples.cil_type(this, Name, Kind, type, SourceDeclaration);
yield return Tuples.cil_type_parameter(type, index, this);
}
}
}
}