mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
7.9 KiB
251 lines
7.9 KiB
// 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; |
|
|
|
#nullable enable |
|
|
|
namespace ICSharpCode.Decompiler.TypeSystem |
|
{ |
|
/// <summary> |
|
/// Provides helper methods for inheritance. |
|
/// </summary> |
|
public static class InheritanceHelper |
|
{ |
|
// TODO: maybe these should be extension methods? |
|
// or even part of the interface itself? (would allow for easy caching) |
|
|
|
#region GetBaseMember |
|
/// <summary> |
|
/// Gets the base member that has the same signature. |
|
/// </summary> |
|
public static IMember? GetBaseMember(IMember member) |
|
{ |
|
return GetBaseMembers(member, 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, bool includeImplementedInterfaces) |
|
{ |
|
if (member == null) |
|
throw new ArgumentNullException(nameof(member)); |
|
|
|
if (includeImplementedInterfaces) |
|
{ |
|
if (member.IsExplicitInterfaceImplementation && member.ExplicitlyImplementedInterfaceMembers.Count() == 1) |
|
{ |
|
// C#-style explicit interface implementation |
|
member = member.ExplicitlyImplementedInterfaceMembers.First(); |
|
yield return member; |
|
} |
|
} |
|
|
|
// Remove generic specialization |
|
var substitution = member.Substitution; |
|
member = member.MemberDefinition; |
|
|
|
if (member.DeclaringTypeDefinition == null) |
|
{ |
|
// For global methods, return empty list. (prevent SharpDevelop UDC crash 4524) |
|
yield break; |
|
} |
|
|
|
IEnumerable<IType> allBaseTypes; |
|
if (includeImplementedInterfaces) |
|
{ |
|
allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes(); |
|
} |
|
else |
|
{ |
|
allBaseTypes = member.DeclaringTypeDefinition.GetNonInterfaceBaseTypes(); |
|
} |
|
foreach (IType baseType in allBaseTypes.Reverse()) |
|
{ |
|
if (baseType == member.DeclaringTypeDefinition) |
|
continue; |
|
|
|
IEnumerable<IMember> baseMembers; |
|
if (member.SymbolKind == SymbolKind.Accessor) |
|
{ |
|
baseMembers = baseType.GetAccessors(m => m.Name == member.Name && m.Accessibility > Accessibility.Private, GetMemberOptions.IgnoreInheritedMembers); |
|
} |
|
else |
|
{ |
|
baseMembers = baseType.GetMembers(m => m.Name == member.Name && m.Accessibility > Accessibility.Private, GetMemberOptions.IgnoreInheritedMembers); |
|
} |
|
foreach (IMember baseMember in baseMembers) |
|
{ |
|
System.Diagnostics.Debug.Assert(baseMember.Accessibility != Accessibility.Private); |
|
if (SignatureComparer.Ordinal.Equals(member, baseMember)) |
|
{ |
|
yield return baseMember.Specialize(substitution); |
|
} |
|
} |
|
} |
|
} |
|
#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) |
|
{ |
|
if (baseMember == null) |
|
throw new ArgumentNullException(nameof(baseMember)); |
|
if (derivedType == null) |
|
throw new ArgumentNullException(nameof(derivedType)); |
|
|
|
if (baseMember.Compilation != derivedType.Compilation) |
|
throw new ArgumentException("baseMember and derivedType must be from the same compilation"); |
|
|
|
baseMember = baseMember.MemberDefinition; |
|
bool includeInterfaces = baseMember.DeclaringTypeDefinition?.Kind == TypeKind.Interface; |
|
if (baseMember is IMethod method) |
|
{ |
|
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, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) |
|
return derivedMethod; |
|
} |
|
} |
|
} |
|
} |
|
if (baseMember is IProperty property) |
|
{ |
|
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, 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 |
|
|
|
#region Attributes |
|
internal static IEnumerable<IAttribute> GetAttributes(ITypeDefinition typeDef) |
|
{ |
|
foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse()) |
|
{ |
|
ITypeDefinition? baseTypeDef = baseType.GetDefinition(); |
|
if (baseTypeDef == null) |
|
continue; |
|
foreach (var attr in baseTypeDef.GetAttributes()) |
|
{ |
|
yield return attr; |
|
} |
|
} |
|
} |
|
|
|
internal static IAttribute? GetAttribute(ITypeDefinition typeDef, KnownAttribute attributeType) |
|
{ |
|
foreach (var baseType in typeDef.GetNonInterfaceBaseTypes().Reverse()) |
|
{ |
|
ITypeDefinition? baseTypeDef = baseType.GetDefinition(); |
|
if (baseTypeDef == null) |
|
continue; |
|
var attr = baseTypeDef.GetAttribute(attributeType); |
|
if (attr != null) |
|
return attr; |
|
} |
|
return null; |
|
} |
|
|
|
internal static IEnumerable<IAttribute> GetAttributes(IMember member) |
|
{ |
|
HashSet<IMember> visitedMembers = new HashSet<IMember>(); |
|
while (true) |
|
{ |
|
member = member.MemberDefinition; // it's sufficient to look at the definitions |
|
if (!visitedMembers.Add(member)) |
|
{ |
|
// abort if we seem to be in an infinite loop (cyclic inheritance) |
|
break; |
|
} |
|
foreach (var attr in member.GetAttributes()) |
|
{ |
|
yield return attr; |
|
} |
|
if (!member.IsOverride) |
|
break; |
|
var baseMember = GetBaseMember(member); |
|
if (baseMember == null) |
|
break; |
|
member = baseMember; |
|
} |
|
} |
|
|
|
internal static IAttribute? GetAttribute(IMember member, KnownAttribute attributeType) |
|
{ |
|
HashSet<IMember> visitedMembers = new HashSet<IMember>(); |
|
while (true) |
|
{ |
|
member = member.MemberDefinition; // it's sufficient to look at the definitions |
|
if (!visitedMembers.Add(member)) |
|
{ |
|
// abort if we seem to be in an infinite loop (cyclic inheritance) |
|
break; |
|
} |
|
var attr = member.GetAttribute(attributeType); |
|
if (attr != null) |
|
return attr; |
|
if (!member.IsOverride) |
|
break; |
|
var baseMember = GetBaseMember(member); |
|
if (baseMember == null) |
|
break; |
|
member = baseMember; |
|
} |
|
return null; |
|
} |
|
#endregion |
|
} |
|
}
|
|
|