1 | // Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team |
---|
2 | // |
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this |
---|
4 | // software and associated documentation files (the "Software"), to deal in the Software |
---|
5 | // without restriction, including without limitation the rights to use, copy, modify, merge, |
---|
6 | // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
---|
7 | // to whom the Software is furnished to do so, subject to the following conditions: |
---|
8 | // |
---|
9 | // The above copyright notice and this permission notice shall be included in all copies or |
---|
10 | // substantial portions of the Software. |
---|
11 | // |
---|
12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
---|
13 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
---|
14 | // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
---|
15 | // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
---|
16 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
17 | // DEALINGS IN THE SOFTWARE. |
---|
18 | |
---|
19 | using System; |
---|
20 | using System.Collections.Generic; |
---|
21 | using System.Linq; |
---|
22 | using ICSharpCode.NRefactory.TypeSystem.Implementation; |
---|
23 | |
---|
24 | namespace ICSharpCode.NRefactory.TypeSystem |
---|
25 | { |
---|
26 | /// <summary> |
---|
27 | /// Provides helper methods for inheritance. |
---|
28 | /// </summary> |
---|
29 | public static class InheritanceHelper |
---|
30 | { |
---|
31 | // TODO: maybe these should be extension methods? |
---|
32 | // or even part of the interface itself? (would allow for easy caching) |
---|
33 | |
---|
34 | #region GetBaseMember |
---|
35 | /// <summary> |
---|
36 | /// Gets the base member that has the same signature. |
---|
37 | /// </summary> |
---|
38 | public static IMember GetBaseMember(IMember member) |
---|
39 | { |
---|
40 | return GetBaseMembers(member, false).FirstOrDefault(); |
---|
41 | } |
---|
42 | |
---|
43 | /// <summary> |
---|
44 | /// Gets all base members that have the same signature. |
---|
45 | /// </summary> |
---|
46 | /// <returns> |
---|
47 | /// List of base members with the same signature. The member from the derived-most base class is returned first. |
---|
48 | /// </returns> |
---|
49 | public static IEnumerable<IMember> GetBaseMembers(IMember member, bool includeImplementedInterfaces) |
---|
50 | { |
---|
51 | if (member == null) |
---|
52 | throw new ArgumentNullException("member"); |
---|
53 | |
---|
54 | if (member.IsExplicitInterfaceImplementation && member.ImplementedInterfaceMembers.Count == 1) { |
---|
55 | // C#-style explicit interface implementation |
---|
56 | member = member.ImplementedInterfaceMembers[0]; |
---|
57 | yield return member; |
---|
58 | } |
---|
59 | |
---|
60 | // Remove generic specialization |
---|
61 | var substitution = member.Substitution; |
---|
62 | member = member.MemberDefinition; |
---|
63 | |
---|
64 | if (member.DeclaringTypeDefinition == null) { |
---|
65 | // For global methods, return empty list. (prevent SharpDevelop UDC crash 4524) |
---|
66 | yield break; |
---|
67 | } |
---|
68 | |
---|
69 | IEnumerable<IType> allBaseTypes; |
---|
70 | if (includeImplementedInterfaces) { |
---|
71 | allBaseTypes = member.DeclaringTypeDefinition.GetAllBaseTypes(); |
---|
72 | } else { |
---|
73 | allBaseTypes = member.DeclaringTypeDefinition.GetNonInterfaceBaseTypes(); |
---|
74 | } |
---|
75 | foreach (IType baseType in allBaseTypes.Reverse()) { |
---|
76 | if (baseType == member.DeclaringTypeDefinition) |
---|
77 | continue; |
---|
78 | |
---|
79 | IEnumerable<IMember> baseMembers; |
---|
80 | if (member.SymbolKind == SymbolKind.Accessor) { |
---|
81 | baseMembers = baseType.GetAccessors(m => m.Name == member.Name && !m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); |
---|
82 | } else { |
---|
83 | baseMembers = baseType.GetMembers(m => m.Name == member.Name && !m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); |
---|
84 | } |
---|
85 | foreach (IMember baseMember in baseMembers) { |
---|
86 | if (SignatureComparer.Ordinal.Equals(member, baseMember)) { |
---|
87 | yield return baseMember.Specialize(substitution); |
---|
88 | } |
---|
89 | } |
---|
90 | } |
---|
91 | } |
---|
92 | #endregion |
---|
93 | |
---|
94 | #region GetDerivedMember |
---|
95 | /// <summary> |
---|
96 | /// Finds the member declared in 'derivedType' that has the same signature (could override) 'baseMember'. |
---|
97 | /// </summary> |
---|
98 | public static IMember GetDerivedMember(IMember baseMember, ITypeDefinition derivedType) |
---|
99 | { |
---|
100 | if (baseMember == null) |
---|
101 | throw new ArgumentNullException("baseMember"); |
---|
102 | if (derivedType == null) |
---|
103 | throw new ArgumentNullException("derivedType"); |
---|
104 | |
---|
105 | if (baseMember.Compilation != derivedType.Compilation) |
---|
106 | throw new ArgumentException("baseMember and derivedType must be from the same compilation"); |
---|
107 | |
---|
108 | baseMember = baseMember.MemberDefinition; |
---|
109 | bool includeInterfaces = baseMember.DeclaringTypeDefinition.Kind == TypeKind.Interface; |
---|
110 | IMethod method = baseMember as IMethod; |
---|
111 | if (method != null) { |
---|
112 | foreach (IMethod derivedMethod in derivedType.Methods) { |
---|
113 | if (derivedMethod.Name == method.Name && derivedMethod.Parameters.Count == method.Parameters.Count) { |
---|
114 | if (derivedMethod.TypeParameters.Count == method.TypeParameters.Count) { |
---|
115 | // The method could override the base method: |
---|
116 | if (GetBaseMembers(derivedMethod, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) |
---|
117 | return derivedMethod; |
---|
118 | } |
---|
119 | } |
---|
120 | } |
---|
121 | } |
---|
122 | IProperty property = baseMember as IProperty; |
---|
123 | if (property != null) { |
---|
124 | foreach (IProperty derivedProperty in derivedType.Properties) { |
---|
125 | if (derivedProperty.Name == property.Name && derivedProperty.Parameters.Count == property.Parameters.Count) { |
---|
126 | // The property could override the base property: |
---|
127 | if (GetBaseMembers(derivedProperty, includeInterfaces).Any(m => m.MemberDefinition == baseMember)) |
---|
128 | return derivedProperty; |
---|
129 | } |
---|
130 | } |
---|
131 | } |
---|
132 | if (baseMember is IEvent) { |
---|
133 | foreach (IEvent derivedEvent in derivedType.Events) { |
---|
134 | if (derivedEvent.Name == baseMember.Name) |
---|
135 | return derivedEvent; |
---|
136 | } |
---|
137 | } |
---|
138 | if (baseMember is IField) { |
---|
139 | foreach (IField derivedField in derivedType.Fields) { |
---|
140 | if (derivedField.Name == baseMember.Name) |
---|
141 | return derivedField; |
---|
142 | } |
---|
143 | } |
---|
144 | return null; |
---|
145 | } |
---|
146 | #endregion |
---|
147 | } |
---|
148 | } |
---|