mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-18 03:09:45 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
65 lines
2.4 KiB
C#
65 lines
2.4 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
|
|
namespace Sandbox;
|
|
|
|
internal class BlacklistCodeWalker( SemanticModel semanticModel ) : CSharpSyntaxWalker
|
|
{
|
|
public static readonly DiagnosticDescriptor BlacklistDescriptor = new( "SB500", "Blacklist Error", "Prohibited type '{0}' used", "Sandbox.Compiling", DiagnosticSeverity.Error, true );
|
|
|
|
public List<Diagnostic> Diagnostics { get; set; } = [];
|
|
|
|
record LineSymbol( int Line, ISymbol Symbol );
|
|
HashSet<LineSymbol> LineSymbols = [];
|
|
|
|
private readonly SemanticModel _semanticModel = semanticModel;
|
|
|
|
static readonly SymbolDisplayFormat FullyQualifiedSymbolFormat = new SymbolDisplayFormat(
|
|
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
|
|
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
|
|
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
|
|
memberOptions: SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeContainingType,
|
|
parameterOptions: SymbolDisplayParameterOptions.IncludeType,
|
|
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes
|
|
);
|
|
|
|
/// <summary>
|
|
/// Visits every node type, unless that node type has been explicitly overridden.
|
|
/// This gives us complete coverage of every type of possible syntax node.
|
|
/// From there we can see if it references any blacklisted symbols.
|
|
/// </summary>
|
|
public override void DefaultVisit( SyntaxNode node )
|
|
{
|
|
var symbolInfo = _semanticModel.GetSymbolInfo( node );
|
|
|
|
// Consider the CandidateSymbols even though you'd assume it can't compile.. It can!
|
|
var symbol = symbolInfo.Symbol ?? symbolInfo.CandidateSymbols.FirstOrDefault();
|
|
|
|
if ( symbol is null )
|
|
{
|
|
base.DefaultVisit( node );
|
|
return;
|
|
}
|
|
|
|
var fullyQualifiedName = symbol.ToDisplayString( FullyQualifiedSymbolFormat );
|
|
|
|
if ( !CompilerRules.Blacklist.Any( x => x.IsMatch( fullyQualifiedName ) ) )
|
|
{
|
|
base.DefaultVisit( node );
|
|
return;
|
|
}
|
|
|
|
// This isn't strictly needed, it just makes the diagnostics a bit neater and easier to test against
|
|
var lineSymbol = new LineSymbol( node.GetLocation().GetMappedLineSpan().StartLinePosition.Line, symbol );
|
|
if ( LineSymbols.Add( lineSymbol ) == false )
|
|
{
|
|
base.DefaultVisit( node );
|
|
return;
|
|
}
|
|
|
|
Diagnostics.Add( Diagnostic.Create( BlacklistDescriptor, node.GetLocation(), fullyQualifiedName ) );
|
|
|
|
base.DefaultVisit( node );
|
|
}
|
|
}
|