Files
sbox-public/engine/Sandbox.Access/AssemblyAccess.Touch.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

165 lines
4.0 KiB
C#

using Microsoft.CodeAnalysis;
using Mono.Cecil;
using System;
namespace Sandbox;
internal partial class AssemblyAccess
{
public class Access
{
public string Name { get; set; }
public string Type { get; set; }
public int Count { get; set; }
public List<AccessControl.CodeLocation> Locations { get; set; } = new( 5 );
}
bool Touch( string name, string type )
{
bool alreadyTouched = false;
Touched.AddOrUpdate( name,
add => new Access { Name = name, Type = type, Count = 1, Locations = new List<AccessControl.CodeLocation> { Location } },
( name, update ) =>
{
update.Count++;
if ( update.Locations.Count() < 5 )
update.Locations.Add( Location );
alreadyTouched = true;
return update;
} );
return alreadyTouched;
}
bool Touch( TypeDefinition typedef )
{
return Touch( $"{typedef.Module.Assembly.Name.Name}/{typedef.FullName}", "type" );
}
bool Touch( TypeReference typeRef )
{
if ( typeRef == null )
return false;
switch ( typeRef.MetadataType )
{
case Mono.Cecil.MetadataType.Void:
case Mono.Cecil.MetadataType.Single:
case Mono.Cecil.MetadataType.Int32:
case Mono.Cecil.MetadataType.Int16:
case Mono.Cecil.MetadataType.Int64:
case Mono.Cecil.MetadataType.Boolean:
case Mono.Cecil.MetadataType.String:
return true;
}
if ( typeRef.IsGenericParameter )
return false;
if ( typeRef is IModifierType typeMod )
return Touch( typeMod.ModifierType ) || Touch( typeMod.ElementType );
if ( typeRef is GenericInstanceType git )
{
foreach ( var param in git.GenericArguments )
{
Touch( param );
}
}
if ( typeRef.IsArray || typeRef.IsByReference )
{
return Touch( typeRef.GetElementType() );
}
var typeDef = typeRef.Resolve();
if ( typeDef == null )
throw new Exception( $"TypeDefinition was null - couldn't resolve {typeRef}" );
//
// If this type is in a dll we've already approved, or in this assembly we're scanning
// then just let it slide because we're already gonna have whitelisted them
//
if ( typeDef.Module.Assembly == Assembly )
return true;
if ( Global.Assemblies.Any( x => x.Value == typeDef.Module.Assembly ) )
return true;
return Touch( typeDef );
}
/// <summary>
/// These methods show up a lot and unexplitable, easy to skip
/// </summary>
static string[] skipMethods = new string[]
{
"System.Void System.Runtime.CompilerServices.RuntimeHelpers::EnsureSufficientExecutionStack()"
};
bool Touch( MethodReference source )
{
var typedef = source.Resolve();
if ( typedef is null )
throw new System.Exception( $"MethodDefinition was null - couldn't resolve {source}" );
// No need to investigate this - we'll investigate in our crawl
if ( typedef.DeclaringType.Module.Assembly == Assembly )
return true;
// This is called a LOT, lets skip it when we can
if ( typedef.DeclaringType.Module.Assembly.Name.Name == "System.Private.CoreLib" &&
typedef.FullName == "System.Void System.Runtime.CompilerServices.RuntimeHelpers::EnsureSufficientExecutionStack()" )
{
return true;
}
return Touch( typedef );
}
bool Touch( MethodDefinition typedef )
{
var touchName = $"{typedef.Module.Assembly.Name.Name}/{typedef.DeclaringType.FullName}.{typedef.Name}";
if ( typedef.HasGenericParameters )
{
var gparms = string.Join( ",", typedef.GenericParameters.Select( x => x.Name.ToString() ) );
if ( !string.IsNullOrWhiteSpace( gparms ) ) gparms = $"<{gparms}>";
touchName += gparms;
}
if ( typedef.HasParameters )
{
var parms = string.Join( ", ", typedef.Parameters.Select( x => x.ParameterType.ToString() ) );
if ( !string.IsNullOrWhiteSpace( parms ) ) parms = $" {parms} ";
touchName += $"({parms})";
}
else
{
touchName += "()";
}
if ( Touch( touchName, "method" ) )
return true;
//
// Note - this is the definition - we can't test the generic parameters here
// but they should be checked on usage !
//
Touch( typedef.ReturnType );
foreach ( var param in typedef.Parameters )
{
Touch( param.ParameterType );
}
return false;
}
}