// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.TypeSystem.Implementation { /// /// Provides helper methods for implementing GetMembers() on IType-implementations. /// Note: GetMembersHelper will recursively call back into IType.GetMembers(), but only with /// both GetMemberOptions.IgnoreInheritedMembers and GetMemberOptions.ReturnMemberDefinitions set, /// and only the 'simple' overloads (not taking type arguments). /// /// Ensure that your IType implementation does not use the GetMembersHelper if both flags are set, /// otherwise you'll get a StackOverflowException! /// static class GetMembersHelper { #region GetNestedTypes public static IEnumerable GetNestedTypes(IType type, Predicate filter, GetMemberOptions options) { return GetNestedTypes(type, null, filter, options); } public static IEnumerable GetNestedTypes(IType type, IList nestedTypeArguments, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetNestedTypesImpl(type, nestedTypeArguments, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetNestedTypesImpl(t, nestedTypeArguments, filter, options)); } } static IEnumerable GetNestedTypesImpl(IType outerType, IList nestedTypeArguments, Predicate filter, GetMemberOptions options) { ITypeDefinition outerTypeDef = outerType.GetDefinition(); if (outerTypeDef == null) yield break; int outerTypeParameterCount = outerTypeDef.TypeParameterCount; ParameterizedType pt = outerType as ParameterizedType; foreach (ITypeDefinition nestedType in outerTypeDef.NestedTypes) { int totalTypeParameterCount = nestedType.TypeParameterCount; if (nestedTypeArguments != null) { if (totalTypeParameterCount - outerTypeParameterCount != nestedTypeArguments.Count) continue; } if (!(filter == null || filter(nestedType))) continue; if (totalTypeParameterCount == 0 || (options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { yield return nestedType; } else { // We need to parameterize the nested type IType[] newTypeArguments = new IType[totalTypeParameterCount]; for (int i = 0; i < outerTypeParameterCount; i++) { newTypeArguments[i] = pt != null ? pt.GetTypeArgument(i) : outerTypeDef.TypeParameters[i]; } for (int i = outerTypeParameterCount; i < totalTypeParameterCount; i++) { if (nestedTypeArguments != null) newTypeArguments[i] = nestedTypeArguments[i - outerTypeParameterCount]; else newTypeArguments[i] = SpecialType.UnboundTypeArgument; } yield return new ParameterizedType(nestedType, newTypeArguments); } } } #endregion #region GetMethods public static IEnumerable GetMethods(IType type, Predicate filter, GetMemberOptions options) { return GetMethods(type, null, filter, options); } public static IEnumerable GetMethods(IType type, IList typeArguments, Predicate filter, GetMemberOptions options) { if (typeArguments != null && typeArguments.Count > 0) { filter = FilterTypeParameterCount(typeArguments.Count).And(filter); } if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetMethodsImpl(type, typeArguments, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetMethodsImpl(t, typeArguments, filter, options)); } } static Predicate FilterTypeParameterCount(int expectedTypeParameterCount) { return m => m.TypeParameters.Count == expectedTypeParameterCount; } const GetMemberOptions declaredMembers = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; static IEnumerable GetMethodsImpl(IType baseType, IList methodTypeArguments, Predicate filter, GetMemberOptions options) { IEnumerable declaredMethods = baseType.GetMethods(filter, options | declaredMembers); ParameterizedType pt = baseType as ParameterizedType; if ((options & GetMemberOptions.ReturnMemberDefinitions) == 0 && (pt != null || (methodTypeArguments != null && methodTypeArguments.Count > 0))) { TypeParameterSubstitution substitution = null; foreach (IMethod m in declaredMethods) { if (methodTypeArguments != null && methodTypeArguments.Count > 0) { if (m.TypeParameters.Count != methodTypeArguments.Count) continue; } if (substitution == null) { if (pt != null) substitution = pt.GetSubstitution(methodTypeArguments); else substitution = new TypeParameterSubstitution(null, methodTypeArguments); } yield return new SpecializedMethod(m, substitution); } } else { foreach (IMethod m in declaredMethods) { yield return m; } } } #endregion #region GetAccessors public static IEnumerable GetAccessors(IType type, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetAccessorsImpl(type, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetAccessorsImpl(t, filter, options)); } } static IEnumerable GetAccessorsImpl(IType baseType, Predicate filter, GetMemberOptions options) { return GetConstructorsOrAccessorsImpl(baseType, baseType.GetAccessors(filter, options | declaredMembers), filter, options); } #endregion #region GetConstructors public static IEnumerable GetConstructors(IType type, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetConstructorsImpl(type, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetConstructorsImpl(t, filter, options)); } } static IEnumerable GetConstructorsImpl(IType baseType, Predicate filter, GetMemberOptions options) { return GetConstructorsOrAccessorsImpl(baseType, baseType.GetConstructors(filter, options | declaredMembers), filter, options); } static IEnumerable GetConstructorsOrAccessorsImpl(IType baseType, IEnumerable declaredMembers, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { return declaredMembers; } ParameterizedType pt = baseType as ParameterizedType; if (pt != null) { var substitution = pt.GetSubstitution(); return declaredMembers.Select(m => new SpecializedMethod(m, substitution) { DeclaringType = pt }); } else { return declaredMembers; } } #endregion #region GetProperties public static IEnumerable GetProperties(IType type, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetPropertiesImpl(type, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetPropertiesImpl(t, filter, options)); } } static IEnumerable GetPropertiesImpl(IType baseType, Predicate filter, GetMemberOptions options) { IEnumerable declaredProperties = baseType.GetProperties(filter, options | declaredMembers); if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { return declaredProperties; } ParameterizedType pt = baseType as ParameterizedType; if (pt != null) { var substitution = pt.GetSubstitution(); return declaredProperties.Select(m => new SpecializedProperty(m, substitution) { DeclaringType = pt }); } else { return declaredProperties; } } #endregion #region GetFields public static IEnumerable GetFields(IType type, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetFieldsImpl(type, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetFieldsImpl(t, filter, options)); } } static IEnumerable GetFieldsImpl(IType baseType, Predicate filter, GetMemberOptions options) { IEnumerable declaredFields = baseType.GetFields(filter, options | declaredMembers); if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { return declaredFields; } ParameterizedType pt = baseType as ParameterizedType; if (pt != null) { var substitution = pt.GetSubstitution(); return declaredFields.Select(m => new SpecializedField(m, substitution) { DeclaringType = pt }); } else { return declaredFields; } } #endregion #region GetEvents public static IEnumerable GetEvents(IType type, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetEventsImpl(type, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetEventsImpl(t, filter, options)); } } static IEnumerable GetEventsImpl(IType baseType, Predicate filter, GetMemberOptions options) { IEnumerable declaredEvents = baseType.GetEvents(filter, options | declaredMembers); if ((options & GetMemberOptions.ReturnMemberDefinitions) == GetMemberOptions.ReturnMemberDefinitions) { return declaredEvents; } ParameterizedType pt = baseType as ParameterizedType; if (pt != null) { var substitution = pt.GetSubstitution(); return declaredEvents.Select(m => new SpecializedEvent(m, substitution) { DeclaringType = pt }); } else { return declaredEvents; } } #endregion #region GetMembers public static IEnumerable GetMembers(IType type, Predicate filter, GetMemberOptions options) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { return GetMembersImpl(type, filter, options); } else { return type.GetNonInterfaceBaseTypes().SelectMany(t => GetMembersImpl(t, filter, options)); } } static IEnumerable GetMembersImpl(IType baseType, Predicate filter, GetMemberOptions options) { foreach (var m in GetMethodsImpl(baseType, null, filter, options)) yield return m; foreach (var m in GetPropertiesImpl(baseType, filter, options)) yield return m; foreach (var m in GetFieldsImpl(baseType, filter, options)) yield return m; foreach (var m in GetEventsImpl(baseType, filter, options)) yield return m; } #endregion } }