using System; using System.IO; namespace Semmle.Extraction.CSharp { /// /// A key. Either a simple key, e.g. `@"bool A.M();method"`, or a compound key, e.g. /// `@"{0} {1}.M();method"` where `0` and `1` are both labels. /// public class Key { private readonly StringWriter trapBuilder = new StringWriter(); /// /// Creates a new key by concatenating the contents of the supplied arguments. /// public Key(params object[] args) { trapBuilder = new StringWriter(); foreach (var arg in args) { if (arg is IEntity entity) { var key = entity.Label; trapBuilder.Write("{#"); trapBuilder.Write(key.Value.ToString()); trapBuilder.Write("}"); } else { trapBuilder.Write(arg.ToString()); } } } /// /// Creates a new key by applying the supplied action to an empty /// trap builder. /// public Key(Action action) { action(trapBuilder); } public override string ToString() { return trapBuilder.ToString(); } public override bool Equals(object? obj) { if (obj is null || obj.GetType() != GetType()) return false; var id = (Key)obj; return trapBuilder.ToString() == id.trapBuilder.ToString(); } public override int GetHashCode() => trapBuilder.ToString().GetHashCode(); public void AppendTo(TextWriter trapFile) { trapFile.Write("@\""); trapFile.Write(trapBuilder.ToString()); trapFile.Write("\""); } } /// /// A label referencing an entity, of the form "#123". /// public struct Label { public Label(int value) : this() { Value = value; } public int Value { get; private set; } public static Label InvalidLabel { get; } = new Label(0); public bool Valid => Value > 0; public override string ToString() { if (!Valid) throw new InvalidOperationException("Attempt to use an invalid label"); return $"#{Value}"; } public static bool operator ==(Label l1, Label l2) => l1.Value == l2.Value; public static bool operator !=(Label l1, Label l2) => l1.Value != l2.Value; public override bool Equals(object? other) { if (other is null) return false; return GetType() == other.GetType() && ((Label)other).Value == Value; } public override int GetHashCode() => 61 * Value; /// /// Constructs a unique string for this label. /// /// The trap builder used to store the result. public void AppendTo(System.IO.TextWriter trapFile) { if (!Valid) throw new InvalidOperationException("Attempt to use an invalid label"); trapFile.Write('#'); trapFile.Write(Value); } } }