예제 #1
0
        /// <summary>
        /// Returns the method contract, if any, that has been associated with the given object. Returns null if no association exits.
        /// </summary>
        /// <param name="method">An object that might have been associated with a method contract. This can be any kind of object.</param>
        /// <returns></returns>
        public IMethodContract /*?*/ GetMethodContractFor(object method)
        {
            IMethodContract contract = this.underlyingContractProvider.GetMethodContractFor(method);

            if (contract != null)
            {
                return(contract == ContractDummy.MethodContract ? null : contract);
            }

            IMethodReference methodReference = method as IMethodReference;

            if (methodReference == null)
            {
                this.underlyingContractProvider.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                return(null);
            }

            IMethodDefinition methodDefinition = methodReference.ResolvedMethod;

            if (methodDefinition is Dummy)
            {
                this.underlyingContractProvider.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                return(null);
            }

            if (methodDefinition.IsAbstract || methodDefinition.IsExternal) // precondition of Body getter
            // Need to see if the method is marked with any attributes that impact the contract
            {
                if (ContractHelper.IsPure(this.host, methodDefinition))
                {
                    var pureMC = new MethodContract()
                    {
                        IsPure = true,
                    };
                    this.underlyingContractProvider.AssociateMethodWithContract(method, pureMC);
                    return(pureMC);
                }
                else
                {
                    this.underlyingContractProvider.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                    return(null);
                }
            }

            var unspecializedMethodDefintion = ContractHelper.UninstantiateAndUnspecializeMethodDefinition(methodDefinition);

            if (unspecializedMethodDefintion != methodDefinition)
            {
                contract = this.underlyingContractProvider.GetMethodContractFor(unspecializedMethodDefintion);
                if (contract != null)
                {
                    return(ContractHelper.InstantiateAndSpecializeContract(this.host, contract, methodDefinition, unspecializedMethodDefintion));
                }
            }

            IMethodBody methodBody = unspecializedMethodDefintion.Body;

            if (methodBody is Dummy)
            {
                this.underlyingContractProvider.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                return(null);
            }

            ISourceMethodBody /*?*/ sourceMethodBody = methodBody as ISourceMethodBody;

            if (sourceMethodBody == null)
            {
                sourceMethodBody = Decompiler.GetCodeModelFromMetadataModel(this.host, methodBody, this.pdbReader, DecompilerOptions.AnonymousDelegates);
            }

            MethodContractAndMethodBody result = this.SplitMethodBodyIntoContractAndCode(sourceMethodBody);

            var methodContract = result.MethodContract;

            if (methodContract != null && unspecializedMethodDefintion != methodDefinition)
            {
                var instantiatedContract = ContractHelper.InstantiateAndSpecializeContract(this.host, result.MethodContract, methodDefinition, unspecializedMethodDefintion);
                methodContract = instantiatedContract;
            }

            #region Auto-properties get their contract from mining the invariant
            if (ContractHelper.IsAutoPropertyMember(host, unspecializedMethodDefintion))
            {
                var            tc = this.GetTypeContractFor(unspecializedMethodDefintion.ContainingTypeDefinition);
                MethodContract mc = ContractHelper.GetAutoPropertyContract(this.host, tc, unspecializedMethodDefintion);
                if (mc != null)
                {
                    if (unspecializedMethodDefintion != methodDefinition)
                    {
                        var mutableContract = ContractHelper.InstantiateAndSpecializeContract(this.host, mc, methodDefinition, unspecializedMethodDefintion);
                        mc = mutableContract;
                    }

                    if (methodContract == null)
                    {
                        methodContract = mc;
                    }
                    else
                    {
                        ContractHelper.AddMethodContract(mc, methodContract);
                    }
                }
            }
            #endregion

            if (methodContract == null)
            {
                this.underlyingContractProvider.AssociateMethodWithContract(method, ContractDummy.MethodContract); // so we don't try to extract more than once
            }
            else
            {
                this.underlyingContractProvider.AssociateMethodWithContract(method, methodContract);
            }

            // Notify all interested parties
            foreach (var c in this.callbacks)
            {
                c.ProvideResidualMethodBody(methodDefinition, result.BlockStatement);
            }

            return(methodContract);
        }