1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
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:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
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.
20
using System.Collections.Generic;
23
namespace ICSharpCode.NRefactory.TypeSystem
26
/// Holds the full name of a type definition.
27
/// A full type name uniquely identifies a type definition within a single assembly.
30
/// A full type name can only represent type definitions, not arbitrary types.
31
/// It does not include any type arguments, and can not refer to array or pointer types.
33
/// A full type name represented as reflection name has the syntax:
34
/// <c>NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] }</c>
37
public struct FullTypeName : IEquatable<FullTypeName>
42
public readonly string Name;
43
public readonly int AdditionalTypeParameterCount;
45
public NestedTypeName(string name, int additionalTypeParameterCount)
48
throw new ArgumentNullException("name");
50
this.AdditionalTypeParameterCount = additionalTypeParameterCount;
54
readonly TopLevelTypeName topLevelType;
55
readonly NestedTypeName[] nestedTypes;
57
FullTypeName(TopLevelTypeName topLevelTypeName, NestedTypeName[] nestedTypes)
59
this.topLevelType = topLevelTypeName;
60
this.nestedTypes = nestedTypes;
64
/// Constructs a FullTypeName representing the given top-level type.
67
/// FullTypeName has an implicit conversion operator from TopLevelTypeName,
68
/// so you can simply write:
69
/// <c>FullTypeName f = new TopLevelTypeName(...);</c>
71
public FullTypeName(TopLevelTypeName topLevelTypeName)
73
this.topLevelType = topLevelTypeName;
74
this.nestedTypes = null;
78
/// Constructs a FullTypeName by parsing the given reflection name.
79
/// Note that FullTypeName can only represent type definition names. If the reflection name
80
/// might refer to a parameterized type or array etc., use
81
/// <see cref="ReflectionHelper.ParseReflectionName(string)"/> instead.
84
/// Expected syntax: <c>NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] }</c>
85
/// where # are type parameter counts
87
public FullTypeName(string reflectionName)
89
int pos = reflectionName.IndexOf('+');
92
this.topLevelType = new TopLevelTypeName(reflectionName);
93
this.nestedTypes = null;
96
string[] parts = reflectionName.Split('+');
97
this.topLevelType = new TopLevelTypeName(parts[0]);
98
this.nestedTypes = new NestedTypeName[parts.Length - 1];
99
for (int i = 0; i < nestedTypes.Length; i++) {
101
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(parts[i + 1], out tpc);
102
nestedTypes[i] = new NestedTypeName(name, tpc);
108
/// Gets the top-level type name.
110
public TopLevelTypeName TopLevelTypeName {
111
get { return topLevelType; }
115
/// Gets whether this is a nested type.
117
public bool IsNested {
119
return nestedTypes != null;
124
/// Gets the nesting level.
126
public int NestingLevel {
128
return nestedTypes != null ? nestedTypes.Length : 0;
133
/// Gets the name of the type.
134
/// For nested types, this is the name of the innermost type.
138
if (nestedTypes != null)
139
return nestedTypes[nestedTypes.Length - 1].Name;
141
return topLevelType.Name;
145
public string ReflectionName {
147
if (nestedTypes == null)
148
return topLevelType.ReflectionName;
149
StringBuilder b = new StringBuilder(topLevelType.ReflectionName);
150
foreach (NestedTypeName nt in nestedTypes) {
153
if (nt.AdditionalTypeParameterCount > 0) {
155
b.Append(nt.AdditionalTypeParameterCount);
163
/// Gets the total type parameter count.
165
public int TypeParameterCount {
167
int tpc = topLevelType.TypeParameterCount;
168
if (nestedTypes != null) {
169
foreach (var nt in nestedTypes) {
170
tpc += nt.AdditionalTypeParameterCount;
178
/// Gets the name of the nested type at the given level.
180
public string GetNestedTypeName(int nestingLevel)
182
if (nestedTypes == null)
183
throw new InvalidOperationException();
184
return nestedTypes[nestingLevel].Name;
188
/// Gets the number of additional type parameters of the nested type at the given level.
190
public int GetNestedTypeAdditionalTypeParameterCount(int nestingLevel)
192
if (nestedTypes == null)
193
throw new InvalidOperationException();
194
return nestedTypes[nestingLevel].AdditionalTypeParameterCount;
198
/// Gets the declaring type name.
200
/// <exception cref="InvalidOperationException">This is a top-level type name.</exception>
201
/// <example><c>new FullTypeName("NS.A+B+C").GetDeclaringType()</c> will return <c>new FullTypeName("NS.A+B")</c></example>
202
public FullTypeName GetDeclaringType()
204
if (nestedTypes == null)
205
throw new InvalidOperationException();
206
if (nestedTypes.Length == 1)
208
NestedTypeName[] outerNestedTypeNames = new NestedTypeName[nestedTypes.Length - 1];
209
Array.Copy(nestedTypes, 0, outerNestedTypeNames, 0, outerNestedTypeNames.Length);
210
return new FullTypeName(topLevelType, nestedTypes);
214
/// Creates a nested type name.
216
/// <example><c>new FullTypeName("NS.A+B").NestedType("C", 1)</c> will return <c>new FullTypeName("NS.A+B+C`1")</c></example>
217
public FullTypeName NestedType(string name, int additionalTypeParameterCount)
220
throw new ArgumentNullException("name");
221
var newNestedType = new NestedTypeName(name, additionalTypeParameterCount);
222
if (nestedTypes == null)
223
return new FullTypeName(topLevelType, new[] { newNestedType });
224
NestedTypeName[] newNestedTypeNames = new NestedTypeName[nestedTypes.Length + 1];
225
nestedTypes.CopyTo(newNestedTypeNames, 0);
226
newNestedTypeNames[newNestedTypeNames.Length - 1] = newNestedType;
227
return new FullTypeName(topLevelType, newNestedTypeNames);
230
public static implicit operator FullTypeName(TopLevelTypeName topLevelTypeName)
232
return new FullTypeName(topLevelTypeName);
235
public override string ToString()
237
return this.ReflectionName;
240
#region Equals and GetHashCode implementation
241
public override bool Equals(object obj)
243
return obj is FullTypeName && Equals((FullTypeName)obj);
246
public bool Equals(FullTypeName other)
248
return FullTypeNameComparer.Ordinal.Equals(this, other);
251
public override int GetHashCode()
253
return FullTypeNameComparer.Ordinal.GetHashCode(this);
256
public static bool operator ==(FullTypeName left, FullTypeName right)
258
return left.Equals(right);
261
public static bool operator !=(FullTypeName left, FullTypeName right)
263
return !left.Equals(right);
269
public sealed class FullTypeNameComparer : IEqualityComparer<FullTypeName>
271
public static readonly FullTypeNameComparer Ordinal = new FullTypeNameComparer(StringComparer.Ordinal);
272
public static readonly FullTypeNameComparer OrdinalIgnoreCase = new FullTypeNameComparer(StringComparer.OrdinalIgnoreCase);
274
public readonly StringComparer NameComparer;
276
public FullTypeNameComparer(StringComparer nameComparer)
278
this.NameComparer = nameComparer;
281
public bool Equals(FullTypeName x, FullTypeName y)
283
if (x.NestingLevel != y.NestingLevel)
285
TopLevelTypeName topX = x.TopLevelTypeName;
286
TopLevelTypeName topY = y.TopLevelTypeName;
287
if (topX.TypeParameterCount == topY.TypeParameterCount
288
&& NameComparer.Equals(topX.Name, topY.Name)
289
&& NameComparer.Equals(topX.Namespace, topY.Namespace))
291
for (int i = 0; i < x.NestingLevel; i++) {
292
if (x.GetNestedTypeAdditionalTypeParameterCount(i) != y.GetNestedTypeAdditionalTypeParameterCount(i))
294
if (!NameComparer.Equals(x.GetNestedTypeName(i), y.GetNestedTypeName(i)))
302
public int GetHashCode(FullTypeName obj)
304
TopLevelTypeName top = obj.TopLevelTypeName;
305
int hash = NameComparer.GetHashCode(top.Name) ^ NameComparer.GetHashCode(top.Namespace) ^ top.TypeParameterCount;
307
for (int i = 0; i < obj.NestingLevel; i++) {
309
hash += NameComparer.GetHashCode(obj.Name) ^ obj.TypeParameterCount;