-
-
Notifications
You must be signed in to change notification settings - Fork 129
/
SymbolExtensions.cs
79 lines (63 loc) · 3.29 KB
/
SymbolExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
namespace Riok.Mapperly.Helpers;
internal static class SymbolExtensions
{
internal static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeSymbol)
=> symbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeSymbol));
internal static bool IsImmutable(this ISymbol symbol)
=> symbol is INamedTypeSymbol namedSymbol && (namedSymbol.IsReadOnly || namedSymbol.SpecialType == SpecialType.System_String);
internal static bool IsAccessible(this ISymbol symbol, bool allowProtected = false)
=> symbol.DeclaredAccessibility.HasFlag(Accessibility.Internal)
|| symbol.DeclaredAccessibility.HasFlag(Accessibility.Public)
|| (symbol.DeclaredAccessibility.HasFlag(Accessibility.Protected) && allowProtected);
internal static bool HasAccessibleParameterlessConstructor(this ITypeSymbol symbol, bool allowProtected = false)
=> symbol is INamedTypeSymbol { IsAbstract: false } namedTypeSymbol
&& namedTypeSymbol.Constructors.Any(c => c.Parameters.IsDefaultOrEmpty && c.IsAccessible(allowProtected));
internal static bool IsArrayType(this ITypeSymbol symbol)
=> symbol is IArrayTypeSymbol;
internal static bool IsEnum(this ITypeSymbol t)
=> TryGetEnumUnderlyingType(t, out _);
internal static bool TryGetEnumUnderlyingType(this ITypeSymbol t, [NotNullWhen(true)] out INamedTypeSymbol? enumType)
{
enumType = (t.NonNullable() as INamedTypeSymbol)?.EnumUnderlyingType;
return enumType != null;
}
internal static IEnumerable<ISymbol> GetAllMembers(this ITypeSymbol symbol, string name)
=> symbol.GetAllMembers(name, StringComparer.Ordinal);
internal static IEnumerable<ISymbol> GetAllMembers(this ITypeSymbol symbol, string name, IEqualityComparer<string> comparer)
=> symbol.GetAllMembers().Where(x => comparer.Equals(name, x.Name));
internal static IEnumerable<ISymbol> GetAllMembers(this ITypeSymbol symbol)
{
var members = symbol.GetMembers();
if (symbol.TypeKind == TypeKind.Interface)
{
var interfaceProperties = symbol.AllInterfaces.SelectMany(i => i.GetAllMembers());
return members.Concat(interfaceProperties);
}
return symbol.BaseType == null
? members
: members.Concat(symbol.BaseType.GetAllMembers());
}
internal static IEnumerable<IPropertySymbol> GetAllAccessibleProperties(this ITypeSymbol symbol)
{
return symbol
.GetAllMembers()
.OfType<IPropertySymbol>()
.Where(x => x.IsAccessible())
.DistinctBy(x => x.Name);
}
internal static bool ImplementsGeneric(
this ITypeSymbol t,
INamedTypeSymbol genericInterfaceSymbol,
[NotNullWhen(true)] out INamedTypeSymbol? genericIntf)
{
if (SymbolEqualityComparer.Default.Equals(t.OriginalDefinition, genericInterfaceSymbol))
{
genericIntf = (INamedTypeSymbol)t;
return true;
}
genericIntf = t.AllInterfaces.FirstOrDefault(x => x.IsGenericType && SymbolEqualityComparer.Default.Equals(x.OriginalDefinition, genericInterfaceSymbol));
return genericIntf != null;
}
}