// Copyright (c) 2024 citrus - [Link]
org
// Licensed under the MIT License.
using System;
namespace [Link];
// Copyright (c) 2024 citrus - [Link]
// Licensed under the MIT License.
using System;
using [Link];
using [Link];
using [Link];
using [Link];
using [Link];
using [Link];
using static [Link];
namespace [Link];
/// <summary>
/// Provides information about a valid specifier for one or more tags.
/// </summary>
internal sealed record KnownSpecifierInfo(string SpecifierName, Tag Tag,
UhtSpecifierValueType ValueType);
/// <summary>
/// Provides a method for finding all supported specifiers using reflection.
/// </summary>
internal static class SpecifierFinder
{
/// <summary>
/// A list of assemblies to search for specifiers.
/// </summary>
private static readonly IReadOnlyList<Assembly> AssembliesToSearch = new[]
{
// The UHT itself is included.
typeof(UhtType).Assembly
};
/// <summary>
/// A map between a table name to one or more tags that can use the specifier.
/// </summary>
private static readonly IReadOnlyDictionary<string, Tag> TableNameToTag = new
Dictionary<string, Tag>
{
[[Link]] = UCLASS | UINTERFACE,
[[Link]] = UCLASS,
[[Link]] = UPROPERTY | UCLASS | USTRUCT | UENUM | UMETA |
UPARAM | UINTERFACE | UDELEGATE | UFUNCTION,
[[Link]] = UENUM,
[[Link]] = UCLASS | UENUM | UFUNCTION | USTRUCT | UDELEGATE |
UINTERFACE,
[[Link]] = UFUNCTION | UDELEGATE,
[[Link]] = UINTERFACE,
[[Link]] = UPARAM,
[[Link]] = UPROPERTY,
[[Link]] = USTRUCT
};
/// <summary>
/// Finds all supported specifiers.
/// </summary>
public static IEnumerable<KnownSpecifierInfo> FindAllSpecifiers()
{
Dictionary<string, KnownSpecifierInfo> dedupedSpecifiers = new();
foreach (KnownSpecifierInfo specifier in FindAllSpecifiersInAssemblies())
{
if ([Link]([Link], out
KnownSpecifierInfo? existingSpecifierInfo))
{
dedupedSpecifiers[[Link]] =
existingSpecifierInfo with
{
Tag = [Link] | [Link]
};
}
else
{
[Link]([Link], specifier);
}
}
return [Link];
}
/// <summary>
/// Uses reflection against UHT to find all supported specifiers. This will
produce duplicate specifiers for each
/// supported tag.
/// </summary>
private static IEnumerable<KnownSpecifierInfo> FindAllSpecifiersInAssemblies()
{
const BindingFlags methodSearchFlags
= [Link]
| [Link]
| [Link]
| [Link]
| [Link];
foreach (Assembly assembly in AssembliesToSearch)
{
var specifiers = from type in [Link]()
from method in [Link](methodSearchFlags)
from attribute in
[Link]<UhtSpecifierAttribute>()
select CreateSpecifierInfo(type, method, attribute);
foreach (var specifier in specifiers)
{
if (specifier is not null)
{
yield return specifier;
}
}
}
}
/// <summary>
/// Extracts information about a specifier from reflection data.
/// </summary>
private static KnownSpecifierInfo? CreateSpecifierInfo(
Type @class, MethodInfo methodInfo, UhtSpecifierAttribute attribute)
{
// Use the explicit name of the specifier if set; otherwise, get it from
the method name.
string specifierName = [Link](@class,
methodInfo, [Link], "Specifier");
if ( && [Link] is not
[Link])
{
return new KnownSpecifierInfo(specifierName,
TableNameToTag[[Link]], [Link]);
}
return null;
}
}
/// <summary>
/// Indicates the tag that contains a specifier or metadata.
/// </summary>
[Flags]
public enum Tag
{
UPROPERTY = 1,
UCLASS = 2,
USTRUCT = 4,
UENUM = 8,
UMETA = 16,
UPARAM = 32,
UINTERFACE = 64,
UDELEGATE = 128,
UFUNCTION = 256,
}