• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Sholtee / proxygen / 937

29 Mar 2025 07:30AM UTC coverage: 89.287% (-2.1%) from 91.359%
937

push

appveyor

Sholtee
introduce IInterceptor interface, implement method interception functionality in ClassProxySyntaxFactory

4509 of 5050 relevant lines covered (89.29%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.36
/SRC/Private/SyntaxFactories/InterfaceProxySyntaxFactory.PropertyInterceptorFactory.cs
1
/********************************************************************************
2
* InterfaceProxySyntaxFactory.PropertyInterceptorFactory.cs                     *
3
*                                                                               *
4
* Author: Denes Solti                                                           *
5
********************************************************************************/
6
using System;
7
using System.Collections.Generic;
8
using System.Linq;
9

10
using Microsoft.CodeAnalysis.CSharp;
11
using Microsoft.CodeAnalysis.CSharp.Syntax;
12

13
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
14

15
namespace Solti.Utils.Proxy.Internals
16
{
17
    internal partial class InterfaceProxySyntaxFactory
18
    {
19
        #if DEBUG
20
        internal
21
        #endif
22
        protected override ClassDeclarationSyntax ResolveProperties(ClassDeclarationSyntax cls, object context)
23
        {
1✔
24
            foreach (IPropertyInfo prop in InterfaceType.Properties)
1✔
25
            {
1✔
26
                if (AlreadyImplemented(prop, InterceptorType.Properties, SignatureEquals))
1✔
27
                    continue;
×
28

29
                cls = ResolveProperty(cls, context, prop);
1✔
30
            }
1✔
31

32
            return cls;
1✔
33

34
            static bool SignatureEquals(IPropertyInfo targetProp, IPropertyInfo ifaceProp)
35
            {
1✔
36
                //
37
                // We allow the implementation to declare a getter or setter that is not required by the interface.
38
                //
39

40
                if (ifaceProp.GetMethod is not null)
1✔
41
                {
1✔
42
                    if (targetProp.GetMethod?.SignatureEquals(ifaceProp.GetMethod) is not true)
1✔
43
                        return false;
1✔
44
                }
×
45

46
                if (ifaceProp.SetMethod is not null)
×
47
                {
×
48
                    if (targetProp.SetMethod?.SignatureEquals(ifaceProp.SetMethod) is not true)
×
49
                        return false;
×
50
                }
×
51

52
                return true;
×
53
            }
1✔
54
        }
1✔
55

56
        /// <summary>
57
        /// <code>
58
        /// private static readonly InterfaceInterceptionContext FxXx = new InterfaceInterceptionContext(static (ITarget target, object[] args) =>  
59
        /// {                                                                                                 
60
        ///     return target.Prop;                                                                           
61
        /// }, CALL_INDEX, InterfaceMap&lt;TInterface, TTarget&gt;.Value | null);                                                                                          
62
        /// private static readonly InterfaceInterceptionContext FyYy = new InterfaceInterceptionContext(static (ITarget target, object[] args) =>  
63
        /// {                                                                                                
64
        ///     TValue _value = (TValue) args[0];                                                             
65
        ///     target.Prop = _value;                                                                         
66
        ///     return null;                                                                                   
67
        /// }, CALL_INDEX, InterfaceMap&lt;TInterface, TTarget&gt;.Value | null);                                                                                            
68
        /// TResult IInterface.Prop                                                                          
69
        /// {                                                                                                 
70
        ///     get                                                                                            
71
        ///     {                                                                                            
72
        ///         object[] args = new object[] { };                                                          
73
        ///         return (TResult) Invoke(new InvocationContext(args, FxXx));                               
74
        ///     }                                                                                            
75
        ///     set                                                                                         
76
        ///     {                                                                                            
77
        ///         object[] args = new object[] { value };                                                  
78
        ///         Invoke(new InvocationContext(args, FyYy));                                               
79
        ///     }                                                                                              
80
        /// }
81
        /// </code>
82
        /// </summary>
83
        #if DEBUG
84
        internal
85
        #endif
86
        protected override ClassDeclarationSyntax ResolveProperty(ClassDeclarationSyntax cls, object context, IPropertyInfo property)
87
        {
1✔
88
            //
89
            // For now, we only have call-index of 0
90
            //
91

92
            const int CALL_INDEX = 0;
93

94
            List<MemberDeclarationSyntax> members = new();
1✔
95

96
            BlockSyntax?
1✔
97
                get = null,
1✔
98
                set = null;
1✔
99

100
            if (property.GetMethod is not null)
1✔
101
            {
1✔
102
                FieldDeclarationSyntax getCtx = ResolveMethodContext
1✔
103
                (
1✔
104
                    property.GetMethod.GetMD5HashCode(),
1✔
105
                    ResolveInvokeTarget
1✔
106
                    (
1✔
107
                        property.GetMethod,
1✔
108
                        hasTarget: true,
1✔
109
                        (paramz, locals) => PropertyAccess
×
110
                        (
×
111
                            property,
×
112
                            IdentifierName(paramz[0].Identifier),
×
113
                            castTargetTo: property.DeclaringType,
×
114
                            indices: locals.Select(ResolveArgument)
×
115
                        )
×
116
                    ),
1✔
117
                    CALL_INDEX
1✔
118
                );
1✔
119
                members.Add(getCtx);
1✔
120

121
                LocalDeclarationStatementSyntax argsArray = ResolveArgumentsArray(property.GetMethod);
1✔
122

123
                get = Block
1✔
124
                (
1✔
125
                    argsArray,
1✔
126
                    ReturnResult
1✔
127
                    (
1✔
128
                        property.Type,
1✔
129
                        InvokeMethod
1✔
130
                        (
1✔
131
                            Invoke,
1✔
132
                            arguments: Argument
1✔
133
                            (
1✔
134
                                ResolveObject<InterfaceInvocationContext>
1✔
135
                                (
1✔
136
                                    ResolveArgument(argsArray),
1✔
137
                                    Argument
1✔
138
                                    (
1✔
139
                                        StaticMemberAccess(cls, getCtx)
1✔
140
                                    )
1✔
141
                                )
1✔
142
                            )
1✔
143
                        )
1✔
144
                    )
1✔
145
                );
1✔
146
            }
1✔
147

148
            if (property.SetMethod is not null)
1✔
149
            {
1✔
150
                FieldDeclarationSyntax setCtx = ResolveMethodContext
1✔
151
                (
1✔
152
                    property.SetMethod.GetMD5HashCode(),
1✔
153
                    ResolveInvokeTarget
1✔
154
                    (
1✔
155
                        property.SetMethod,
1✔
156
                        hasTarget: true,
1✔
157
                        (paramz, locals) => AssignmentExpression
×
158
                        (
×
159
                            kind: SyntaxKind.SimpleAssignmentExpression,
×
160
                            left: PropertyAccess
×
161
                            (
×
162
                                property,
×
163
                                IdentifierName(paramz[0].Identifier),
×
164
                                castTargetTo: property.DeclaringType,
×
165
                                indices: locals
×
166
                                    .Take(locals.Count - 1)
×
167
                                    .Select(ResolveArgument)
×
168
                            ),
×
169
                            right: ResolveIdentifierName(locals[locals.Count - 1])
×
170
                        )
×
171
                    ),
1✔
172
                    CALL_INDEX
1✔
173
                );
1✔
174
                members.Add(setCtx);
1✔
175

176
                LocalDeclarationStatementSyntax argsArray = ResolveArgumentsArray(property.SetMethod);
1✔
177

178
                set = Block
1✔
179
                (
1✔
180
                    argsArray,
1✔
181
                    ExpressionStatement
1✔
182
                    (
1✔
183
                        InvokeMethod
1✔
184
                        (
1✔
185
                            Invoke,
1✔
186
                            arguments: Argument
1✔
187
                            (
1✔
188
                                ResolveObject<InterfaceInvocationContext>
1✔
189
                                (
1✔
190
                                    ResolveArgument(argsArray),
1✔
191
                                    Argument
1✔
192
                                    (
1✔
193
                                        StaticMemberAccess(cls, setCtx)
1✔
194
                                    )
1✔
195
                                )
1✔
196
                            )
1✔
197
                        )
1✔
198
                    )
1✔
199
                );
1✔
200
            }
1✔
201

202
            members.Add
1✔
203
            (
1✔
204
                property.Indices.Any() 
1✔
205
                    ? ResolveIndexer(property, get, set, false)
1✔
206
                    : ResolveProperty(property, get, set, false)
1✔
207
            );
1✔
208

209
            return cls.WithMembers
1✔
210
            (
1✔
211
                cls.Members.AddRange(members)
1✔
212
            );
1✔
213
        }
1✔
214
    }
215
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc