mirror of
https://github.com/github/codeql.git
synced 2026-05-04 13:15:21 +02:00
C#: Separate all classes to dedicated files in CIL extractor
This commit is contained in:
77
csharp/extractor/Semmle.Extraction.CIL/Entities/ArrayType.cs
Normal file
77
csharp/extractor/Semmle.Extraction.CIL/Entities/ArrayType.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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; // ??
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// The CIL database type-kind.
|
||||
/// </summary>
|
||||
public enum CilTypeKind
|
||||
{
|
||||
ValueOrRefType,
|
||||
TypeParameter,
|
||||
Array,
|
||||
Pointer
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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; // ??
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
csharp/extractor/Semmle.Extraction.CIL/Entities/ErrorType.cs
Normal file
33
csharp/extractor/Semmle.Extraction.CIL/Entities/ErrorType.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IExceptionRegion : IExtractedEntity
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An exception region entity.
|
||||
/// </summary>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An array type.
|
||||
/// </summary>
|
||||
internal interface IArrayType : IType
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IAssembly : ILocation
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A CIL attribute.
|
||||
/// </summary>
|
||||
internal interface IAttribute : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An event.
|
||||
/// </summary>
|
||||
internal interface IEvent : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IExceptionRegion : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// An entity representing a field.
|
||||
/// </summary>
|
||||
internal interface IField : IMember
|
||||
{
|
||||
}
|
||||
}
|
||||
6
csharp/extractor/Semmle.Extraction.CIL/Entities/IFile.cs
Normal file
6
csharp/extractor/Semmle.Extraction.CIL/Entities/IFile.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IFile : IFileOrFolder
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IFileOrFolder : IEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IFolder : IFileOrFolder
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface ILocal : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
public interface ILocation : IEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
10
csharp/extractor/Semmle.Extraction.CIL/Entities/IMember.cs
Normal file
10
csharp/extractor/Semmle.Extraction.CIL/Entities/IMember.cs
Normal 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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A method entity.
|
||||
/// </summary>
|
||||
internal interface IMethod : IMember
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A method implementation entity.
|
||||
/// </summary>
|
||||
internal interface IMethodImplementation : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A namespace.
|
||||
/// </summary>
|
||||
internal interface INamespace : ITypeContainer
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A parameter entity.
|
||||
/// </summary>
|
||||
internal interface IParameter : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface IPointerType : IType
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A property.
|
||||
/// </summary>
|
||||
internal interface IProperty : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
public interface ISourceLocation : ILocation
|
||||
{
|
||||
}
|
||||
}
|
||||
9
csharp/extractor/Semmle.Extraction.CIL/Entities/IType.cs
Normal file
9
csharp/extractor/Semmle.Extraction.CIL/Entities/IType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A type.
|
||||
/// </summary>
|
||||
internal interface IType : IEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A type container (namespace/types/method).
|
||||
/// </summary>
|
||||
internal interface ITypeContainer : IExtractedEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface ITypeParameter : IType
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
internal interface ITypeSignature
|
||||
{
|
||||
void WriteId(TextWriter trapFile, GenericContext gc);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,6 @@ using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A namespace.
|
||||
/// </summary>
|
||||
internal interface INamespace : ITypeContainer
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A namespace.
|
||||
/// </summary>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,6 @@ using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// A property.
|
||||
/// </summary>
|
||||
internal interface IProperty : IExtractedEntity
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A property.
|
||||
/// </summary>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user