@@ -394,6 +394,98 @@ static TProperty FallbackAccessor(TSyntax syntax, TArg argument)
394394 return expression . Compile ( ) ;
395395 }
396396
397+ internal static Func < TSyntax , TArg1 , TArg2 , TProperty > CreateSyntaxPropertyAccessor < TSyntax , TArg1 , TArg2 , TProperty > ( Type type , Type argumentType1 , Type argumentType2 , string accessorMethodName )
398+ {
399+ static TProperty FallbackAccessor ( TSyntax syntax , TArg1 argument1 , TArg2 argument2 )
400+ {
401+ if ( syntax == null )
402+ {
403+ // Unlike an extension method which would throw ArgumentNullException here, the light-up
404+ // behavior needs to match behavior of the underlying property.
405+ throw new NullReferenceException ( ) ;
406+ }
407+
408+ return default ;
409+ }
410+
411+ if ( type == null )
412+ {
413+ return FallbackAccessor ;
414+ }
415+
416+ if ( ! typeof ( TSyntax ) . GetTypeInfo ( ) . IsAssignableFrom ( type . GetTypeInfo ( ) ) )
417+ {
418+ throw new InvalidOperationException ( ) ;
419+ }
420+
421+ if ( ! typeof ( TArg1 ) . GetTypeInfo ( ) . IsAssignableFrom ( argumentType1 . GetTypeInfo ( ) ) )
422+ {
423+ throw new InvalidOperationException ( ) ;
424+ }
425+
426+ if ( ! typeof ( TArg2 ) . GetTypeInfo ( ) . IsAssignableFrom ( argumentType2 . GetTypeInfo ( ) ) )
427+ {
428+ throw new InvalidOperationException ( ) ;
429+ }
430+
431+ var methods = type . GetTypeInfo ( ) . GetDeclaredMethods ( accessorMethodName ) ;
432+ MethodInfo method = null ;
433+ foreach ( var candidate in methods )
434+ {
435+ var parameters = candidate . GetParameters ( ) ;
436+ if ( parameters . Length != 2 )
437+ {
438+ continue ;
439+ }
440+
441+ if ( ! Equals ( argumentType1 , parameters [ 0 ] . ParameterType ) )
442+ {
443+ continue ;
444+ }
445+
446+ if ( ! Equals ( argumentType2 , parameters [ 1 ] . ParameterType ) )
447+ {
448+ continue ;
449+ }
450+
451+ method = candidate ;
452+ }
453+
454+ if ( method == null )
455+ {
456+ return FallbackAccessor ;
457+ }
458+
459+ if ( ! typeof ( TProperty ) . GetTypeInfo ( ) . IsAssignableFrom ( method . ReturnType . GetTypeInfo ( ) ) )
460+ {
461+ throw new InvalidOperationException ( ) ;
462+ }
463+
464+ var syntaxParameter = Expression . Parameter ( typeof ( TSyntax ) , "syntax" ) ;
465+ var arg1Parameter = Expression . Parameter ( typeof ( TArg1 ) , "arg1" ) ;
466+ var arg2Parameter = Expression . Parameter ( typeof ( TArg2 ) , "arg2" ) ;
467+ Expression instance =
468+ type . GetTypeInfo ( ) . IsAssignableFrom ( typeof ( TSyntax ) . GetTypeInfo ( ) )
469+ ? ( Expression ) syntaxParameter
470+ : Expression . Convert ( syntaxParameter , type ) ;
471+ Expression argument1 =
472+ argumentType1 . GetTypeInfo ( ) . IsAssignableFrom ( typeof ( TArg1 ) . GetTypeInfo ( ) )
473+ ? ( Expression ) arg1Parameter
474+ : Expression . Convert ( arg1Parameter , argumentType1 ) ;
475+ Expression argument2 =
476+ argumentType2 . GetTypeInfo ( ) . IsAssignableFrom ( typeof ( TArg2 ) . GetTypeInfo ( ) )
477+ ? ( Expression ) arg2Parameter
478+ : Expression . Convert ( arg2Parameter , argumentType2 ) ;
479+
480+ Expression < Func < TSyntax , TArg1 , TArg2 , TProperty > > expression =
481+ Expression . Lambda < Func < TSyntax , TArg1 , TArg2 , TProperty > > (
482+ Expression . Call ( instance , method , argument1 , argument2 ) ,
483+ syntaxParameter ,
484+ arg1Parameter ,
485+ arg2Parameter ) ;
486+ return expression . Compile ( ) ;
487+ }
488+
397489 internal static TryGetValueAccessor < TSyntax , TKey , TValue > CreateTryGetValueAccessor < TSyntax , TKey , TValue > ( Type type , Type keyType , string methodName )
398490 {
399491 static bool FallbackAccessor ( TSyntax syntax , TKey key , out TValue value )
0 commit comments