SharpGen/Transform/NamingRulesManager.MultipleMarshallable.cs (125 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using SharpGen.Config;
using SharpGen.CppModel;
namespace SharpGen.Transform
{
public sealed partial class NamingRulesManager
{
/// <summary>
/// Renames the specified C++ fields.
/// </summary>
/// <param name="cppFields">The C++ fields.</param>
/// <returns>The C# names of these fields.</returns>
public IReadOnlyList<string> Rename(IReadOnlyList<CppField> cppFields) =>
RenameMarshallableCore(cppFields, PostprocessFieldName);
/// <summary>
/// Renames the specified C++ parameters.
/// </summary>
/// <param name="cppParameters">The C++ parameters.</param>
/// <returns>The C# names of these parameters.</returns>
public IReadOnlyList<string> Rename(IReadOnlyList<CppParameter> cppParameters) =>
RenameMarshallableCore(cppParameters, PostprocessParameterName);
private delegate string PostprocessName<in T>(T element, string name, bool isFinal) where T : CppMarshallable;
private static string PostprocessFieldName(CppField element, string name, bool isFinal)
{
if (char.IsDigit(name[0]))
name = "Field" + name;
return UnKeyword(name);
}
private static string PostprocessParameterName(CppParameter element, string name, bool isFinal)
{
if (char.IsDigit(name[0]))
name = "arg" + name;
if (!isFinal && !char.IsLower(name[0]))
name = char.ToLower(name[0]) + name.Substring(1);
return UnKeyword(name);
}
private IReadOnlyList<string> RenameMarshallableCore<T>(IReadOnlyList<T> cppItems,
PostprocessName<T> postprocessName)
where T : CppMarshallable
{
if (cppItems == null) throw new ArgumentNullException(nameof(cppItems));
if (postprocessName == null) throw new ArgumentNullException(nameof(postprocessName));
var count = cppItems.Count;
var names = new string[count][];
var result = new string[count];
HashSet<string> nameSet = new();
for (var index = 0; index < count; index++)
{
var cppItem = cppItems[index];
var originalName = cppItem.Name;
var tag = cppItem.Rule;
var name = RenameCore(originalName, tag, null, out var isFinal, out var isPreempted);
if (isFinal)
{
Debug.Assert(!isPreempted);
var finalName = postprocessName(cppItem, name, true);
nameSet.Add(finalName);
result[index] = finalName;
}
else
{
List<string> variantList = new(2);
var namingFlags = tag.NamingFlags is { } flags ? flags : NamingFlags.Default;
var noPrematureBreak = (namingFlags & NamingFlags.NoPrematureBreak) != 0;
string PascalCaseIfNeeded(string name)
{
if (isPreempted && !noPrematureBreak)
return name;
return ConvertToPascalCase(name, namingFlags);
}
if (!isPreempted || noPrematureBreak)
{
if ((namingFlags & NamingFlags.NoHungarianNotationHandler) == 0)
{
var originalNameLower = originalName.ToLowerInvariant();
foreach (var prefix in _hungarianNotation)
if (prefix.Apply(cppItem, name, originalName, originalNameLower, out var variants))
{
variantList.AddRange(variants);
break;
}
}
}
if (variantList.Count == 0)
variantList.Add(name);
names[index] = variantList.Select(x => postprocessName(cppItem, PascalCaseIfNeeded(x), false))
.ToArray();
}
}
Dictionary<string, uint> duplicateCount = new();
string DeduplicateName(string name)
{
if (nameSet.Add(name))
return name;
string newName;
do
{
if (!duplicateCount.TryGetValue(name, out var nameCount))
nameCount = 0;
duplicateCount[name] = ++nameCount;
newName = name + nameCount;
} while (!nameSet.Add(newName));
return newName;
}
for (var index = 0; index < count; index++)
{
if (result[index] != null)
continue;
var nameList = names[index];
switch (nameList.Length)
{
case < 1:
Debug.Fail($"Expected to have non-empty {nameof(nameList)}");
result[index] = "SHARPGEN_FAILURE";
continue;
case 1:
result[index] = DeduplicateName(nameList[0]);
continue;
}
var withoutDuplicates = nameList.Except(nameSet).ToArray();
result[index] = DeduplicateName(
withoutDuplicates.Length switch
{
>= 1 => withoutDuplicates[0],
< 1 => nameList[0]
}
);
}
return result;
}
}
}