77using System . Linq ;
88using System . Linq . Expressions ;
99using System . Reflection ;
10+ using System . Reflection . Emit ;
1011using System . Runtime . CompilerServices ;
1112
1213namespace ExpressionDebugger
@@ -35,7 +36,7 @@ public DebugInfoInjector(string filename)
3536
3637 public DebugInfoInjector ( TextWriter writer )
3738 {
38- _document = Expression . SymbolDocument ( "unnamed.cs" ) ;
39+ _document = null ;
3940 _writer = writer ;
4041 }
4142
@@ -631,9 +632,11 @@ Expression VisitConditionalBlock(ConditionalExpression node, bool shouldReturn,
631632 Outdent ( ) ;
632633 }
633634 }
634- return Expression . Block (
635- debug ,
636- Expression . Condition ( test , ifTrue , ifFalse ) ) ;
635+
636+ Expression condition = Expression . Condition ( test , ifTrue , ifFalse , typeof ( void ) ) ;
637+ if ( debug != null )
638+ condition = Expression . Block ( debug , condition ) ;
639+ return condition ;
637640 }
638641
639642 protected override Expression VisitConditional ( ConditionalExpression node )
@@ -645,7 +648,6 @@ protected override Expression VisitConstant(ConstantExpression node)
645648 {
646649 var value = node . Value ;
647650
648- Type t ;
649651 if ( value == null )
650652 Write ( "null" ) ;
651653 else if ( value is string )
@@ -654,17 +656,59 @@ protected override Expression VisitConstant(ConstantExpression node)
654656 Write ( $ "\' { value } \' ") ;
655657 else if ( value is bool )
656658 Write ( value . ToString ( ) . ToLower ( ) ) ;
657- else if ( ( t = value as Type ) != null )
659+ else if ( value is Type t )
658660 Write ( $ "typeof({ Translate ( t ) } )") ;
659661 else
660662 {
661- var type = value . GetType ( ) ;
663+ Type type = value . GetType ( ) ;
662664 if ( type . GetTypeInfo ( ) . IsPrimitive || type == typeof ( decimal ) )
663665 Write ( value . ToString ( ) ) ;
664666 else
665667 Write ( "valueof(" , Translate ( type ) , ", \" " , value . ToString ( ) , "\" )" ) ;
666668 }
667- return node ;
669+
670+ if ( _document == null || CanEmitConstant ( value , node . Type ) )
671+ return node ;
672+
673+ var i = GlobalReference . GetIndex ( value ) ;
674+ return Expression . Convert (
675+ Expression . Call (
676+ typeof ( GlobalReference ) . GetMethod ( nameof ( GlobalReference . GetObject ) ) ,
677+ Expression . Constant ( i ) ) ,
678+ node . Type ) ;
679+ }
680+
681+ private static bool CanEmitConstant ( object value , Type type )
682+ {
683+ if ( value == null
684+ || type . GetTypeInfo ( ) . IsPrimitive
685+ || type == typeof ( string )
686+ || type == typeof ( decimal ) )
687+ return true ;
688+
689+ if ( value is Type t )
690+ return ShouldLdtoken ( t ) ;
691+
692+ if ( value is MethodBase mb )
693+ return ShouldLdtoken ( mb ) ;
694+
695+ return false ;
696+ }
697+
698+ private static bool ShouldLdtoken ( Type t )
699+ {
700+ return t is TypeBuilder
701+ || t . IsGenericParameter
702+ || t . IsVisible ;
703+ }
704+
705+ private static bool ShouldLdtoken ( MethodBase mb )
706+ {
707+ if ( mb is DynamicMethod )
708+ return false ;
709+
710+ Type dt = mb . DeclaringType ;
711+ return dt == null || ShouldLdtoken ( dt ) ;
668712 }
669713
670714 protected override Expression VisitDefault ( DefaultExpression node )
@@ -683,30 +727,26 @@ static Expression Update(DynamicExpression node, IEnumerable<Expression> args)
683727
684728 protected override Expression VisitDynamic ( DynamicExpression node )
685729 {
686- var convert = node . Binder as ConvertBinder ;
687- if ( convert != null )
730+ if ( node . Binder is ConvertBinder convert )
688731 {
689732 Write ( "(" , Translate ( convert . Type ) , ")" ) ;
690733 var expr = VisitGroup ( node . Arguments [ 0 ] , ExpressionType . Convert ) ;
691- return Update ( node , new [ ] { expr } . Concat ( node . Arguments . Skip ( 1 ) ) ) ;
734+ return Update ( node , new [ ] { expr } . Concat ( node . Arguments . Skip ( 1 ) ) ) ;
692735 }
693- var getMember = node . Binder as GetMemberBinder ;
694- if ( getMember != null )
736+ if ( node . Binder is GetMemberBinder getMember )
695737 {
696738 var expr = VisitGroup ( node . Arguments [ 0 ] , ExpressionType . MemberAccess ) ;
697739 Write ( "." , getMember . Name ) ;
698740 return Update ( node , new [ ] { expr } . Concat ( node . Arguments . Skip ( 1 ) ) ) ;
699741 }
700- var setMember = node . Binder as SetMemberBinder ;
701- if ( setMember != null )
742+ if ( node . Binder is SetMemberBinder setMember )
702743 {
703744 var expr = VisitGroup ( node . Arguments [ 0 ] , ExpressionType . MemberAccess ) ;
704745 Write ( "." , setMember . Name , " = " ) ;
705746 var value = VisitGroup ( node . Arguments [ 1 ] , ExpressionType . Assign ) ;
706747 return Update ( node , new [ ] { expr , value } . Concat ( node . Arguments . Skip ( 2 ) ) ) ;
707748 }
708- var deleteMember = node . Binder as DeleteMemberBinder ;
709- if ( deleteMember != null )
749+ if ( node . Binder is DeleteMemberBinder deleteMember )
710750 {
711751 var expr = VisitGroup ( node . Arguments [ 0 ] , ExpressionType . MemberAccess ) ;
712752 Write ( "." , deleteMember . Name , " = null" ) ;
@@ -733,8 +773,7 @@ protected override Expression VisitDynamic(DynamicExpression node)
733773 Write ( " = null" ) ;
734774 return Update ( node , new [ ] { expr } . Concat ( args ) ) ;
735775 }
736- var invokeMember = node . Binder as InvokeMemberBinder ;
737- if ( invokeMember != null )
776+ if ( node . Binder is InvokeMemberBinder invokeMember )
738777 {
739778 var expr = VisitGroup ( node . Arguments [ 0 ] , ExpressionType . MemberAccess ) ;
740779 Write ( "." , invokeMember . Name ) ;
@@ -754,14 +793,12 @@ protected override Expression VisitDynamic(DynamicExpression node)
754793 var args = VisitArguments ( "(" , node . Arguments . Skip ( 1 ) . ToList ( ) , Visit , ")" ) ;
755794 return Update ( node , new [ ] { expr } . Concat ( args ) ) ;
756795 }
757- var unary = node . Binder as UnaryOperationBinder ;
758- if ( unary != null )
796+ if ( node . Binder is UnaryOperationBinder unary )
759797 {
760798 var expr = VisitUnary ( node . Arguments [ 0 ] , unary . Operation ) ;
761799 return Update ( node , new [ ] { expr } . Concat ( node . Arguments . Skip ( 1 ) ) ) ;
762800 }
763- var binary = node . Binder as BinaryOperationBinder ;
764- if ( binary != null )
801+ if ( node . Binder is BinaryOperationBinder binary )
765802 {
766803 var left = VisitGroup ( node . Arguments [ 0 ] , node . NodeType ) ;
767804 Write ( " " , Translate ( binary . Operation ) , " " ) ;
@@ -1013,9 +1050,8 @@ protected override Expression VisitLoop(LoopExpression node)
10131050 if ( node . Body . NodeType == ExpressionType . Conditional )
10141051 {
10151052 var condExpr = ( ConditionalExpression ) node . Body ;
1016- var @break = condExpr . IfFalse as GotoExpression ;
10171053
1018- if ( @break != null && @break . Target == node . BreakLabel )
1054+ if ( condExpr . IfFalse is GotoExpression @break && @break . Target == node . BreakLabel )
10191055 {
10201056 WriteNextLine ( "while (" ) ;
10211057 var position = GetPosition ( ) ;
@@ -1025,11 +1061,13 @@ protected override Expression VisitLoop(LoopExpression node)
10251061 Indent ( ) ;
10261062 body = VisitBody ( condExpr . IfTrue ) ;
10271063 Outdent ( ) ;
1064+
1065+ Expression condition = Expression . Condition ( test , body , @break , typeof ( void ) ) ;
1066+ if ( debug != null )
1067+ condition = Expression . Block ( debug , condition ) ;
10281068 return Expression . Loop (
1029- Expression . Block (
1030- debug ,
1031- Expression . Condition ( test , body , @break ) ) ,
1032- node . BreakLabel ,
1069+ condition ,
1070+ node . BreakLabel ,
10331071 node . ContinueLabel ) ;
10341072 }
10351073 }
0 commit comments