~ubuntu-branches/ubuntu/trusty/smuxi/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/db4o-net/Db4objects.Db4o.NativeQueries/native/Db4objects.Db4o.NativeQueries/QueryExpressionBuilder.cs

  • Committer: Package Import Robot
  • Author(s): Mirco Bauer
  • Date: 2013-05-25 22:11:31 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20130525221131-nd2mc0kzubuwyx20
Tags: 0.8.11-1
* [22d13d5] Imported Upstream version 0.8.11
* [6d2b95a] Refreshed patches
* [89eb66e] Added ServiceStack libraries to smuxi-engine package
* [848ab10] Enable Campfire engine
* [c6dbdc7] Always build db4o for predictable build result
* [13ec489] Exclude OS X specific libraries from dh_clideps

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2004-2006   Versant Inc.   http://www.db4o.com */
2
 
 
3
 
using System.Collections.Generic;
4
 
using Db4objects.Db4o.Activation;
5
 
using Db4objects.Db4o.Instrumentation.Cecil;
6
 
using Db4objects.Db4o.TA;
7
 
using Mono.Collections.Generic;
8
 
 
9
 
namespace Db4objects.Db4o.NativeQueries
10
 
{
11
 
        using System;
12
 
        using System.Collections;
13
 
        using System.Reflection;
14
 
 
15
 
        using Mono.Cecil;
16
 
 
17
 
        using Cecil.FlowAnalysis;
18
 
        using Cecil.FlowAnalysis.ActionFlow;
19
 
        using Cecil.FlowAnalysis.CodeStructure;
20
 
        using Ast = Cecil.FlowAnalysis.CodeStructure;
21
 
 
22
 
        using Expr;
23
 
        using Expr.Cmp;
24
 
        using Expr.Cmp.Operand;
25
 
        using NQExpression = Expr.IExpression;
26
 
        using Internal.Query;
27
 
 
28
 
        /// <summary>
29
 
        /// Build a Db4objects.Db4o.Nativequery.Expr tree out of a predicate method definition.
30
 
        /// </summary>
31
 
        public class QueryExpressionBuilder
32
 
        {
33
 
                protected static ICachingStrategy<string, AssemblyDefinition> _assemblyCachingStrategy = 
34
 
                                new SingleItemCachingStrategy<string, AssemblyDefinition>( delegate(string location)
35
 
                                                                                                                                                        {
36
 
                                                                                                                                                                return AssemblyDefinition.ReadAssembly(location);
37
 
                                                                                                                                                        });
38
 
 
39
 
                protected static ICachingStrategy<MethodBase, IExpression> _expressionCachingStrategy = 
40
 
                                new SingleItemCachingStrategy<MethodBase, IExpression>(
41
 
                                                                                                                                                delegate(MethodBase method)
42
 
                                                                                                                                                        {
43
 
                                                                                                                                                                MethodDefinition methodDef = GetMethodDefinition(method);
44
 
                                                                                                                                                                return AdjustBoxedValueTypes(FromMethodDefinition(methodDef));
45
 
                                                                                                                                                        }
46
 
                                                                                                                                                );
47
 
 
48
 
                public NQExpression FromMethod(MethodBase method)
49
 
                {
50
 
                        if (method == null) throw new ArgumentNullException("method");
51
 
                        
52
 
                        return GetCachedExpression(method);
53
 
                }
54
 
 
55
 
                private static NQExpression GetCachedExpression(MethodBase method)
56
 
                {
57
 
                        return _expressionCachingStrategy.Get(method);
58
 
                }
59
 
 
60
 
                private static MethodDefinition GetMethodDefinition(MethodBase method)
61
 
                {
62
 
                        string location = GetAssemblyLocation(method);
63
 
#if CF
64
 
                        MethodDefinition methodDef = MethodDefinitionFor(method);
65
 
#else
66
 
                        AssemblyDefinition assembly = _assemblyCachingStrategy.Get(location);
67
 
 
68
 
                        MethodDefinition methodDef = (MethodDefinition)assembly.MainModule.LookupToken(method.MetadataToken);
69
 
#endif
70
 
                        if (null == methodDef) UnsupportedPredicate(string.Format("Unable to load the definition of '{0}' from assembly '{1}'", method, location));
71
 
                        
72
 
                        return methodDef;
73
 
                }
74
 
 
75
 
                private static MethodDefinition MethodDefinitionFor(MethodBase method)
76
 
                {
77
 
                        string location = GetAssemblyLocation(method);
78
 
                        AssemblyDefinition assembly = _assemblyCachingStrategy.Get(location);
79
 
 
80
 
#if CF
81
 
                        TypeDefinition declaringType = FindTypeDefinition(assembly.MainModule, method.DeclaringType);
82
 
                        if (declaringType == null)
83
 
                        {
84
 
                                return null;
85
 
                        }
86
 
 
87
 
                        foreach (MethodDefinition candidate in declaringType.Methods)
88
 
                        {
89
 
                                if (candidate.Name != method.Name) continue;
90
 
                                if (candidate.Parameters.Count != method.GetParameters().Length) continue;
91
 
                                if (!ParametersMatch(candidate.Parameters, GetParameterTypes(method, assembly.MainModule))) continue;
92
 
                                {
93
 
                                        return candidate;
94
 
                                }
95
 
                        }
96
 
 
97
 
                        return null;
98
 
 
99
 
#else
100
 
                        return (MethodDefinition) assembly.MainModule.LookupToken(method.MetadataToken);
101
 
#endif
102
 
                }
103
 
 
104
 
                private static NQExpression AdjustBoxedValueTypes(NQExpression expression)
105
 
                {
106
 
                        expression.Accept(new BoxedValueTypeProcessor());
107
 
                        return expression;
108
 
                }
109
 
 
110
 
                private static IList<TypeReference> GetParameterTypes(MethodBase method, ModuleDefinition module)
111
 
                {
112
 
                        IList<TypeReference> types = new List<TypeReference>();
113
 
                        foreach (ParameterInfo parameter in ParametersFor(method))
114
 
                        {
115
 
                                types.Add(FindTypeDefinition(module, parameter.ParameterType));
116
 
                        }
117
 
 
118
 
                        return types;
119
 
                }
120
 
 
121
 
                private static ParameterInfo[] ParametersFor(MethodBase method)
122
 
                {
123
 
                        if (method.IsGenericMethod)
124
 
                        {
125
 
                                MethodInfo methodInfo = (MethodInfo) method;
126
 
                                return methodInfo.GetGenericMethodDefinition().GetParameters();
127
 
                        }
128
 
 
129
 
                        return method.DeclaringType.IsGenericType 
130
 
                                                                ? method.DeclaringType.GetGenericTypeDefinition().GetMethod(method.Name).GetParameters() 
131
 
                                                                : method.GetParameters();
132
 
                }
133
 
 
134
 
                private static TypeDefinition FindTypeDefinition(ModuleDefinition module, Type type)
135
 
                {
136
 
                        return IsNested(type)
137
 
                                ? FindNestedTypeDefinition(module, type)
138
 
                                : FindTypeDefinition(module, type.IsGenericType ? type.Name : type.FullName);
139
 
                }
140
 
 
141
 
                private static bool IsNested(Type type)
142
 
                {
143
 
                        return type.IsNestedPublic || type.IsNestedPrivate || type.IsNestedAssembly;
144
 
                }
145
 
 
146
 
                private static TypeDefinition FindNestedTypeDefinition(ModuleDefinition module, Type type)
147
 
                {
148
 
                        foreach (TypeDefinition td in FindTypeDefinition(module, type.DeclaringType).NestedTypes)
149
 
                        {
150
 
                                if (td.Name == type.Name) return td;
151
 
                        }
152
 
                        return null;
153
 
                }
154
 
 
155
 
                private static TypeDefinition FindTypeDefinition(ModuleDefinition module, string name)
156
 
                {
157
 
                        return module.GetType(name);
158
 
                }
159
 
 
160
 
                private static string GetAssemblyLocation(MethodBase method)
161
 
                {
162
 
                        return method.DeclaringType.Module.FullyQualifiedName;
163
 
                }
164
 
 
165
 
                public static NQExpression FromMethodDefinition(MethodDefinition method)
166
 
                {
167
 
                        ValidatePredicateMethodDefinition(method);
168
 
 
169
 
                        Expression expression = GetQueryExpression(method);
170
 
                        if (null == expression) UnsupportedPredicate("No expression found.");
171
 
                        
172
 
                        Visitor visitor = new Visitor(method, new AssemblyResolver(_assemblyCachingStrategy));
173
 
                        expression.Accept(visitor);
174
 
                        return visitor.Expression;
175
 
                }
176
 
 
177
 
                private static void ValidatePredicateMethodDefinition(MethodDefinition method)
178
 
                {
179
 
                        if (method == null)
180
 
                                throw new ArgumentNullException("method");
181
 
                        if (1 != method.Parameters.Count)
182
 
                                UnsupportedPredicate("A predicate must take a single argument.");
183
 
                        if (0 != method.Body.ExceptionHandlers.Count)
184
 
                                UnsupportedPredicate("A predicate can not contain exception handlers.");
185
 
                        if (method.ReturnType.FullName != typeof(bool).FullName)
186
 
                                UnsupportedPredicate("A predicate must have a boolean return type.");
187
 
                }
188
 
 
189
 
                private static Expression GetQueryExpression(MethodDefinition method)
190
 
                {
191
 
                        ActionFlowGraph afg = FlowGraphFactory.CreateActionFlowGraph(FlowGraphFactory.CreateControlFlowGraph(method));
192
 
                        return GetQueryExpression(afg);
193
 
                }
194
 
 
195
 
                private static void UnsupportedPredicate(string reason)
196
 
                {
197
 
                        throw new UnsupportedPredicateException(reason);
198
 
                }
199
 
 
200
 
                private static void UnsupportedExpression(Expression node)
201
 
                {
202
 
                        UnsupportedPredicate("Unsupported expression: " + ExpressionPrinter.ToString(node));
203
 
                }
204
 
 
205
 
                private static Expression GetQueryExpression(ActionFlowGraph afg)
206
 
                {
207
 
                        IDictionary<int, Expression> variables = new Dictionary<int, Expression>();
208
 
                        ActionBlock block = afg.Blocks[0];
209
 
                        while (block != null)
210
 
                        {
211
 
                                switch (block.ActionType)
212
 
                                {
213
 
                                        case ActionType.Invoke:
214
 
                                                InvokeActionBlock invokeBlock = (InvokeActionBlock)block;
215
 
                                                MethodInvocationExpression invocation = invokeBlock.Expression;
216
 
                                                if (IsActivateInvocation(invocation) 
217
 
                                                        || IsNoSideEffectIndirectActivationInvocation(invocation))
218
 
                                                {
219
 
                                                        block = invokeBlock.Next;
220
 
                                                        break;
221
 
                                                }
222
 
 
223
 
                                                UnsupportedExpression(invocation);
224
 
                                                break;
225
 
 
226
 
                                        case ActionType.ConditionalBranch:
227
 
                                                UnsupportedPredicate("Conditional blocks are not supported.");
228
 
                                                break;
229
 
 
230
 
                                        case ActionType.Branch:
231
 
                                                block = ((BranchActionBlock)block).Target;
232
 
                                                break;
233
 
 
234
 
                                        case ActionType.Assign:
235
 
                                                {
236
 
                                                        AssignActionBlock assignBlock = (AssignActionBlock)block;
237
 
                                                        AssignExpression assign = assignBlock.AssignExpression;
238
 
                                                        VariableReferenceExpression variable = assign.Target as VariableReferenceExpression;
239
 
                                                        if (null == variable)
240
 
                                                        {
241
 
                                                                UnsupportedExpression(assign);
242
 
                                                        }
243
 
                                                        else
244
 
                                                        {
245
 
                                                                if (variables.ContainsKey(variable.Variable.Index))
246
 
                                                                        UnsupportedExpression(assign.Expression);
247
 
                                                                
248
 
                                                                variables.Add(variable.Variable.Index, assign.Expression);
249
 
                                                                block = assignBlock.Next;
250
 
                                                        }
251
 
                                                        break;
252
 
                                                }
253
 
 
254
 
                                        case ActionType.Return:
255
 
                                                {
256
 
                                                        Expression expression = ((ReturnActionBlock)block).Expression;
257
 
                                                        VariableReferenceExpression variable = expression as VariableReferenceExpression;
258
 
                                                        return null == variable
259
 
                                                                ? expression
260
 
                                                                : variables[variable.Variable.Index];
261
 
                                                }
262
 
                                }
263
 
                        }
264
 
                        return null;
265
 
                }
266
 
 
267
 
                private static bool IsNoSideEffectIndirectActivationInvocation(MethodInvocationExpression invocation)
268
 
                {
269
 
                        MethodDefinition methodDefinition = MethodDefinitionFor(invocation);
270
 
                        if (null == methodDefinition) return false;
271
 
                        ActionFlowGraph afg = FlowGraphFactory.CreateActionFlowGraph(FlowGraphFactory.CreateControlFlowGraph(methodDefinition));
272
 
 
273
 
                        if (afg.Blocks.Count == 2 && afg.Blocks[0].ActionType == ActionType.Invoke)
274
 
                        {
275
 
                                InvokeActionBlock invocationBlock = (InvokeActionBlock) afg.Blocks[0];
276
 
                                return IsActivateInvocation(invocationBlock.Expression);
277
 
                        }
278
 
 
279
 
                        return false;
280
 
                }
281
 
 
282
 
                private static MethodDefinition MethodDefinitionFor(MethodInvocationExpression invocation)
283
 
                {
284
 
                        MethodReferenceExpression methodRef = invocation.Target as MethodReferenceExpression;
285
 
                        if (null == methodRef) return null;
286
 
 
287
 
                        return GetMethodDefinition(methodRef);
288
 
                }
289
 
 
290
 
                private static bool IsActivateInvocation(MethodInvocationExpression invocation)
291
 
                {
292
 
                        MethodReferenceExpression methodRef = invocation.Target as MethodReferenceExpression;
293
 
                        if (null == methodRef) return false;
294
 
                        return IsActivateMethod(methodRef.Method);
295
 
                }
296
 
 
297
 
                private static bool IsActivateMethod(MethodReference method)
298
 
                {
299
 
                        if (method.Name != "Activate") return false;
300
 
                        return method.DeclaringType.FullName == typeof(IActivatable).FullName ||
301
 
                                   IsOverridenActivateMethod(method);
302
 
                }
303
 
 
304
 
                private static bool IsOverridenActivateMethod(MethodReference method)
305
 
                {
306
 
                        TypeDefinition declaringType = FindTypeDefinition(method.DeclaringType.Module, method.DeclaringType.FullName);
307
 
                        if (!DeclaringTypeImplementsIActivatable(declaringType)) return false;
308
 
                        if (method.Parameters.Count != 1 || 
309
 
                                method.Parameters[0].ParameterType.FullName != typeof(ActivationPurpose).FullName) return false;
310
 
 
311
 
                        return true;
312
 
                }
313
 
 
314
 
                private static bool DeclaringTypeImplementsIActivatable(TypeDefinition type)
315
 
                {
316
 
                        foreach (TypeReference itf in type.Interfaces)
317
 
                        {
318
 
                                if (itf.FullName == typeof (IActivatable).FullName)
319
 
                                {
320
 
                                        return true;
321
 
                                }
322
 
                        }
323
 
 
324
 
                        return false;
325
 
                }
326
 
 
327
 
                private static MethodDefinition GetMethodDefinition(MethodReferenceExpression methodRef)
328
 
                {
329
 
                        MethodDefinition definition = methodRef.Method as MethodDefinition;
330
 
                        return definition ?? LoadExternalMethodDefinition(methodRef);
331
 
                }
332
 
 
333
 
                private static MethodDefinition LoadExternalMethodDefinition(MethodReferenceExpression methodRef)
334
 
                {
335
 
                        MethodReference method = methodRef.Method;
336
 
                        AssemblyDefinition assemblyDef = new AssemblyResolver(_assemblyCachingStrategy).ForTypeReference(method.DeclaringType);
337
 
                        TypeDefinition type = assemblyDef.MainModule.GetType(method.DeclaringType.FullName);
338
 
                        return GetMethod(type, method);
339
 
                }
340
 
 
341
 
                private static MethodDefinition GetMethod(TypeDefinition type, MethodReference template)
342
 
                {
343
 
                        foreach (MethodDefinition method in type.Methods)
344
 
                        {
345
 
                                if (method.Name != template.Name) continue;
346
 
                                if (method.Parameters.Count != template.Parameters.Count) continue;
347
 
                                if (!ParametersMatch(method.Parameters, template.Parameters)) continue;
348
 
 
349
 
                                return method;
350
 
                        }
351
 
 
352
 
                        return null;
353
 
                }
354
 
 
355
 
#if CF
356
 
                private static bool ParametersMatch(Collection<ParameterDefinition> parameters, IList<TypeReference> templates)
357
 
                {
358
 
                        return ParametersMatch(parameters, templates, delegate(ParameterDefinition candidate, TypeReference template)
359
 
                        {
360
 
                                return candidate.ParameterType.FullName == template.FullName;
361
 
                        });
362
 
                }
363
 
#endif
364
 
 
365
 
                private static bool ParametersMatch(IList<ParameterDefinition> parameters, IList<ParameterDefinition> templates)
366
 
                {
367
 
                        return ParametersMatch(parameters, templates, delegate(ParameterDefinition candidate, ParameterDefinition template)
368
 
                                                                        {
369
 
                                                                                return candidate.ParameterType.FullName == template.ParameterType.FullName;
370
 
                                                                        });
371
 
                }
372
 
 
373
 
                private static bool ParametersMatch<T>(IList<ParameterDefinition> parameters, IList<T> templates, ParameterMatch<T> predicate)
374
 
                {
375
 
                        if (parameters.Count != templates.Count) return false;
376
 
 
377
 
                        for (int i = 0; i < parameters.Count; i++)
378
 
                        {
379
 
                                ParameterDefinition parameter = parameters[i];
380
 
                                if (!predicate(parameter, templates[i])) return false;
381
 
                        }
382
 
 
383
 
                        return true;
384
 
                }
385
 
 
386
 
                private delegate bool ParameterMatch<T>(ParameterDefinition candidate, T template);
387
 
 
388
 
                class Visitor : AbstractCodeStructureVisitor
389
 
                {
390
 
                        private object _current;
391
 
                        private int _insideCandidate;
392
 
                        readonly IList _methodDefinitionStack = new ArrayList();
393
 
                        private readonly CecilReferenceProvider _referenceProvider;
394
 
 
395
 
                        public Visitor(MethodDefinition topLevelMethod, AssemblyResolver resolver)
396
 
                        {
397
 
                                EnterMethodDefinition(topLevelMethod);
398
 
                                AssemblyDefinition assembly = resolver.ForType(topLevelMethod.DeclaringType);
399
 
                                _referenceProvider = CecilReferenceProvider.ForModule(assembly.MainModule);
400
 
                        }
401
 
 
402
 
                        private void EnterMethodDefinition(MethodDefinition method)
403
 
                        {
404
 
                                _methodDefinitionStack.Add(method);
405
 
                        }
406
 
 
407
 
                        private void LeaveMethodDefinition(MethodDefinition method)
408
 
                        {
409
 
                                int lastIndex = _methodDefinitionStack.Count - 1;
410
 
                                object popped = _methodDefinitionStack[lastIndex];
411
 
                                System.Diagnostics.Debug.Assert(method == popped);
412
 
                                _methodDefinitionStack.RemoveAt(lastIndex);
413
 
                        }
414
 
 
415
 
                        public NQExpression Expression
416
 
                        {
417
 
                                get
418
 
                                {
419
 
                                    ConstValue value = _current as ConstValue;
420
 
                                    if (null != value)
421
 
                                    {
422
 
                        return ToNQExpression(value);
423
 
                                    }
424
 
                                    return (NQExpression)_current;
425
 
                                }
426
 
                        }
427
 
 
428
 
                    private static NQExpression ToNQExpression(ConstValue value)
429
 
                    {
430
 
                if (IsTrue(value.Value())) return BoolConstExpression.True;
431
 
                        return BoolConstExpression.False;
432
 
                    }
433
 
 
434
 
                    private static bool IsTrue(object o)
435
 
                    {
436
 
                return ((IConvertible) o).ToBoolean(null);
437
 
                    }
438
 
 
439
 
                    private bool InsideCandidate
440
 
                        {
441
 
                                get { return _insideCandidate > 0; }
442
 
                        }
443
 
 
444
 
                        public override void Visit(CastExpression node)
445
 
                        {
446
 
                                node.Target.Accept(this);
447
 
                        }
448
 
 
449
 
                        public override void Visit(AssignExpression node)
450
 
                        {
451
 
                                UnsupportedExpression(node);
452
 
                        }
453
 
 
454
 
                        public override void Visit(VariableReferenceExpression node)
455
 
                        {
456
 
                                UnsupportedExpression(node);
457
 
                        }
458
 
 
459
 
                        public override void Visit(ArgumentReferenceExpression node)
460
 
                        {
461
 
                                UnsupportedExpression(node);
462
 
                        }
463
 
 
464
 
                        public override void Visit(UnaryExpression node)
465
 
                        {
466
 
                                switch (node.Operator)
467
 
                                {
468
 
                                        case UnaryOperator.Not:
469
 
                                                Visit(node.Operand);
470
 
                                                Negate();
471
 
                                                break;
472
 
 
473
 
                                        default:
474
 
                                                UnsupportedExpression(node);
475
 
                                                break;
476
 
                                }
477
 
                        }
478
 
 
479
 
                        public override void Visit(Ast.BinaryExpression node)
480
 
                        {
481
 
                                switch (node.Operator)
482
 
                                {
483
 
                                        case BinaryOperator.ValueEquality:
484
 
                                                PushComparison(node.Left, node.Right, ComparisonOperator.ValueEquality);
485
 
                                                break;
486
 
 
487
 
                                        case BinaryOperator.ValueInequality:
488
 
                                                PushComparison(node.Left, node.Right, ComparisonOperator.ValueEquality);
489
 
                                                Negate();
490
 
                                                break;
491
 
 
492
 
                                        case BinaryOperator.LessThan:
493
 
                                                PushComparison(node.Left, node.Right, ComparisonOperator.Smaller);
494
 
                                                break;
495
 
 
496
 
                                        case BinaryOperator.GreaterThan:
497
 
                                                PushComparison(node.Left, node.Right, ComparisonOperator.Greater);
498
 
                                                break;
499
 
 
500
 
                                        case BinaryOperator.GreaterThanOrEqual:
501
 
                                                PushComparison(node.Left, node.Right, ComparisonOperator.Smaller);
502
 
                                                Negate();
503
 
                                                break;
504
 
 
505
 
                                        case BinaryOperator.LessThanOrEqual:
506
 
                                                PushComparison(node.Left, node.Right, ComparisonOperator.Greater);
507
 
                                                Negate();
508
 
                                                break;
509
 
 
510
 
                                        case BinaryOperator.LogicalOr:
511
 
                                                Push(new OrExpression(Convert(node.Left), Convert(node.Right)));
512
 
                                                break;
513
 
 
514
 
                                        case BinaryOperator.LogicalAnd:
515
 
                                                Push(new AndExpression(Convert(node.Left), Convert(node.Right)));
516
 
                                                break;
517
 
 
518
 
                                        default:
519
 
                                                UnsupportedExpression(node);
520
 
                                                break;
521
 
                                }
522
 
                        }
523
 
 
524
 
                        private void Negate()
525
 
                        {
526
 
                                NQExpression top = (NQExpression)Pop();
527
 
                                NotExpression topNot = top as NotExpression;
528
 
                                if (topNot != null)
529
 
                                {
530
 
                                        Push(topNot.Expr());
531
 
                                        return;
532
 
                                }
533
 
                                Push(new NotExpression(top));
534
 
                        }
535
 
 
536
 
                        private void PushComparison(Expression lhs, Expression rhs, ComparisonOperator op)
537
 
                        {
538
 
                                Visit(lhs);
539
 
                                object left = Pop();
540
 
                                Visit(rhs);
541
 
                                object right = Pop();
542
 
 
543
 
                                bool areOperandsSwapped = IsCandidateFieldValue(right);
544
 
                                if (areOperandsSwapped)
545
 
                                {
546
 
                                        object temp = left;
547
 
                                        left = right;
548
 
                                        right = temp;
549
 
                                }
550
 
 
551
 
                                AssertType(left, typeof(FieldValue), lhs);
552
 
                                AssertType(right, typeof(IComparisonOperand), rhs);
553
 
 
554
 
                                Push(new ComparisonExpression((FieldValue)left, (IComparisonOperand)right, op));
555
 
 
556
 
                                if (areOperandsSwapped && !op.IsSymmetric())
557
 
                                {
558
 
                                        Negate();
559
 
                                }
560
 
                        }
561
 
 
562
 
                        private static bool IsCandidateFieldValue(object o)
563
 
                        {
564
 
                                FieldValue value = o as FieldValue;
565
 
                                if (value == null) return false;
566
 
                                return value.Root() is CandidateFieldRoot;
567
 
                        }
568
 
 
569
 
                        public override void Visit(MethodInvocationExpression node)
570
 
                        {
571
 
                                MethodReferenceExpression methodRef = node.Target as MethodReferenceExpression;
572
 
                                if (null == methodRef)
573
 
                                        UnsupportedExpression(node);
574
 
 
575
 
                                MethodReference method = methodRef.Method;
576
 
                                if (IsOperator(method))
577
 
                                {
578
 
                                        ProcessOperatorMethodInvocation(node, method);
579
 
                                        return;
580
 
                                }
581
 
 
582
 
                                if (IsSystemString(method.DeclaringType))
583
 
                                {
584
 
                                        ProcessStringMethod(node, methodRef);
585
 
                                        return;
586
 
                                }
587
 
 
588
 
                                ProcessRegularMethodInvocation(node, methodRef);
589
 
                        }
590
 
 
591
 
                        private static bool IsSystemString(TypeReference type)
592
 
                        {
593
 
                                return type.FullName == "System.String";
594
 
                        }
595
 
 
596
 
                        private void ProcessStringMethod(MethodInvocationExpression node, MethodReferenceExpression methodRef)
597
 
                        {
598
 
                                MethodReference method = methodRef.Method;
599
 
 
600
 
                                if (method.Parameters.Count != 1
601
 
                                        || !IsSystemString(method.Parameters[0].ParameterType))
602
 
                                {
603
 
                                        UnsupportedExpression(methodRef);
604
 
                                }
605
 
 
606
 
                                switch (method.Name)
607
 
                                {
608
 
                                        case "Contains":
609
 
                                                PushComparison(methodRef.Target, node.Arguments[0], ComparisonOperator.Contains);
610
 
                                                break;
611
 
 
612
 
                                        case "StartsWith":
613
 
                                                PushComparison(methodRef.Target, node.Arguments[0], ComparisonOperator.StartsWith);
614
 
                                                break;
615
 
 
616
 
                                        case "EndsWith":
617
 
                                                PushComparison(methodRef.Target, node.Arguments[0], ComparisonOperator.EndsWith);
618
 
                                                break;
619
 
 
620
 
                                        case "Equals":
621
 
                                                PushComparison(methodRef.Target, node.Arguments[0], ComparisonOperator.ValueEquality);
622
 
                                                break;
623
 
 
624
 
                                        default:
625
 
                                                UnsupportedExpression(methodRef);
626
 
                                                break;
627
 
                                }
628
 
                        }
629
 
 
630
 
                        private void ProcessRegularMethodInvocation(MethodInvocationExpression node, MethodReferenceExpression methodRef)
631
 
                        {
632
 
                                if (node.Arguments.Count != 0)
633
 
                                        UnsupportedExpression(node);
634
 
 
635
 
                                Expression target = methodRef.Target;
636
 
                                switch (target.CodeElementType)
637
 
                                {
638
 
                                        case CodeElementType.ThisReferenceExpression:
639
 
                                                if (!InsideCandidate)
640
 
                                                        UnsupportedExpression(node);
641
 
                                                ProcessCandidateMethodInvocation(node, methodRef);
642
 
                                                break;
643
 
 
644
 
                                        case CodeElementType.ArgumentReferenceExpression:
645
 
                                                ProcessCandidateMethodInvocation(node, methodRef);
646
 
                                                break;
647
 
 
648
 
                                        default:
649
 
                                                Push(ToFieldValue(target));
650
 
                                                ProcessCandidateMethodInvocation(node, methodRef);
651
 
                                                break;
652
 
                                }
653
 
                        }
654
 
 
655
 
                        private void ProcessOperatorMethodInvocation(MethodInvocationExpression node, MemberReference methodReference)
656
 
                        {
657
 
                                switch (methodReference.Name)
658
 
                                {
659
 
                                        case "op_Equality":
660
 
                                                PushComparison(node.Arguments[0], node.Arguments[1], ComparisonOperator.ValueEquality);
661
 
                                                break;
662
 
 
663
 
                                        case "op_Inequality":
664
 
                                                PushComparison(node.Arguments[0], node.Arguments[1], ComparisonOperator.ValueEquality);
665
 
                                                Negate();
666
 
                                                break;
667
 
 
668
 
                                        // XXX: check if the operations below are really supported for the
669
 
                                        // data types in question
670
 
                                        case "op_GreaterThanOrEqual":
671
 
                                                PushComparison(node.Arguments[0], node.Arguments[1], ComparisonOperator.Smaller);
672
 
                                                Negate();
673
 
                                                break;
674
 
 
675
 
                                        case "op_LessThanOrEqual":
676
 
                                                PushComparison(node.Arguments[0], node.Arguments[1], ComparisonOperator.Greater);
677
 
                                                Negate();
678
 
                                                break;
679
 
 
680
 
                                        case "op_LessThan":
681
 
                                                PushComparison(node.Arguments[0], node.Arguments[1], ComparisonOperator.Smaller);
682
 
                                                break;
683
 
 
684
 
                                        case "op_GreaterThan":
685
 
                                                PushComparison(node.Arguments[0], node.Arguments[1], ComparisonOperator.Greater);
686
 
                                                break;
687
 
 
688
 
                                        default:
689
 
                                                UnsupportedExpression(node);
690
 
                                                break;
691
 
                                }
692
 
                        }
693
 
 
694
 
                        private void ProcessCandidateMethodInvocation(Expression methodInvocationExpression, MethodReferenceExpression methodRef)
695
 
                        {
696
 
                                MethodDefinition method = GetMethodDefinition(methodRef);
697
 
                                if (null == method)
698
 
                                        UnsupportedExpression(methodInvocationExpression);
699
 
 
700
 
                                AssertMethodCanBeVisited(methodInvocationExpression, method);
701
 
 
702
 
                                Expression expression = GetQueryExpression(method);
703
 
                                if (null == expression)
704
 
                                        UnsupportedExpression(methodInvocationExpression);
705
 
 
706
 
                                EnterCandidateMethod(method);
707
 
                                try
708
 
                                {
709
 
                                        Visit(expression);
710
 
                                }
711
 
                                finally
712
 
                                {
713
 
                                        LeaveCandidateMethod(method);
714
 
                                }
715
 
                        }
716
 
 
717
 
                        private void AssertMethodCanBeVisited(Expression methodInvocationExpression, MethodDefinition method)
718
 
                        {
719
 
                                if (_methodDefinitionStack.Contains(method))
720
 
                                        UnsupportedExpression(methodInvocationExpression);
721
 
                        }
722
 
 
723
 
                        private void EnterCandidateMethod(MethodDefinition method)
724
 
                        {
725
 
                                EnterMethodDefinition(method);
726
 
                                ++_insideCandidate;
727
 
                        }
728
 
 
729
 
                        private void LeaveCandidateMethod(MethodDefinition method)
730
 
                        {
731
 
                                --_insideCandidate;
732
 
                                LeaveMethodDefinition(method);
733
 
                        }
734
 
 
735
 
                        private static bool IsOperator(MethodReference method)
736
 
                        {
737
 
                                return !method.HasThis && method.Name.StartsWith("op_") && 2 == method.Parameters.Count;
738
 
                        }
739
 
 
740
 
                        public override void Visit(FieldReferenceExpression node)
741
 
                        {
742
 
                                PushFieldValueForTarget(node, node.Target);
743
 
                        }
744
 
 
745
 
                        private void PushFieldValueForTarget(FieldReferenceExpression node, Expression target)
746
 
                        {
747
 
                                switch (target.CodeElementType)
748
 
                                {
749
 
                                        case CodeElementType.ArgumentReferenceExpression:
750
 
                                                PushFieldValue(CandidateFieldRoot.Instance, node.Field);
751
 
                                                break;
752
 
 
753
 
                                        case CodeElementType.ThisReferenceExpression:
754
 
                                                if (InsideCandidate)
755
 
                                                {
756
 
                                                        if (_current != null)
757
 
                                                        {
758
 
                                                                FieldValue current = PopFieldValue(node);
759
 
                                                                PushFieldValue(current, node.Field);
760
 
                                                        }
761
 
                                                        else
762
 
                                                        {
763
 
                                                                PushFieldValue(CandidateFieldRoot.Instance, node.Field);
764
 
                                                        }
765
 
                                                }
766
 
                                                else
767
 
                                                {
768
 
                                                        PushFieldValue(PredicateFieldRoot.Instance, node.Field);
769
 
                                                }
770
 
                                                break;
771
 
 
772
 
                                        case CodeElementType.MethodInvocationExpression:
773
 
                                        case CodeElementType.FieldReferenceExpression:
774
 
                                                FieldValue value = ToFieldValue(target);
775
 
                                                PushFieldValue(value, node.Field);
776
 
                                                break;
777
 
 
778
 
                                        case CodeElementType.CastExpression:
779
 
                                                PushFieldValueForTarget(node, ((CastExpression)node.Target).Target);
780
 
                                                break;
781
 
 
782
 
                                        default:
783
 
                                                UnsupportedExpression(node);
784
 
                                                break;
785
 
                                }
786
 
                        }
787
 
 
788
 
                        private void PushFieldValue(IComparisonOperandAnchor value, FieldReference field)
789
 
                        {       
790
 
                                Push(new FieldValue(value, _referenceProvider.ForCecilField(field)));
791
 
                        }
792
 
 
793
 
                        public override void Visit(LiteralExpression node)
794
 
                        {
795
 
                                Push(new ConstValue(node.Value));
796
 
                        }
797
 
 
798
 
                        NQExpression Convert(Expression node)
799
 
                        {
800
 
                                return ReconstructNullComparisonIfNecessary(node);
801
 
                        }
802
 
 
803
 
                        private NQExpression ReconstructNullComparisonIfNecessary(Expression node)
804
 
                        {
805
 
                                Visit(node);
806
 
 
807
 
                                object top = Pop();
808
 
                                FieldValue fieldValue = top as FieldValue;
809
 
                                if (fieldValue == null)
810
 
                                {
811
 
                                        AssertType(top, typeof(NQExpression), node);
812
 
                                        return (NQExpression)top;
813
 
                                }
814
 
 
815
 
                                return
816
 
                                        new NotExpression(
817
 
                                                new ComparisonExpression(
818
 
                                                        fieldValue,
819
 
                                                        new ConstValue(null),
820
 
                                                        ComparisonOperator.ValueEquality));
821
 
                        }
822
 
 
823
 
                        FieldValue ToFieldValue(Expression node)
824
 
                        {
825
 
                                Visit(node);
826
 
                                return PopFieldValue(node);
827
 
                        }
828
 
 
829
 
                        private FieldValue PopFieldValue(Expression node)
830
 
                        {
831
 
                                return (FieldValue)Pop(node, typeof(FieldValue));
832
 
                        }
833
 
 
834
 
                        void Push(object value)
835
 
                        {
836
 
                                Assert(_current == null, "expression stack must be empty before Push");
837
 
                                _current = value;
838
 
                        }
839
 
 
840
 
                        object Pop(Expression node, Type expectedType)
841
 
                        {
842
 
                                object value = Pop();
843
 
                                AssertType(value, expectedType, node);
844
 
                                return value;
845
 
                        }
846
 
 
847
 
                        private static void AssertType(object value, Type expectedType, Expression sourceExpression)
848
 
                        {
849
 
                                Type actualType = value.GetType();
850
 
                                if (!expectedType.IsAssignableFrom(actualType))
851
 
                                {
852
 
                                        UnsupportedPredicate(
853
 
                                                string.Format("Unsupported expression: {0}. Unexpected type on stack. Expected: {1}, Got: {2}.",
854
 
                                                                          ExpressionPrinter.ToString(sourceExpression), expectedType, actualType));
855
 
                                }
856
 
                        }
857
 
 
858
 
                        object Pop()
859
 
                        {
860
 
                                Assert(_current != null, "expression stack is empty");
861
 
                                object value = _current;
862
 
                                _current = null;
863
 
                                return value;
864
 
                        }
865
 
 
866
 
                        private static void Assert(bool condition, string message)
867
 
                        {
868
 
                                System.Diagnostics.Debug.Assert(condition, message);
869
 
                        }
870
 
                }
871
 
        }
872
 
 
873
 
        internal class BoxedValueTypeProcessor : TraversingExpressionVisitor
874
 
        {
875
 
                override public void Visit(ComparisonExpression expression)
876
 
                {
877
 
                        TypeReference fieldType = GetFieldType(expression.Left());
878
 
                        if (!fieldType.IsValueType) return;
879
 
                        
880
 
                        ConstValue constValue = expression.Right() as ConstValue;
881
 
                        if (constValue == null) return;
882
 
 
883
 
                        AdjustConstValue(fieldType, constValue);
884
 
                }
885
 
 
886
 
                private static TypeReference GetFieldType(FieldValue field)
887
 
                {
888
 
                        return ((CecilFieldRef) field.Field).FieldType;
889
 
                }
890
 
 
891
 
                private static void AdjustConstValue(TypeReference typeRef, ConstValue constValue)
892
 
                {
893
 
                        object value = constValue.Value();
894
 
                        if (!value.GetType().IsValueType) return;
895
 
                        
896
 
                        System.Type type = ResolveTypeReference(typeRef);
897
 
                        if (!type.IsEnum || value.GetType() == type) return;
898
 
 
899
 
                        constValue.Value(Enum.ToObject(type, value));
900
 
                }
901
 
 
902
 
                private static Type ResolveTypeReference(TypeReference typeRef)
903
 
                {
904
 
                        Assembly assembly = LoadAssembly(typeRef.Scope);
905
 
                        return assembly.GetType(typeRef.FullName.Replace('/', '+'), true);
906
 
                }
907
 
 
908
 
                private static Assembly LoadAssembly(IMetadataScope scope)
909
 
                {
910
 
                        AssemblyNameReference nameRef = scope as AssemblyNameReference;
911
 
                        if (null != nameRef) return Assembly.Load(nameRef.FullName);
912
 
                        ModuleDefinition moduleDef = scope as ModuleDefinition;
913
 
                        return LoadAssembly(moduleDef.Assembly.Name);
914
 
                }
915
 
        }
916
 
}
 
 
b'\\ No newline at end of file'