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);
}
}
}