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