/// <summary> /// Given a method contract (<paramref name="methodContract"/> for a unspecialized/uninstantiated method reference/definition /// (<paramref name="unspec"/>), specialize and instantiate (i.e., the generics) in the contract so that it is a contract /// relative to the specialized/instantiated method reference/definition (<paramref name="mr"/>). /// </summary> /// <param name="host"></param> /// <param name="methodContract"></param> /// <param name="mr"></param> /// <param name="unspec"></param> /// <returns> /// A deep copy of <paramref name="methodContract"/>, properly specialized and instantiated. /// </returns> public static MethodContract InstantiateAndSpecializeContract(IMetadataHost host, IMethodContract methodContract, IMethodReference mr, IMethodReference unspec) { //Contract.Requires(mr is IGenericMethodInstanceReference || mr is ISpecializedMethodReference); var copier = new CodeAndContractDeepCopier(host); var mutableContract = copier.Copy(methodContract); var unspecializedTypeReferences = new List<ITypeReference>(); var specializedTypeReferences = new List<ITypeReference>(); var copyOfUnspecializedContainingType = copier.Copy(unspec.ContainingType); unspecializedTypeReferences.Add(copyOfUnspecializedContainingType); var containingType = mr.ContainingType; var gtir2 = containingType as IGenericTypeInstanceReference; var copyOfSpecializedContainingType = gtir2 != null ? copier.Copy(gtir2) : copier.Copy(containingType); specializedTypeReferences.Add(copyOfSpecializedContainingType); var unspecializedMethodDefinition = unspec as IMethodDefinition; #region Map generic type parameters var smr = mr as ISpecializedMethodReference; if (smr != null) { if (unspecializedMethodDefinition != null) { foreach (var t in unspecializedMethodDefinition.ContainingTypeDefinition.GenericParameters) { // without the cast, the copy is not object equals to references within the contract var copyOfT = copier.Copy((IGenericTypeParameterReference)t); unspecializedTypeReferences.Add(copyOfT); } var gtir = smr.ContainingType as IGenericTypeInstanceReference; if (gtir != null) { foreach (var t in gtir.GenericArguments) { var copyOfT = copier.Copy(t); specializedTypeReferences.Add(copyOfT); } } } } #endregion #region Map generic method parameters var gmir = mr as IGenericMethodInstanceReference; if (gmir != null) { var unspecialized = gmir.GenericMethod.ResolvedMethod; foreach (var t in unspecialized.GenericParameters) { var copyOfT = copier.Copy(t); unspecializedTypeReferences.Add(copyOfT); } foreach (var t in gmir.GenericArguments) { var copyOfT = copier.Copy(t); specializedTypeReferences.Add(copyOfT); } } #endregion var d = new Dictionary<uint, ITypeReference>(); IteratorHelper.Zip(unspecializedTypeReferences, specializedTypeReferences, (u, s) => d.Add(u.InternedKey, s)); var specializer = new CodeSpecializer(host, d); mutableContract = (MethodContract)specializer.Rewrite(mutableContract); mutableContract = (MethodContract)ContractHelper.CopyContractIntoNewContext(host, mutableContract, smr != null ? smr.ResolvedMethod : mr.ResolvedMethod, unspecializedMethodDefinition); return mutableContract; }
/// <summary> /// Returns a method contract containing the 'effective' contract for the given /// method definition. The effective contract contains all contracts for the method: /// any that it has on its own, as well as all those inherited from any methods /// that it overrides or interface methods that it implements (either implicitly /// or explicitly). /// All parameters in inherited contracts are substituted for by /// the method's own parameters. /// If there are no contracts, then it returns null. /// Any preconditions that were written as legacy-preconditions or calls to Requires<E> are /// included iff <paramref name="keepLegacyPreconditions"/>. /// </summary> public static IMethodContract GetMethodContractForIncludingInheritedContracts(IContractAwareHost host, IMethodDefinition methodDefinition, bool keepLegacyPreconditions = true) { MethodContract cumulativeContract = new MethodContract(); bool atLeastOneContract = false; IMethodContract/*?*/ mc = ContractHelper.GetMethodContractFor(host, methodDefinition); if (mc != null) { Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, mc); atLeastOneContract = true; } #region Overrides of base class methods if (!methodDefinition.IsNewSlot) { // REVIEW: Is there a better test? IMethodDefinition overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(methodDefinition) as IMethodDefinition; while (overriddenMethod != null && !(overriddenMethod is Dummy)) { IMethodContract/*?*/ overriddenContract = ContractHelper.GetMethodContractFor(host, overriddenMethod); if (overriddenContract != null) { overriddenContract = CopyContractIntoNewContext(host, overriddenContract, methodDefinition, overriddenMethod); overriddenContract = FilterUserMessageAndLegacyPreconditions(host, overriddenContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions); // if the method is generic, then need to specialize the contract to have the same method type parameters as the method if (methodDefinition.IsGeneric) { var d = new Dictionary<uint, ITypeReference>(); IteratorHelper.Zip(overriddenMethod.GenericParameters, methodDefinition.GenericParameters, (i, j) => d.Add(i.InternedKey, j)); var cs = new CodeSpecializer(host, d); overriddenContract = cs.Rewrite(overriddenContract); } Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, overriddenContract); atLeastOneContract = true; } overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(overriddenMethod) as IMethodDefinition; } } #endregion Overrides of base class methods #region Implicit interface implementations foreach (IMethodDefinition ifaceMethod in ContractHelper.GetAllImplicitlyImplementedInterfaceMethods(methodDefinition)) { IMethodContract/*?*/ ifaceContract = ContractHelper.GetMethodContractFor(host, ifaceMethod); if (ifaceContract == null) continue; ifaceContract = CopyContractIntoNewContext(host, ifaceContract, methodDefinition, ifaceMethod); ifaceContract = FilterUserMessageAndLegacyPreconditions(host, ifaceContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions); Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, ifaceContract); atLeastOneContract = true; } #endregion Implicit interface implementations #region Explicit interface implementations and explicit method overrides foreach (IMethodReference ifaceMethodRef in MemberHelper.GetExplicitlyOverriddenMethods(methodDefinition)) { IMethodDefinition/*?*/ ifaceMethod = ifaceMethodRef.ResolvedMethod; if (ifaceMethod == null) continue; IMethodContract/*?*/ ifaceContract = ContractHelper.GetMethodContractFor(host, ifaceMethod); if (ifaceContract == null) continue; ifaceContract = CopyContractIntoNewContext(host, ifaceContract, methodDefinition, ifaceMethod); ifaceContract = FilterUserMessageAndLegacyPreconditions(host, ifaceContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions); Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, ifaceContract); atLeastOneContract = true; } #endregion Explicit interface implementations and explicit method overrides return atLeastOneContract ? cumulativeContract : null; }