mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
157 lines
4.3 KiB
C#
157 lines
4.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace Semmle.Extraction
|
|
{
|
|
/// <summary>
|
|
/// An ID. Either a fresh ID (`*`), a key, or a label (https://semmle.com/wiki/display/IN/TRAP+Files):
|
|
///
|
|
/// ```
|
|
/// id ::= '*' | key | label
|
|
/// ```
|
|
/// </summary>
|
|
public interface IId
|
|
{
|
|
/// <summary>
|
|
/// Appends this ID to the supplied trap builder.
|
|
/// </summary>
|
|
void AppendTo(TextWriter trapFile);
|
|
}
|
|
|
|
/// <summary>
|
|
/// A fresh ID (`*`).
|
|
/// </summary>
|
|
public class FreshId : IId
|
|
{
|
|
FreshId() { }
|
|
|
|
/// <summary>
|
|
/// Gets the singleton <see cref="FreshId"/> instance.
|
|
/// </summary>
|
|
public static IId Instance { get; } = new FreshId();
|
|
|
|
public override string ToString() => "*";
|
|
|
|
public override bool Equals(object? obj) => obj?.GetType() == GetType();
|
|
|
|
public override int GetHashCode() => 0;
|
|
|
|
public void AppendTo(TextWriter trapFile)
|
|
{
|
|
trapFile.Write('*');
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public class Key : IId
|
|
{
|
|
readonly StringWriter TrapBuilder = new StringWriter();
|
|
|
|
/// <summary>
|
|
/// Creates a new key by concatenating the contents of the supplied arguments.
|
|
/// </summary>
|
|
public Key(params object[] args)
|
|
{
|
|
TrapBuilder = new StringWriter();
|
|
foreach (var arg in args)
|
|
{
|
|
if (arg is IEntity)
|
|
{
|
|
var key = ((IEntity)arg).Label;
|
|
TrapBuilder.Write("{#");
|
|
TrapBuilder.Write(key.Value.ToString());
|
|
TrapBuilder.Write("}");
|
|
}
|
|
else
|
|
TrapBuilder.Write(arg.ToString());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new key by applying the supplied action to an empty
|
|
/// trap builder.
|
|
/// </summary>
|
|
public Key(Action<TextWriter> 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("\"");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A label referencing an entity, of the form "#123".
|
|
/// </summary>
|
|
public struct Label
|
|
{
|
|
public Label(int value) : this()
|
|
{
|
|
Value = value;
|
|
}
|
|
|
|
public int Value { get; private set; }
|
|
|
|
static public readonly Label InvalidLabel = new Label(0);
|
|
|
|
public bool Valid => Value > 0;
|
|
|
|
public override string ToString()
|
|
{
|
|
if (!Valid)
|
|
throw new NullReferenceException("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;
|
|
|
|
/// <summary>
|
|
/// Constructs a unique string for this label.
|
|
/// </summary>
|
|
/// <param name="trapFile">The trap builder used to store the result.</param>
|
|
public void AppendTo(System.IO.TextWriter trapFile)
|
|
{
|
|
if (!Valid)
|
|
throw new NullReferenceException("Attempt to use an invalid label");
|
|
|
|
trapFile.Write('#');
|
|
trapFile.Write(Value);
|
|
}
|
|
}
|
|
}
|