Skip to content

Commit

Permalink
Cleanup name validity (#177)
Browse files Browse the repository at this point in the history
* Cleanup name validity

Remove event generation

Add missing uses of MakeValidInSource

* More efficient Utf8String filtering

* ReadOnlySpan

* cleaner implementation
  • Loading branch information
ds5678 authored Oct 6, 2024
1 parent 01dd79c commit 9d4599d
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 51 deletions.
8 changes: 2 additions & 6 deletions Il2CppInterop.Generator/Contexts/FieldRewriteContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ private string UnmangleFieldNameBase(FieldDefinition field, GeneratorOptions opt

if (!field.Name.IsObfuscated(options))
{
if (!field.Name.IsInvalidInSource())
return field.Name!;
return field.Name.FilterInvalidInSourceChars();
return field.Name.MakeValidInSource();
}

Debug.Assert(field.Signature is not null);
Expand All @@ -64,9 +62,7 @@ private string UnmangleFieldName(FieldDefinition field, GeneratorOptions options

if (!field.Name.IsObfuscated(options))
{
if (!field.Name.IsInvalidInSource())
return field.Name!;
return field.Name.FilterInvalidInSourceChars();
return field.Name.MakeValidInSource();
}

if (renamedFieldCounts == null) throw new ArgumentNullException(nameof(renamedFieldCounts));
Expand Down
28 changes: 10 additions & 18 deletions Il2CppInterop.Generator/Contexts/MethodRewriteContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using AsmResolver;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Metadata.Tables;
Expand Down Expand Up @@ -73,12 +74,9 @@ public MethodRewriteContext(TypeRewriteContext declaringType, MethodDefinition o

foreach (var oldParameter in genericParams)
{
var genericParameter = new GenericParameter(oldParameter.Name);
genericParameter.Attributes = oldParameter.Attributes.StripValueTypeConstraint();
newMethod.GenericParameters.Add(genericParameter);

if (genericParameter.Name.IsInvalidInSource())
genericParameter.Name = genericParameter.Name.FilterInvalidInSourceChars();
newMethod.GenericParameters.Add(new GenericParameter(
oldParameter.Name.MakeValidInSource(),
oldParameter.Attributes.StripValueTypeConstraint()));
}
}

Expand All @@ -94,7 +92,7 @@ public MethodRewriteContext(TypeRewriteContext declaringType, MethodDefinition o
declaringType.AssemblyContext.GlobalContext.MethodStartAddresses.Add(FileOffset);
}

public string? UnmangledName { get; private set; }
public Utf8String? UnmangledName { get; private set; }
public string? UnmangledNameWithSignature { get; private set; }

public TypeDefinition? GenericInstantiationsStore { get; private set; }
Expand Down Expand Up @@ -137,9 +135,7 @@ public void CtorPhase2()
for (var index = 0; index < genericParams.Count; index++)
{
var oldParameter = genericParams[index];
var genericParameter = new GenericParameter(oldParameter.Name);
if (genericParameter.Name.IsInvalidInSource())
genericParameter.Name = genericParameter.Name.FilterInvalidInSourceChars();
var genericParameter = new GenericParameter(oldParameter.Name.MakeValidInSource());
genericMethodInfoStoreType.GenericParameters.Add(genericParameter);
selfSubstRef.TypeArguments.Add(genericParameter.ToTypeSignature());
var newParameter = NewMethod.GenericParameters[index];
Expand Down Expand Up @@ -204,22 +200,18 @@ private string UnmangleMethodName()
if (method.Name.IsObfuscated(DeclaringType.AssemblyContext.GlobalContext.Options))
return UnmangleMethodNameWithSignature();

if (method.Name.IsInvalidInSource())
return method.Name.FilterInvalidInSourceChars();

return method.Name!;
return method.Name.MakeValidInSource();
}

private string ProduceMethodSignatureBase()
{
var method = OriginalMethod;

var name = method.Name;
string name;
if (method.Name.IsObfuscated(DeclaringType.AssemblyContext.GlobalContext.Options))
name = "Method";

if (name.IsInvalidInSource())
name = name.FilterInvalidInSourceChars();
else
name = method.Name.MakeValidInSource();

if (method.Name == "GetType" && method.Parameters.Count == 0)
name = "GetIl2CppType";
Expand Down
5 changes: 1 addition & 4 deletions Il2CppInterop.Generator/Contexts/RewriteGlobalContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,7 @@ public TypeRewriteContext GetContextForNewType(TypeDefinition type)
var paramsMethod = new MethodDefinition(newMethod.Name, newMethod.Attributes, MethodSignatureCreator.CreateMethodSignature(newMethod.Attributes, newMethod.Signature!.ReturnType, newMethod.Signature.GenericParameterCount));
foreach (var genericParameter in originalMethod.GenericParameters)
{
var newGenericParameter = new GenericParameter(genericParameter.Name, genericParameter.Attributes);

if (newGenericParameter.Name.IsInvalidInSource())
newGenericParameter.Name = newGenericParameter.Name.FilterInvalidInSourceChars();
var newGenericParameter = new GenericParameter(genericParameter.Name.MakeValidInSource(), genericParameter.Attributes);

foreach (var constraint in genericParameter.Constraints)
{
Expand Down
82 changes: 68 additions & 14 deletions Il2CppInterop.Generator/Extensions/StringEx.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using AsmResolver;
Expand Down Expand Up @@ -43,26 +44,79 @@ public static string UnSystemify(this Utf8String? str, GeneratorOptions options)
return UnSystemify(str?.Value ?? "", options);
}

public static string FilterInvalidInSourceChars(this string str)
public static string MakeValidInSource(this string str)
{
var chars = str.ToCharArray();
for (var i = 0; i < chars.Length; i++)
if (string.IsNullOrEmpty(str))
return "";

char[]? chars = null;
for (var i = 0; i < str.Length; i++)
{
var it = chars[i];
if (!char.IsDigit(it) && !((it >= 'a' && it <= 'z') || (it >= 'A' && it <= 'Z')) && it != '_' &&
it != '`') chars[i] = '_';
var it = str[i];
if (IsValidInSource(it))
continue;

chars ??= str.ToCharArray();
chars[i] = '_';
}

return new string(chars);
var result = chars is null ? str : new string(chars);
return char.IsDigit(result[0]) ? "_" + result : result;
}

public static string FilterInvalidInSourceChars(this Utf8String? str)
private static bool IsValidInSource(char c) => char.IsDigit(c) || (c is >= 'a' and <= 'z') || (c is >= 'A' and <= 'Z') || c == '_' || c == '`';

public static Utf8String MakeValidInSource(this Utf8String? str)
{
return str?.Value.FilterInvalidInSourceChars() ?? "";
if (Utf8String.IsNullOrEmpty(str))
return Utf8String.Empty;

ReadOnlySpan<byte> data = str.GetBytesUnsafe();

var length = data.Length;
byte[]? rentedArray = null;
Span<byte> rentedArraySpan = default;

if (char.IsDigit((char)data[0]))
{
length++;
rentedArray = ArrayPool<byte>.Shared.Rent(length);
rentedArray[0] = (byte)'_';
rentedArraySpan = rentedArray.AsSpan(1);
data.CopyTo(rentedArraySpan);
}

for (var i = 0; i < data.Length; i++)
{
if (IsValidInSource((char)data[i]))
continue;

if (rentedArray is null)
{
rentedArray = ArrayPool<byte>.Shared.Rent(length);
rentedArraySpan = rentedArray.AsSpan();
data.CopyTo(rentedArraySpan);
}
rentedArraySpan[i] = (byte)'_';
}

if (rentedArray is not null)
{
var result = new Utf8String(rentedArray, 0, length);
ArrayPool<byte>.Shared.Return(rentedArray);
return result;
}
else
{
return str;
}
}

public static bool IsInvalidInSource(this string str)
public static bool IsInvalidInSource([NotNullWhen(true)] this string? str)
{
if (str is null)
return false;

for (var i = 0; i < str.Length; i++)
{
var it = str[i];
Expand All @@ -73,9 +127,9 @@ public static bool IsInvalidInSource(this string str)
return false;
}

public static bool IsInvalidInSource(this Utf8String? str)
public static bool IsInvalidInSource([NotNullWhen(true)] this Utf8String? str)
{
return IsInvalidInSource(str?.Value ?? "");
return IsInvalidInSource(str?.Value);
}

public static bool IsObfuscated([NotNullWhen(true)] this string? str, GeneratorOptions options)
Expand Down Expand Up @@ -149,9 +203,9 @@ public static string GetUnmangledName(this TypeSignature typeRef, TypeDefinition
else if (typeRef is GenericParameterSignature genericParameter)
{
if (genericParameter.ParameterType == GenericParameterType.Type)
builder.Append(declaringType!.GenericParameters[genericParameter.Index].Name);
builder.Append(declaringType!.GenericParameters[genericParameter.Index].Name.MakeValidInSource());
else
builder.Append(declaringMethod!.GenericParameters[genericParameter.Index].Name);
builder.Append(declaringMethod!.GenericParameters[genericParameter.Index].Name.MakeValidInSource());
}
else
{
Expand Down
3 changes: 3 additions & 0 deletions Il2CppInterop.Generator/Il2CppInterop.Generator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

<ItemGroup>
<PackageReference Include="AsmResolver.DotNet" Version="6.0.0-beta.1" />
<PackageReference Include="MonoMod.Backports" Version="1.1.2">
<Aliases>MonoModBackports</Aliases><!-- Transitive dependency from AsmResolver. Extern alias prevents it from affecting us. -->
</PackageReference>
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
5 changes: 1 addition & 4 deletions Il2CppInterop.Generator/Passes/Pass10CreateTypedefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,7 @@ internal static (string? Namespace, string Name) GetConvertedTypeName(
return (null, convertedTypeName);
}

if (type.Name.IsInvalidInSource())
return (null, type.Name.FilterInvalidInSourceChars());

return (null, type.Name!);
return (null, type.Name.MakeValidInSource());
}

private static TypeAttributes AdjustAttributes(TypeAttributes typeAttributes)
Expand Down
6 changes: 2 additions & 4 deletions Il2CppInterop.Generator/Passes/Pass12FillTypedefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ public static void DoPass(RewriteGlobalContext context)
{
foreach (var originalParameter in typeContext.OriginalType.GenericParameters)
{
var newParameter = new GenericParameter(originalParameter.Name);
if (newParameter.Name.IsInvalidInSource())
newParameter.Name = newParameter.Name.FilterInvalidInSourceChars();
var newParameter = new GenericParameter(originalParameter.Name.MakeValidInSource(),
originalParameter.Attributes.StripValueTypeConstraint());
typeContext.NewType.GenericParameters.Add(newParameter);
newParameter.Attributes = originalParameter.Attributes.StripValueTypeConstraint();
}

if (typeContext.OriginalType.IsEnum)
Expand Down
2 changes: 1 addition & 1 deletion Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public static void DoPass(RewriteGlobalContext context)

foreach (var unityMethodGenericParameter in unityMethod.GenericParameters)
{
var newParameter = new GenericParameter(unityMethodGenericParameter.Name);
var newParameter = new GenericParameter(unityMethodGenericParameter.Name.MakeValidInSource());
newParameter.Attributes = unityMethodGenericParameter.Attributes;
foreach (var genericParameterConstraint in unityMethodGenericParameter.Constraints)
{
Expand Down

0 comments on commit 9d4599d

Please sign in to comment.