Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory-5.5.0/TypeSystem/TypeParameterSubstitution.cs @ 11700

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

#2077: created branch and added first version

File size: 6.6 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  /// Substitutes class and method type parameters.
27  /// </summary>
28  public class TypeParameterSubstitution : TypeVisitor
29  {
30    /// <summary>
31    /// The identity function.
32    /// </summary>
33    public static readonly TypeParameterSubstitution Identity = new TypeParameterSubstitution(null, null);
34   
35    readonly IList<IType> classTypeArguments;
36    readonly IList<IType> methodTypeArguments;
37   
38    /// <summary>
39    /// Creates a new type parameter substitution.
40    /// </summary>
41    /// <param name="classTypeArguments">
42    /// The type arguments to substitute for class type parameters.
43    /// Pass <c>null</c> to keep class type parameters unmodified.
44    /// </param>
45    /// <param name="methodTypeArguments">
46    /// The type arguments to substitute for method type parameters.
47    /// Pass <c>null</c> to keep method type parameters unmodified.
48    /// </param>
49    public TypeParameterSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments)
50    {
51      this.classTypeArguments = classTypeArguments;
52      this.methodTypeArguments = methodTypeArguments;
53    }
54   
55    /// <summary>
56    /// Gets the list of class type arguments.
57    /// Returns <c>null</c> if this substitution keeps class type parameters unmodified.
58    /// </summary>
59    public IList<IType> ClassTypeArguments {
60      get { return classTypeArguments; }
61    }
62   
63    /// <summary>
64    /// Gets the list of method type arguments.
65    /// Returns <c>null</c> if this substitution keeps method type parameters unmodified.
66    /// </summary>
67    public IList<IType> MethodTypeArguments {
68      get { return methodTypeArguments; }
69    }
70   
71    #region Compose
72    /// <summary>
73    /// Computes a single TypeParameterSubstitution so that for all types <c>t</c>:
74    /// <c>t.AcceptVisitor(Compose(g, f)) equals t.AcceptVisitor(f).AcceptVisitor(g)</c>
75    /// </summary>
76    /// <remarks>If you consider type parameter substitution to be a function, this is function composition.</remarks>
77    public static TypeParameterSubstitution Compose(TypeParameterSubstitution g, TypeParameterSubstitution f)
78    {
79      if (g == null)
80        return f;
81      if (f == null || (f.classTypeArguments == null && f.methodTypeArguments == null))
82        return g;
83      // The composition is a copy of 'f', with 'g' applied on the array elements.
84      // If 'f' has a null list (keeps type parameters unmodified), we have to treat it as
85      // the identity function, and thus use the list from 'g'.
86      var classTypeArguments = f.classTypeArguments != null ? GetComposedTypeArguments(f.classTypeArguments, g) : g.classTypeArguments;
87      var methodTypeArguments = f.methodTypeArguments != null ? GetComposedTypeArguments(f.methodTypeArguments, g) : g.methodTypeArguments;
88      return new TypeParameterSubstitution(classTypeArguments, methodTypeArguments);
89    }
90   
91    static IList<IType> GetComposedTypeArguments(IList<IType> input, TypeParameterSubstitution substitution)
92    {
93      IType[] result = new IType[input.Count];
94      for (int i = 0; i < result.Length; i++) {
95        result[i] = input[i].AcceptVisitor(substitution);
96      }
97      return result;
98    }
99    #endregion
100   
101    #region Equals and GetHashCode implementation
102    public override bool Equals(object obj)
103    {
104      TypeParameterSubstitution other = obj as TypeParameterSubstitution;
105      if (other == null)
106        return false;
107      return TypeListEquals(classTypeArguments, other.classTypeArguments)
108        && TypeListEquals(methodTypeArguments, other.methodTypeArguments);
109    }
110   
111    public override int GetHashCode()
112    {
113      unchecked {
114        return 1124131 * TypeListHashCode(classTypeArguments) + 1821779 * TypeListHashCode(methodTypeArguments);
115      }
116    }
117   
118    static bool TypeListEquals(IList<IType> a, IList<IType> b)
119    {
120      if (a == b)
121        return true;
122      if (a == null || b == null)
123        return false;
124      if (a.Count != b.Count)
125        return false;
126      for (int i = 0; i < a.Count; i++) {
127        if (!a[i].Equals(b[i]))
128          return false;
129      }
130      return true;
131    }
132   
133    static int TypeListHashCode(IList<IType> obj)
134    {
135      if (obj == null)
136        return 0;
137      unchecked {
138        int hashCode = 1;
139        foreach (var element in obj) {
140          hashCode *= 27;
141          hashCode += element.GetHashCode();
142        }
143        return hashCode;
144      }
145    }
146    #endregion
147   
148    public override IType VisitTypeParameter(ITypeParameter type)
149    {
150      int index = type.Index;
151      if (classTypeArguments != null && type.OwnerType == SymbolKind.TypeDefinition) {
152        if (index >= 0 && index < classTypeArguments.Count)
153          return classTypeArguments[index];
154        else
155          return SpecialType.UnknownType;
156      } else if (methodTypeArguments != null && type.OwnerType == SymbolKind.Method) {
157        if (index >= 0 && index < methodTypeArguments.Count)
158          return methodTypeArguments[index];
159        else
160          return SpecialType.UnknownType;
161      } else {
162        return base.VisitTypeParameter(type);
163      }
164    }
165   
166    public override string ToString()
167    {
168      StringBuilder b = new StringBuilder();
169      b.Append('[');
170      bool first = true;
171      if (classTypeArguments != null) {
172        for (int i = 0; i < classTypeArguments.Count; i++) {
173          if (first) first = false; else b.Append(", ");
174          b.Append('`');
175          b.Append(i);
176          b.Append(" -> ");
177          b.Append(classTypeArguments[i].ReflectionName);
178        }
179      }
180      if (methodTypeArguments != null) {
181        for (int i = 0; i < methodTypeArguments.Count; i++) {
182          if (first) first = false; else b.Append(", ");
183          b.Append("``");
184          b.Append(i);
185          b.Append(" -> ");
186          b.Append(methodTypeArguments[i].ReflectionName);
187        }
188      }
189      b.Append(']');
190      return b.ToString();
191    }
192  }
193}
Note: See TracBrowser for help on using the repository browser.