1+ using System ;
2+ using System . Linq ;
3+ using Microsoft . CodeAnalysis ;
4+
5+ namespace PrimeFuncPack ;
6+
7+ partial class CodeAnalysisExtensions
8+ {
9+ public static ITypeSymbol ? GetCollectionTypeOrDefault ( this ITypeSymbol typeSymbol )
10+ {
11+ if ( typeSymbol is IArrayTypeSymbol arrayTypeSymbol )
12+ {
13+ return arrayTypeSymbol . ElementType ;
14+ }
15+
16+ if ( typeSymbol is not INamedTypeSymbol namedTypeSymbol )
17+ {
18+ return null ;
19+ }
20+
21+ var enumerableInterface = namedTypeSymbol . AllInterfaces . FirstOrDefault ( IsGenericEnumerable ) ;
22+ if ( enumerableInterface is not null )
23+ {
24+ return enumerableInterface . TypeArguments [ 0 ] ;
25+ }
26+
27+ return typeSymbol . GetMembers ( ) . OfType < IMethodSymbol > ( ) . Where ( IsEnumeratorMethod ) . Select ( GetEnumeratorType ) . FirstOrDefault ( NotNull ) ;
28+
29+ static bool IsGenericEnumerable ( INamedTypeSymbol symbol )
30+ =>
31+ InnerIsType ( symbol , "System.Collections.Generic" , "IEnumerable" ) && symbol . TypeArguments . Length is 1 ;
32+
33+ static bool IsEnumeratorMethod ( IMethodSymbol methodSymbol )
34+ =>
35+ methodSymbol . IsGenericMethod is false &&
36+ methodSymbol . Parameters . Length is 0 &&
37+ string . Equals ( methodSymbol . Name , "GetEnumerator" , StringComparison . InvariantCulture ) ;
38+
39+ static ITypeSymbol ? GetEnumeratorType ( IMethodSymbol methodSymbol )
40+ =>
41+ methodSymbol . ReturnType ? . InnerGetEnumeratorTypeOrDefault ( ) ;
42+
43+ static bool NotNull ( ITypeSymbol ? typeSymbol )
44+ =>
45+ typeSymbol is not null ;
46+ }
47+
48+ private static ITypeSymbol ? InnerGetEnumeratorTypeOrDefault ( this ITypeSymbol typeSymbol )
49+ {
50+ if ( typeSymbol is not INamedTypeSymbol namedTypeSymbol )
51+ {
52+ return null ;
53+ }
54+
55+ var enumeratorInterface = namedTypeSymbol . AllInterfaces . FirstOrDefault ( IsGenericEnumerator ) ;
56+ if ( enumeratorInterface is not null )
57+ {
58+ return enumeratorInterface . TypeArguments [ 0 ] ;
59+ }
60+
61+ if ( namedTypeSymbol . GetMembers ( ) . OfType < IMethodSymbol > ( ) . Any ( IsMoveNextMethod ) is false )
62+ {
63+ return null ;
64+ }
65+
66+ return namedTypeSymbol . GetMembers ( ) . OfType < IPropertySymbol > ( ) . FirstOrDefault ( IsCurrentProperty ) ? . Type ;
67+
68+ static bool IsGenericEnumerator ( INamedTypeSymbol symbol )
69+ =>
70+ InnerIsType ( symbol , "System.Collections.Generic" , "IEnumerator" ) && symbol . TypeArguments . Length is 1 ;
71+
72+ static bool IsMoveNextMethod ( IMethodSymbol methodSymbol )
73+ =>
74+ methodSymbol . IsGenericMethod is false &&
75+ methodSymbol . Parameters . Length is 0 &&
76+ methodSymbol . ReturnType . InnerIsType ( SystemNamespace , "Boolean" ) &&
77+ string . Equals ( methodSymbol . Name , "MoveNext" , StringComparison . InvariantCulture ) ;
78+
79+ static bool IsCurrentProperty ( IPropertySymbol propertySymbol )
80+ =>
81+ string . Equals ( propertySymbol . Name , "Current" , StringComparison . InvariantCulture ) ;
82+ }
83+ }
0 commit comments