mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-19 11:49:44 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
165 lines
4.0 KiB
C#
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;
|
|
}
|
|
|
|
}
|