void AddExternalType(IReturnType rt, List <ClassNameTypeCountPair> externalTypes, int classCount) { if (rt.IsDefaultReturnType) { ClassNameTypeCountPair pair = new ClassNameTypeCountPair(rt); if (!classIndices.ContainsKey(pair)) { classIndices.Add(pair, externalTypes.Count + classCount); externalTypes.Add(pair); } } else if (rt.IsGenericReturnType) { // ignore } else if (rt.IsArrayReturnType) { AddExternalType(rt.CastToArrayReturnType().ArrayElementType, externalTypes, classCount); } else if (rt.IsConstructedReturnType) { AddExternalType(rt.CastToConstructedReturnType().UnboundType, externalTypes, classCount); foreach (IReturnType typeArgument in rt.CastToConstructedReturnType().TypeArguments) { AddExternalType(typeArgument, externalTypes, classCount); } } else { LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { builder.Append('['); int dimensions = returnType.CastToArrayReturnType().ArrayDimensions; for (int i = 1; i < dimensions; ++i) { builder.Append(','); } builder.Append(']'); UnpackNestedType(builder, returnType.CastToArrayReturnType().ArrayElementType); } else if (returnType.IsConstructedReturnType) { UnpackNestedType(builder, returnType.CastToConstructedReturnType().UnboundType); builder.Append('<'); IList <IReturnType> ta = returnType.CastToConstructedReturnType().TypeArguments; for (int i = 0; i < ta.Count; ++i) { if (i > 0) { builder.Append(", "); } builder.Append(Convert(ta[i])); } builder.Append('>'); } }
private void AppendReturnType(StringBuilder builder, IReturnType returnType, bool forceFullyQualifiedName) { var arrayReturnType = returnType; returnType = GetElementType(returnType); if (returnType == null) { return; } var fullName = returnType.FullyQualifiedName; string shortName; var isConstructedType = returnType.IsConstructedReturnType; if (fullName != null && !isConstructedType && TypeConversionTable.TryGetValue(fullName, out shortName)) { builder.Append(shortName); } else { IClass c = returnType.GetUnderlyingClass(); if (c != null) { IList <IReturnType> ta = isConstructedType ? returnType.CastToConstructedReturnType().TypeArguments : null; AppendClassNameWithTypeParameters(builder, c, forceFullyQualifiedName || UseFullyQualifiedTypeNames, false, ta); } else { if (UseFullyQualifiedTypeNames || forceFullyQualifiedName) { builder.Append(fullName); } else { builder.Append(returnType.Name); } if (isConstructedType) { builder.Append('<'); IList <IReturnType> ta = returnType.CastToConstructedReturnType().TypeArguments; for (int i = 0; i < ta.Count; ++i) { if (i > 0) { builder.Append(", "); } AppendReturnType(builder, ta[i], false); } builder.Append('>'); } } } UnpackArrayType(builder, arrayReturnType); }
/// <summary> /// Gets if <paramref name="t"/> is/contains a generic return type referring to a class type parameter. /// </summary> bool CheckReturnType(IReturnType t) { if (t == null) { return(false); } if (t.IsGenericReturnType) { return(t.CastToGenericReturnType().TypeParameter.Method == null); } else if (t.IsArrayReturnType) { return(CheckReturnType(t.CastToArrayReturnType().ArrayElementType)); } else if (t.IsConstructedReturnType) { foreach (IReturnType para in t.CastToConstructedReturnType().TypeArguments) { if (CheckReturnType(para)) { return(true); } } return(false); } else { return(false); } }
/// <summary> /// Returns true if the short name of a type is valid in the given context. /// Returns false for primitive types because they should be passed around using their /// fully qualified names to allow the ambience or output visitor to use the intrinsic /// type name. /// </summary> public static bool CanUseShortTypeName(IReturnType returnType, ClassFinder context) { switch (returnType.FullyQualifiedName) { case "System.Void": case "System.String": case "System.Char": case "System.Boolean": case "System.Single": case "System.Double": case "System.Decimal": case "System.Byte": case "System.SByte": case "System.Int16": case "System.Int32": case "System.Int64": case "System.UInt16": case "System.UInt32": case "System.UInt64": // don't use short name -> output visitor will use the instrinsic name return(false); } int typeArgumentCount = (returnType.IsConstructedReturnType) ? returnType.CastToConstructedReturnType().TypeArguments.Count : 0; IReturnType typeInTargetContext = context.SearchType(returnType.Name, typeArgumentCount); return(typeInTargetContext != null && typeInTargetContext.FullyQualifiedName == returnType.FullyQualifiedName); }
/// <summary> /// Returns true if the short name of a type is valid in the given context. /// Returns false for primitive types because they should be passed around using their /// fully qualified names to allow the ambience or output visitor to use the intrinsic /// type name. /// </summary> public static bool CanUseShortTypeName(IReturnType returnType, ClassFinder context) { int typeArgumentCount = (returnType.IsConstructedReturnType) ? returnType.CastToConstructedReturnType().TypeArguments.Count : 0; IReturnType typeInTargetContext = context.SearchType(returnType.Name, typeArgumentCount); return(typeInTargetContext != null && typeInTargetContext.FullyQualifiedName == returnType.FullyQualifiedName); }
public static string FormatName(this IReturnType type) { if (type == null) { return(string.Empty); } if (type.Name == "Nullable") { return(string.Format("{0}?", type.CastToConstructedReturnType().TypeArguments[0].FormatName())); } var formattedName = type.GetFormattedNameOrNull(); if (formattedName != null) { return(formattedName); } var underlyingClass = type.GetUnderlyingClass(); if (underlyingClass != null) { return(underlyingClass.FormatName()); } return(type.Name); }
static int GetMoreSpecific(IReturnType r, IReturnType s) { if (r == null && s == null) { return(0); } if (r == null) { return(2); } if (s == null) { return(1); } if (r.IsGenericReturnType && !(s.IsGenericReturnType)) { return(2); } if (s.IsGenericReturnType && !(r.IsGenericReturnType)) { return(1); } if (r.IsArrayReturnType && s.IsArrayReturnType) { return(GetMoreSpecific(r.CastToArrayReturnType().ArrayElementType, s.CastToArrayReturnType().ArrayElementType)); } if (r.IsConstructedReturnType && s.IsConstructedReturnType) { return(GetMoreSpecific(r.CastToConstructedReturnType().TypeArguments, s.CastToConstructedReturnType().TypeArguments)); } return(0); }
void WriteType(IReturnType rt) { if (rt == null) { writer.Write(NullRTReferenceCode); return; } if (rt.IsDefaultReturnType) { string name = rt.FullyQualifiedName; if (name == "System.Void") { writer.Write(VoidRTCode); } else { writer.Write(classIndices[new ClassNameTypeCountPair(rt)]); } } else if (rt.IsGenericReturnType) { GenericReturnType grt = rt.CastToGenericReturnType(); if (grt.TypeParameter.Method != null) { writer.Write(MethodGenericRTCode); } else { writer.Write(TypeGenericRTCode); } writer.Write(grt.TypeParameter.Index); } else if (rt.IsArrayReturnType) { writer.Write(ArrayRTCode); writer.Write(rt.CastToArrayReturnType().ArrayDimensions); WriteType(rt.CastToArrayReturnType().ArrayElementType); } else if (rt.IsConstructedReturnType) { ConstructedReturnType crt = rt.CastToConstructedReturnType(); writer.Write(ConstructedRTCode); WriteType(crt.UnboundType); writer.Write((byte)crt.TypeArguments.Count); foreach (IReturnType typeArgument in crt.TypeArguments) { WriteType(typeArgument); } } else if (rt.IsDecoratingReturnType <PointerReturnType>()) { writer.Write(PointerRTCode); WriteType(rt.CastToDecoratingReturnType <PointerReturnType>().BaseType); } else { writer.Write(NullRTReferenceCode); LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
static bool IsConstructedConversionToGenericReturnType(IReturnType from, IReturnType to, IMethod allowGenericTargetsOnThisMethod) { // null could be passed when type arguments could not be resolved/inferred if (from == null && to == null) { return(true); } if (from == null || to == null) { return(false); } if (from.Equals(to)) { return(true); } if (allowGenericTargetsOnThisMethod == null) { return(false); } if (to.IsGenericReturnType) { ITypeParameter typeParameter = to.CastToGenericReturnType().TypeParameter; if (typeParameter.Method != allowGenericTargetsOnThisMethod) { return(false); } foreach (IReturnType constraintType in typeParameter.Constraints) { if (!ConversionExistsInternal(from, constraintType, allowGenericTargetsOnThisMethod)) { return(false); } } return(true); } // for conversions like from IEnumerable<string> to IEnumerable<T>, where T is a GenericReturnType ConstructedReturnType cFrom = from.CastToConstructedReturnType(); ConstructedReturnType cTo = to.CastToConstructedReturnType(); if (cFrom != null && cTo != null) { if (cFrom.FullyQualifiedName == cTo.FullyQualifiedName && cFrom.TypeArguments.Count == cTo.TypeArguments.Count) { for (int i = 0; i < cFrom.TypeArguments.Count; i++) { if (!IsConstructedConversionToGenericReturnType(cFrom.TypeArguments[i], cTo.TypeArguments[i], allowGenericTargetsOnThisMethod)) { return(false); } } return(true); } } return(false); }
public void TypeParameterPassedToBaseClassTestDictionary() { IReturnType[] stringInt = { msc.SystemTypes.String, msc.SystemTypes.Int32 }; IReturnType rrt = new ConstructedReturnType(DictionaryRT, stringInt); IReturnType res = MemberLookupHelper.GetTypeParameterPassedToBaseClass(rrt, EnumerableClass, 0); Assert.AreEqual("System.Collections.Generic.KeyValuePair", res.FullyQualifiedName); ConstructedReturnType resc = res.CastToConstructedReturnType(); Assert.AreEqual("System.String", resc.TypeArguments[0].FullyQualifiedName); Assert.AreEqual("System.Int32", resc.TypeArguments[1].FullyQualifiedName); }
void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { ArrayReturnType art = returnType.CastToArrayReturnType(); builder.Append('('); UnpackNestedType(builder, art.ArrayElementType); if (art.ArrayDimensions > 1) { builder.Append(','); builder.Append(art.ArrayDimensions); } builder.Append(')'); } else if (returnType.IsConstructedReturnType) { ConstructedReturnType crt = returnType.CastToConstructedReturnType(); UnpackNestedType(builder, crt.UnboundType); builder.Append("[of "); for (int i = 0; i < crt.TypeArguments.Count; ++i) { if (i > 0) { builder.Append(", "); } builder.Append(Convert(crt.TypeArguments[i])); } builder.Append(']'); } else { string fullName = returnType.FullyQualifiedName; if (fullName != null && typeConversionTable.ContainsKey(fullName)) { builder.Append(typeConversionTable[fullName].ToString()); } else { if (UseFullyQualifiedTypeNames) { builder.Append(fullName); } else { builder.Append(returnType.Name); } } } }
public virtual ConstructedReturnType CastToConstructedReturnType() { IReturnType baseType = BaseType; ConstructedReturnType temp; if (baseType != null && TryEnter()) { temp = baseType.CastToConstructedReturnType(); } else { throw new InvalidCastException("Cannot cast " + ToString() + " to expected type."); } _busy = false; return(temp); }
/// <summary> /// Gets whether this type parameter occurs in the specified return type. /// </summary> public bool OccursIn(IReturnType rt) { ArrayReturnType art = rt.CastToArrayReturnType(); if (art != null) { return OccursIn(art.ArrayElementType); } ConstructedReturnType crt = rt.CastToConstructedReturnType(); if (crt != null) { return crt.TypeArguments.Any(ta => OccursIn(ta)); } GenericReturnType grt = rt.CastToGenericReturnType(); if (grt != null) { return this.TypeParameter.Equals(grt.TypeParameter); } return false; }
bool CheckReturnType(IReturnType t) { if (t.IsGenericReturnType) { return t.CastToGenericReturnType().TypeParameter.Method == null; } else if (t.IsArrayReturnType) { return CheckReturnType(t.CastToArrayReturnType().ArrayElementType); } else if (t.IsConstructedReturnType) { foreach (IReturnType para in t.CastToConstructedReturnType().TypeArguments) { if (para != null) { if (CheckReturnType(para)) return true; } } return false; } else { return false; } }
/// <summary> /// Translates typeToTranslate using the type arguments from parentType; /// </summary> static IReturnType TranslateIfRequired(IReturnType parentType, IReturnType typeToTranslate) { if (typeToTranslate == null) { return(null); } ConstructedReturnType parentConstructedType = parentType.CastToConstructedReturnType(); if (parentConstructedType != null) { return(ConstructedReturnType.TranslateType(typeToTranslate, parentConstructedType.TypeArguments, false)); } else { return(typeToTranslate); } }
/// <summary> /// Make exact inference from U for V. /// </summary> void MakeExactInference(IReturnType U, IReturnType V) { Log(" MakeExactInference from " + U + " for " + V); if (U == null || V == null) { return; } // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is an array type Ve[…] of the same rank // then an exact inference from Ue to Ve is made ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); if (arrU != null && arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions) { MakeExactInference(arrU.ArrayElementType, arrV.ArrayElementType); return; } // Otherwise if V is a constructed type C<V1…Vk> and U is a constructed // type C<U1…Uk> then an exact inference is made from each Ui to the corresponding Vi. ConstructedReturnType CU = U.CastToConstructedReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (CU != null && CV != null && object.Equals(CU.UnboundType, CV.UnboundType) && CU.TypeArgumentCount == CV.TypeArgumentCount && CU.TypeArguments.Count == CU.TypeArgumentCount && CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU.TypeArgumentCount; i++) { MakeExactInference(CU.TypeArguments[i], CV.TypeArguments[i]); } return; } }
internal static IMethod GetDelegateOrExpressionTreeSignature(IReturnType rt, bool allowExpressionTree) { if (rt == null) return null; IClass c = rt.GetUnderlyingClass(); if (allowExpressionTree && c != null && c.FullyQualifiedName == "System.Linq.Expressions.Expression") { ConstructedReturnType crt = rt.CastToConstructedReturnType(); if (crt != null && crt.TypeArguments.Count == 1) { // get delegate type from expression type rt = crt.TypeArguments[0]; c = rt != null ? rt.GetUnderlyingClass() : null; } } if (c != null && c.ClassType == ClassType.Delegate) { return rt.GetMethods().FirstOrDefault((IMethod m) => m.Name == "Invoke"); } return null; }
/// <summary> /// Gets the type parameter that was passed to a certain base class. /// For example, when <paramref name="returnType"/> is Dictionary(of string, int) /// this method will return KeyValuePair(of string, int) /// </summary> public static IReturnType GetTypeParameterPassedToBaseClass(IReturnType parentType, IClass baseClass, int baseClassTypeParameterIndex) { if (!parentType.IsConstructedReturnType) { return(null); } ConstructedReturnType returnType = parentType.CastToConstructedReturnType(); IClass c = returnType.GetUnderlyingClass(); if (c == null) { return(null); } if (baseClass.CompareTo(c) == 0) { if (baseClassTypeParameterIndex >= returnType.TypeArguments.Count) { return(null); } return(returnType.TypeArguments[baseClassTypeParameterIndex]); } foreach (IReturnType baseType in c.BaseTypes) { if (baseClass.CompareTo(baseType.GetUnderlyingClass()) == 0) { if (!baseType.IsConstructedReturnType) { return(null); } ConstructedReturnType baseTypeCRT = baseType.CastToConstructedReturnType(); if (baseClassTypeParameterIndex >= baseTypeCRT.TypeArguments.Count) { return(null); } IReturnType result = baseTypeCRT.TypeArguments[baseClassTypeParameterIndex]; if (returnType.TypeArguments != null) { result = ConstructedReturnType.TranslateType(result, returnType.TypeArguments, false); } return(result); } } return(null); }
public static IReturnType TranslateType(IReturnType input, IList <IReturnType> typeParameters, bool convertForMethod) { if (input == null || typeParameters == null || typeParameters.Count == 0) { return(input); // nothing to do when there are no type parameters specified } if (input.IsGenericReturnType) { GenericReturnType rt = input.CastToGenericReturnType(); if (convertForMethod ? (rt.TypeParameter.Method != null) : (rt.TypeParameter.Method == null)) { if (rt.TypeParameter.Index < typeParameters.Count) { IReturnType newType = typeParameters[rt.TypeParameter.Index]; if (newType != null) { return(newType); } } } } else if (input.IsArrayReturnType) { ArrayReturnType arInput = input.CastToArrayReturnType(); IReturnType e = arInput.ArrayElementType; IReturnType t = TranslateType(e, typeParameters, convertForMethod); if (e != t && t != null) { return(new ArrayReturnType(arInput.ProjectContent, t, arInput.ArrayDimensions)); } } else if (input.IsConstructedReturnType) { ConstructedReturnType cinput = input.CastToConstructedReturnType(); List <IReturnType> para = new List <IReturnType>(cinput.TypeArguments.Count); foreach (IReturnType argument in cinput.TypeArguments) { para.Add(TranslateType(argument, typeParameters, convertForMethod)); } return(new ConstructedReturnType(cinput.UnboundType, para)); } return(input); }
public static TypeReference ConvertType(IReturnType returnType, ClassFinder context) { if (returnType == null) { return(TypeReference.Null); } if (returnType is NullReturnType) { return(TypeReference.Null); } TypeReference typeRef; if (IsPrimitiveType(returnType)) { typeRef = new TypeReference(returnType.FullyQualifiedName, true); } else if (context != null && CanUseShortTypeName(returnType, context)) { typeRef = new TypeReference(returnType.Name); } else { typeRef = new TypeReference(returnType.FullyQualifiedName); } while (returnType.IsArrayReturnType) { int[] rank = typeRef.RankSpecifier ?? new int[0]; Array.Resize(ref rank, rank.Length + 1); rank[rank.Length - 1] = returnType.CastToArrayReturnType().ArrayDimensions - 1; typeRef.RankSpecifier = rank; returnType = returnType.CastToArrayReturnType().ArrayElementType; } if (returnType.IsConstructedReturnType) { foreach (IReturnType typeArgument in returnType.CastToConstructedReturnType().TypeArguments) { typeRef.GenericTypes.Add(ConvertType(typeArgument, context)); } } return(typeRef); }
public void AssemblyAttribute() { var attributes = GetAssemblyAttributes(typeof(TypeTestAttribute).Assembly); var typeTest = attributes.First(a => a.AttributeType.FullyQualifiedName == typeof(TypeTestAttribute).FullName); Assert.AreEqual(3, typeTest.PositionalArguments.Count); // first argument is (int)42 Assert.AreEqual(42, (int)typeTest.PositionalArguments[0]); // second argument is typeof(System.Action<>) IReturnType rt = (IReturnType)typeTest.PositionalArguments[1]; Assert.IsNull(rt.CastToConstructedReturnType()); // rt must not be constructed - it's just an unbound type Assert.AreEqual("System.Action", rt.FullyQualifiedName); Assert.AreEqual(1, rt.TypeArgumentCount); // third argument is typeof(IDictionary<string, IList<TestAttribute>>) ConstructedReturnType crt = ((IReturnType)typeTest.PositionalArguments[2]).CastToConstructedReturnType(); Assert.AreEqual("System.Collections.Generic.IDictionary", crt.FullyQualifiedName); Assert.AreEqual("System.String", crt.TypeArguments[0].FullyQualifiedName); Assert.AreEqual("System.Collections.Generic.IList{NUnit.Framework.TestAttribute}", crt.TypeArguments[1].DotNetName); }
/// <summary> /// Gets whether this type parameter occurs in the specified return type. /// </summary> public bool OccursIn(IReturnType rt) { ArrayReturnType art = rt.CastToArrayReturnType(); if (art != null) { return(OccursIn(art.ArrayElementType)); } ConstructedReturnType crt = rt.CastToConstructedReturnType(); if (crt != null) { return(crt.TypeArguments.Any(ta => OccursIn(ta))); } GenericReturnType grt = rt.CastToGenericReturnType(); if (grt != null) { return(this.TypeParameter.Equals(grt.TypeParameter)); } return(false); }
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) { IReturnType type = ResolveType(unaryOperatorExpression.Expression); if (type == null) { return(null); } switch (unaryOperatorExpression.Op) { case UnaryOperatorType.AddressOf: return(CreateResolveResult(new PointerReturnType(type))); case UnaryOperatorType.Dereference: PointerReturnType prt = type.CastToDecoratingReturnType <PointerReturnType>(); if (prt != null) { return(CreateResolveResult(prt.BaseType)); } else { return(null); } case UnaryOperatorType.Await: var crt = type.CastToConstructedReturnType(); if (crt != null && crt.Name == "Task" && crt.TypeArguments.Count == 1) { return(CreateResolveResult(crt.TypeArguments[0])); } else { return(null); } default: return(CreateResolveResult(type)); } }
internal static IMethod GetDelegateOrExpressionTreeSignature(IReturnType rt, bool allowExpressionTree) { if (rt == null) { return(null); } IClass c = rt.GetUnderlyingClass(); if (allowExpressionTree && c != null && c.FullyQualifiedName == "System.Linq.Expressions.Expression") { ConstructedReturnType crt = rt.CastToConstructedReturnType(); if (crt != null && crt.TypeArguments.Count == 1) { // get delegate type from expression type rt = crt.TypeArguments[0]; c = rt != null?rt.GetUnderlyingClass() : null; } } if (c != null && c.ClassType == ClassType.Delegate) { return(rt.GetMethods().FirstOrDefault((IMethod m) => m.Name == "Invoke")); } return(null); }
void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { builder.Append('('); int dimensions = returnType.CastToArrayReturnType().ArrayDimensions; for (int i = 1; i < dimensions; ++i) { builder.Append(','); } builder.Append(')'); UnpackNestedType(builder, returnType.CastToArrayReturnType().ArrayElementType); } else if (returnType.IsConstructedReturnType) { UnpackNestedType(builder, returnType.CastToConstructedReturnType().UnboundType); builder.Append("(Of "); IList<IReturnType> ta = returnType.CastToConstructedReturnType().TypeArguments; for (int i = 0; i < ta.Count; ++i) { if (i > 0) builder.Append(", "); builder.Append(Convert(ta[i])); } builder.Append(')'); } }
/// <summary> /// Make exact inference from U for V. /// </summary> void MakeExactInference(IReturnType U, IReturnType V) { Log(" MakeExactInference from " + U + " for " + V); if (U == null || V == null) return; // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is an array type Ve[…] of the same rank // then an exact inference from Ue to Ve is made ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); if (arrU != null && arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions) { MakeExactInference(arrU.ArrayElementType, arrV.ArrayElementType); return; } // Otherwise if V is a constructed type C<V1…Vk> and U is a constructed // type C<U1…Uk> then an exact inference is made from each Ui to the corresponding Vi. ConstructedReturnType CU = U.CastToConstructedReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (CU != null && CV != null && object.Equals(CU.UnboundType, CV.UnboundType) && CU.TypeArgumentCount == CV.TypeArgumentCount && CU.TypeArguments.Count == CU.TypeArgumentCount && CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU.TypeArgumentCount; i++) { MakeExactInference(CU.TypeArguments[i], CV.TypeArguments[i]); } return; } }
/// <summary> /// Make lower bound inference from U for V. /// </summary> void MakeLowerBoundInference(IReturnType U, IReturnType V) { Log(" MakeLowerBoundInference from " + U + " for " + V); if (U == null || V == null) { return; } // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is either an array type Ve[…]of the // same rank, or if U is a onedimensional array type Ue[]and V is one of // IEnumerable<Ve>, ICollection<Ve> or IList<Ve> then ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (arrU != null && (arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions || (arrU.ArrayDimensions == 1 && IsIEnumerableCollectionOrList(CV)))) { IReturnType Ue = arrU.ArrayElementType; IReturnType Ve = arrV != null ? arrV.ArrayElementType : CV.TypeArguments[0]; // If Ue is known to be a reference type then a lowerbound inference from Ue to Ve is made if (IsReferenceType(Ue) ?? false) { MakeLowerBoundInference(Ue, Ve); } else { // Otherwise an exact inference from Ue to Ve is made MakeExactInference(Ue, Ve); } return; } // Otherwise if V is a constructed type C<V1…Vk> and there is a unique set of // types U1…Uk such that a standard implicit conversion exists from U to C<U1…Uk> // then an exact inference is made from each Ui for the corresponding Vi. if (CV != null) { foreach (IReturnType U2 in MemberLookupHelper.GetTypeInheritanceTree(U)) { ConstructedReturnType CU2 = U2.CastToConstructedReturnType(); if (CU2 != null && object.Equals(CU2.UnboundType, CV.UnboundType) && CU2.TypeArgumentCount == CV.TypeArgumentCount && CU2.TypeArguments.Count == CU2.TypeArgumentCount && // unfortunately these might not be the same... CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU2.TypeArgumentCount; i++) { MakeExactInference(CU2.TypeArguments[i], CV.TypeArguments[i]); } return; } } } }
void AddExternalType(IReturnType rt, List<ClassNameTypeCountPair> externalTypes, int classCount) { if (rt.IsDefaultReturnType) { ClassNameTypeCountPair pair = new ClassNameTypeCountPair(rt); if (!classIndices.ContainsKey(pair)) { classIndices.Add(pair, externalTypes.Count + classCount); externalTypes.Add(pair); } } else if (rt.IsGenericReturnType) { // ignore } else if (rt.IsArrayReturnType) { AddExternalType(rt.CastToArrayReturnType().ArrayElementType, externalTypes, classCount); } else if (rt.IsConstructedReturnType) { AddExternalType(rt.CastToConstructedReturnType().UnboundType, externalTypes, classCount); foreach (IReturnType typeArgument in rt.CastToConstructedReturnType().TypeArguments) { AddExternalType(typeArgument, externalTypes, classCount); } } else if (rt.IsDecoratingReturnType<PointerReturnType>()) { AddExternalType(rt.CastToDecoratingReturnType<PointerReturnType>().BaseType, externalTypes, classCount); } else { LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
void WriteType(IReturnType rt) { if (rt == null) { writer.Write(NullRTReferenceCode); return; } if (rt.IsDefaultReturnType) { string name = rt.FullyQualifiedName; if (name == "System.Void") { writer.Write(VoidRTCode); } else { writer.Write(classIndices[new ClassNameTypeCountPair(rt)]); } } else if (rt.IsGenericReturnType) { GenericReturnType grt = rt.CastToGenericReturnType(); if (grt.TypeParameter.Method != null) { writer.Write(MethodGenericRTCode); } else { writer.Write(TypeGenericRTCode); } writer.Write(grt.TypeParameter.Index); } else if (rt.IsArrayReturnType) { writer.Write(ArrayRTCode); writer.Write(rt.CastToArrayReturnType().ArrayDimensions); WriteType(rt.CastToArrayReturnType().ArrayElementType); } else if (rt.IsConstructedReturnType) { ConstructedReturnType crt = rt.CastToConstructedReturnType(); writer.Write(ConstructedRTCode); WriteType(crt.UnboundType); writer.Write((byte)crt.TypeArguments.Count); foreach (IReturnType typeArgument in crt.TypeArguments) { WriteType(typeArgument); } } else if (rt.IsDecoratingReturnType<PointerReturnType>()) { writer.Write(PointerRTCode); WriteType(rt.CastToDecoratingReturnType<PointerReturnType>().BaseType); } else { writer.Write(NullRTReferenceCode); LoggingService.Warn("Unknown return type: " + rt.ToString()); } }
/// <summary> /// Checks if an implicit conversion exists from <paramref name="from"/> to <paramref name="to"/>. /// </summary> public static bool ConversionExists(IReturnType from, IReturnType to) { // ECMA-334, § 13.1 Implicit conversions // Identity conversion: if (from == to) { return(true); } if (from == null || to == null) { return(false); } if (from.Equals(to)) { return(true); } bool fromIsDefault = from.IsDefaultReturnType; bool toIsDefault = to.IsDefaultReturnType; if (fromIsDefault && toIsDefault) { // Implicit numeric conversions: int f = GetPrimitiveType(from); int t = GetPrimitiveType(to); if (f == SByte && (t == Short || t == Int || t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Byte && (t == Short || t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Short && (t == Int || t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == UShort && (t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Int && (t == Long || t == Float || t == Double || t == Decimal)) { return(true); } if (f == UInt && (t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if ((f == Long || f == ULong) && (t == Float || t == Double || t == Decimal)) { return(true); } if (f == Char && (t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) { return(true); } if (f == Float && t == Double) { return(true); } } // Implicit reference conversions: if (toIsDefault && to.FullyQualifiedName == "System.Object") { return(true); // from any type to object } if (toIsDefault && (fromIsDefault || from.IsArrayReturnType)) { IClass c1 = from.GetUnderlyingClass(); IClass c2 = to.GetUnderlyingClass(); if (c1 != null && c1.IsTypeInInheritanceTree(c2)) { return(true); } } if (from.IsArrayReturnType && to.IsArrayReturnType) { ArrayReturnType fromArt = from.CastToArrayReturnType(); ArrayReturnType toArt = to.CastToArrayReturnType(); // from array to other array type if (fromArt.ArrayDimensions == toArt.ArrayDimensions) { return(ConversionExists(fromArt.ArrayElementType, toArt.ArrayElementType)); } } if (from.IsConstructedReturnType && to.IsConstructedReturnType) { if (from.FullyQualifiedName == to.FullyQualifiedName) { IList <IReturnType> fromTypeArguments = from.CastToConstructedReturnType().TypeArguments; IList <IReturnType> toTypeArguments = to.CastToConstructedReturnType().TypeArguments; if (fromTypeArguments.Count == toTypeArguments.Count) { for (int i = 0; i < fromTypeArguments.Count; i++) { if (fromTypeArguments[i] == toTypeArguments[i]) { continue; } if (object.Equals(fromTypeArguments[i], toTypeArguments[i])) { continue; } if (!(toTypeArguments[i].IsGenericReturnType)) { return(false); } } return(true); } } } return(false); }
/// <summary> /// Checks if an implicit conversion exists from <paramref name="from"/> to <paramref name="to"/>. /// </summary> public static bool ConversionExists(IReturnType from, IReturnType to) { // ECMA-334, § 13.1 Implicit conversions // Identity conversion: if (from == to) return true; if (from == null || to == null) return false; if (from.Equals(to)) { return true; } bool fromIsDefault = from.IsDefaultReturnType; bool toIsDefault = to.IsDefaultReturnType; if (fromIsDefault && toIsDefault) { // Implicit numeric conversions: int f = GetPrimitiveType(from); int t = GetPrimitiveType(to); if (f == SByte && (t == Short || t == Int || t == Long || t == Float || t == Double || t == Decimal)) return true; if (f == Byte && (t == Short || t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if (f == Short && (t == Int || t == Long || t == Float || t == Double || t == Decimal)) return true; if (f == UShort && (t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if (f == Int && (t == Long || t == Float || t == Double || t == Decimal)) return true; if (f == UInt && (t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if ((f == Long || f == ULong) && (t == Float || t == Double || t == Decimal)) return true; if (f == Char && (t == UShort || t == Int || t == UInt || t == Long || t == ULong || t == Float || t == Double || t == Decimal)) return true; if (f == Float && t == Double) return true; } // Implicit reference conversions: if (toIsDefault && to.FullyQualifiedName == "System.Object") { return true; // from any type to object } if (toIsDefault && (fromIsDefault || from.IsArrayReturnType)) { IClass c1 = from.GetUnderlyingClass(); IClass c2 = to.GetUnderlyingClass(); if (c1 != null && c1.IsTypeInInheritanceTree(c2)) { return true; } } if (from.IsArrayReturnType && to.IsArrayReturnType) { ArrayReturnType fromArt = from.CastToArrayReturnType(); ArrayReturnType toArt = to.CastToArrayReturnType(); // from array to other array type if (fromArt.ArrayDimensions == toArt.ArrayDimensions) { return ConversionExists(fromArt.ArrayElementType, toArt.ArrayElementType); } } if (from.IsConstructedReturnType && to.IsConstructedReturnType) { if (from.FullyQualifiedName == to.FullyQualifiedName) { IList<IReturnType> fromTypeArguments = from.CastToConstructedReturnType().TypeArguments; IList<IReturnType> toTypeArguments = to.CastToConstructedReturnType().TypeArguments; if (fromTypeArguments.Count == toTypeArguments.Count) { for (int i = 0; i < fromTypeArguments.Count; i++) { if (fromTypeArguments[i] == toTypeArguments[i]) continue; if (object.Equals(fromTypeArguments[i], toTypeArguments[i])) continue; if (!(toTypeArguments[i].IsGenericReturnType)) return false; } return true; } } } return false; }
void UnpackNestedType(StringBuilder builder, IReturnType returnType) { if (returnType.IsArrayReturnType) { ArrayReturnType art = returnType.CastToArrayReturnType(); builder.Append('('); UnpackNestedType(builder, art.ArrayElementType); if (art.ArrayDimensions > 1) { builder.Append(','); builder.Append(art.ArrayDimensions); } builder.Append(')'); } else if (returnType.IsConstructedReturnType) { ConstructedReturnType crt = returnType.CastToConstructedReturnType(); UnpackNestedType(builder, crt.UnboundType); builder.Append("[of "); for (int i = 0; i < crt.TypeArguments.Count; ++i) { if (i > 0) builder.Append(", "); builder.Append(Convert(crt.TypeArguments[i])); } builder.Append(']'); } else { string fullName = returnType.FullyQualifiedName; if (fullName != null && typeConversionTable.ContainsKey(fullName)) { builder.Append(typeConversionTable[fullName].ToString()); } else { if (UseFullyQualifiedTypeNames) { builder.Append(fullName); } else { builder.Append(returnType.Name); } } } }
/// <summary> /// Infers type arguments specified by passing expectedArgument as parameter where passedArgument /// was expected. The resulting type arguments are written to outputArray. /// Returns false when expectedArgument and passedArgument are incompatible, otherwise true /// is returned (true is used both for successful inferring and other kind of errors). /// </summary> /// <remarks> /// The C# spec (§ 25.6.4) has a bug: it says that type inference works if the passedArgument is IEnumerable{T} /// and the expectedArgument is an array; passedArgument and expectedArgument must be swapped here. /// </remarks> public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray) { if (expectedArgument == null) { return(true); } if (passedArgument == null || passedArgument == NullReturnType.Instance) { return(true); } if (passedArgument.IsArrayReturnType) { IReturnType passedArrayElementType = passedArgument.CastToArrayReturnType().ArrayElementType; if (expectedArgument.IsArrayReturnType && expectedArgument.CastToArrayReturnType().ArrayDimensions == passedArgument.CastToArrayReturnType().ArrayDimensions) { return(InferTypeArgument(expectedArgument.CastToArrayReturnType().ArrayElementType, passedArrayElementType, outputArray)); } else if (expectedArgument.IsConstructedReturnType) { switch (expectedArgument.FullyQualifiedName) { case "System.Collections.Generic.IList": case "System.Collections.Generic.ICollection": case "System.Collections.Generic.IEnumerable": return(InferTypeArgument(expectedArgument.CastToConstructedReturnType().TypeArguments[0], passedArrayElementType, outputArray)); } } // If P is an array type, and A is not an array type of the same rank, // or an instantiation of IList<>, ICollection<>, or IEnumerable<>, then // type inference fails for the generic method. return(false); } if (expectedArgument.IsGenericReturnType) { GenericReturnType methodTP = expectedArgument.CastToGenericReturnType(); if (methodTP.TypeParameter.Method != null) { if (methodTP.TypeParameter.Index < outputArray.Length) { outputArray[methodTP.TypeParameter.Index] = passedArgument; } return(true); } } if (expectedArgument.IsConstructedReturnType) { // The spec for this case is quite complex. // For our purposes, we can simplify enourmously: if (!passedArgument.IsConstructedReturnType) { return(false); } IList <IReturnType> expectedTA = expectedArgument.CastToConstructedReturnType().TypeArguments; IList <IReturnType> passedTA = passedArgument.CastToConstructedReturnType().TypeArguments; int count = Math.Min(expectedTA.Count, passedTA.Count); for (int i = 0; i < count; i++) { InferTypeArgument(expectedTA[i], passedTA[i], outputArray); } } return(true); }
static int GetMoreSpecific(IReturnType r, IReturnType s) { if (r == null && s == null) return 0; if (r == null) return 2; if (s == null) return 1; if (r.IsGenericReturnType && !(s.IsGenericReturnType)) return 2; if (s.IsGenericReturnType && !(r.IsGenericReturnType)) return 1; if (r.IsArrayReturnType && s.IsArrayReturnType) return GetMoreSpecific(r.CastToArrayReturnType().ArrayElementType, s.CastToArrayReturnType().ArrayElementType); if (r.IsConstructedReturnType && s.IsConstructedReturnType) return GetMoreSpecific(r.CastToConstructedReturnType().TypeArguments, s.CastToConstructedReturnType().TypeArguments); return 0; }
public static TypeReference ConvertType(IReturnType returnType, ClassFinder context) { if (returnType == null) { return(TypeReference.Null); } if (returnType is NullReturnType) { return(TypeReference.Null); } ArrayReturnType arrayReturnType = returnType.CastToArrayReturnType(); if (arrayReturnType != null) { TypeReference typeRef = ConvertType(arrayReturnType.ArrayElementType, context); int[] rank = typeRef.RankSpecifier ?? new int[0]; Array.Resize(ref rank, rank.Length + 1); rank[rank.Length - 1] = arrayReturnType.ArrayDimensions - 1; typeRef.RankSpecifier = rank; return(typeRef); } PointerReturnType pointerReturnType = returnType.CastToDecoratingReturnType <PointerReturnType>(); if (pointerReturnType != null) { TypeReference typeRef = ConvertType(pointerReturnType.BaseType, context); typeRef.PointerNestingLevel++; return(typeRef); } IList <IReturnType> typeArguments = EmptyList <IReturnType> .Instance; if (returnType.IsConstructedReturnType) { typeArguments = returnType.CastToConstructedReturnType().TypeArguments; } IClass c = returnType.GetUnderlyingClass(); if (c != null) { return(CreateTypeReference(c, typeArguments, context)); } else { TypeReference typeRef; if (IsPrimitiveType(returnType)) { typeRef = new TypeReference(returnType.FullyQualifiedName, true); } else if (context != null && CanUseShortTypeName(returnType, context)) { typeRef = new TypeReference(returnType.Name); } else { string fullName = returnType.FullyQualifiedName; if (string.IsNullOrEmpty(fullName)) { fullName = returnType.Name; } typeRef = new TypeReference(fullName); } foreach (IReturnType typeArgument in typeArguments) { typeRef.GenericTypes.Add(ConvertType(typeArgument, context)); } return(typeRef); } }
/// <summary> /// Infers type arguments specified by passing expectedArgument as parameter where passedArgument /// was expected. The resulting type arguments are written to outputArray. /// Returns false when expectedArgument and passedArgument are incompatible, otherwise true /// is returned (true is used both for successful inferring and other kind of errors). /// </summary> public static bool InferTypeArgument(IReturnType expectedArgument, IReturnType passedArgument, IReturnType[] outputArray) { if (expectedArgument == null) return true; if (passedArgument == null) return true; // TODO: NullTypeReference if (expectedArgument.IsArrayReturnType) { IReturnType expectedArrayElementType = expectedArgument.CastToArrayReturnType().ArrayElementType; if (passedArgument.IsArrayReturnType && expectedArgument.CastToArrayReturnType().ArrayDimensions == passedArgument.CastToArrayReturnType().ArrayDimensions) { return InferTypeArgument(expectedArrayElementType, passedArgument.CastToArrayReturnType().ArrayElementType, outputArray); } else if (passedArgument.IsConstructedReturnType) { switch (passedArgument.FullyQualifiedName) { case "System.Collections.Generic.IList": case "System.Collections.Generic.ICollection": case "System.Collections.Generic.IEnumerable": return InferTypeArgument(expectedArrayElementType, passedArgument.CastToConstructedReturnType().TypeArguments[0], outputArray); } } // If P is an array type, and A is not an array type of the same rank, // or an instantiation of IList<>, ICollection<>, or IEnumerable<>, then // type inference fails for the generic method. return false; } if (expectedArgument.IsGenericReturnType) { GenericReturnType methodTP = expectedArgument.CastToGenericReturnType(); if (methodTP.TypeParameter.Method != null) { if (methodTP.TypeParameter.Index < outputArray.Length) { outputArray[methodTP.TypeParameter.Index] = passedArgument; } return true; } } if (expectedArgument.IsConstructedReturnType) { // The spec for this case is quite complex. // For our purposes, we can simplify enourmously: if (!passedArgument.IsConstructedReturnType) return false; IList<IReturnType> expectedTA = expectedArgument.CastToConstructedReturnType().TypeArguments; IList<IReturnType> passedTA = passedArgument.CastToConstructedReturnType().TypeArguments; int count = Math.Min(expectedTA.Count, passedTA.Count); for (int i = 0; i < count; i++) { InferTypeArgument(expectedTA[i], passedTA[i], outputArray); } } return true; }
public static IReturnType TranslateType(IReturnType input, IList<IReturnType> typeParameters, bool convertForMethod) { if (typeParameters == null || typeParameters.Count == 0) { return input; // nothing to do when there are no type parameters specified } if (input.IsGenericReturnType) { GenericReturnType rt = input.CastToGenericReturnType(); if (convertForMethod ? (rt.TypeParameter.Method != null) : (rt.TypeParameter.Method == null)) { if (rt.TypeParameter.Index < typeParameters.Count) { IReturnType newType = typeParameters[rt.TypeParameter.Index]; if (newType != null) { return newType; } } } } else if (input.IsArrayReturnType) { ArrayReturnType arInput = input.CastToArrayReturnType(); IReturnType e = arInput.ArrayElementType; IReturnType t = TranslateType(e, typeParameters, convertForMethod); if (e != t && t != null) return new ArrayReturnType(arInput.ProjectContent, t, arInput.ArrayDimensions); } else if (input.IsConstructedReturnType) { ConstructedReturnType cinput = input.CastToConstructedReturnType(); List<IReturnType> para = new List<IReturnType>(cinput.TypeArguments.Count); foreach (IReturnType argument in cinput.TypeArguments) { para.Add(TranslateType(argument, typeParameters, convertForMethod)); } return new ConstructedReturnType(cinput.UnboundType, para); } return input; }
/// <summary> /// Make lower bound inference from U for V. /// </summary> void MakeLowerBoundInference(IReturnType U, IReturnType V) { Log(" MakeLowerBoundInference from " + U + " for " + V); if (U == null || V == null) return; // If V is one of the unfixed Xi then U is added to the set of bounds for Xi. TP tp = GetTPForType(V); if (tp != null && tp.Fixed == false) { Log(" Add bound '" + U.DotNetName + "' to " + tp); tp.Bounds.Add(U); return; } // Otherwise if U is an array type Ue[…] and V is either an array type Ve[…]of the // same rank, or if U is a onedimensional array type Ue[]and V is one of // IEnumerable<Ve>, ICollection<Ve> or IList<Ve> then ArrayReturnType arrU = U.CastToArrayReturnType(); ArrayReturnType arrV = V.CastToArrayReturnType(); ConstructedReturnType CV = V.CastToConstructedReturnType(); if (arrU != null && (arrV != null && arrU.ArrayDimensions == arrV.ArrayDimensions || (arrU.ArrayDimensions == 1 && IsIEnumerableCollectionOrList(CV)))) { IReturnType Ue = arrU.ArrayElementType; IReturnType Ve = arrV != null ? arrV.ArrayElementType : CV.TypeArguments[0]; // If Ue is known to be a reference type then a lowerbound inference from Ue to Ve is made if (IsReferenceType(Ue) ?? false) { MakeLowerBoundInference(Ue, Ve); } else { // Otherwise an exact inference from Ue to Ve is made MakeExactInference(Ue, Ve); } return; } // Otherwise if V is a constructed type C<V1…Vk> and there is a unique set of // types U1…Uk such that a standard implicit conversion exists from U to C<U1…Uk> // then an exact inference is made from each Ui for the corresponding Vi. if (CV != null) { foreach (IReturnType U2 in MemberLookupHelper.GetTypeInheritanceTree(U)) { ConstructedReturnType CU2 = U2.CastToConstructedReturnType(); if (CU2 != null && object.Equals(CU2.UnboundType, CV.UnboundType) && CU2.TypeArgumentCount == CV.TypeArgumentCount && CU2.TypeArguments.Count == CU2.TypeArgumentCount // unfortunately these might not be the same... && CV.TypeArguments.Count == CV.TypeArgumentCount) { for (int i = 0; i < CU2.TypeArgumentCount; i++) { MakeExactInference(CU2.TypeArguments[i], CV.TypeArguments[i]); } return; } } } }
void AppendReturnType(StringBuilder builder, IReturnType returnType, bool forceFullyQualifiedName) { IReturnType arrayReturnType = returnType; returnType = GetElementType(returnType); if (returnType == null) return; string fullName = returnType.FullyQualifiedName; string shortName; bool isConstructedType = returnType.IsConstructedReturnType; if (fullName != null && !isConstructedType && TypeConversionTable.TryGetValue(fullName, out shortName)) { builder.Append(shortName); } else { IClass c = returnType.GetUnderlyingClass(); if (c != null) { IList<IReturnType> ta = isConstructedType ? returnType.CastToConstructedReturnType().TypeArguments : null; AppendClassNameWithTypeParameters(builder, c, forceFullyQualifiedName || UseFullyQualifiedTypeNames, false, ta); } else { if (UseFullyQualifiedTypeNames || forceFullyQualifiedName) { builder.Append(fullName); } else { builder.Append(returnType.Name); } if (isConstructedType) { builder.Append('<'); IList<IReturnType> ta = returnType.CastToConstructedReturnType().TypeArguments; for (int i = 0; i < ta.Count; ++i) { if (i > 0) builder.Append(", "); AppendReturnType(builder, ta[i], false); } builder.Append('>'); } } } UnpackArrayType(builder, arrayReturnType); }
/// <summary> /// Gets the type parameter that was passed to a certain base class. /// For example, when <paramref name="returnType"/> is Dictionary(of string, int) /// this method will return KeyValuePair(of string, int) /// </summary> public static IReturnType GetTypeParameterPassedToBaseClass(IReturnType parentType, IClass baseClass, int baseClassTypeParameterIndex) { if (!parentType.IsConstructedReturnType) return null; ConstructedReturnType returnType = parentType.CastToConstructedReturnType(); IClass c = returnType.GetUnderlyingClass(); if (c == null) return null; if (baseClass.CompareTo(c) == 0) { if (baseClassTypeParameterIndex >= returnType.TypeArguments.Count) return null; return returnType.TypeArguments[baseClassTypeParameterIndex]; } foreach (IReturnType baseType in c.BaseTypes) { if (baseClass.CompareTo(baseType.GetUnderlyingClass()) == 0) { if (!baseType.IsConstructedReturnType) return null; ConstructedReturnType baseTypeCRT = baseType.CastToConstructedReturnType(); if (baseClassTypeParameterIndex >= baseTypeCRT.TypeArguments.Count) return null; IReturnType result = baseTypeCRT.TypeArguments[baseClassTypeParameterIndex]; if (returnType.TypeArguments != null) { result = ConstructedReturnType.TranslateType(result, returnType.TypeArguments, false); } return result; } } return null; }