C#: Cleanup CIL extraction 'Type' classes

This commit is contained in:
Tamas Vajk
2020-12-03 14:47:35 +01:00
parent b649ccd880
commit 151379edd8
13 changed files with 101 additions and 165 deletions

View File

@@ -27,27 +27,26 @@ namespace Semmle.Extraction.CIL.Entities
return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank;
}
public override int GetHashCode()
{
return elementType.GetHashCode() * 5 + rank;
}
public override int GetHashCode() => HashCode.Combine(elementType, rank);
public override void WriteId(TextWriter trapFile, bool inContext)
{
elementType.GetId(trapFile, inContext);
trapFile.Write('[');
for (var i = 1; i < rank; ++i)
trapFile.Write(',');
if (rank > 1)
{
trapFile.Write(new string(',', rank - 1));
}
trapFile.Write(']');
}
public override string Name => elementType.Name + "[]";
public override Namespace Namespace => Cx.SystemNamespace;
public override Namespace ContainingNamespace => Cx.SystemNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameters => elementType.ThisTypeParameters;
public override int ThisTypeParameterCount => elementType.ThisTypeParameterCount;
public override CilTypeKind Kind => CilTypeKind.Array;
@@ -71,7 +70,5 @@ namespace Semmle.Extraction.CIL.Entities
public override IEnumerable<Type> GenericArguments => elementType.GenericArguments;
public override IEnumerable<Type> TypeParameters => elementType.TypeParameters;
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
}
}

View File

@@ -43,7 +43,7 @@ namespace Semmle.Extraction.CIL.Entities
{
decoded = attrib.DecodeValue(new CustomAttributeDecoder(Cx));
}
catch (NotImplementedException)
catch (Exception exc)
{
// Attribute decoding is only partial at this stage.
yield break;

View File

@@ -17,6 +17,8 @@ namespace Semmle.Extraction.CIL.Entities
// Either null or notEmpty
private readonly Type[]? thisTypeArguments;
private readonly Type? containingType;
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments.EnumerateNull();
public override IEnumerable<Type> ThisGenericArguments => thisTypeArguments.EnumerateNull();
@@ -29,7 +31,7 @@ namespace Semmle.Extraction.CIL.Entities
yield return c;
var i = 0;
foreach (var type in ThisGenericArguments)
foreach (var type in ThisTypeArguments)
{
yield return type;
yield return Tuples.cil_type_argument(this, i++, type);
@@ -42,11 +44,11 @@ namespace Semmle.Extraction.CIL.Entities
public ConstructedType(Context cx, Type unboundType, IEnumerable<Type> typeArguments) : base(cx)
{
var suppliedArgs = typeArguments.Count();
if (suppliedArgs != unboundType.TotalTypeParametersCheck)
if (suppliedArgs != unboundType.TotalTypeParametersCount)
throw new InternalError("Unexpected number of type arguments in ConstructedType");
unboundGenericType = unboundType;
var thisParams = unboundType.ThisTypeParameters;
var thisParams = unboundType.ThisTypeParameterCount;
if (typeArguments.Count() == thisParams)
{
@@ -88,14 +90,13 @@ namespace Semmle.Extraction.CIL.Entities
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 Namespace ContainingNamespace => unboundGenericType.ContainingNamespace!;
public override int ThisTypeParameters => thisTypeArguments == null ? 0 : thisTypeArguments.Length;
public override int ThisTypeParameterCount => thisTypeArguments == null ? 0 : thisTypeArguments.Length;
public override CilTypeKind Kind => unboundGenericType.Kind;
@@ -115,9 +116,9 @@ namespace Semmle.Extraction.CIL.Entities
{
WriteAssemblyPrefix(trapFile);
if (!Namespace.IsGlobalNamespace)
if (!ContainingNamespace.IsGlobalNamespace)
{
Namespace.WriteId(trapFile);
ContainingNamespace.WriteId(trapFile);
trapFile.Write('.');
}
}
@@ -139,7 +140,5 @@ namespace Semmle.Extraction.CIL.Entities
public override void WriteAssemblyPrefix(TextWriter trapFile) => unboundGenericType.WriteAssemblyPrefix(trapFile);
public override IEnumerable<Type> TypeParameters => GenericArguments;
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
}
}

View File

@@ -16,18 +16,16 @@ namespace Semmle.Extraction.CIL.Entities
public override string Name => "!error";
public override Namespace Namespace => Cx.GlobalNamespace;
public override Namespace ContainingNamespace => Cx.GlobalNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
public override int ThisTypeParameterCount => 0;
public override void WriteAssemblyPrefix(TextWriter trapFile) => throw new NotImplementedException();
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
}
}

View File

@@ -41,8 +41,6 @@ namespace Semmle.Extraction.CIL.Entities
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override IEnumerable<IExtractionProduct> Contents
{
get

View File

@@ -18,11 +18,7 @@ namespace Semmle.Extraction.CIL.Entities
return obj is PointerType pt && pointee.Equals(pt.pointee);
}
public override int GetHashCode()
{
return pointee.GetHashCode() * 29;
}
public override int GetHashCode() => HashCode.Combine(pointee, nameof(PointerType));
public override void WriteId(TextWriter trapFile, bool inContext)
{
@@ -32,13 +28,13 @@ namespace Semmle.Extraction.CIL.Entities
public override string Name => pointee.Name + "*";
public override Namespace? Namespace => pointee.Namespace;
public override Namespace? ContainingNamespace => pointee.ContainingNamespace;
public override Type? ContainingType => pointee.ContainingType;
public override TypeContainer Parent => pointee.Parent;
public override int ThisTypeParameters => 0;
public override int ThisTypeParameterCount => 0;
public override CilTypeKind Kind => CilTypeKind.Pointer;
@@ -46,8 +42,6 @@ namespace Semmle.Extraction.CIL.Entities
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

View File

@@ -18,24 +18,20 @@ namespace Semmle.Extraction.CIL.Entities
return obj is PrimitiveType pt && typeCode == pt.typeCode;
}
public override int GetHashCode()
{
return 1337 * (int)typeCode;
}
public override int GetHashCode() => typeCode.GetHashCode();
public override void WriteId(TextWriter trapFile, bool inContext)
{
trapFile.Write("builtin:");
trapFile.Write(Name);
Type.WritePrimitiveTypeId(trapFile, Name);
}
public override string Name => typeCode.Id();
public override Namespace Namespace => Cx.SystemNamespace;
public override Namespace ContainingNamespace => Cx.SystemNamespace;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
public override int ThisTypeParameterCount => 0;
public override CilTypeKind Kind => CilTypeKind.ValueOrRefType;
@@ -43,8 +39,6 @@ namespace Semmle.Extraction.CIL.Entities
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
public override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public override Type Construct(IEnumerable<Type> typeArguments) => throw new NotImplementedException();
}
}

View File

@@ -21,8 +21,10 @@ namespace Semmle.Extraction.CIL.Entities
{
elementType.WriteId(trapFile, gc);
trapFile.Write('[');
for (var i = 1; i < shape.Rank; ++i)
trapFile.Write(',');
if (shape.Rank > 1)
{
trapFile.Write(string.Join(",", shape.Rank - 1));
}
trapFile.Write(']');
}
}

View File

@@ -1,8 +1,8 @@
using System.Reflection.Metadata;
using System.Collections.Generic;
using Semmle.Util;
using System.IO;
using System.Diagnostics.CodeAnalysis;
using System;
namespace Semmle.Extraction.CIL.Entities
{
@@ -12,8 +12,9 @@ namespace Semmle.Extraction.CIL.Entities
public abstract class Type : TypeContainer, IMember
{
public override string IdSuffix => ";cil-type";
internal const string PrimitiveTypePrefix = "builtin:";
public sealed override void WriteId(TextWriter trapFile) => WriteId(trapFile, false);
protected Type(Context cx) : base(cx) { }
/// <summary>
/// Find the method in this type matching the name and signature.
@@ -67,22 +68,11 @@ namespace Semmle.Extraction.CIL.Entities
/// </param>
public abstract void WriteId(TextWriter trapFile, bool inContext);
public void GetId(TextWriter trapFile, bool inContext)
{
if (inContext)
WriteId(trapFile, true);
else
WriteId(trapFile);
}
public sealed override void WriteId(TextWriter trapFile) => WriteId(trapFile, false);
protected Type(Context cx) : base(cx) { }
public void GetId(TextWriter trapFile, bool inContext) => WriteId(trapFile, inContext);
public abstract CilTypeKind Kind
{
get;
}
public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? Namespace!;
public abstract CilTypeKind Kind { get; }
public override IEnumerable<IExtractionProduct> Contents
{
@@ -92,31 +82,29 @@ namespace Semmle.Extraction.CIL.Entities
}
}
/// <summary>
/// Whether this type is visible outside the current assembly.
/// </summary>
public virtual bool IsVisible => true;
public abstract string Name { get; }
public abstract Namespace? Namespace { get; }
public abstract Namespace? ContainingNamespace { get; }
public abstract Type? ContainingType { get; }
public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? ContainingNamespace!;
public abstract Type Construct(IEnumerable<Type> typeArguments);
/// <summary>
/// The number of type arguments, or 0 if this isn't generic.
/// The containing type may also have type arguments.
/// </summary>
public abstract int ThisTypeParameters { get; }
public abstract int ThisTypeParameterCount { get; }
/// <summary>
/// The total number of type parameters (including parent types).
/// This is used for internal consistency checking only.
/// </summary>
public int TotalTypeParametersCheck =>
ContainingType == null ? ThisTypeParameters : ThisTypeParameters + ContainingType.TotalTypeParametersCheck;
public int TotalTypeParametersCount => ContainingType == null
? ThisTypeParameterCount
: ThisTypeParameterCount + ContainingType.TotalTypeParametersCount;
/// <summary>
/// Returns all bound/unbound generic arguments
@@ -139,6 +127,7 @@ namespace Semmle.Extraction.CIL.Entities
foreach (var t in ContainingType.GenericArguments)
yield return t;
}
foreach (var t in ThisGenericArguments)
yield return t;
}
@@ -146,12 +135,34 @@ namespace Semmle.Extraction.CIL.Entities
public virtual Type SourceDeclaration => this;
public void PrimitiveTypeId(TextWriter trapFile)
public static void WritePrimitiveTypeId(TextWriter trapFile, string name)
{
trapFile.Write("builtin:");
trapFile.Write(Name);
trapFile.Write(PrimitiveTypePrefix);
trapFile.Write(name);
}
private static readonly Dictionary<string, PrimitiveTypeCode> primitiveTypeCodeMapping = new Dictionary<string, PrimitiveTypeCode>
{
{"Boolean", PrimitiveTypeCode.Boolean},
{"Object", PrimitiveTypeCode.Object},
{"Byte", PrimitiveTypeCode.Byte},
{"SByte", PrimitiveTypeCode.SByte},
{"Int16", PrimitiveTypeCode.Int16},
{"UInt16", PrimitiveTypeCode.UInt16},
{"Int32", PrimitiveTypeCode.Int32},
{"UInt32", PrimitiveTypeCode.UInt32},
{"Int64", PrimitiveTypeCode.Int64},
{"UInt64", PrimitiveTypeCode.UInt64},
{"Single", PrimitiveTypeCode.Single},
{"Double", PrimitiveTypeCode.Double},
{"String", PrimitiveTypeCode.String},
{"Void", PrimitiveTypeCode.Void},
{"IntPtr", PrimitiveTypeCode.IntPtr},
{"UIntPtr", PrimitiveTypeCode.UIntPtr},
{"Char", PrimitiveTypeCode.Char},
{"TypedReference", PrimitiveTypeCode.TypedReference}
};
/// <summary>
/// Gets the primitive type corresponding to this type, if possible.
/// </summary>
@@ -171,73 +182,21 @@ namespace Semmle.Extraction.CIL.Entities
private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code)
{
if (ContainingType == null && Namespace?.Name == Cx.SystemNamespace.Name)
if (ContainingType == null &&
ContainingNamespace?.Name == Cx.SystemNamespace.Name &&
primitiveTypeCodeMapping.TryGetValue(Name, out code))
{
switch (Name)
{
case "Boolean":
code = PrimitiveTypeCode.Boolean;
return true;
case "Object":
code = PrimitiveTypeCode.Object;
return true;
case "Byte":
code = PrimitiveTypeCode.Byte;
return true;
case "SByte":
code = PrimitiveTypeCode.SByte;
return true;
case "Int16":
code = PrimitiveTypeCode.Int16;
return true;
case "UInt16":
code = PrimitiveTypeCode.UInt16;
return true;
case "Int32":
code = PrimitiveTypeCode.Int32;
return true;
case "UInt32":
code = PrimitiveTypeCode.UInt32;
return true;
case "Int64":
code = PrimitiveTypeCode.Int64;
return true;
case "UInt64":
code = PrimitiveTypeCode.UInt64;
return true;
case "Single":
code = PrimitiveTypeCode.Single;
return true;
case "Double":
code = PrimitiveTypeCode.Double;
return true;
case "String":
code = PrimitiveTypeCode.String;
return true;
case "Void":
code = PrimitiveTypeCode.Void;
return true;
case "IntPtr":
code = PrimitiveTypeCode.IntPtr;
return true;
case "UIntPtr":
code = PrimitiveTypeCode.UIntPtr;
return true;
case "Char":
code = PrimitiveTypeCode.Char;
return true;
case "TypedReference":
code = PrimitiveTypeCode.TypedReference;
return true;
}
return true;
}
code = default(PrimitiveTypeCode);
code = default;
return false;
}
protected bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _);
public sealed override IEnumerable<Type> MethodParameters => throw new NotImplementedException();
public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) =>
gc.Cx.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Cx.TypeSignatureDecoder, gc);
}

View File

@@ -14,8 +14,10 @@ namespace Semmle.Extraction.CIL.Entities
/// </summary>
public sealed class TypeDefinitionType : Type
{
private readonly Handle handle;
private readonly TypeDefinitionHandle handle;
private readonly TypeDefinition td;
private readonly Lazy<IEnumerable<TypeTypeParameter>> typeParams;
private readonly Type? declType;
public TypeDefinitionType(Context cx, TypeDefinitionHandle handle) : base(cx)
{
@@ -41,7 +43,7 @@ namespace Semmle.Extraction.CIL.Entities
{
if (IsPrimitiveType)
{
PrimitiveTypeId(trapFile);
WritePrimitiveTypeId(trapFile, Name);
return;
}
@@ -56,7 +58,7 @@ namespace Semmle.Extraction.CIL.Entities
{
WriteAssemblyPrefix(trapFile);
var ns = Namespace;
var ns = ContainingNamespace;
if (!ns.IsGlobalNamespace)
{
ns.WriteId(trapFile);
@@ -77,13 +79,11 @@ namespace Semmle.Extraction.CIL.Entities
}
}
public override Namespace Namespace => Cx.Create(td.NamespaceDefinition);
private readonly Type? declType;
public override Namespace ContainingNamespace => Cx.Create(td.NamespaceDefinition);
public override Type? ContainingType => declType;
public override int ThisTypeParameters
public override int ThisTypeParameterCount
{
get
{
@@ -99,6 +99,9 @@ namespace Semmle.Extraction.CIL.Entities
public override Type Construct(IEnumerable<Type> typeArguments)
{
if (TotalTypeParametersCount != typeArguments.Count())
throw new InternalError("Mismatched type arguments");
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));
}
@@ -108,17 +111,17 @@ namespace Semmle.Extraction.CIL.Entities
if (ct is null)
Cx.WriteAssemblyPrefix(trapFile);
else if (IsPrimitiveType)
trapFile.Write("builtin:");
trapFile.Write(Type.PrimitiveTypePrefix);
else
ct.WriteAssemblyPrefix(trapFile);
}
private IEnumerable<TypeTypeParameter> MakeTypeParameters()
{
if (ThisTypeParameters == 0)
if (ThisTypeParameterCount == 0)
return Enumerable.Empty<TypeTypeParameter>();
var newTypeParams = new TypeTypeParameter[ThisTypeParameters];
var newTypeParams = new TypeTypeParameter[ThisTypeParameterCount];
var genericParams = td.GetGenericParameters();
var toSkip = genericParams.Count - newTypeParams.Length;
@@ -130,10 +133,6 @@ namespace Semmle.Extraction.CIL.Entities
return newTypeParams;
}
private readonly Lazy<IEnumerable<TypeTypeParameter>> typeParams;
public override IEnumerable<Type> MethodParameters => Enumerable.Empty<Type>();
public override IEnumerable<Type> TypeParameters
{
get

View File

@@ -16,11 +16,11 @@ namespace Semmle.Extraction.CIL.Entities
this.gc = gc;
}
public override Namespace? Namespace => null;
public override Namespace? ContainingNamespace => null;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
public override int ThisTypeParameterCount => 0;
public override CilTypeKind Kind => CilTypeKind.TypeParameter;

View File

@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CIL.Entities
private TypeTypeParameter[] MakeTypeParameters()
{
var newTypeParams = new TypeTypeParameter[ThisTypeParameters];
var newTypeParams = new TypeTypeParameter[ThisTypeParameterCount];
for (var i = 0; i < newTypeParams.Length; ++i)
{
newTypeParams[i] = new TypeTypeParameter(this, this, i);
@@ -66,9 +66,9 @@ namespace Semmle.Extraction.CIL.Entities
}
}
public override Namespace Namespace => Cx.CreateNamespace(tr.Namespace);
public override Namespace ContainingNamespace => Cx.CreateNamespace(tr.Namespace);
public override int ThisTypeParameters
public override int ThisTypeParameterCount
{
get
{
@@ -92,9 +92,9 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
if (tr.ResolutionScope.Kind == HandleKind.TypeReference)
return (Type)Cx.Create((TypeReferenceHandle)tr.ResolutionScope);
return null;
return tr.ResolutionScope.Kind == HandleKind.TypeReference
? (Type)Cx.Create((TypeReferenceHandle)tr.ResolutionScope)
: null;
}
}
@@ -122,13 +122,11 @@ namespace Semmle.Extraction.CIL.Entities
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);
WritePrimitiveTypeId(trapFile, Name);
return;
}
@@ -144,9 +142,9 @@ namespace Semmle.Extraction.CIL.Entities
WriteAssemblyPrefix(trapFile);
}
if (!Namespace.IsGlobalNamespace)
if (!ContainingNamespace.IsGlobalNamespace)
{
Namespace.WriteId(trapFile);
ContainingNamespace.WriteId(trapFile);
}
}
@@ -156,7 +154,7 @@ namespace Semmle.Extraction.CIL.Entities
public override Type Construct(IEnumerable<Type> typeArguments)
{
if (TotalTypeParametersCheck != typeArguments.Count())
if (TotalTypeParametersCount != typeArguments.Count())
throw new InternalError("Mismatched type arguments");
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));

View File

@@ -37,8 +37,6 @@ namespace Semmle.Extraction.CIL.Entities
public override IEnumerable<Type> TypeParameters => Enumerable.Empty<Type>();
public override IEnumerable<Type> MethodParameters => Enumerable.Empty<Type>();
public override IEnumerable<IExtractionProduct> Contents
{
get