1+ // ReSharper disable LoopCanBeConvertedToQuery
12namespace Pure . DI . InterfaceGeneration ;
23
34using System ;
45using System . Collections . Generic ;
6+ using System . Collections . Immutable ;
57using System . Linq ;
68using System . Text ;
79using Microsoft . CodeAnalysis ;
@@ -10,7 +12,9 @@ namespace Pure.DI.InterfaceGeneration;
1012
1113sealed class InterfaceBuilder (
1214 IRoslynSymbols roslynSymbols ,
13- ITypes types ) : IInterfaceBuilder
15+ ITypes types ,
16+ Func < IBuilder < GeneratedInterfaceDetails , Lines > > interfaceCodeBuilderFactory )
17+ : IInterfaceBuilder
1418{
1519 private static readonly SymbolDisplayFormat FullyQualifiedDisplayFormat = new (
1620 genericsOptions : SymbolDisplayGenericsOptions . IncludeTypeParameters ,
@@ -28,68 +32,74 @@ sealed class InterfaceBuilder(
2832 globalNamespaceStyle : FullyQualifiedDisplayFormat . GlobalNamespaceStyle ,
2933 miscellaneousOptions : FullyQualifiedDisplayFormat . MiscellaneousOptions ) ;
3034
31- public string BuildInterfaceFor ( SemanticModel semanticModel , ITypeSymbol typeSymbol , ClassDeclarationSyntax classSyntax )
35+ public Lines BuildInterfaceFor ( SemanticModel semanticModel , ITypeSymbol typeSymbol , ClassDeclarationSyntax classSyntax )
3236 {
3337 if ( typeSymbol is not INamedTypeSymbol namedTypeSymbol )
3438 {
35- return string . Empty ;
39+ return new Lines ( ) ;
3640 }
3741
3842 var generationAttribute = typeSymbol . GetAttributes ( ) . FirstOrDefault ( x =>
3943 x . AttributeClass != null && x . AttributeClass . Name . Contains ( Names . GenerateInterfaceAttributeName , StringComparison . Ordinal ) ) ;
4044
41- var symbolDetails = new GeneratedInterfaceDetails ( generationAttribute , typeSymbol , classSyntax ) ;
42- var interfaceGenerator = new InterfaceCodeBuilder ( symbolDetails . NamespaceName , symbolDetails . InterfaceName , symbolDetails . AccessLevel ) ;
43-
44- interfaceGenerator . AddClassDocumentation ( GetDocumentationForClass ( classSyntax ) ) ;
45- interfaceGenerator . AddGeneric ( GetGeneric ( classSyntax , namedTypeSymbol ) ) ;
45+ var symbolDetails = new GeneratedInterfaceDetails ( semanticModel , generationAttribute , typeSymbol , classSyntax )
46+ {
47+ ClassDocumentation = GetDocumentationForClass ( classSyntax ) ,
48+ GenericType = GetGeneric ( classSyntax , namedTypeSymbol )
49+ } ;
4650
4751 var members = roslynSymbols . GetAllMembers ( typeSymbol )
4852 . Where ( x => x . DeclaredAccessibility == Accessibility . Public )
4953 . Where ( x => ! x . IsStatic )
5054 . Where ( x => ! HasIgnoreAttribute ( x ) )
5155 . ToList ( ) ;
5256
53- AddPropertiesToInterface ( members , interfaceGenerator ) ;
54- AddMethodsToInterface ( semanticModel , members , interfaceGenerator ) ;
55- AddEventsToInterface ( members , interfaceGenerator ) ;
57+ var hasNullable = false ;
58+ symbolDetails . PropertyInfos = GetProperties ( members , ref hasNullable ) ;
59+ symbolDetails . MethodInfos = GetMethods ( semanticModel , members , ref hasNullable ) ;
60+ symbolDetails . Events = GetEvents ( members , ref hasNullable ) ;
5661
57- return interfaceGenerator . Build ( ) ;
62+ return interfaceCodeBuilderFactory ( ) . Build ( symbolDetails ) ;
5863 }
5964
60- private void AddMethodsToInterface ( SemanticModel semanticModel , List < ISymbol > members , InterfaceCodeBuilder codeGenerator )
65+ private ImmutableArray < MethodInfo > GetMethods ( SemanticModel semanticModel , List < ISymbol > members , ref bool hasNullable )
6166 {
62- members . Where ( x => x . Kind == SymbolKind . Method )
63- . OfType < IMethodSymbol > ( )
64- . Where ( x => x . MethodKind is MethodKind . Ordinary )
65- . Where ( x => ! types . TypeEquals ( x . ContainingType , semanticModel . Compilation . GetSpecialType ( SpecialType . System_Object ) ) )
66- . Where ( x => ! HasIgnoreAttribute ( x ) )
67- . GroupBy ( x => x . ToDisplayString ( FullyQualifiedDisplayFormatForGrouping ) )
68- . Select ( g => g . First ( ) )
69- . ToList ( )
70- . ForEach ( method => AddMethod ( codeGenerator , method ) ) ;
67+ var methods = new List < MethodInfo > ( ) ;
68+ foreach ( var method in members . Where ( x => x . Kind == SymbolKind . Method )
69+ . OfType < IMethodSymbol > ( )
70+ . Where ( x => x . MethodKind is MethodKind . Ordinary )
71+ . Where ( x => ! types . TypeEquals ( x . ContainingType , semanticModel . Compilation . GetSpecialType ( SpecialType . System_Object ) ) )
72+ . Where ( x => ! HasIgnoreAttribute ( x ) )
73+ . GroupBy ( x => x . ToDisplayString ( FullyQualifiedDisplayFormatForGrouping ) )
74+ . Select ( g => g . First ( ) ) )
75+ {
76+ methods . Add ( GetMethodInfo ( method , ref hasNullable ) ) ;
77+ }
78+
79+ return methods . ToImmutableArray ( ) ;
7180 }
7281
73- private void AddMethod ( InterfaceCodeBuilder codeGenerator , IMethodSymbol method )
82+ private MethodInfo GetMethodInfo ( IMethodSymbol method , ref bool hasNullable )
7483 {
75- ActivateNullableIfNeeded ( codeGenerator , method ) ;
84+ ActivateNullableIfNeeded ( ref hasNullable , method ) ;
7685
7786 var paramResult = new HashSet < string > ( ) ;
78- foreach ( var parameter in method . Parameters . Select ( p => GetParameterDisplayString ( p , codeGenerator . HasNullable ) ) )
87+ foreach ( var methodParameter in method . Parameters )
7988 {
89+ var parameter = GetParameterDisplayString ( methodParameter , hasNullable ) ;
8090 paramResult . Add ( parameter ) ;
8191 }
8292
8393 var typedArgs = method . TypeParameters
8494 . Select ( arg => ( arg . ToDisplayString ( FullyQualifiedDisplayFormat ) , roslynSymbols . GetWhereStatement ( arg , FullyQualifiedDisplayFormat ) ) )
8595 . ToList ( ) ;
8696
87- codeGenerator . AddMethodToInterface (
97+ return new MethodInfo (
8898 method . Name ,
8999 GetMethodReturnType ( method ) ,
90100 InheritDoc ( method ) ,
91- paramResult ,
92- typedArgs ) ;
101+ paramResult . ToImmutableArray ( ) ,
102+ typedArgs . ToImmutableArray ( ) ) ;
93103 }
94104
95105 private static string GetMethodReturnType ( IMethodSymbol method )
@@ -98,19 +108,19 @@ private static string GetMethodReturnType(IMethodSymbol method)
98108 return prefix + method . ReturnType . ToDisplayString ( FullyQualifiedDisplayFormat ) ;
99109 }
100110
101- private static void ActivateNullableIfNeeded ( InterfaceCodeBuilder codeGenerator , ITypeSymbol typeSymbol )
111+ private static void ActivateNullableIfNeeded ( ref bool hasNullable , ITypeSymbol typeSymbol )
102112 {
103113 if ( IsNullable ( typeSymbol ) )
104114 {
105- codeGenerator . HasNullable = true ;
115+ hasNullable = true ;
106116 }
107117 }
108118
109- private static void ActivateNullableIfNeeded ( InterfaceCodeBuilder codeGenerator , IMethodSymbol method )
119+ private static void ActivateNullableIfNeeded ( ref bool hasNullable , IMethodSymbol method )
110120 {
111121 if ( method . Parameters . Any ( x => IsNullable ( x . Type ) ) || IsNullable ( method . ReturnType ) )
112122 {
113- codeGenerator . HasNullable = true ;
123+ hasNullable = true ;
114124 }
115125 }
116126
@@ -172,40 +182,42 @@ private static string GetParameterDisplayString(IParameterSymbol param, bool nul
172182 return typeSb . Append ( restSb ) . ToString ( ) ;
173183 }
174184
175- private static void AddEventsToInterface ( List < ISymbol > members , InterfaceCodeBuilder codeGenerator )
185+ private static ImmutableArray < EventInfo > GetEvents ( List < ISymbol > members , ref bool hasNullable )
176186 {
177- members . Where ( x => x . Kind == SymbolKind . Event )
178- . OfType < IEventSymbol > ( )
179- . GroupBy ( x => x . ToDisplayString ( FullyQualifiedDisplayFormatForGrouping ) )
180- . Select ( g => g . First ( ) )
181- . ToList ( )
182- . ForEach ( evt =>
183- {
184- ActivateNullableIfNeeded ( codeGenerator , evt . Type ) ;
185- codeGenerator . AddEventToInterface ( evt . Name , evt . Type . ToDisplayString ( FullyQualifiedDisplayFormat ) , InheritDoc ( evt ) ) ;
186- } ) ;
187+ var events = new List < EventInfo > ( ) ;
188+ foreach ( var evt in members . Where ( x => x . Kind == SymbolKind . Event )
189+ . OfType < IEventSymbol > ( )
190+ . GroupBy ( x => x . ToDisplayString ( FullyQualifiedDisplayFormatForGrouping ) )
191+ . Select ( g => g . First ( ) ) )
192+ {
193+ ActivateNullableIfNeeded ( ref hasNullable , evt . Type ) ;
194+ events . Add ( new EventInfo ( evt . Name , evt . Type . ToDisplayString ( FullyQualifiedDisplayFormat ) , InheritDoc ( evt ) ) ) ;
195+ }
196+
197+ return events . ToImmutableArray ( ) ;
187198 }
188199
189- private static void AddPropertiesToInterface ( List < ISymbol > members , InterfaceCodeBuilder interfaceGenerator )
200+ private static ImmutableArray < PropertyInfo > GetProperties ( List < ISymbol > members , ref bool hasNullable )
190201 {
191- members . Where ( x => x . Kind == SymbolKind . Property )
192- . OfType < IPropertySymbol > ( )
193- . Where ( x => ! x . IsIndexer )
194- . GroupBy ( x => x . Name )
195- . Select ( g => g . First ( ) )
196- . ToList ( )
197- . ForEach ( prop =>
198- {
199- ActivateNullableIfNeeded ( interfaceGenerator , prop . Type ) ;
200-
201- interfaceGenerator . AddPropertyToInterface (
202- prop . Name ,
203- prop . Type . ToDisplayString ( FullyQualifiedDisplayFormat ) ,
204- prop . GetMethod ? . DeclaredAccessibility == Accessibility . Public ,
205- GetSetKind ( prop . SetMethod ) ,
206- prop . ReturnsByRef ,
207- InheritDoc ( prop ) ) ;
208- } ) ;
202+ var properties = new List < PropertyInfo > ( ) ;
203+ foreach ( var prop in members . Where ( x => x . Kind == SymbolKind . Property )
204+ . OfType < IPropertySymbol > ( )
205+ . Where ( x => ! x . IsIndexer )
206+ . GroupBy ( x => x . Name )
207+ . Select ( g => g . First ( ) ) )
208+ {
209+ ActivateNullableIfNeeded ( ref hasNullable , prop . Type ) ;
210+
211+ properties . Add ( new PropertyInfo (
212+ prop . Name ,
213+ prop . Type . ToDisplayString ( FullyQualifiedDisplayFormat ) ,
214+ prop . GetMethod ? . DeclaredAccessibility == Accessibility . Public ,
215+ GetSetKind ( prop . SetMethod ) ,
216+ prop . ReturnsByRef ,
217+ InheritDoc ( prop ) ) ) ;
218+ }
219+
220+ return properties . ToImmutableArray ( ) ;
209221 }
210222
211223 private static PropertySetKind GetSetKind ( IMethodSymbol ? setMethodSymbol ) =>
@@ -251,4 +263,4 @@ private string GetGeneric(TypeDeclarationSyntax classSyntax, INamedTypeSymbol ty
251263
252264 private static string InheritDoc ( ISymbol source ) =>
253265 $ "/// <inheritdoc cref=\" { source . ToDisplayString ( ) . Replace ( "<" , "{" ) . Replace ( ">" , "}" ) . Replace ( "params " , string . Empty ) } \" />";
254- }
266+ }
0 commit comments