0% found this document useful (0 votes)
0 views3 pages

Metadata Usage Finder

The document defines a system for finding and managing metadata usages in source code, specifically for Unreal Header Tool (UHT) generated metadata. It includes classes and methods for filtering out certain metadata keys and determining the appropriate tags for various UHT types. The primary functionality allows for the extraction of metadata information from packages and types, while excluding UHT-generated intermediate metadata that should not be used directly in code.

Uploaded by

lecocoy949
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views3 pages

Metadata Usage Finder

The document defines a system for finding and managing metadata usages in source code, specifically for Unreal Header Tool (UHT) generated metadata. It includes classes and methods for filtering out certain metadata keys and determining the appropriate tags for various UHT types. The primary functionality allows for the extraction of metadata information from packages and types, while excluding UHT-generated intermediate metadata that should not be used directly in code.

Uploaded by

lecocoy949
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 3

// Copyright (c) 2024 citrus - https://unrealist.

org
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using EpicGames.UHT.Types;
using static Citrus.Plugins.SpecifierReferenceViewer.ReferenceGenerator.Tag;

namespace Citrus.Plugins.SpecifierReferenceViewer.ReferenceGenerator;

/// <summary>
/// Provides information about a specific use of a metadata specifier.
/// </summary>
internal sealed record MetadataUsageInfo(string Key, string Value, Tag Tag, string
FilePath);

/// <summary>
/// Provides a method for finding all metadata used in the source code.
/// </summary>
internal static class MetadataUsageFinder
{
/// <summary>
/// If a metadata key starts with any value in this list, it will be excluded
from the result. Technically, these
/// can be used, but all are UHT-generated intermediate metadata that should
not be directly used in code.
/// </summary>
private static readonly IReadOnlyList<string> FilterPrefixes
= new[]
{
// Intermediate metadata generated by UHT.
"CPP_"
};

private static readonly IReadOnlySet<string> Filter


= new HashSet<string> {
// The comment immediately preceding a declaration is stored as
metadata. This value is assigned to the
// Tooltip metadata by UHT if one was not explicitly set. This has no
effect after compilation and should
// not be directly used.
"Comment"
};

/// <summary>
/// Searches for all metadata usages in a set of packages.
/// </summary>
public static IEnumerable<MetadataUsageInfo>
FindAllMetadataUsages(IEnumerable<UhtPackage> packages)
{
foreach (UhtPackage package in packages)
{
foreach (MetadataUsageInfo metadata in FindAllMetadataUsages(package))
{
yield return metadata;
}
}
}
/// <summary>
/// Searches for all metadata usages in a UHT type.
/// </summary>
private static IEnumerable<MetadataUsageInfo> FindAllMetadataUsages(UhtType
type)
{
if (DetermineTagFromType(type) is Tag tag and not default(Tag))
{
if (type.MetaData is not null && !type.MetaData.IsEmpty())
{
foreach (var (key, value) in type.MetaData.Dictionary!)
{
bool isFiltered =
FilterPrefixes.Any(prefix => key.Name.StartsWith(prefix,
StringComparison.OrdinalIgnoreCase)) ||
Filter.Contains(key.Name);

if (!isFiltered)
{
// Special handling is required to differentiate between
UENUM and UMETA.
if (tag is UENUM && key.Index >= 0)
{
yield return new MetadataUsageInfo(key.Name, value,
UMETA, type.HeaderFile.FilePath);
}
else
{
yield return new MetadataUsageInfo(key.Name, value,
tag, type.HeaderFile.FilePath);
}
}
}
}
}

foreach (UhtType child in type.Children)


{
foreach (MetadataUsageInfo metadata in FindAllMetadataUsages(child))
{
yield return metadata;
}
}
}

/// <summary>
/// Determines the appropriate tag to use for a UHT type.
/// </summary>
private static Tag DetermineTagFromType(UhtType type)
{
return type switch
{
UhtEnum => UENUM,
UhtScriptStruct => USTRUCT,
UhtClass @class => IsInterface(@class) ? UINTERFACE : UCLASS,
UhtFunction function => IsDelegate(function) ? UDELEGATE : UFUNCTION,
UhtProperty property => IsParameter(property) ? UPARAM : UPROPERTY,
_ => default
};
}

/// <summary>
/// Determines whether a UPROPERTY is actually a UPARAM.
/// </summary>
private static bool IsParameter(UhtProperty property)
=> property.PropertyCategory == UhtPropertyCategory.Return
|| property.PropertyCategory == UhtPropertyCategory.RegularParameter
|| property.PropertyCategory == UhtPropertyCategory.ReplicatedParameter;

/// <summary>
/// Determines whether a UCLASS is actually an UINTERFACE.
/// </summary>
private static bool IsInterface(UhtClass @class) =>
@class.ClassFlags.HasFlag(EpicGames.Core.EClassFlags.Interface);

/// <summary>
/// Determines whether a UFUNCTION is actually a UDELEGATE.
/// </summary>
private static bool IsDelegate(UhtFunction function)
=> function.FunctionType == UhtFunctionType.Delegate
|| function.FunctionType == UhtFunctionType.SparseDelegate;
}

You might also like