If the original method that contained the anonymous delegate is generic, then the code generated by the compiler, the "closure method", is also generic. If the anonymous delegate didn't capture any locals or parameters, then a (generic) static method was generated to implement the lambda. If it did capture things, then the closure method is a non-generic instance method in a generic class. In either case, any references to those generic parameters need to be mapped back to become references to the original method's generic parameters. Create an instance of this class for each anonymous delegate using the appropriate constructor. This is known from whether the closure method is (static and generic) or (instance and not-generic, but whose containing type is generic). Those are the only two patterns created by the compiler.
Inheritance: Microsoft.Cci.MutableCodeModel.Contracts.CodeAndContractRewriter
Example #1
0
        // TODO: First search the moveNextBody to see if there are any contracts at all.
        /// <summary>
        ///
        /// </summary>
        /// <param name="host"></param>
        /// <param name="extractor"></param>
        /// <param name="iteratorMethodBody"></param>
        /// <param name="moveNextBody"></param>
        /// <param name="pdbReader"></param>
        /// <returns></returns>
        public static MethodContract GetMethodContractFromMoveNext(
            IContractAwareHost host,
            ContractExtractor extractor,
            ISourceMethodBody iteratorMethodBody,
            ISourceMethodBody moveNextBody,
            PdbReader pdbReader
            )
        {
            // Walk the iterator method and collect all of the state that is assigned to fields in the iterator class
            // That state needs to replace any occurrences of the fields in the contracts (if they exist...)
            var iteratorStmts = new List <IStatement>(iteratorMethodBody.Block.Statements);
            Dictionary <uint, IExpression> capturedThings = new Dictionary <uint, IExpression>();

            // Find all of the state captured for the IEnumerable
            // REVIEW: Is this state ever used in the contracts? Since they're all sitting in the MoveNext
            // method, maybe they always use the IEnumerator state?
            if (1 < iteratorStmts.Count)
            {
                // First statement should be the creation of the iterator class
                int j = 1;
                while (j < iteratorStmts.Count)
                {
                    var es = iteratorStmts[j++] as IExpressionStatement;
                    if (es == null)
                    {
                        break;
                    }
                    var assign = es.Expression as IAssignment;
                    if (assign == null)
                    {
                        break;
                    }
                    var field         = assign.Target.Definition as IFieldReference;
                    var capturedThing = assign.Source;
                    var k             = field.InternedKey;
                    var spec          = field as ISpecializedFieldReference;
                    if (spec != null)
                    {
                        k = spec.UnspecializedVersion.InternedKey;
                    }
                    capturedThings.Add(k, capturedThing);
                }
            }
            else
            {
                var ret = iteratorStmts[0] as IReturnStatement;
                if (ret != null)
                {
                    var be = ret.Expression as IBlockExpression;
                    if (be != null)
                    {
                        var beStmts = new List <IStatement>(be.BlockStatement.Statements);
                        var j       = 1;
                        while (j < beStmts.Count)
                        {
                            var es = beStmts[j++] as IExpressionStatement;
                            if (es == null)
                            {
                                break;
                            }
                            var assign = es.Expression as IAssignment;
                            if (assign == null)
                            {
                                break;
                            }
                            var field         = assign.Target.Definition as IFieldReference;
                            var capturedThing = assign.Source;
                            var k             = field.InternedKey;
                            var spec          = field as ISpecializedFieldReference;
                            if (spec != null)
                            {
                                k = spec.UnspecializedVersion.InternedKey;
                            }
                            capturedThings.Add(k, capturedThing);
                        }
                    }
                }
            }
            // Find all of the state captured for the IEnumerator
            // That state is captured at the beginning of the IEnumerable<T>.GetEnumerator method
            IMethodDefinition getEnumerator = null;
            var t = moveNextBody.MethodDefinition.ContainingTypeDefinition;

            foreach (IMethodImplementation methodImplementation in t.ExplicitImplementationOverrides)
            {
                if (methodImplementation.ImplementedMethod.Name == host.NameTable.GetNameFor("GetEnumerator"))
                {
                    var gtir = methodImplementation.ImplementedMethod.ContainingType as IGenericTypeInstanceReference;
                    if (gtir != null && TypeHelper.TypesAreEquivalent(gtir.GenericType, host.PlatformType.SystemCollectionsGenericIEnumerable))
                    {
                        getEnumerator = methodImplementation.ImplementingMethod.ResolvedMethod as IMethodDefinition;
                        break;
                    }
                }
            }
            if (getEnumerator != null)
            {
                IMethodBody geBody       = getEnumerator.Body;
                var         sourceGeBody = geBody as ISourceMethodBody;
                if (sourceGeBody == null)
                {
                    sourceGeBody = Decompiler.GetCodeModelFromMetadataModel(host, geBody, pdbReader, DecompilerOptions.AnonymousDelegates);
                }
                foreach (var stmt in sourceGeBody.Block.Statements)
                {
                    var es = stmt as IExpressionStatement;
                    if (es == null)
                    {
                        continue;
                    }
                    var assign = es.Expression as IAssignment;
                    if (assign == null)
                    {
                        continue;
                    }
                    var field2 = assign.Target.Definition as IFieldReference;
                    if (field2 == null)
                    {
                        continue;
                    }
                    var k    = field2.InternedKey;
                    var spec = field2 as ISpecializedFieldReference;
                    if (spec != null)
                    {
                        k = spec.UnspecializedVersion.InternedKey;
                    }

                    var sourceBe = assign.Source as IBoundExpression;
                    if (sourceBe == null)
                    {
                        continue;
                    }
                    var field3 = sourceBe.Definition as IFieldReference;
                    if (field3 == null)
                    {
                        continue;
                    }
                    var k3    = field3.InternedKey;
                    var spec3 = field3 as ISpecializedFieldReference;
                    if (spec3 != null)
                    {
                        k3 = spec3.UnspecializedVersion.InternedKey;
                    }
                    IExpression capturedThing = null;
                    if (!capturedThings.TryGetValue(k3, out capturedThing))
                    {
                        continue;
                    }
                    capturedThings[k] = capturedThing;
                }
            }

            var mc = HermansAlwaysRight.ExtractContracts(host, pdbReader, extractor, moveNextBody);

            if (mc == null)
            {
                return(mc);
            }

            // substitute all field references in contract with the captured state
            var replacer = new Replacer(host, capturedThings, iteratorMethodBody.MethodDefinition, moveNextBody.MethodDefinition);

            replacer.RewriteChildren(mc);

            if (moveNextBody.MethodDefinition.ContainingTypeDefinition.IsGeneric)
            {
                var genericParameterMapper = new GenericMethodParameterMapper(host, iteratorMethodBody.MethodDefinition, moveNextBody.MethodDefinition.ContainingType as INestedTypeReference);
                mc = genericParameterMapper.Rewrite(mc) as MethodContract;
            }

            return(mc);
        }