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