Esempio n. 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)
        {
            var cachedContract = this.contractProviderCache.GetMethodContractFor(method);

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

            IMethodReference methodReference = method as IMethodReference;

            if (methodReference == null)
            {
                this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                return(null);
            }
            IMethodDefinition methodDefinition = methodReference.ResolvedMethod;

            if (methodDefinition is Dummy)
            {
                this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                return(null);
            }
            var underlyingContract = this.underlyingContractProvider.GetMethodContractFor(method);

            if (!methodDefinition.IsAbstract)
            {
                if (underlyingContract != null)
                {
                    return(underlyingContract);
                }
                else
                {
                    this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                    return(null);
                }
            }

            // The method is definitely an abstract method, so either:
            //  (a) we've never looked for a contract for it before, or else
            //  (b) it is a specialized/instantiated method and the uninstantiated version has already
            //      had its contract extracted.

            var unspecializedMethodDefinition = ContractHelper.UninstantiateAndUnspecializeMethodDefinition(methodDefinition);

            cachedContract = this.contractProviderCache.GetMethodContractFor(unspecializedMethodDefinition);

            if (cachedContract == null) // (a)

            // Check to see if its containing type points to a class holding the contract
            {
                IMethodDefinition /*?*/ proxyMethod = ContractHelper.GetMethodFromContractClass(this.host, unspecializedMethodDefinition);
                if (proxyMethod == null)
                {
                    this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                    return(null);
                }
                MethodContract cumulativeContract = new MethodContract();
                if (underlyingContract != null)
                {
                    ContractHelper.AddMethodContract(cumulativeContract, underlyingContract);
                }

                IMethodContract proxyContract = this.underlyingContractProvider.GetMethodContractFor(proxyMethod);
                ITypeReference  contractClass = proxyMethod.ContainingTypeDefinition;
                var             gtir          = contractClass as IGenericTypeInstanceReference;
                if (gtir != null)
                {
                    contractClass = gtir.GenericType;
                }

                if (proxyContract == null)
                {
                    if (underlyingContract == null)
                    {
                        // then there was nothing on the abstract method (like purity markings)
                        this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
                        return(null);
                    }
                    else
                    {
                        // nothing on proxy, but something on abstract method
                        this.contractProviderCache.AssociateMethodWithContract(method, cumulativeContract);
                        return(cumulativeContract);
                    }
                }
                var copier = new CodeAndContractDeepCopier(this.host);
                proxyContract = copier.Copy(proxyContract);

                var cccc = new ConvertContractClassContract(this.host, contractClass, unspecializedMethodDefinition.ContainingType);
                proxyContract = cccc.Rewrite(proxyContract);
                proxyContract = ContractHelper.CopyContractIntoNewContext(this.host, proxyContract, unspecializedMethodDefinition, proxyMethod);

                ContractHelper.AddMethodContract(cumulativeContract, proxyContract);

                // Cache the unspecialized contract: specialize and instantiate on demand
                this.contractProviderCache.AssociateMethodWithContract(unspecializedMethodDefinition, cumulativeContract);
                cachedContract = cumulativeContract;
            }

            if (unspecializedMethodDefinition == methodDefinition)
            {
                return(cachedContract == ContractDummy.MethodContract ? null : cachedContract);
            }
            else // (b)
            {
                var mc = ContractHelper.InstantiateAndSpecializeContract(this.host, cachedContract, methodDefinition, unspecializedMethodDefinition);
                mc = (MethodContract)ContractHelper.CopyContractIntoNewContext(this.host, mc, methodDefinition, unspecializedMethodDefinition);
                return(mc);
            }
        }
Esempio n. 2
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.contractProviderCache.GetMethodContractFor(method);
              if (contract != null) return contract == ContractDummy.MethodContract ? null : contract;

              IMethodReference methodReference = method as IMethodReference;
              if (methodReference == null) {
            this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
            return null;
              }
              IMethodDefinition methodDefinition = methodReference.ResolvedMethod;
              if (methodDefinition == Dummy.Method) {
            this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
            return null;
              }
              if (!methodDefinition.IsAbstract) {
            contract = this.underlyingContractProvider.GetMethodContractFor(method);
            if (contract != null) {
              return contract;
            } else {
              this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
              return null;
            }
              }

              // But if it is an abstract method, then check to see if its containing type points to a class holding the contract
              IMethodDefinition/*?*/ proxyMethod = ContractHelper.GetMethodFromContractClass(this.host, methodDefinition);
              if (proxyMethod == null) {
            this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
            return null;
              }
              ITypeDefinition contractClass;
              var specializedProxyMethod = proxyMethod as ISpecializedMethodDefinition;
              IMethodDefinition unspec = null;
              if (specializedProxyMethod != null) {
            unspec = ContractHelper.UninstantiateAndUnspecialize(specializedProxyMethod).ResolvedMethod;
            contract = this.underlyingContractProvider.GetMethodContractFor(unspec);
            contractClass = unspec.ContainingTypeDefinition;
              } else {
            contract = this.underlyingContractProvider.GetMethodContractFor(proxyMethod);
            contractClass = proxyMethod.ContainingTypeDefinition;
              }
              if (contract == null) {
            this.contractProviderCache.AssociateMethodWithContract(method, ContractDummy.MethodContract);
            return null;
              }
              var cccc = new ConvertContractClassContract(this.host, contractClass, methodDefinition.ContainingTypeDefinition);
              cccc.Traverse(contract);
              contract = ContractHelper.CopyContract(this.host, contract, methodDefinition, specializedProxyMethod != null ? unspec : proxyMethod);
              if (specializedProxyMethod != null || proxyMethod.IsGeneric || proxyMethod.ContainingTypeDefinition.IsGeneric) {
            var stdm = specializedProxyMethod as Immutable.SpecializedTypeDefinitionMember<IMethodDefinition>;
            var sourceTypeReferences = stdm == null ?
              (proxyMethod.ContainingTypeDefinition.IsGeneric ?
            IteratorHelper.GetConversionEnumerable<IGenericTypeParameter, ITypeReference>(methodDefinition.ContainingTypeDefinition.GenericParameters)
            : Enumerable<ITypeReference>.Empty)
              : stdm.ContainingGenericTypeInstance.GenericArguments;
            contract = ContractHelper.SpecializeMethodContract(this.host, contract, unspec == null ? proxyMethod.ContainingTypeDefinition : unspec.ContainingTypeDefinition, unspec == null ? proxyMethod.ContainingTypeDefinition.GenericParameters : unspec.ContainingTypeDefinition.GenericParameters, sourceTypeReferences,
              unspec == null ? proxyMethod.GenericParameters : unspec.GenericParameters, methodDefinition.GenericParameters);
              }
              this.contractProviderCache.AssociateMethodWithContract(methodDefinition, contract);
              return contract;
        }