Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 57 additions & 7 deletions src/BitMono.Core/Analyzing/CriticalBaseTypesCriticalAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace BitMono.Core.Analyzing;
using System.Text.RegularExpressions;

namespace BitMono.Core.Analyzing;

[SuppressMessage("ReSharper", "InvertIf")]
public class CriticalBaseTypesCriticalAnalyzer : ICriticalAnalyzer<TypeDefinition>
{
private readonly CriticalsSettings _criticalsSettings;
Expand All @@ -12,19 +13,68 @@ public CriticalBaseTypesCriticalAnalyzer(IOptions<CriticalsSettings> criticals)

public bool NotCriticalToMakeChanges(TypeDefinition type)
{
if (_criticalsSettings.UseCriticalBaseTypes == false)
if (!_criticalsSettings.UseCriticalBaseTypes)
{
return true;
}
if (type.HasBaseType())
foreach (string ancestorFullName in YieldAncestors(type))
{
var criticalBaseTypes = _criticalsSettings.CriticalBaseTypes!;
var typeBaseTypeName = type.BaseType?.Name?.Value.Split('`')[0] ?? string.Empty;
if (criticalBaseTypes.FirstOrDefault(c => c.StartsWith(typeBaseTypeName)) != null)
if (IsCriticalBaseType(ancestorFullName))
{
return false;
}
}
return true;
}

private bool IsCriticalBaseType(string ancestorFullName)
{
ancestorFullName = StripGenerics(ancestorFullName);
foreach (string criticalBaseType in _criticalsSettings.CriticalBaseTypes)
{
bool matches;
if (criticalBaseType.Contains('*'))
{
string regex = "^" + Regex.Escape(criticalBaseType).Replace(@"\*", ".*") + "$";
matches = Regex.IsMatch(ancestorFullName, regex);
}
else
{
matches = criticalBaseType == ancestorFullName;
}
if (matches)
{
return true;
}
}
return false;
}

private static string StripGenerics(string fullName)
{
int genericDelimeterIndex = fullName.IndexOf('`');
if (genericDelimeterIndex == -1)
{
return fullName;
}
return fullName[..genericDelimeterIndex];
}

/// <summary>
/// Yields the full class names of all ancestors across the inheritence chain of <paramref name="current"/>, including itself.
/// </summary>
private static IEnumerable<string> YieldAncestors(TypeDefinition? current)
{
while (current != null)
{
yield return current.FullName;
ITypeDefOrRef? baseType = current.BaseType;
current = baseType?.Resolve();
if (current == null && baseType != null)
{
//Type is in an unresolved dependency assembly, stop the search but yield the type name
yield return baseType.FullName;
}
}
}
}
11 changes: 5 additions & 6 deletions src/BitMono.Host/criticals.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,15 @@
"UseCriticalBaseTypes": true,
"CriticalBaseTypes": [
// RocketMod
"RocketPlugin",
"RocketPlugin*",

// OpenMod
"OpenModUnturnedPlugin",
"OpenModUniversalPlugin",
"Command",
"OpenModUnturnedPlugin*",
"OpenModUniversalPlugin*",
"Command*",

// rust-oxide-umod
"RustPlugin"

"RustPlugin*"
],

// Exclude from obfuscation if the member starts with string
Expand Down
Loading