public SpecializedMethod(IMethod methodDefinition, TypeParameterSubstitution substitution) : base(methodDefinition) { SpecializedMethod specializedMethodDefinition = methodDefinition as SpecializedMethod; if (specializedMethodDefinition != null) { this.genericMethodIsSpecialized = specializedMethodDefinition.genericMethodIsSpecialized; } // The base ctor might have unpacked a SpecializedMember // (in case we are specializing an already-specialized method) methodDefinition = (IMethod)base.baseMember; this.methodDefinition = methodDefinition; if (methodDefinition.TypeParameters.Count > 0) { // The method is generic, so we need to specialize the type parameters // (for specializing the constraints, and also to set the correct Owner) specializedTypeParameters = new ITypeParameter[methodDefinition.TypeParameters.Count]; for (int i = 0; i < specializedTypeParameters.Length; i++) { specializedTypeParameters[i] = new SpecializedTypeParameter(methodDefinition.TypeParameters[i], this); } if (!genericMethodIsSpecialized) { // Add substitution that replaces the base method's type parameters with our specialized version // but do this only if the type parameters on the baseMember have not already been substituted substitutionWithoutSpecializedTypeParameters = this.Substitution; AddSubstitution(new TypeParameterSubstitution(null, specializedTypeParameters)); } } // Add the main substitution after the method type parameter specialization. AddSubstitution(substitution); if (substitutionWithoutSpecializedTypeParameters != null) { // If we already have a substitution without specialized type parameters, update that: substitutionWithoutSpecializedTypeParameters = TypeParameterSubstitution.Compose(substitution, substitutionWithoutSpecializedTypeParameters); } else { // Otherwise just use the whole substitution, as that doesn't contain specialized type parameters // in this case. substitutionWithoutSpecializedTypeParameters = this.Substitution; } if (substitution != null && substitution.MethodTypeArguments != null && methodDefinition.TypeParameters.Count > 0) { this.genericMethodIsSpecialized = true; } if (specializedTypeParameters != null) { // Set the substitution on the type parameters to the final composed substitution foreach (var tp in specializedTypeParameters.OfType <SpecializedTypeParameter>()) { if (tp.Owner == this) { tp.substitution = base.Substitution; } } } }
public override bool Equals(object obj) { SpecializedMethod other = obj as SpecializedMethod; if (other == null) { return(false); } return(object.Equals(this.memberDefinition, other.memberDefinition) && object.Equals(this.declaringType, other.declaringType)); }
public override bool Equals(object obj) { SpecializedMethod other = obj as SpecializedMethod; if (other == null) { return(false); } return(this.baseMember.Equals(other.baseMember) && this.substitutionWithoutSpecializedTypeParameters.Equals(other.substitutionWithoutSpecializedTypeParameters)); }
internal IMethod WrapAccessor(ref IMethod cachingField, IMethod accessorDefinition) { if (accessorDefinition == null) { return(null); } var result = LazyInit.VolatileRead(ref cachingField); if (result != null) { return(result); } else { var sm = new SpecializedMethod(accessorDefinition, substitution); //sm.AccessorOwner = this; return(LazyInit.GetOrSet(ref cachingField, sm)); } }
public IEnumerable <IMethod> GetConstructors(Predicate <IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) { if (filter == null || filter(dummyConstructor)) { var resolvedCtor = (IMethod)dummyConstructor.CreateResolved(compilation.TypeResolveContext); IMethod m = new SpecializedMethod(this, resolvedCtor, EmptyList <IType> .Instance); return(new [] { m }); } } return(EmptyList <IMethod> .Instance); } else { return(GetMembersHelper.GetConstructors(this, filter, options)); } }
public override bool Equals(object obj) { SpecializedMethod other = obj as SpecializedMethod; if (!base.Equals(other)) { return(false); } if (typeArguments.Count != other.typeArguments.Count) { return(false); } for (int i = 0; i < typeArguments.Count; i++) { if (!typeArguments[i].Equals(other.typeArguments[i])) { return(false); } } return(true); }
public IEnumerable <IMethod> GetConstructors(Predicate <IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) { if (filter == null || filter(dummyConstructor)) { var resolvedCtor = GetDummyConstructor(compilation); IMethod m = new SpecializedMethod(resolvedCtor, TypeParameterSubstitution.Identity) { DeclaringType = this }; return(new [] { m }); } } return(EmptyList <IMethod> .Instance); } else { return(GetMembersHelper.GetConstructors(this, filter, options)); } }
/// <summary> /// Gets the extension methods that are called 'name' /// and are applicable with a first argument type of 'targetType'. /// </summary> /// <param name="targetType">Type of the 'this' argument</param> /// <param name="name">Name of the extension method</param> /// <param name="typeArguments">Explicitly provided type arguments. /// An empty list will return all matching extension method definitions; /// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods /// with the matching number of type parameters.</param> /// <remarks> /// The results are stored in nested lists because they are grouped by using scope. /// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }", /// the return value will be /// new List { /// new List { all extensions from MoreExtensions }, /// new List { all extensions from SomeExtensions } /// } /// </remarks> public List<List<IMethod>> GetExtensionMethods(IType targetType, string name, IList<IType> typeArguments = null) { List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>(); foreach (var inputGroup in GetAllExtensionMethods()) { List<IMethod> outputGroup = new List<IMethod>(); foreach (var method in inputGroup) { if (method.Name != name) continue; if (typeArguments != null && typeArguments.Count > 0) { if (method.TypeParameters.Count != typeArguments.Count) continue; SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments); // TODO: verify targetType outputGroup.Add(sm); } else { // TODO: verify targetType outputGroup.Add(method); } } if (outputGroup.Count > 0) extensionMethodGroups.Add(outputGroup); } return extensionMethodGroups; }
public void GetIndexDoubleSpecialization() { var testClass = GetTypeDefinition(typeof(GenericClass<,>)); // GenericClass<A, B>.GetIndex<T> var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex"); // GenericClass<B, A>.GetIndex<A> var m1 = new SpecializedMethod(methodDef, new TypeParameterSubstitution( new[] { testClass.TypeParameters[1], testClass.TypeParameters[0] }, new[] { testClass.TypeParameters[0] } )); // GenericClass<string, int>.GetIndex<int> var m2 = new SpecializedMethod(m1, new TypeParameterSubstitution( new[] { compilation.FindType(KnownTypeCode.Int32), compilation.FindType(KnownTypeCode.String) }, null )); // GenericClass<string, int>.GetIndex<int> var m12 = new SpecializedMethod(methodDef, new TypeParameterSubstitution( new[] { compilation.FindType(KnownTypeCode.String), compilation.FindType(KnownTypeCode.Int32) }, new[] { compilation.FindType(KnownTypeCode.Int32) } )); Assert.AreEqual(m12, m2); }
public void GetIndexSpecializedTypeParameter() { var testClass = GetTypeDefinition(typeof(GenericClass<,>)); var methodDef = testClass.Methods.Single(me => me.Name == "GetIndex"); var m = new SpecializedMethod(methodDef, new TypeParameterSubstitution( new[] { compilation.FindType(KnownTypeCode.Int16), compilation.FindType(KnownTypeCode.Int32) }, null )); Assert.AreEqual("T", m.TypeParameters[0].Name); Assert.AreEqual(EntityType.Method, m.TypeParameters[0].OwnerType); Assert.AreSame(m, m.TypeParameters[0].Owner); ParameterizedType constraint = (ParameterizedType)m.TypeParameters[0].DirectBaseTypes.First(); Assert.AreEqual("IEquatable", constraint.Name); Assert.AreEqual(1, constraint.TypeParameterCount); Assert.AreEqual(1, constraint.TypeArguments.Count); Assert.AreSame(m.TypeParameters[0], constraint.TypeArguments[0]); }
IMember Specialize(IMember member, Func<ITypeReference, ITypeReference> substitution) { IMethod method = member as IMethod; if (method != null) { SpecializedMethod m = new SpecializedMethod(method); m.SetDeclaringType(this); m.SubstituteTypes(substitution); return m; } IProperty property = member as IProperty; if (property != null) { SpecializedProperty p = new SpecializedProperty(property); p.SetDeclaringType(this); p.SubstituteTypes(substitution); return p; } IField field = member as IField; if (field != null) { SpecializedField f = new SpecializedField(field); f.SetDeclaringType(this); f.ReturnType = substitution(f.ReturnType); return f; } IEvent ev = member as IEvent; if (ev != null) { SpecializedEvent e = new SpecializedEvent(ev); e.SetDeclaringType(this); e.ReturnType = substitution(e.ReturnType); return e; } throw new ArgumentException("Unknown member"); }
/// <summary> /// Gets the extension methods that are called 'name' /// and are applicable with a first argument type of 'targetType'. /// </summary> /// <param name="targetType">Type of the 'this' argument</param> /// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param> /// <param name="typeArguments">Explicitly provided type arguments. /// An empty list will return all matching extension method definitions; /// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods /// with the matching number of type parameters.</param> /// <param name="substituteInferredTypes"> /// Specifies whether to produce a <see cref="SpecializedMethod"/> /// when type arguments could be inferred from <paramref name="targetType"/>. This parameter /// is only used for inferred types and has no effect if <paramref name="typeArguments"/> is non-empty. /// </param> /// <remarks> /// The results are stored in nested lists because they are grouped by using scope. /// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }", /// the return value will be /// new List { /// new List { all extensions from MoreExtensions }, /// new List { all extensions from SomeExtensions } /// } /// </remarks> public List<List<IMethod>> GetExtensionMethods(IType targetType, string name = null, IList<IType> typeArguments = null, bool substituteInferredTypes = false) { List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>(); foreach (var inputGroup in GetAllExtensionMethods()) { List<IMethod> outputGroup = new List<IMethod>(); foreach (var method in inputGroup) { if (name != null && method.Name != name) continue; IType[] inferredTypes; if (typeArguments != null && typeArguments.Count > 0) { if (method.TypeParameters.Count != typeArguments.Count) continue; SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments); if (IsEligibleExtensionMethod(targetType, method, false, out inferredTypes)) outputGroup.Add(sm); } else { if (IsEligibleExtensionMethod(targetType, method, true, out inferredTypes)) { if (substituteInferredTypes && inferredTypes != null) { outputGroup.Add(new SpecializedMethod(method.DeclaringType, method, inferredTypes)); } else { outputGroup.Add(method); } } } } if (outputGroup.Count > 0) extensionMethodGroups.Add(outputGroup); } return extensionMethodGroups; }
public static IMethod CreateTypeCheckMethod(IType type, ICompilation compilation) { IMethod method = new DefaultResolvedMethod(new DefaultUnresolvedMethod(type.GetDefinition().Parts[0], "IsInstanceOfType"), compilation.TypeResolveContext.WithCurrentTypeDefinition(type.GetDefinition())); if (type is ParameterizedType) method = new SpecializedMethod(method, new TypeParameterSubstitution(classTypeArguments: ((ParameterizedType)type).TypeArguments, methodTypeArguments: null)); return method; }
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null) { Substitution substitution = new Substitution(typeArguments); Func<ITypeReference, ITypeReference> substitutionFunc = t => t.Resolve(context).AcceptVisitor(substitution); List<IMethod> methods = genericType.GetConstructors(context, filter).ToList(); for (int i = 0; i < methods.Count; i++) { SpecializedMethod m = new SpecializedMethod(methods[i]); m.SetDeclaringType(this); m.SubstituteTypes(substitutionFunc); methods[i] = m; } return methods; }
public static IMethod CreateDummyMethodForFieldInitialization(IMember member, ICompilation compilation) { var unresolved = new DefaultUnresolvedMethod(member.DeclaringTypeDefinition.Parts[0], "initialization for " + member.Name) { Parameters = { new DefaultUnresolvedParameter(member.ReturnType.ToTypeReference(), "value") }, IsStatic = member.IsStatic, }; IMethod method = new DefaultResolvedMethod(unresolved, compilation.TypeResolveContext.WithCurrentTypeDefinition(member.DeclaringTypeDefinition)); if (member.DeclaringType is ParameterizedType) method = new SpecializedMethod(method, new TypeParameterSubstitution(classTypeArguments: ((ParameterizedType)member.DeclaringType).TypeArguments, methodTypeArguments: null)); return method; }
public void Specialized_GetIndex_SpecializeWithIdentityHasNoEffect() { var genericClass = compilation.FindType(typeof(GenericClass<string, object>)); IType[] methodTypeArguments = { DummyTypeParameter.GetMethodTypeParameter(0) }; var method = (SpecializedMethod)genericClass.GetMethods(methodTypeArguments, m => m.Name == "GetIndex").Single(); // GenericClass<string,object>.GetIndex<!!0>() Assert.AreSame(method, method.TypeParameters[0].Owner); Assert.AreNotEqual(method.TypeParameters[0], method.TypeArguments[0]); Assert.IsNull(((ITypeParameter)method.TypeArguments[0]).Owner); // Now apply identity substitution: var method2 = new SpecializedMethod(method, TypeParameterSubstitution.Identity); Assert.AreSame(method2, method2.TypeParameters[0].Owner); Assert.AreNotEqual(method2.TypeParameters[0], method2.TypeArguments[0]); Assert.IsNull(((ITypeParameter)method2.TypeArguments[0]).Owner); Assert.AreEqual(method, method2); }
internal IMethod WrapAccessor(ref IMethod cachingField, IMethod accessorDefinition) { if (accessorDefinition == null) return null; var result = LazyInit.VolatileRead(ref cachingField); if (result != null) { return result; } else { var sm = new SpecializedMethod(accessorDefinition, substitution); //sm.AccessorOwner = this; return LazyInit.GetOrSet(ref cachingField, sm); } }
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null) { Substitution substitution = new Substitution(typeArguments); List<IMethod> methods = genericType.GetMethods(context, filter).ToList(); for (int i = 0; i < methods.Count; i++) { SpecializedMethod m = new SpecializedMethod(methods[i]); m.SetDeclaringType(this); m.SubstituteTypes(context, substitution); methods[i] = m; } return methods; }