mirror of
https://github.com/github/codeql.git
synced 2025-12-17 09:13:20 +01:00
205 lines
6.5 KiB
C#
205 lines
6.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Reflection.Metadata;
|
|
|
|
namespace Semmle.Extraction.CIL
|
|
{
|
|
/// <summary>
|
|
/// An ID fragment which is designed to be shared, reused
|
|
/// and composed using the + operator.
|
|
/// </summary>
|
|
public abstract class Id : IId
|
|
{
|
|
public void AppendTo(ITrapBuilder tb)
|
|
{
|
|
tb.Append("@\"");
|
|
BuildParts(tb);
|
|
tb.Append("\"");
|
|
}
|
|
|
|
public abstract void BuildParts(ITrapBuilder tb);
|
|
|
|
public static Id operator +(Id l1, Id l2) => Create(l1, l2);
|
|
|
|
public static Id operator +(Id l1, string l2) => Create(l1, Create(l2));
|
|
|
|
public static Id operator +(Id l1, int l2) => Create(l1, Create(l2));
|
|
|
|
public static Id operator +(string l1, Id l2) => Create(Create(l1), l2);
|
|
|
|
public static Id operator +(int l1, Id l2) => Create(Create(l1), l2);
|
|
|
|
public static Id Create(string s) => s == null ? null : new StringId(s);
|
|
|
|
public static Id Create(int i) => new IntId(i);
|
|
|
|
static readonly Id openCurly = Create("{#");
|
|
static readonly Id closeCurly = Create("}");
|
|
|
|
public static Id Create(Label l) => openCurly + l.Value + closeCurly;
|
|
|
|
static readonly Id comma = Id.Create(",");
|
|
|
|
public static Id CommaSeparatedList(IEnumerable<Id> items)
|
|
{
|
|
Id result = null;
|
|
bool first = true;
|
|
foreach (var i in items)
|
|
{
|
|
if (first) first = false; else result += comma;
|
|
result += i;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static Id Create(Id l1, Id l2)
|
|
{
|
|
return l1 == null ? l2 : l2 == null ? l1 : new ConsId(l1, l2);
|
|
}
|
|
|
|
public abstract string Value { get; }
|
|
|
|
public override string ToString() => Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// An ID concatenating two other IDs.
|
|
/// </summary>
|
|
public sealed class ConsId : Id
|
|
{
|
|
readonly Id left, right;
|
|
readonly int hash;
|
|
|
|
public ConsId(Id l1, Id l2)
|
|
{
|
|
left = l1;
|
|
right = l2;
|
|
hash = unchecked(12 + 3 * (left.GetHashCode() + 51 * right.GetHashCode()));
|
|
}
|
|
|
|
public override void BuildParts(ITrapBuilder tb)
|
|
{
|
|
left.BuildParts(tb);
|
|
right.BuildParts(tb);
|
|
}
|
|
|
|
public override bool Equals(object other)
|
|
{
|
|
return other is ConsId && Equals((ConsId)other);
|
|
}
|
|
|
|
public bool Equals(ConsId other)
|
|
{
|
|
return this == other ||
|
|
(hash == other.hash && left.Equals(other.left) && right.Equals(other.right));
|
|
}
|
|
|
|
public override int GetHashCode() => hash;
|
|
|
|
public override string Value => left.Value + right.Value;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// A leaf ID storing a string.
|
|
/// </summary>
|
|
public sealed class StringId : Id
|
|
{
|
|
readonly string value;
|
|
public override string Value => value;
|
|
|
|
public StringId(string s)
|
|
{
|
|
value = s;
|
|
}
|
|
|
|
public override void BuildParts(ITrapBuilder tb)
|
|
{
|
|
tb.Append(value);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is StringId && ((StringId)obj).value == value;
|
|
}
|
|
|
|
public override int GetHashCode() => Value.GetHashCode() * 31 + 9;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A leaf ID storing an integer.
|
|
/// </summary>
|
|
public sealed class IntId : Id
|
|
{
|
|
readonly int value;
|
|
public override string Value => value.ToString();
|
|
|
|
public IntId(int i)
|
|
{
|
|
value = i;
|
|
}
|
|
|
|
public override void BuildParts(ITrapBuilder tb)
|
|
{
|
|
tb.Append(value);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is IntId && ((IntId)obj).value == value;
|
|
}
|
|
|
|
public override int GetHashCode() => unchecked(12 + value * 17);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Some predefined IDs.
|
|
/// </summary>
|
|
public static class IdUtils
|
|
{
|
|
public static StringId boolId = new StringId("Boolean");
|
|
public static StringId byteId = new StringId("Byte");
|
|
public static StringId charId = new StringId("Char");
|
|
public static StringId doubleId = new StringId("Double");
|
|
public static StringId shortId = new StringId("Int16");
|
|
public static StringId intId = new StringId("Int32");
|
|
public static StringId longId = new StringId("Int64");
|
|
public static StringId intptrId = new StringId("IntPtr");
|
|
public static StringId objectId = new StringId("Object");
|
|
public static StringId sbyteId = new StringId("SByte");
|
|
public static StringId floatId = new StringId("Single");
|
|
public static StringId stringId = new StringId("String");
|
|
public static StringId ushortId = new StringId("UInt16");
|
|
public static StringId uintId = new StringId("UInt32");
|
|
public static StringId ulongId = new StringId("UInt64");
|
|
public static StringId uintptrId = new StringId("UIntPtr");
|
|
public static StringId voidId = new StringId("Void");
|
|
public static StringId typedReferenceId = new StringId("TypedReference");
|
|
|
|
public static StringId Id(this PrimitiveTypeCode typeCode)
|
|
{
|
|
switch (typeCode)
|
|
{
|
|
case PrimitiveTypeCode.Boolean: return boolId;
|
|
case PrimitiveTypeCode.Byte: return byteId;
|
|
case PrimitiveTypeCode.Char: return charId;
|
|
case PrimitiveTypeCode.Double: return doubleId;
|
|
case PrimitiveTypeCode.Int16: return shortId;
|
|
case PrimitiveTypeCode.Int32: return intId;
|
|
case PrimitiveTypeCode.Int64: return longId;
|
|
case PrimitiveTypeCode.IntPtr: return intptrId;
|
|
case PrimitiveTypeCode.Object: return objectId;
|
|
case PrimitiveTypeCode.SByte: return sbyteId;
|
|
case PrimitiveTypeCode.Single: return floatId;
|
|
case PrimitiveTypeCode.String: return stringId;
|
|
case PrimitiveTypeCode.UInt16: return ushortId;
|
|
case PrimitiveTypeCode.UInt32: return uintId;
|
|
case PrimitiveTypeCode.UInt64: return ulongId;
|
|
case PrimitiveTypeCode.UIntPtr: return uintptrId;
|
|
case PrimitiveTypeCode.Void: return voidId;
|
|
case PrimitiveTypeCode.TypedReference: return typedReferenceId;
|
|
default: throw new InternalError("Unhandled type code {0}", typeCode);
|
|
}
|
|
}
|
|
}
|
|
}
|