Skip to content

Instantly share code, notes, and snippets.

@rodion-m
Created July 13, 2024 21:42
Show Gist options
  • Save rodion-m/f116db6b7f745c0f535b1ed615c4b8f0 to your computer and use it in GitHub Desktop.
Save rodion-m/f116db6b7f745c0f535b1ed615c4b8f0 to your computer and use it in GitHub Desktop.
A factory for creating instances of the internal SymbolDisplayFormat class from the Roslyn library.
using System.Reflection;
using Microsoft.CodeAnalysis;
namespace Gend.Domain;
/// <summary>
/// Provides a factory for creating instances of the internal SymbolDisplayFormat class from the Roslyn library.
/// </summary>
public static class SymbolDisplayFormatFactory
{
private static readonly ConstructorInfo ConstructorInfo;
private static readonly Type SymbolDisplayCompilerInternalOptionsType;
/// <summary>
/// Static constructor to initialize reflection-based access to internal Roslyn types.
/// </summary>
static SymbolDisplayFormatFactory()
{
try
{
Assembly assembly = typeof(SymbolDisplayFormat).Assembly;
Type symbolDisplayFormatType = typeof(SymbolDisplayFormat);
string enumTypeName = "Microsoft.CodeAnalysis.SymbolDisplayCompilerInternalOptions";
SymbolDisplayCompilerInternalOptionsType = assembly.GetType(enumTypeName)
?? throw new InvalidOperationException($"Type '{enumTypeName}' not found.");
ConstructorInfo? constructorInfo = symbolDisplayFormatType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(c => c.GetParameters().Length == 12);
ConstructorInfo = constructorInfo
?? throw new InvalidOperationException("Constructor with 12 parameters not found.");
}
catch (Exception ex)
{
throw new InvalidOperationException(
"Failed to initialize SymbolDisplayFormatFactory. " +
"Please check the version of the 'Microsoft.CodeAnalysis' package (it surely works with 4.10).", ex);
}
}
/// <summary>
/// Creates an instance of the internal SymbolDisplayFormat class using reflection.
/// </summary>
public static SymbolDisplayFormat CreateSymbolDisplayFormat(
SymbolDisplayCompilerInternalOptions compilerInternalOptions,
SymbolDisplayGlobalNamespaceStyle globalNamespaceStyle = default,
SymbolDisplayTypeQualificationStyle typeQualificationStyle = default,
SymbolDisplayGenericsOptions genericsOptions = default,
SymbolDisplayMemberOptions memberOptions = default,
SymbolDisplayParameterOptions parameterOptions = default,
SymbolDisplayDelegateStyle delegateStyle = default,
SymbolDisplayExtensionMethodStyle extensionMethodStyle = default,
SymbolDisplayPropertyStyle propertyStyle = default,
SymbolDisplayLocalOptions localOptions = default,
SymbolDisplayKindOptions kindOptions = default,
SymbolDisplayMiscellaneousOptions miscellaneousOptions = default)
{
object internalCompilerOptions = Enum.ToObject(
SymbolDisplayCompilerInternalOptionsType,
(int)compilerInternalOptions);
return (SymbolDisplayFormat)ConstructorInfo.Invoke(new[]
{
internalCompilerOptions,
globalNamespaceStyle,
typeQualificationStyle,
genericsOptions,
memberOptions,
parameterOptions,
delegateStyle,
extensionMethodStyle,
propertyStyle,
localOptions,
kindOptions,
miscellaneousOptions
});
}
/// <summary>
/// Represents compiler internal options for symbol display in Roslyn.
/// This enum mirrors the internal SymbolDisplayCompilerInternalOptions enum in the Roslyn library.
/// </summary>
[Flags]
public enum SymbolDisplayCompilerInternalOptions
{
/// <summary>
/// No special options.
/// </summary>
None = 0,
/// <summary>
/// Use metadata method names (e.g., ".ctor" instead of "Goo").
/// </summary>
UseMetadataMethodNames = 1 << 0,
/// <summary>
/// Use arity for generic types (e.g., "List`1" instead of "List&lt;T&gt;").
/// Overrides GenericsOptions on types.
/// </summary>
UseArityForGenericTypes = 1 << 1,
/// <summary>
/// Append "[Missing]" to missing Metadata types (for testing).
/// </summary>
FlagMissingMetadataTypes = 1 << 2,
/// <summary>
/// Include the Script type when qualifying type names.
/// </summary>
IncludeScriptType = 1 << 3,
/// <summary>
/// Include custom modifiers (e.g., modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) on
/// the member (return) type and parameters.
/// </summary>
IncludeCustomModifiers = 1 << 4,
/// <summary>
/// Reverse array rank specifiers (e.g., "int[,][]" instead of "int[][,]").
/// </summary>
ReverseArrayRankSpecifiers = 1 << 5,
/// <summary>
/// Display `System.[U]IntPtr` instead of `n[u]int`.
/// </summary>
UseNativeIntegerUnderlyingType = 1 << 6,
/// <summary>
/// Separate nested types from containing types using '+' instead of '.' (dot).
/// </summary>
UsePlusForNestedTypes = 1 << 7,
/// <summary>
/// Display `MyType@File.cs` instead of `MyType`.
/// </summary>
IncludeContainingFileForFileTypes = 1 << 8,
/// <summary>
/// Does not include parameter name if the parameter is displayed on its own
/// (i.e., not as part of a method, delegate, or indexer).
/// </summary>
ExcludeParameterNameIfStandalone = 1 << 9,
/// <summary>
/// Display `&lt;File&gt;F&lt;sha256-hex-string&gt;_MyType` instead of `MyType`.
/// Differs from IncludeContainingFileForFileTypes because it guarantees that
/// the prefix will be unique for all files which are permitted to declare file-local types.
/// </summary>
IncludeFileLocalTypesPrefix = 1 << 10
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment