-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExt.GetCollectionType.cs
More file actions
83 lines (67 loc) · 3.02 KB
/
Ext.GetCollectionType.cs
File metadata and controls
83 lines (67 loc) · 3.02 KB
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
80
81
82
83
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
namespace PrimeFuncPack;
partial class CodeAnalysisExtensions
{
public static ITypeSymbol? GetCollectionTypeOrDefault(this ITypeSymbol typeSymbol)
{
if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol)
{
return arrayTypeSymbol.ElementType;
}
if (typeSymbol is not INamedTypeSymbol namedTypeSymbol)
{
return null;
}
var enumerableInterface = namedTypeSymbol.AllInterfaces.FirstOrDefault(IsGenericEnumerable);
if (enumerableInterface is not null)
{
return enumerableInterface.TypeArguments[0];
}
return typeSymbol.GetMembers().OfType<IMethodSymbol>().Where(IsEnumeratorMethod).Select(GetEnumeratorType).FirstOrDefault(NotNull);
static bool IsGenericEnumerable(INamedTypeSymbol symbol)
=>
InnerIsType(symbol, "System.Collections.Generic", "IEnumerable") && symbol.TypeArguments.Length is 1;
static bool IsEnumeratorMethod(IMethodSymbol methodSymbol)
=>
methodSymbol.IsGenericMethod is false &&
methodSymbol.Parameters.Length is 0 &&
string.Equals(methodSymbol.Name, "GetEnumerator", StringComparison.InvariantCulture);
static ITypeSymbol? GetEnumeratorType(IMethodSymbol methodSymbol)
=>
methodSymbol.ReturnType?.InnerGetEnumeratorTypeOrDefault();
static bool NotNull(ITypeSymbol? typeSymbol)
=>
typeSymbol is not null;
}
private static ITypeSymbol? InnerGetEnumeratorTypeOrDefault(this ITypeSymbol typeSymbol)
{
if (typeSymbol is not INamedTypeSymbol namedTypeSymbol)
{
return null;
}
var enumeratorInterface = namedTypeSymbol.AllInterfaces.FirstOrDefault(IsGenericEnumerator);
if (enumeratorInterface is not null)
{
return enumeratorInterface.TypeArguments[0];
}
if (namedTypeSymbol.GetMembers().OfType<IMethodSymbol>().Any(IsMoveNextMethod) is false)
{
return null;
}
return namedTypeSymbol.GetMembers().OfType<IPropertySymbol>().FirstOrDefault(IsCurrentProperty)?.Type;
static bool IsGenericEnumerator(INamedTypeSymbol symbol)
=>
InnerIsType(symbol, "System.Collections.Generic", "IEnumerator") && symbol.TypeArguments.Length is 1;
static bool IsMoveNextMethod(IMethodSymbol methodSymbol)
=>
methodSymbol.IsGenericMethod is false &&
methodSymbol.Parameters.Length is 0 &&
methodSymbol.ReturnType.InnerIsType(SystemNamespace, "Boolean") &&
string.Equals(methodSymbol.Name, "MoveNext", StringComparison.InvariantCulture);
static bool IsCurrentProperty(IPropertySymbol propertySymbol)
=>
string.Equals(propertySymbol.Name, "Current", StringComparison.InvariantCulture);
}
}