Free cookie consent management tool by TermsFeed Policy Generator

source: tags/3.3.13/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory-5.5.0/TypeSystem/FullTypeName.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 9.9 KB
Line 
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
19using System;
20using System.Collections.Generic;
21using System.Text;
22
23namespace ICSharpCode.NRefactory.TypeSystem
24{
25  /// <summary>
26  /// Holds the full name of a type definition.
27  /// A full type name uniquely identifies a type definition within a single assembly.
28  /// </summary>
29  /// <remarks>
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.
32  ///
33  /// A full type name represented as reflection name has the syntax:
34  /// <c>NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] }</c>
35  /// </remarks>
36  [Serializable]
37  public struct FullTypeName : IEquatable<FullTypeName>
38  {
39    [Serializable]
40    struct NestedTypeName
41    {
42      public readonly string Name;
43      public readonly int AdditionalTypeParameterCount;
44     
45      public NestedTypeName(string name, int additionalTypeParameterCount)
46      {
47        if (name == null)
48          throw new ArgumentNullException("name");
49        this.Name = name;
50        this.AdditionalTypeParameterCount = additionalTypeParameterCount;
51      }
52    }
53   
54    readonly TopLevelTypeName topLevelType;
55    readonly NestedTypeName[] nestedTypes;
56   
57    FullTypeName(TopLevelTypeName topLevelTypeName, NestedTypeName[] nestedTypes)
58    {
59      this.topLevelType = topLevelTypeName;
60      this.nestedTypes = nestedTypes;
61    }
62   
63    /// <summary>
64    /// Constructs a FullTypeName representing the given top-level type.
65    /// </summary>
66    /// <remarks>
67    /// FullTypeName has an implicit conversion operator from TopLevelTypeName,
68    /// so you can simply write:
69    /// <c>FullTypeName f = new TopLevelTypeName(...);</c>
70    /// </remarks>
71    public FullTypeName(TopLevelTypeName topLevelTypeName)
72    {
73      this.topLevelType = topLevelTypeName;
74      this.nestedTypes = null;
75    }
76   
77    /// <summary>
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.
82    /// </summary>
83    /// <remarks>
84    /// Expected syntax: <c>NamespaceName '.' TopLevelTypeName ['`'#] { '+' NestedTypeName ['`'#] }</c>
85    /// where # are type parameter counts
86    /// </remarks>
87    public FullTypeName(string reflectionName)
88    {
89      int pos = reflectionName.IndexOf('+');
90      if (pos < 0) {
91        // top-level type
92        this.topLevelType = new TopLevelTypeName(reflectionName);
93        this.nestedTypes = null;
94      } else {
95        // nested type
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++) {
100          int tpc;
101          string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(parts[i + 1], out tpc);
102          nestedTypes[i] = new NestedTypeName(name, tpc);
103        }
104      }
105    }
106   
107    /// <summary>
108    /// Gets the top-level type name.
109    /// </summary>
110    public TopLevelTypeName TopLevelTypeName {
111      get { return topLevelType; }
112    }
113   
114    /// <summary>
115    /// Gets whether this is a nested type.
116    /// </summary>
117    public bool IsNested {
118      get {
119        return nestedTypes != null;
120      }
121    }
122   
123    /// <summary>
124    /// Gets the nesting level.
125    /// </summary>
126    public int NestingLevel {
127      get {
128        return nestedTypes != null ? nestedTypes.Length : 0;
129      }
130    }
131   
132    /// <summary>
133    /// Gets the name of the type.
134    /// For nested types, this is the name of the innermost type.
135    /// </summary>
136    public string Name {
137      get {
138        if (nestedTypes != null)
139          return nestedTypes[nestedTypes.Length - 1].Name;
140        else
141          return topLevelType.Name;
142      }
143    }
144   
145    public string ReflectionName {
146      get {
147        if (nestedTypes == null)
148          return topLevelType.ReflectionName;
149        StringBuilder b = new StringBuilder(topLevelType.ReflectionName);
150        foreach (NestedTypeName nt in nestedTypes) {
151          b.Append('+');
152          b.Append(nt.Name);
153          if (nt.AdditionalTypeParameterCount > 0) {
154            b.Append('`');
155            b.Append(nt.AdditionalTypeParameterCount);
156          }
157        }
158        return b.ToString();
159      }
160    }
161   
162    /// <summary>
163    /// Gets the total type parameter count.
164    /// </summary>
165    public int TypeParameterCount {
166      get {
167        int tpc = topLevelType.TypeParameterCount;
168        if (nestedTypes != null) {
169          foreach (var nt in nestedTypes) {
170            tpc += nt.AdditionalTypeParameterCount;
171          }
172        }
173        return tpc;
174      }
175    }
176   
177    /// <summary>
178    /// Gets the name of the nested type at the given level.
179    /// </summary>
180    public string GetNestedTypeName(int nestingLevel)
181    {
182      if (nestedTypes == null)
183        throw new InvalidOperationException();
184      return nestedTypes[nestingLevel].Name;
185    }
186   
187    /// <summary>
188    /// Gets the number of additional type parameters of the nested type at the given level.
189    /// </summary>
190    public int GetNestedTypeAdditionalTypeParameterCount(int nestingLevel)
191    {
192      if (nestedTypes == null)
193        throw new InvalidOperationException();
194      return nestedTypes[nestingLevel].AdditionalTypeParameterCount;
195    }
196   
197    /// <summary>
198    /// Gets the declaring type name.
199    /// </summary>
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()
203    {
204      if (nestedTypes == null)
205        throw new InvalidOperationException();
206      if (nestedTypes.Length == 1)
207        return topLevelType;
208      NestedTypeName[] outerNestedTypeNames = new NestedTypeName[nestedTypes.Length - 1];
209      Array.Copy(nestedTypes, 0, outerNestedTypeNames, 0, outerNestedTypeNames.Length);
210      return new FullTypeName(topLevelType, nestedTypes);
211    }
212   
213    /// <summary>
214    /// Creates a nested type name.
215    /// </summary>
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)
218    {
219      if (name == null)
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);
228    }
229   
230    public static implicit operator FullTypeName(TopLevelTypeName topLevelTypeName)
231    {
232      return new FullTypeName(topLevelTypeName);
233    }
234   
235    public override string ToString()
236    {
237      return this.ReflectionName;
238    }
239   
240    #region Equals and GetHashCode implementation
241    public override bool Equals(object obj)
242    {
243      return obj is FullTypeName && Equals((FullTypeName)obj);
244    }
245   
246    public bool Equals(FullTypeName other)
247    {
248      return FullTypeNameComparer.Ordinal.Equals(this, other);
249    }
250   
251    public override int GetHashCode()
252    {
253      return FullTypeNameComparer.Ordinal.GetHashCode(this);
254    }
255   
256    public static bool operator ==(FullTypeName left, FullTypeName right)
257    {
258      return left.Equals(right);
259    }
260   
261    public static bool operator !=(FullTypeName left, FullTypeName right)
262    {
263      return !left.Equals(right);
264    }
265    #endregion
266  }
267 
268  [Serializable]
269  public sealed class FullTypeNameComparer : IEqualityComparer<FullTypeName>
270  {
271    public static readonly FullTypeNameComparer Ordinal = new FullTypeNameComparer(StringComparer.Ordinal);
272    public static readonly FullTypeNameComparer OrdinalIgnoreCase = new FullTypeNameComparer(StringComparer.OrdinalIgnoreCase);
273   
274    public readonly StringComparer NameComparer;
275   
276    public FullTypeNameComparer(StringComparer nameComparer)
277    {
278      this.NameComparer = nameComparer;
279    }
280   
281    public bool Equals(FullTypeName x, FullTypeName y)
282    {
283      if (x.NestingLevel != y.NestingLevel)
284        return false;
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))
290      {
291        for (int i = 0; i < x.NestingLevel; i++) {
292          if (x.GetNestedTypeAdditionalTypeParameterCount(i) != y.GetNestedTypeAdditionalTypeParameterCount(i))
293            return false;
294          if (!NameComparer.Equals(x.GetNestedTypeName(i), y.GetNestedTypeName(i)))
295            return false;
296        }
297        return true;
298      }
299      return false;
300    }
301   
302    public int GetHashCode(FullTypeName obj)
303    {
304      TopLevelTypeName top = obj.TopLevelTypeName;
305      int hash = NameComparer.GetHashCode(top.Name) ^ NameComparer.GetHashCode(top.Namespace) ^ top.TypeParameterCount;
306      unchecked {
307        for (int i = 0; i < obj.NestingLevel; i++) {
308          hash *= 31;
309          hash += NameComparer.GetHashCode(obj.Name) ^ obj.TypeParameterCount;
310        }
311      }
312      return hash;
313    }
314  }
315}
Note: See TracBrowser for help on using the repository browser.