mirror of
https://github.com/AssetRipper/Cpp2IL.git
synced 2026-11-13 04:26:33 -10:00
187 lines
6.3 KiB
C#
187 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Cpp2IL.Core.Model.Contexts;
|
|
using LibCpp2IL.Metadata;
|
|
|
|
namespace Cpp2IL.Core.Extensions;
|
|
|
|
internal static class AccessibilityExtensions
|
|
{
|
|
public static bool IsAccessibleTo(this TypeAnalysisContext referenceType, TypeAnalysisContext referencingType)
|
|
{
|
|
if (referenceType == referencingType)
|
|
return true;
|
|
|
|
var declaringTypesHierarchy = referenceType.GetTypeAndDeclaringTypes().ToArray();
|
|
var inheritsFromIndex = declaringTypesHierarchy.IndexOf(t => referencingType.IsAssignableTo(t));
|
|
var declaringTypeIndex = Array.IndexOf(declaringTypesHierarchy, referencingType);
|
|
|
|
if (referenceType.DeclaringAssembly == referencingType.DeclaringAssembly /*or internals visible*/)
|
|
{
|
|
for (var i = 0; i < declaringTypesHierarchy.Length; i++)
|
|
{
|
|
if (i == declaringTypeIndex - 1)
|
|
{
|
|
//All nested classes are accesible to their immediate declaring type.
|
|
}
|
|
else if (i == inheritsFromIndex - 1)
|
|
{
|
|
if (declaringTypesHierarchy[i].Visibility is TypeAttributes.NestedPrivate)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (declaringTypesHierarchy[i].Visibility is TypeAttributes.NestedPrivate or TypeAttributes.NestedFamily or TypeAttributes.NestedFamANDAssem)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if (referenceType.DeclaringAssembly.IsDependencyOf(referencingType.DeclaringAssembly))
|
|
{
|
|
for (var i = 0; i < declaringTypesHierarchy.Length; i++)
|
|
{
|
|
if (i == declaringTypeIndex - 1)
|
|
{
|
|
//All nested classes are accesible to their immediate declaring type.
|
|
}
|
|
else if (i == inheritsFromIndex - 1)
|
|
{
|
|
if (declaringTypesHierarchy[i].Visibility is TypeAttributes.NotPublic or TypeAttributes.NestedPrivate or TypeAttributes.NestedAssembly or TypeAttributes.NestedFamANDAssem)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (declaringTypesHierarchy[i].Visibility is TypeAttributes.NotPublic or TypeAttributes.NestedPrivate or TypeAttributes.NestedFamily or TypeAttributes.NestedAssembly or TypeAttributes.NestedFamANDAssem or TypeAttributes.NestedFamORAssem)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static bool IsAssignableTo(this TypeAnalysisContext derivedType, TypeAnalysisContext baseType)
|
|
{
|
|
if (baseType.IsInterface)
|
|
{
|
|
return derivedType.IsAssignableToInterface(baseType);
|
|
}
|
|
else
|
|
{
|
|
return derivedType.InheritsFrom(baseType);
|
|
}
|
|
}
|
|
|
|
private static int IndexOf<T>(this IEnumerable<T> enumerable, Func<T, bool> selector)
|
|
{
|
|
var index = 0;
|
|
foreach (var item in enumerable)
|
|
{
|
|
if (selector(item))
|
|
{
|
|
return index;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
private static IEnumerable<TypeAnalysisContext> GetTypeAndDeclaringTypes(this TypeAnalysisContext type)
|
|
{
|
|
var current = type;
|
|
while (current != null)
|
|
{
|
|
yield return current;
|
|
current = current.DeclaringType;
|
|
}
|
|
}
|
|
|
|
private static bool InheritsFrom(this TypeAnalysisContext derivedType, TypeAnalysisContext baseType)
|
|
{
|
|
var current = derivedType;
|
|
while (current != null)
|
|
{
|
|
if (current == baseType)
|
|
return true;
|
|
current = current.BaseType;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool IsAssignableToInterface(this TypeAnalysisContext derivedType, TypeAnalysisContext baseInterface)
|
|
{
|
|
if (derivedType == baseInterface)
|
|
return true;
|
|
|
|
foreach (var @interface in derivedType.InterfaceContexts)
|
|
{
|
|
if (@interface.IsAssignableToInterface(baseInterface))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool IsDependencyOf(this AssemblyAnalysisContext referencedAssembly, AssemblyAnalysisContext referencingAssembly)
|
|
{
|
|
if (referencingAssembly.Definition is null)
|
|
{
|
|
// Injected assemblies can access everything
|
|
return true;
|
|
}
|
|
if (referencedAssembly.Definition is null)
|
|
{
|
|
// Injected assemblies cannot be accessed by metadata assemblies
|
|
return false;
|
|
}
|
|
return referencedAssembly.Definition.IsDependencyOf(referencingAssembly.Definition);
|
|
}
|
|
|
|
private static bool IsDependencyOf(this Il2CppAssemblyDefinition referencedAssembly, Il2CppAssemblyDefinition referencingAssembly)
|
|
{
|
|
if (Array.IndexOf(referencingAssembly.ReferencedAssemblies, referencedAssembly) >= 0)
|
|
return true;
|
|
|
|
if (Array.IndexOf(referencedAssembly.ReferencedAssemblies, referencingAssembly) >= 0)
|
|
return false;
|
|
|
|
return referencingAssembly.CollectAllDependencies().Contains(referencedAssembly);
|
|
}
|
|
|
|
private static HashSet<Il2CppAssemblyDefinition> CollectAllDependencies(this Il2CppAssemblyDefinition referencingAssembly)
|
|
{
|
|
var dependencies = new HashSet<Il2CppAssemblyDefinition> { referencingAssembly };
|
|
referencingAssembly.CollectAllDependencies(dependencies);
|
|
return dependencies;
|
|
}
|
|
|
|
private static void CollectAllDependencies(this Il2CppAssemblyDefinition referencingAssembly, HashSet<Il2CppAssemblyDefinition> dependencies)
|
|
{
|
|
foreach (var dependency in referencingAssembly.ReferencedAssemblies)
|
|
{
|
|
//Assemblies can have circular references
|
|
if (dependencies.Add(dependency))
|
|
{
|
|
dependency.CollectAllDependencies(dependencies);
|
|
}
|
|
}
|
|
}
|
|
}
|