14 changed files with 776 additions and 346 deletions
@ -0,0 +1,332 @@
@@ -0,0 +1,332 @@
|
||||
// Copyright (c) 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 |
||||
{ |
||||
/// <summary>
|
||||
/// Base class for <see cref="ITypeParameter"/> implementations.
|
||||
/// </summary>
|
||||
[Serializable] |
||||
public abstract class AbstractTypeParameter : AbstractFreezable, ITypeParameter |
||||
{ |
||||
EntityType ownerType; |
||||
int index; |
||||
string name; |
||||
|
||||
IList<IAttribute> attributes; |
||||
DomRegion region; |
||||
VarianceModifier variance; |
||||
|
||||
protected override void FreezeInternal() |
||||
{ |
||||
attributes = FreezeList(attributes); |
||||
base.FreezeInternal(); |
||||
} |
||||
|
||||
protected AbstractTypeParameter(EntityType ownerType, int index, string name) |
||||
{ |
||||
if (!(ownerType == EntityType.TypeDefinition || ownerType == EntityType.Method)) |
||||
throw new ArgumentException("owner must be a type or a method", "ownerType"); |
||||
if (index < 0) |
||||
throw new ArgumentOutOfRangeException("index", index, "Value must not be negative"); |
||||
if (name == null) |
||||
throw new ArgumentNullException("name"); |
||||
this.ownerType = ownerType; |
||||
this.index = index; |
||||
this.name = name; |
||||
} |
||||
|
||||
public EntityType OwnerType { |
||||
get { return ownerType; } |
||||
} |
||||
|
||||
public int Index { |
||||
get { return index; } |
||||
} |
||||
|
||||
public TypeKind Kind { |
||||
get { return TypeKind.TypeParameter; } |
||||
} |
||||
|
||||
public string Name { |
||||
get { return name; } |
||||
} |
||||
|
||||
string INamedElement.FullName { |
||||
get { return name; } |
||||
} |
||||
|
||||
string INamedElement.Namespace { |
||||
get { return string.Empty; } |
||||
} |
||||
|
||||
public string ReflectionName { |
||||
get { |
||||
if (this.OwnerType == EntityType.Method) |
||||
return "``" + index.ToString(); |
||||
else |
||||
return "`" + index.ToString(); |
||||
} |
||||
} |
||||
|
||||
public abstract bool? IsReferenceType(ITypeResolveContext context); |
||||
|
||||
protected bool? IsReferenceTypeHelper(IType effectiveBaseClass) |
||||
{ |
||||
// A type parameter is known to be a reference type if it has the reference type constraint
|
||||
// or its effective base class is not object or System.ValueType.
|
||||
if (effectiveBaseClass.Kind == TypeKind.Class || effectiveBaseClass.Kind == TypeKind.Delegate) { |
||||
if (effectiveBaseClass.Namespace == "System" && effectiveBaseClass.TypeParameterCount == 0) { |
||||
switch (effectiveBaseClass.Name) { |
||||
case "Object": |
||||
case "ValueType": |
||||
case "Enum": |
||||
return null; |
||||
} |
||||
} |
||||
return true; |
||||
} else if (effectiveBaseClass.Kind == TypeKind.Struct || effectiveBaseClass.Kind == TypeKind.Enum) { |
||||
return false; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
int IType.TypeParameterCount { |
||||
get { return 0; } |
||||
} |
||||
|
||||
IType IType.DeclaringType { |
||||
get { return null; } |
||||
} |
||||
|
||||
ITypeDefinition IType.GetDefinition() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
IType ITypeReference.Resolve(ITypeResolveContext context) |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
public virtual bool Equals(IType other) |
||||
{ |
||||
// Use reference equality for type parameters. While we could consider any types with same
|
||||
// ownerType + index as equal for the type system, doing so makes it difficult to cache calculation
|
||||
// results based on types - e.g. the cache in the Conversions class.
|
||||
return this == other; |
||||
// We can still consider type parameters of different methods/classes to be equal to each other,
|
||||
// if they have been interned. But then also all constraints are equal, so caching conversions
|
||||
// are valid in that case.
|
||||
} |
||||
|
||||
public IList<IAttribute> Attributes { |
||||
get { |
||||
if (attributes == null) |
||||
attributes = new List<IAttribute>(); |
||||
return attributes; |
||||
} |
||||
} |
||||
|
||||
public VarianceModifier Variance { |
||||
get { return variance; } |
||||
set { |
||||
CheckBeforeMutation(); |
||||
variance = value; |
||||
} |
||||
} |
||||
|
||||
public DomRegion Region { |
||||
get { return region; } |
||||
set { |
||||
CheckBeforeMutation(); |
||||
region = value; |
||||
} |
||||
} |
||||
|
||||
public IType AcceptVisitor(TypeVisitor visitor) |
||||
{ |
||||
return visitor.VisitTypeParameter(this); |
||||
} |
||||
|
||||
public IType VisitChildren(TypeVisitor visitor) |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
static readonly SimpleProjectContent dummyProjectContent = new SimpleProjectContent(); |
||||
|
||||
DefaultTypeDefinition GetDummyClassForTypeParameter(ITypeParameterConstraints constraints) |
||||
{ |
||||
DefaultTypeDefinition c = new DefaultTypeDefinition(dummyProjectContent, string.Empty, this.Name); |
||||
c.Region = this.Region; |
||||
if (constraints.HasValueTypeConstraint) { |
||||
c.Kind = TypeKind.Struct; |
||||
} else if (constraints.HasDefaultConstructorConstraint) { |
||||
c.Kind = TypeKind.Class; |
||||
} else { |
||||
c.Kind = TypeKind.Interface; |
||||
} |
||||
return c; |
||||
} |
||||
|
||||
public IEnumerable<IMethod> GetConstructors(ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { |
||||
ITypeParameterConstraints constraints = GetConstraints(context); |
||||
if (constraints.HasDefaultConstructorConstraint || constraints.HasValueTypeConstraint) { |
||||
DefaultMethod m = DefaultMethod.CreateDefaultConstructor(GetDummyClassForTypeParameter(constraints)); |
||||
if (filter(m)) |
||||
return new [] { m }; |
||||
} |
||||
return EmptyList<IMethod>.Instance; |
||||
} else { |
||||
return GetMembersHelper.GetConstructors(this, context, filter, options); |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<IMethod> GetMethods(ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) |
||||
return EmptyList<IMethod>.Instance; |
||||
else |
||||
return GetMembersHelper.GetMethods(this, context, FilterNonStatic(filter), options); |
||||
} |
||||
|
||||
public IEnumerable<IMethod> GetMethods(IList<IType> typeArguments, ITypeResolveContext context, Predicate<IMethod> filter = null, GetMemberOptions options = GetMemberOptions.None) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) |
||||
return EmptyList<IMethod>.Instance; |
||||
else |
||||
return GetMembersHelper.GetMethods(this, typeArguments, context, FilterNonStatic(filter), options); |
||||
} |
||||
|
||||
public IEnumerable<IProperty> GetProperties(ITypeResolveContext context, Predicate<IProperty> filter = null, GetMemberOptions options = GetMemberOptions.None) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) |
||||
return EmptyList<IProperty>.Instance; |
||||
else |
||||
return GetMembersHelper.GetProperties(this, context, FilterNonStatic(filter), options); |
||||
} |
||||
|
||||
public IEnumerable<IField> GetFields(ITypeResolveContext context, Predicate<IField> filter = null, GetMemberOptions options = GetMemberOptions.None) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) |
||||
return EmptyList<IField>.Instance; |
||||
else |
||||
return GetMembersHelper.GetFields(this, context, FilterNonStatic(filter), options); |
||||
} |
||||
|
||||
public IEnumerable<IEvent> GetEvents(ITypeResolveContext context, Predicate<IEvent> filter = null, GetMemberOptions options = GetMemberOptions.None) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) |
||||
return EmptyList<IEvent>.Instance; |
||||
else |
||||
return GetMembersHelper.GetEvents(this, context, FilterNonStatic(filter), options); |
||||
} |
||||
|
||||
public IEnumerable<IMember> GetMembers(ITypeResolveContext context, Predicate<IMember> filter = null, GetMemberOptions options = GetMemberOptions.None) |
||||
{ |
||||
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) |
||||
return EmptyList<IMember>.Instance; |
||||
else |
||||
return GetMembersHelper.GetMembers(this, context, FilterNonStatic(filter), options); |
||||
} |
||||
|
||||
static Predicate<T> FilterNonStatic<T>(Predicate<T> filter) where T : class, IMember |
||||
{ |
||||
if (filter == null) |
||||
return member => !member.IsStatic; |
||||
else |
||||
return member => !member.IsStatic && filter(member); |
||||
} |
||||
|
||||
IEnumerable<IType> IType.GetNestedTypes(ITypeResolveContext context, Predicate<ITypeDefinition> filter, GetMemberOptions options) |
||||
{ |
||||
return EmptyList<IType>.Instance; |
||||
} |
||||
|
||||
IEnumerable<IType> IType.GetNestedTypes(IList<IType> typeArguments, ITypeResolveContext context, Predicate<ITypeDefinition> filter, GetMemberOptions options) |
||||
{ |
||||
return EmptyList<IType>.Instance; |
||||
} |
||||
|
||||
public abstract IType GetEffectiveBaseClass(ITypeResolveContext context); |
||||
|
||||
public abstract IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context); |
||||
|
||||
public abstract ITypeParameterConstraints GetConstraints(ITypeResolveContext context); |
||||
|
||||
public virtual IEnumerable<IType> GetBaseTypes(ITypeResolveContext context) |
||||
{ |
||||
ITypeParameterConstraints constraints = GetConstraints(context); |
||||
bool hasNonInterfaceConstraint = false; |
||||
foreach (IType c in constraints) { |
||||
yield return c; |
||||
if (c.Kind != TypeKind.Interface) |
||||
hasNonInterfaceConstraint = true; |
||||
} |
||||
// Do not add the 'System.Object' constraint if there is another constraint with a base class.
|
||||
if (constraints.HasValueTypeConstraint || !hasNonInterfaceConstraint) { |
||||
IType defaultBaseType = context.GetTypeDefinition("System", constraints.HasValueTypeConstraint ? "ValueType" : "Object", 0, StringComparer.Ordinal); |
||||
if (defaultBaseType != null) |
||||
yield return defaultBaseType; |
||||
} |
||||
} |
||||
|
||||
protected virtual void PrepareForInterning(IInterningProvider provider) |
||||
{ |
||||
name = provider.Intern(name); |
||||
attributes = provider.InternList(attributes); |
||||
} |
||||
|
||||
protected virtual int GetHashCodeForInterning() |
||||
{ |
||||
unchecked { |
||||
int hashCode = index + name.GetHashCode(); |
||||
if (ownerType == EntityType.Method) |
||||
hashCode += 7613561; |
||||
if (attributes != null) |
||||
hashCode += attributes.GetHashCode(); |
||||
hashCode += 900103 * (int)variance; |
||||
return hashCode; |
||||
} |
||||
} |
||||
|
||||
protected bool EqualsForInterning(AbstractTypeParameter other) |
||||
{ |
||||
return other != null |
||||
&& this.attributes == other.attributes |
||||
&& this.name == other.name |
||||
&& this.ownerType == other.ownerType |
||||
&& this.index == other.index |
||||
&& this.variance == other.variance; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return this.ReflectionName; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 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.Collections.ObjectModel; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.TypeSystem.Implementation |
||||
{ |
||||
/// <summary>
|
||||
/// Implementation of <see cref="ITypeParameterConstraints".
|
||||
/// </summary>
|
||||
public sealed class DefaultTypeParameterConstraints : ReadOnlyCollection<IType>, ITypeParameterConstraints |
||||
{ |
||||
public static readonly ITypeParameterConstraints Empty = new DefaultTypeParameterConstraints(new IType[0], false, false, false); |
||||
|
||||
public bool HasDefaultConstructorConstraint { get; private set; } |
||||
public bool HasReferenceTypeConstraint { get; private set; } |
||||
public bool HasValueTypeConstraint { get; private set; } |
||||
|
||||
public DefaultTypeParameterConstraints(IEnumerable<IType> constraints, bool hasDefaultConstructorConstraint, bool hasReferenceTypeConstraint, bool hasValueTypeConstraint) |
||||
: base(constraints.ToArray()) |
||||
{ |
||||
this.HasDefaultConstructorConstraint = hasDefaultConstructorConstraint; |
||||
this.HasReferenceTypeConstraint = hasReferenceTypeConstraint; |
||||
this.HasValueTypeConstraint = hasValueTypeConstraint; |
||||
} |
||||
|
||||
public ITypeParameterConstraints ApplySubstitution(TypeVisitor substitution) |
||||
{ |
||||
if (substitution == null) |
||||
throw new ArgumentNullException("substitution"); |
||||
if (this.Count == 0) |
||||
return this; |
||||
else |
||||
return new DefaultTypeParameterConstraints( |
||||
this.Select(c => c.AcceptVisitor(substitution)), |
||||
this.HasDefaultConstructorConstraint, this.HasReferenceTypeConstraint, this.HasValueTypeConstraint); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 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; |
||||
|
||||
namespace ICSharpCode.NRefactory.TypeSystem.Implementation |
||||
{ |
||||
/// <summary>
|
||||
/// Represents a type parameter that inherits its constraints from the overridden method in the base class.
|
||||
/// </summary>
|
||||
public sealed class TypeParameterWithInheritedConstraints : AbstractTypeParameter |
||||
{ |
||||
readonly IMethod parentMethod; |
||||
|
||||
public TypeParameterWithInheritedConstraints(IMethod parentMethod, int index, string name) |
||||
: base(EntityType.Method, index, name) |
||||
{ |
||||
if (parentMethod == null) |
||||
throw new ArgumentNullException("parentMethod"); |
||||
this.parentMethod = parentMethod; |
||||
} |
||||
|
||||
ITypeParameter ResolveBaseTypeParameter(ITypeResolveContext context) |
||||
{ |
||||
IMethod baseMethod = null; |
||||
if (parentMethod.IsOverride) { |
||||
foreach (IMethod m in InheritanceHelper.GetBaseMembers(parentMethod, context, false).OfType<IMethod>()) { |
||||
if (!m.IsOverride) { |
||||
baseMethod = m; |
||||
break; |
||||
} |
||||
} |
||||
} else if (parentMethod.InterfaceImplementations.Count == 1) { |
||||
IType interfaceType = parentMethod.InterfaceImplementations[0].InterfaceType.Resolve(context); |
||||
baseMethod = InheritanceHelper.GetMatchingMethodInBaseType(parentMethod, interfaceType, context); |
||||
} |
||||
if (baseMethod != null && this.Index < baseMethod.TypeParameters.Count) |
||||
return baseMethod.TypeParameters[this.Index]; |
||||
else |
||||
return null; |
||||
} |
||||
|
||||
public override bool? IsReferenceType(ITypeResolveContext context) |
||||
{ |
||||
ITypeParameter baseTp = ResolveBaseTypeParameter(context); |
||||
if (baseTp == null) |
||||
return null; |
||||
bool? result = baseTp.IsReferenceType(context); |
||||
if (result != null) |
||||
return result; |
||||
IType effectiveBaseClass = baseTp.GetEffectiveBaseClass(context); |
||||
return IsReferenceTypeHelper(effectiveBaseClass); |
||||
} |
||||
|
||||
public override IEnumerable<IType> GetEffectiveInterfaceSet(ITypeResolveContext context) |
||||
{ |
||||
ITypeParameter baseTp = ResolveBaseTypeParameter(context); |
||||
if (baseTp == null) |
||||
return EmptyList<IType>.Instance; |
||||
else |
||||
return baseTp.GetEffectiveInterfaceSet(context); |
||||
} |
||||
|
||||
public override IType GetEffectiveBaseClass(ITypeResolveContext context) |
||||
{ |
||||
ITypeParameter baseTp = ResolveBaseTypeParameter(context); |
||||
if (baseTp == null) |
||||
return SharedTypes.UnknownType; |
||||
else |
||||
return baseTp.GetEffectiveBaseClass(context); |
||||
} |
||||
|
||||
public override ITypeParameterConstraints GetConstraints(ITypeResolveContext context) |
||||
{ |
||||
ITypeParameter baseTp = ResolveBaseTypeParameter(context); |
||||
if (baseTp == null) |
||||
return DefaultTypeParameterConstraints.Empty; |
||||
else |
||||
return baseTp.GetConstraints(context); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,167 @@
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 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; |
||||
|
||||
namespace ICSharpCode.NRefactory.TypeSystem |
||||
{ |
||||
/// <summary>
|
||||
/// Provides helper methods for inheritance.
|
||||
/// </summary>
|
||||
public class InheritanceHelper |
||||
{ |
||||
// TODO: maybe these should be extension methods?
|
||||
|
||||
#region GetBaseMember
|
||||
/// <summary>
|
||||
/// Gets the base member that has the same signature.
|
||||
/// </summary>
|
||||
public static IMember GetBaseMember(IMember member, ITypeResolveContext context) |
||||
{ |
||||
return GetBaseMembers(member, context, false).FirstOrDefault(); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets all base members that have the same signature.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// List of base members with the same signature. The member from the derived-most base class is returned first.
|
||||
/// </returns>
|
||||
public static IEnumerable<IMember> GetBaseMembers(IMember member, ITypeResolveContext context, bool includeImplementedInterfaces) |
||||
{ |
||||
if (member == null) |
||||
throw new ArgumentNullException("member"); |
||||
if (context == null) |
||||
throw new ArgumentNullException("context"); |
||||
member = member.MemberDefinition; |
||||
IMethod method = member as IMethod; |
||||
IProperty property = member as IProperty; |
||||
IEvent ev = member as IEvent; |
||||
IField field = member as IField; |
||||
using (var ctx = context.Synchronize()) { |
||||
IEnumerable<IType> allBaseTypes; |
||||
if (includeImplementedInterfaces) { |
||||
allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes(ctx); |
||||
} else { |
||||
allBaseTypes = member.DeclaringTypeDefinition.GetNonInterfaceBaseTypes(ctx); |
||||
} |
||||
foreach (IType baseType in allBaseTypes.Reverse()) { |
||||
if (baseType == member.DeclaringTypeDefinition) |
||||
continue; |
||||
|
||||
if (method != null) { |
||||
IMethod baseMethod = GetMatchingMethodInBaseType(method, baseType, ctx); |
||||
if (baseMethod != null) |
||||
yield return baseMethod; |
||||
} |
||||
if (property != null) { |
||||
foreach (IProperty baseProperty in baseType.GetProperties( |
||||
ctx, p => p.Name == property.Name && p.Parameters.Count == property.Parameters.Count, |
||||
GetMemberOptions.IgnoreInheritedMembers)) |
||||
{ |
||||
if (ParameterListComparer.Compare(ctx, property, baseProperty)) |
||||
yield return baseProperty; |
||||
} |
||||
} |
||||
if (ev != null) { |
||||
IEvent baseEvent = baseType.GetEvents(ctx, e => e.Name == ev.Name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); |
||||
if (baseEvent != null) |
||||
yield return baseEvent; |
||||
} |
||||
// Fields can't be overridden, but we handle them anyways, just for consistence
|
||||
if (field != null) { |
||||
IField baseField = baseType.GetFields(ctx, f => f.Name == field.Name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); |
||||
if (baseField != null) |
||||
yield return baseField; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
internal static IMethod GetMatchingMethodInBaseType(IMethod method, IType baseType, ITypeResolveContext context) |
||||
{ |
||||
foreach (IMethod baseMethod in baseType.GetMethods( |
||||
context, m => m.Name == method.Name && m.Parameters.Count == method.Parameters.Count && m.TypeParameters.Count == method.TypeParameters.Count, |
||||
GetMemberOptions.IgnoreInheritedMembers)) |
||||
{ |
||||
if (ParameterListComparer.Compare(context, method, baseMethod)) |
||||
return baseMethod; |
||||
} |
||||
return null; |
||||
} |
||||
#endregion
|
||||
|
||||
#region GetDerivedMember
|
||||
/// <summary>
|
||||
/// Finds the member declared in 'derivedType' that has the same signature (could override) 'baseMember'.
|
||||
/// </summary>
|
||||
public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition derivedType, ITypeResolveContext context) |
||||
{ |
||||
if (baseMember == null) |
||||
throw new ArgumentNullException("baseMember"); |
||||
if (derivedType == null) |
||||
throw new ArgumentNullException("derivedType"); |
||||
if (context == null) |
||||
throw new ArgumentNullException("context"); |
||||
baseMember = baseMember.MemberDefinition; |
||||
bool includeInterfaces = baseMember.DeclaringTypeDefinition.Kind == TypeKind.Interface; |
||||
IMethod method = baseMember as IMethod; |
||||
if (method != null) { |
||||
using (var ctx = context.Synchronize()) { |
||||
foreach (IMethod derivedMethod in derivedType.Methods) { |
||||
if (derivedMethod.Name == method.Name && derivedMethod.Parameters.Count == method.Parameters.Count) { |
||||
if (derivedMethod.TypeParameters.Count == method.TypeParameters.Count) { |
||||
// The method could override the base method:
|
||||
if (GetBaseMembers(derivedMethod, ctx, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) |
||||
return derivedMethod; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
IProperty property = baseMember as IProperty; |
||||
if (property != null) { |
||||
using (var ctx = context.Synchronize()) { |
||||
foreach (IProperty derivedProperty in derivedType.Properties) { |
||||
if (derivedProperty.Name == property.Name && derivedProperty.Parameters.Count == property.Parameters.Count) { |
||||
// The property could override the base property:
|
||||
if (GetBaseMembers(derivedProperty, ctx, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) |
||||
return derivedProperty; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (baseMember is IEvent) { |
||||
foreach (IEvent derivedEvent in derivedType.Events) { |
||||
if (derivedEvent.Name == baseMember.Name) |
||||
return derivedEvent; |
||||
} |
||||
} |
||||
if (baseMember is IField) { |
||||
foreach (IField derivedField in derivedType.Fields) { |
||||
if (derivedField.Name == baseMember.Name) |
||||
return derivedField; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
||||
Loading…
Reference in new issue