@@ -96,6 +96,62 @@ internal static Func<TSyntax, TProperty> CreateSyntaxPropertyAccessor<TSyntax, T
9696 return expression . Compile ( ) ;
9797 }
9898
99+ internal static Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > > CreateSeparatedSyntaxListPropertyAccessor < TSyntax , TProperty > ( Type type , string propertyName )
100+ {
101+ Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > > fallbackAccessor =
102+ syntax =>
103+ {
104+ if ( syntax == null )
105+ {
106+ // Unlike an extension method which would throw ArgumentNullException here, the light-up
107+ // behavior needs to match behavior of the underlying property.
108+ throw new NullReferenceException ( ) ;
109+ }
110+
111+ return SeparatedSyntaxListWrapper < TProperty > . UnsupportedEmpty ;
112+ } ;
113+
114+ if ( type == null )
115+ {
116+ return fallbackAccessor ;
117+ }
118+
119+ if ( ! typeof ( TSyntax ) . GetTypeInfo ( ) . IsAssignableFrom ( type . GetTypeInfo ( ) ) )
120+ {
121+ throw new InvalidOperationException ( ) ;
122+ }
123+
124+ var property = type . GetTypeInfo ( ) . GetDeclaredProperty ( propertyName ) ;
125+ if ( property == null )
126+ {
127+ return fallbackAccessor ;
128+ }
129+
130+ if ( property . PropertyType . GetGenericTypeDefinition ( ) != typeof ( SeparatedSyntaxList < > ) )
131+ {
132+ throw new InvalidOperationException ( ) ;
133+ }
134+
135+ var propertySyntaxType = property . PropertyType . GenericTypeArguments [ 0 ] ;
136+
137+ var syntaxParameter = Expression . Parameter ( typeof ( TSyntax ) , "syntax" ) ;
138+ Expression instance =
139+ type . GetTypeInfo ( ) . IsAssignableFrom ( typeof ( TSyntax ) . GetTypeInfo ( ) )
140+ ? ( Expression ) syntaxParameter
141+ : Expression . Convert ( syntaxParameter , type ) ;
142+ Expression propertyAccess = Expression . Call ( instance , property . GetMethod ) ;
143+
144+ var unboundWrapperType = typeof ( SeparatedSyntaxListWrapper < > . AutoWrapSeparatedSyntaxList < > ) ;
145+ var boundWrapperType = unboundWrapperType . MakeGenericType ( typeof ( TProperty ) , propertySyntaxType ) ;
146+ var constructorInfo = boundWrapperType . GetTypeInfo ( ) . DeclaredConstructors . Single ( ) ;
147+
148+ Expression < Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > > > expression =
149+ Expression . Lambda < Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > > > (
150+ Expression . New ( constructorInfo , propertyAccess ) ,
151+ syntaxParameter ) ;
152+ return expression . Compile ( ) ;
153+ }
154+
99155 internal static Func < TSyntax , TProperty , TSyntax > CreateSyntaxWithPropertyAccessor < TSyntax , TProperty > ( Type type , string propertyName )
100156 {
101157 Func < TSyntax , TProperty , TSyntax > fallbackAccessor =
@@ -158,5 +214,71 @@ internal static Func<TSyntax, TProperty, TSyntax> CreateSyntaxWithPropertyAccess
158214 valueParameter ) ;
159215 return expression . Compile ( ) ;
160216 }
217+
218+ internal static Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > , TSyntax > CreateSeparatedSyntaxListWithPropertyAccessor < TSyntax , TProperty > ( Type type , string propertyName )
219+ {
220+ Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > , TSyntax > fallbackAccessor =
221+ ( syntax , newValue ) =>
222+ {
223+ if ( syntax == null )
224+ {
225+ // Unlike an extension method which would throw ArgumentNullException here, the light-up
226+ // behavior needs to match behavior of the underlying property.
227+ throw new NullReferenceException ( ) ;
228+ }
229+
230+ if ( ReferenceEquals ( newValue , null ) )
231+ {
232+ return syntax ;
233+ }
234+
235+ throw new NotSupportedException ( ) ;
236+ } ;
237+
238+ if ( type == null )
239+ {
240+ return fallbackAccessor ;
241+ }
242+
243+ if ( ! typeof ( TSyntax ) . GetTypeInfo ( ) . IsAssignableFrom ( type . GetTypeInfo ( ) ) )
244+ {
245+ throw new InvalidOperationException ( ) ;
246+ }
247+
248+ var property = type . GetTypeInfo ( ) . GetDeclaredProperty ( propertyName ) ;
249+ if ( property == null )
250+ {
251+ return fallbackAccessor ;
252+ }
253+
254+ if ( property . PropertyType . GetGenericTypeDefinition ( ) != typeof ( SeparatedSyntaxList < > ) )
255+ {
256+ throw new InvalidOperationException ( ) ;
257+ }
258+
259+ var propertySyntaxType = property . PropertyType . GenericTypeArguments [ 0 ] ;
260+
261+ var methodInfo = type . GetTypeInfo ( ) . GetDeclaredMethods ( "With" + propertyName )
262+ . Single ( m => ! m . IsStatic && m . GetParameters ( ) . Length == 1 && m . GetParameters ( ) [ 0 ] . ParameterType . Equals ( property . PropertyType ) ) ;
263+
264+ var syntaxParameter = Expression . Parameter ( typeof ( TSyntax ) , "syntax" ) ;
265+ var valueParameter = Expression . Parameter ( typeof ( SeparatedSyntaxListWrapper < TProperty > ) , methodInfo . GetParameters ( ) [ 0 ] . Name ) ;
266+ Expression instance =
267+ type . GetTypeInfo ( ) . IsAssignableFrom ( typeof ( TSyntax ) . GetTypeInfo ( ) )
268+ ? ( Expression ) syntaxParameter
269+ : Expression . Convert ( syntaxParameter , type ) ;
270+
271+ var underlyingListProperty = typeof ( SeparatedSyntaxListWrapper < TProperty > ) . GetTypeInfo ( ) . GetDeclaredProperty ( nameof ( SeparatedSyntaxListWrapper < TProperty > . UnderlyingList ) ) ;
272+ Expression value = Expression . Convert (
273+ Expression . Call ( valueParameter , underlyingListProperty . GetMethod ) ,
274+ property . PropertyType ) ;
275+
276+ Expression < Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > , TSyntax > > expression =
277+ Expression . Lambda < Func < TSyntax , SeparatedSyntaxListWrapper < TProperty > , TSyntax > > (
278+ Expression . Call ( instance , methodInfo , value ) ,
279+ syntaxParameter ,
280+ valueParameter ) ;
281+ return expression . Compile ( ) ;
282+ }
161283 }
162284}
0 commit comments