/// <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); } }