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;
22
using ICSharpCode.NRefactory.TypeSystem.Implementation;
24
namespace ICSharpCode.NRefactory.TypeSystem
27
/// Static helper methods for reflection names.
29
public static class ReflectionHelper
32
/// A reflection class used to represent <c>null</c>.
34
public sealed class Null {}
37
/// A reflection class used to represent <c>dynamic</c>.
39
public sealed class Dynamic {}
42
/// A reflection class used to represent an unbound type argument.
44
public sealed class UnboundTypeArgument {}
46
#region ICompilation.FindType
48
/// Retrieves the specified type in this compilation.
49
/// Returns <see cref="SpecialType.UnknownType"/> if the type cannot be found in this compilation.
52
/// This method cannot be used with open types; all type parameters will be substituted
53
/// with <see cref="SpecialType.UnknownType"/>.
55
public static IType FindType(this ICompilation compilation, Type type)
57
return type.ToTypeReference().Resolve(compilation.TypeResolveContext);
61
#region Type.ToTypeReference()
63
/// Creates a reference to the specified type.
65
/// <param name="type">The type to be converted.</param>
66
/// <returns>Returns the type reference.</returns>
68
/// If the type is open (contains type parameters '`0' or '``0'),
69
/// an <see cref="ITypeResolveContext"/> with the appropriate CurrentTypeDefinition/CurrentMember is required
70
/// to resolve the type reference.
71
/// For closed types, the root type resolve context for the compilation is sufficient.
73
public static ITypeReference ToTypeReference(this Type type)
76
return SpecialType.UnknownType;
77
if (type.IsGenericType && !type.IsGenericTypeDefinition) {
78
ITypeReference def = ToTypeReference(type.GetGenericTypeDefinition());
79
Type[] arguments = type.GetGenericArguments();
80
ITypeReference[] args = new ITypeReference[arguments.Length];
81
bool allUnbound = true;
82
for (int i = 0; i < arguments.Length; i++) {
83
args[i] = ToTypeReference(arguments[i]);
84
allUnbound &= args[i].Equals(SpecialType.UnboundTypeArgument);
89
return new ParameterizedTypeReference(def, args);
90
} else if (type.IsArray) {
91
return new ArrayTypeReference(ToTypeReference(type.GetElementType()), type.GetArrayRank());
92
} else if (type.IsPointer) {
93
return new PointerTypeReference(ToTypeReference(type.GetElementType()));
94
} else if (type.IsByRef) {
95
return new ByReferenceTypeReference(ToTypeReference(type.GetElementType()));
96
} else if (type.IsGenericParameter) {
97
if (type.DeclaringMethod != null) {
98
return TypeParameterReference.Create(EntityType.Method, type.GenericParameterPosition);
100
return TypeParameterReference.Create(EntityType.TypeDefinition, type.GenericParameterPosition);
102
} else if (type.DeclaringType != null) {
103
if (type == typeof(Dynamic))
104
return SpecialType.Dynamic;
105
else if (type == typeof(Null))
106
return SpecialType.NullType;
107
else if (type == typeof(UnboundTypeArgument))
108
return SpecialType.UnboundTypeArgument;
109
ITypeReference baseTypeRef = ToTypeReference(type.DeclaringType);
110
int typeParameterCount;
111
string name = SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
112
return new NestedTypeReference(baseTypeRef, name, typeParameterCount);
114
IAssemblyReference assemblyReference = new DefaultAssemblyReference(type.Assembly.FullName);
115
int typeParameterCount;
116
string name = SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount);
117
return new GetClassTypeReference(assemblyReference, type.Namespace, name, typeParameterCount);
122
#region SplitTypeParameterCountFromReflectionName
124
/// Removes the ` with type parameter count from the reflection name.
126
/// <remarks>Do not use this method with the full name of inner classes.</remarks>
127
public static string SplitTypeParameterCountFromReflectionName(string reflectionName)
129
int pos = reflectionName.LastIndexOf('`');
131
return reflectionName;
133
return reflectionName.Substring(0, pos);
138
/// Removes the ` with type parameter count from the reflection name.
140
/// <remarks>Do not use this method with the full name of inner classes.</remarks>
141
public static string SplitTypeParameterCountFromReflectionName(string reflectionName, out int typeParameterCount)
143
int pos = reflectionName.LastIndexOf('`');
145
typeParameterCount = 0;
146
return reflectionName;
148
string typeCount = reflectionName.Substring(pos + 1);
149
if (int.TryParse(typeCount, out typeParameterCount))
150
return reflectionName.Substring(0, pos);
152
return reflectionName;
157
#region TypeCode support
159
/// Retrieves a built-in type using the specified type code.
161
public static IType FindType(this ICompilation compilation, TypeCode typeCode)
163
return compilation.FindType((KnownTypeCode)typeCode);
167
/// Creates a reference to the specified type.
169
/// <param name="typeCode">The type to be converted.</param>
170
/// <returns>Returns the type reference.</returns>
171
public static ITypeReference ToTypeReference(this TypeCode typeCode)
173
return KnownTypeReference.Get((KnownTypeCode)typeCode);
177
/// Gets the type code for the specified type, or TypeCode.Empty if none of the other type codes match.
179
public static TypeCode GetTypeCode(IType type)
181
ITypeDefinition def = type as ITypeDefinition;
183
KnownTypeCode typeCode = def.KnownTypeCode;
184
if (typeCode <= KnownTypeCode.String && typeCode != KnownTypeCode.Void)
185
return (TypeCode)typeCode;
187
return TypeCode.Empty;
189
return TypeCode.Empty;
193
#region ParseReflectionName
195
/// Parses a reflection name into a type reference.
197
/// <param name="reflectionTypeName">The reflection name of the type.</param>
198
/// <returns>A type reference that represents the reflection name.</returns>
199
/// <exception cref="ReflectionNameParseException">The syntax of the reflection type name is invalid</exception>
201
/// If the type is open (contains type parameters '`0' or '``0'),
202
/// an <see cref="ITypeResolveContext"/> with the appropriate CurrentTypeDefinition/CurrentMember is required
203
/// to resolve the reference to the ITypeParameter.
204
/// For looking up closed, assembly qualified type names, the root type resolve context for the compilation
206
/// When looking up a type name that isn't assembly qualified, the type reference will look in
207
/// <see cref="ITypeResolveContext.CurrentAssembly"/> first, and if the type is not found there,
208
/// it will look in all other assemblies of the compilation.
210
/// <seealso cref="FullTypeName(string)"/>
211
public static ITypeReference ParseReflectionName(string reflectionTypeName)
213
if (reflectionTypeName == null)
214
throw new ArgumentNullException("reflectionTypeName");
216
ITypeReference r = ParseReflectionName(reflectionTypeName, ref pos);
217
if (pos < reflectionTypeName.Length)
218
throw new ReflectionNameParseException(pos, "Expected end of type name");
222
static bool IsReflectionNameSpecialCharacter(char c)
238
static ITypeReference ParseReflectionName(string reflectionTypeName, ref int pos)
240
if (pos == reflectionTypeName.Length)
241
throw new ReflectionNameParseException(pos, "Unexpected end");
242
ITypeReference reference;
243
if (reflectionTypeName[pos] == '`') {
244
// type parameter reference
246
if (pos == reflectionTypeName.Length)
247
throw new ReflectionNameParseException(pos, "Unexpected end");
248
if (reflectionTypeName[pos] == '`') {
249
// method type parameter reference
251
int index = ReadTypeParameterCount(reflectionTypeName, ref pos);
252
reference = TypeParameterReference.Create(EntityType.Method, index);
254
// class type parameter reference
255
int index = ReadTypeParameterCount(reflectionTypeName, ref pos);
256
reference = TypeParameterReference.Create(EntityType.TypeDefinition, index);
259
// not a type parameter reference: read the actual type name
261
string typeName = ReadTypeName(reflectionTypeName, ref pos, out tpc);
262
string assemblyName = SkipAheadAndReadAssemblyName(reflectionTypeName, pos);
263
reference = CreateGetClassTypeReference(assemblyName, typeName, tpc);
265
// read type suffixes
266
while (pos < reflectionTypeName.Length) {
267
switch (reflectionTypeName[pos++]) {
270
string typeName = ReadTypeName(reflectionTypeName, ref pos, out tpc);
271
reference = new NestedTypeReference(reference, typeName, tpc);
274
reference = new PointerTypeReference(reference);
277
reference = new ByReferenceTypeReference(reference);
280
// this might be an array or a generic type
281
if (pos == reflectionTypeName.Length)
282
throw new ReflectionNameParseException(pos, "Unexpected end");
283
if (reflectionTypeName[pos] == '[') {
284
// it's a generic type
285
List<ITypeReference> typeArguments = new List<ITypeReference>();
287
typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos));
288
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']')
291
throw new ReflectionNameParseException(pos, "Expected end of type argument");
293
while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') {
295
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == '[')
298
throw new ReflectionNameParseException(pos, "Expected another type argument");
300
typeArguments.Add(ParseReflectionName(reflectionTypeName, ref pos));
302
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']')
305
throw new ReflectionNameParseException(pos, "Expected end of type argument");
308
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') {
310
reference = new ParameterizedTypeReference(reference, typeArguments);
312
throw new ReflectionNameParseException(pos, "Expected end of generic type");
317
while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ',') {
321
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ']') {
322
pos++; // end of array
323
reference = new ArrayTypeReference(reference, dimensions);
325
throw new ReflectionNameParseException(pos, "Invalid array modifier");
330
// assembly qualified name, ignore everything up to the end/next ']'
331
while (pos < reflectionTypeName.Length && reflectionTypeName[pos] != ']')
335
pos--; // reset pos to the character we couldn't read
336
if (reflectionTypeName[pos] == ']')
337
return reference; // return from a nested generic
339
throw new ReflectionNameParseException(pos, "Unexpected character: '" + reflectionTypeName[pos] + "'");
345
static ITypeReference CreateGetClassTypeReference(string assemblyName, string typeName, int tpc)
347
IAssemblyReference assemblyReference;
348
if (assemblyName != null) {
349
assemblyReference = new DefaultAssemblyReference(assemblyName);
351
assemblyReference = null;
353
int pos = typeName.LastIndexOf('.');
355
return new GetClassTypeReference(assemblyReference, string.Empty, typeName, tpc);
357
return new GetClassTypeReference(assemblyReference, typeName.Substring(0, pos), typeName.Substring(pos + 1), tpc);
360
static string SkipAheadAndReadAssemblyName(string reflectionTypeName, int pos)
362
int nestingLevel = 0;
363
while (pos < reflectionTypeName.Length) {
364
switch (reflectionTypeName[pos++]) {
369
if (nestingLevel == 0)
374
if (nestingLevel == 0) {
375
// first skip the whitespace
376
while (pos < reflectionTypeName.Length && reflectionTypeName[pos] == ' ')
378
// everything up to the end/next ']' is the assembly name
380
while (endPos < reflectionTypeName.Length && reflectionTypeName[endPos] != ']')
382
return reflectionTypeName.Substring(pos, endPos - pos);
390
static string ReadTypeName(string reflectionTypeName, ref int pos, out int tpc)
393
// skip the simple name portion:
394
while (pos < reflectionTypeName.Length && !IsReflectionNameSpecialCharacter(reflectionTypeName[pos]))
397
throw new ReflectionNameParseException(pos, "Expected type name");
398
string typeName = reflectionTypeName.Substring(startPos, pos - startPos);
399
if (pos < reflectionTypeName.Length && reflectionTypeName[pos] == '`') {
401
tpc = ReadTypeParameterCount(reflectionTypeName, ref pos);
408
internal static int ReadTypeParameterCount(string reflectionTypeName, ref int pos)
411
while (pos < reflectionTypeName.Length) {
412
char c = reflectionTypeName[pos];
413
if (c < '0' || c > '9')
418
if (!int.TryParse(reflectionTypeName.Substring(startPos, pos - startPos), out tpc))
419
throw new ReflectionNameParseException(pos, "Expected type parameter count");