16 changed files with 694 additions and 55 deletions
@ -0,0 +1,306 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using ICSharpCode.NRefactory.CSharp; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.Documentation |
||||||
|
{ |
||||||
|
[TestFixture] |
||||||
|
public class IDStringTests |
||||||
|
{ |
||||||
|
class IDStringTestProjectContent : SimpleProjectContent, IDocumentationProvider |
||||||
|
{ |
||||||
|
public string GetDocumentation(IEntity entity) |
||||||
|
{ |
||||||
|
// Note: there's no mscorlib in the context.
|
||||||
|
// These tests only use primitive types from mscorlib, so the full name is known
|
||||||
|
// without resolving them.
|
||||||
|
return IDStringProvider.GetIDString(entity, this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IDStringTestProjectContent pc; |
||||||
|
|
||||||
|
void Init(string program) |
||||||
|
{ |
||||||
|
pc = new IDStringTestProjectContent(); |
||||||
|
CSharpParser parser = new CSharpParser(); |
||||||
|
|
||||||
|
TypeSystemConvertVisitor cv = new TypeSystemConvertVisitor(pc, "program.cs"); |
||||||
|
parser.Parse(new StringReader(program)).AcceptVisitor(cv, null); |
||||||
|
pc.UpdateProjectContent(null, cv.ParsedFile); |
||||||
|
} |
||||||
|
|
||||||
|
ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount = 0) |
||||||
|
{ |
||||||
|
return pc.GetTypeDefinition(nameSpace, name, typeParameterCount, StringComparer.Ordinal); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void TypeDefinitions() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
enum Color { Red, Blue, Green } |
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
interface IProcess {} |
||||||
|
struct ValueType {} |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public class NestedClass {} |
||||||
|
|
||||||
|
public interface IMenuItem {} |
||||||
|
|
||||||
|
public delegate void Del(int i); |
||||||
|
|
||||||
|
public enum Direction { North, South, East, West } |
||||||
|
} |
||||||
|
class MyList<T> |
||||||
|
{ |
||||||
|
class Helper<U,V> {} |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
Assert.AreEqual("T:Color", GetTypeDefinition(string.Empty, "Color").Documentation); |
||||||
|
Assert.AreEqual("T:Acme.IProcess", GetTypeDefinition("Acme", "IProcess").Documentation); |
||||||
|
Assert.AreEqual("T:Acme.ValueType", GetTypeDefinition("Acme", "ValueType").Documentation); |
||||||
|
|
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("T:Acme.Widget", widget.Documentation); |
||||||
|
Assert.AreEqual("T:Acme.Widget.NestedClass", widget.NestedTypes.Single(t => t.Name == "NestedClass").Documentation); |
||||||
|
Assert.AreEqual("T:Acme.Widget.IMenuItem", widget.NestedTypes.Single(t => t.Name == "IMenuItem").Documentation); |
||||||
|
Assert.AreEqual("T:Acme.Widget.Del", widget.NestedTypes.Single(t => t.Name == "Del").Documentation); |
||||||
|
Assert.AreEqual("T:Acme.Widget.Direction", widget.NestedTypes.Single(t => t.Name == "Direction").Documentation); |
||||||
|
Assert.AreEqual("T:Acme.MyList`1", GetTypeDefinition("Acme", "MyList", 1).Documentation); |
||||||
|
Assert.AreEqual("T:Acme.MyList`1.Helper`2", GetTypeDefinition("Acme", "MyList", 1).NestedTypes.Single().Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void Fields() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget : IProcess |
||||||
|
{ |
||||||
|
public class NestedClass |
||||||
|
{ |
||||||
|
private int value; |
||||||
|
} |
||||||
|
|
||||||
|
private string message; |
||||||
|
private const double PI = 3.14159; |
||||||
|
private unsafe float **ppValues; |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("F:Acme.Widget.NestedClass.value", widget.NestedTypes.Single().Fields.Single().Documentation); |
||||||
|
Assert.AreEqual("F:Acme.Widget.message", widget.Fields.Single(f => f.Name == "message").Documentation); |
||||||
|
Assert.AreEqual("F:Acme.Widget.PI", widget.Fields.Single(f => f.Name == "PI").Documentation); |
||||||
|
Assert.AreEqual("F:Acme.Widget.ppValues", widget.Fields.Single(f => f.Name == "ppValues").Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void Constructors() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
static Widget() {} |
||||||
|
public Widget() {} |
||||||
|
public Widget(string s) {} |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("M:Acme.Widget.#cctor", widget.Methods.Single(m => m.IsStatic).Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.#ctor", widget.Methods.Single(m => !m.IsStatic && m.Parameters.Count == 0).Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.#ctor(System.String)", widget.Methods.Single(m => m.Parameters.Count == 1).Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void Destructor() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
~Widget() { } |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("M:Acme.Widget.Finalize", widget.Methods.Single().Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void Methods() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
enum Color {} |
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
struct ValueType { } |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public class NestedClass |
||||||
|
{ |
||||||
|
public void M(int i) {} |
||||||
|
} |
||||||
|
|
||||||
|
public static void M0() {...} |
||||||
|
public void M1(char c, out float f, ref ValueType v) {...} |
||||||
|
public void M2(short[] x1, int[,] x2, long[][] x3) {...} |
||||||
|
public void M3(long[][] x3, Widget[][,,] x4) {...} |
||||||
|
public unsafe void M4(char *pc, Color **pf) {...} |
||||||
|
public unsafe void M5(void *pv, double *[][,] pd) {...} |
||||||
|
public void M6(int? i, params object[] args) {...} |
||||||
|
} |
||||||
|
|
||||||
|
class MyList<T> |
||||||
|
{ |
||||||
|
public void Test(T t) { } |
||||||
|
} |
||||||
|
|
||||||
|
class UseList |
||||||
|
{ |
||||||
|
public void Process(MyList<Color> list) { } |
||||||
|
public MyList<T> GetValues<T>(T inputValue) { return null; } |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("M:Acme.Widget.NestedClass.M(System.Int32)", widget.NestedTypes.Single().Methods.Single().Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M0", widget.Methods.Single(m => m.Name == "M0").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M1(System.Char,System.Single@,Acme.ValueType@)", |
||||||
|
widget.Methods.Single(m => m.Name == "M1").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M2(System.Int16[],System.Int32[0:,0:],System.Int64[][])", |
||||||
|
widget.Methods.Single(m => m.Name == "M2").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M3(System.Int64[][],Acme.Widget[0:,0:,0:][])", |
||||||
|
widget.Methods.Single(m => m.Name == "M3").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M4(System.Char*,Color**)", |
||||||
|
widget.Methods.Single(m => m.Name == "M4").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M5(System.Void*,System.Double*[0:,0:][])", |
||||||
|
widget.Methods.Single(m => m.Name == "M5").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.M6(System.Nullable{System.Int32},System.Object[])", |
||||||
|
widget.Methods.Single(m => m.Name == "M6").Documentation); |
||||||
|
|
||||||
|
Assert.AreEqual("M:Acme.MyList`1.Test(`0)", |
||||||
|
GetTypeDefinition("Acme", "MyList", 1).Methods.Single().Documentation); |
||||||
|
|
||||||
|
Assert.AreEqual("M:Acme.UseList.Process(Acme.MyList{Color})", |
||||||
|
GetTypeDefinition("Acme", "UseList").Methods.Single(m => m.Name == "Process").Documentation); |
||||||
|
Assert.AreEqual("M:Acme.UseList.GetValues``1(``0)", |
||||||
|
GetTypeDefinition("Acme", "UseList").Methods.Single(m => m.Name == "GetValues").Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void NestedGenerics() |
||||||
|
{ |
||||||
|
Init("class A<X> { class B<Y> { void M(A<Y>.B<X> a) { } } }"); |
||||||
|
ITypeDefinition b = GetTypeDefinition("", "A", 1).NestedTypes.Single(); |
||||||
|
Assert.AreEqual("T:A`1.B`1", b.Documentation); |
||||||
|
Assert.AreEqual("M:A`1.B`1.M(A{`1}.B{`0})", b.Methods.Single().Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void Properties() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public int Width { get {...} set {...} } |
||||||
|
public int this[int i] { get {...} set {...} } |
||||||
|
public int this[string s, int i] { get {...} set {...} } |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("P:Acme.Widget.Width", widget.Properties.Single(p => p.Parameters.Count == 0).Documentation); |
||||||
|
Assert.AreEqual("P:Acme.Widget.Item(System.Int32)", |
||||||
|
widget.Properties.Single(p => p.Parameters.Count == 1).Documentation); |
||||||
|
Assert.AreEqual("P:Acme.Widget.Item(System.String,System.Int32)", |
||||||
|
widget.Properties.Single(p => p.Parameters.Count == 2).Documentation); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void Event() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public event Del AnEvent; |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("E:Acme.Widget.AnEvent", widget.Events.Single().Documentation); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void UnaryOperator() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public static Widget operator+(Widget x) { } |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("M:Acme.Widget.op_UnaryPlus(Acme.Widget)", widget.Methods.Single().Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void BinaryOperator() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public static Widget operator+(Widget x1, Widget x2) { } |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)", widget.Methods.Single().Documentation); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void ConversionOperator() |
||||||
|
{ |
||||||
|
string program = @"
|
||||||
|
namespace Acme |
||||||
|
{ |
||||||
|
class Widget: IProcess |
||||||
|
{ |
||||||
|
public static explicit operator int(Widget x) { } |
||||||
|
public static implicit operator long(Widget x) { } |
||||||
|
} |
||||||
|
}";
|
||||||
|
Init(program); |
||||||
|
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget"); |
||||||
|
Assert.AreEqual("M:Acme.Widget.op_Explicit(Acme.Widget)~System.Int32", widget.Methods.First().Documentation); |
||||||
|
Assert.AreEqual("M:Acme.Widget.op_Implicit(Acme.Widget)~System.Int64", widget.Methods.Last().Documentation); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,260 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Text; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem; |
||||||
|
using ICSharpCode.NRefactory.TypeSystem.Implementation; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.Documentation |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Provides ID strings for entities. (C# 4.0 spec, §A.3.1)
|
||||||
|
/// ID strings are used to identify members in XML documentation files.
|
||||||
|
/// </summary>
|
||||||
|
public static class IDStringProvider |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The type resolve context is optional and is not needed for entities loaded from assemblies:
|
||||||
|
/// This method can get the ID string for any type reference produced by the CecilLoader without
|
||||||
|
/// having to resolve the type reference.
|
||||||
|
/// </remarks>
|
||||||
|
public static string GetIDString(IEntity entity, ITypeResolveContext context = null) |
||||||
|
{ |
||||||
|
StringBuilder b = new StringBuilder(); |
||||||
|
switch (entity.EntityType) { |
||||||
|
case EntityType.TypeDefinition: |
||||||
|
b.Append("T:"); |
||||||
|
AppendTypeName(b, (ITypeDefinition)entity); |
||||||
|
return b.ToString(); |
||||||
|
case EntityType.Field: |
||||||
|
b.Append("F:"); |
||||||
|
break; |
||||||
|
case EntityType.Property: |
||||||
|
case EntityType.Indexer: |
||||||
|
b.Append("P:"); |
||||||
|
break; |
||||||
|
case EntityType.Event: |
||||||
|
b.Append("E:"); |
||||||
|
break; |
||||||
|
default: |
||||||
|
b.Append("M:"); |
||||||
|
break; |
||||||
|
} |
||||||
|
IMember member = (IMember)entity; |
||||||
|
AppendTypeName(b, member.DeclaringType); |
||||||
|
b.Append('.'); |
||||||
|
b.Append(member.Name.Replace('.', '#')); |
||||||
|
IMethod method = member as IMethod; |
||||||
|
if (method != null && method.TypeParameters.Count > 0) { |
||||||
|
b.Append("``"); |
||||||
|
b.Append(method.TypeParameters.Count); |
||||||
|
} |
||||||
|
IParameterizedMember parameterizedMember = member as IParameterizedMember; |
||||||
|
if (parameterizedMember != null && parameterizedMember.Parameters.Count > 0) { |
||||||
|
b.Append('('); |
||||||
|
var parameters = parameterizedMember.Parameters; |
||||||
|
for (int i = 0; i < parameters.Count; i++) { |
||||||
|
if (i > 0) b.Append(','); |
||||||
|
AppendTypeName(b, parameters[i].Type, context); |
||||||
|
} |
||||||
|
b.Append(')'); |
||||||
|
} |
||||||
|
if (member.EntityType == EntityType.Operator && (member.Name == "op_Implicit" || member.Name == "op_Explicit")) { |
||||||
|
b.Append('~'); |
||||||
|
AppendTypeName(b, member.ReturnType, context); |
||||||
|
} |
||||||
|
return b.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetTypeName(IType type) |
||||||
|
{ |
||||||
|
if (type == null) |
||||||
|
throw new ArgumentNullException("type"); |
||||||
|
StringBuilder b = new StringBuilder(); |
||||||
|
AppendTypeName(b, type); |
||||||
|
return b.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
static void AppendTypeName(StringBuilder b, IType type) |
||||||
|
{ |
||||||
|
switch (type.Kind) { |
||||||
|
case TypeKind.Dynamic: |
||||||
|
b.Append("System.Object"); |
||||||
|
break; |
||||||
|
case TypeKind.TypeParameter: |
||||||
|
ITypeParameter tp = (ITypeParameter)type; |
||||||
|
b.Append('`'); |
||||||
|
if (tp.OwnerType == EntityType.Method) |
||||||
|
b.Append('`'); |
||||||
|
b.Append(tp.Index); |
||||||
|
break; |
||||||
|
case TypeKind.Array: |
||||||
|
ArrayType array = (ArrayType)type; |
||||||
|
AppendTypeName(b, array.ElementType); |
||||||
|
b.Append('['); |
||||||
|
if (array.Dimensions > 1) { |
||||||
|
for (int i = 0; i < array.Dimensions; i++) { |
||||||
|
if (i > 0) b.Append(','); |
||||||
|
b.Append("0:"); |
||||||
|
} |
||||||
|
} |
||||||
|
b.Append(']'); |
||||||
|
break; |
||||||
|
case TypeKind.Pointer: |
||||||
|
AppendTypeName(b, ((PointerType)type).ElementType); |
||||||
|
b.Append('*'); |
||||||
|
break; |
||||||
|
case TypeKind.ByReference: |
||||||
|
AppendTypeName(b, ((ByReferenceType)type).ElementType); |
||||||
|
b.Append('@'); |
||||||
|
break; |
||||||
|
default: |
||||||
|
IType declType = type.DeclaringType; |
||||||
|
if (declType != null) { |
||||||
|
AppendTypeName(b, declType); |
||||||
|
b.Append('.'); |
||||||
|
b.Append(type.Name); |
||||||
|
AppendTypeParameters(b, type, declType.TypeParameterCount); |
||||||
|
} else { |
||||||
|
b.Append(type.FullName); |
||||||
|
AppendTypeParameters(b, type, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void AppendTypeParameters(StringBuilder b, IType type, int outerTypeParameterCount) |
||||||
|
{ |
||||||
|
int tpc = type.TypeParameterCount - outerTypeParameterCount; |
||||||
|
if (tpc > 0) { |
||||||
|
ParameterizedType pt = type as ParameterizedType; |
||||||
|
if (pt != null) { |
||||||
|
b.Append('{'); |
||||||
|
var ta = pt.TypeArguments; |
||||||
|
for (int i = outerTypeParameterCount; i < ta.Count; i++) { |
||||||
|
if (i > outerTypeParameterCount) b.Append(','); |
||||||
|
AppendTypeName(b, ta[i]); |
||||||
|
} |
||||||
|
b.Append('}'); |
||||||
|
} else { |
||||||
|
b.Append('`'); |
||||||
|
b.Append(tpc); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void AppendTypeName(StringBuilder b, ITypeReference type, ITypeResolveContext context) |
||||||
|
{ |
||||||
|
IType resolvedType = type as IType; |
||||||
|
if (resolvedType != null) { |
||||||
|
AppendTypeName(b, resolvedType); |
||||||
|
return; |
||||||
|
} |
||||||
|
GetClassTypeReference gctr = type as GetClassTypeReference; |
||||||
|
if (gctr != null) { |
||||||
|
if (!string.IsNullOrEmpty(gctr.Namespace)) { |
||||||
|
b.Append(gctr.Namespace); |
||||||
|
b.Append('.'); |
||||||
|
} |
||||||
|
b.Append(gctr.Name); |
||||||
|
if (gctr.TypeParameterCount > 0) { |
||||||
|
b.Append('`'); |
||||||
|
b.Append(gctr.TypeParameterCount); |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
NestedTypeReference ntr = type as NestedTypeReference; |
||||||
|
if (ntr != null) { |
||||||
|
AppendTypeName(b, ntr.DeclaringTypeReference, context); |
||||||
|
b.Append('.'); |
||||||
|
b.Append(ntr.Name); |
||||||
|
if (ntr.AdditionalTypeParameterCount > 0) { |
||||||
|
b.Append('`'); |
||||||
|
b.Append(ntr.AdditionalTypeParameterCount); |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
ParameterizedTypeReference pt = type as ParameterizedTypeReference; |
||||||
|
if (pt != null && IsGetClassTypeReference(pt.GenericType)) { |
||||||
|
AppendParameterizedTypeName(b, pt.GenericType, pt.TypeArguments, context); |
||||||
|
return; |
||||||
|
} |
||||||
|
ArrayTypeReference array = type as ArrayTypeReference; |
||||||
|
if (array != null) { |
||||||
|
AppendTypeName(b, array.ElementType, context); |
||||||
|
b.Append('['); |
||||||
|
if (array.Dimensions > 1) { |
||||||
|
for (int i = 0; i < array.Dimensions; i++) { |
||||||
|
if (i > 0) b.Append(','); |
||||||
|
b.Append("0:"); |
||||||
|
} |
||||||
|
} |
||||||
|
b.Append(']'); |
||||||
|
return; |
||||||
|
} |
||||||
|
PointerTypeReference ptr = type as PointerTypeReference; |
||||||
|
if (ptr != null) { |
||||||
|
AppendTypeName(b, ptr.ElementType, context); |
||||||
|
b.Append('*'); |
||||||
|
return; |
||||||
|
} |
||||||
|
ByReferenceTypeReference brtr = type as ByReferenceTypeReference; |
||||||
|
if (brtr != null) { |
||||||
|
AppendTypeName(b, brtr.ElementType, context); |
||||||
|
b.Append('@'); |
||||||
|
return; |
||||||
|
} |
||||||
|
if (context == null) |
||||||
|
b.Append('?'); |
||||||
|
else |
||||||
|
AppendTypeName(b, type.Resolve(context)); |
||||||
|
} |
||||||
|
|
||||||
|
static bool IsGetClassTypeReference(ITypeReference type) |
||||||
|
{ |
||||||
|
NestedTypeReference ntr; |
||||||
|
while ((ntr = type as NestedTypeReference) != null) |
||||||
|
type = ntr.DeclaringTypeReference; |
||||||
|
return type is GetClassTypeReference; |
||||||
|
} |
||||||
|
|
||||||
|
static int AppendParameterizedTypeName(StringBuilder b, ITypeReference type, IList<ITypeReference> typeArguments, ITypeResolveContext context) |
||||||
|
{ |
||||||
|
GetClassTypeReference gctr = type as GetClassTypeReference; |
||||||
|
if (gctr != null) { |
||||||
|
if (!string.IsNullOrEmpty(gctr.Namespace)) { |
||||||
|
b.Append(gctr.Namespace); |
||||||
|
b.Append('.'); |
||||||
|
} |
||||||
|
b.Append(gctr.Name); |
||||||
|
if (gctr.TypeParameterCount > 0) { |
||||||
|
b.Append('{'); |
||||||
|
for (int i = 0; i < gctr.TypeParameterCount && i < typeArguments.Count; i++) { |
||||||
|
if (i > 0) b.Append(','); |
||||||
|
AppendTypeName(b, typeArguments[i], context); |
||||||
|
} |
||||||
|
b.Append('}'); |
||||||
|
} |
||||||
|
return gctr.TypeParameterCount; |
||||||
|
} else { |
||||||
|
NestedTypeReference ntr = (NestedTypeReference)type; |
||||||
|
int outerTpc = AppendParameterizedTypeName(b, ntr.DeclaringTypeReference, typeArguments, context); |
||||||
|
b.Append('.'); |
||||||
|
if (ntr.AdditionalTypeParameterCount > 0) { |
||||||
|
b.Append('{'); |
||||||
|
for (int i = 0; i < ntr.AdditionalTypeParameterCount && i + outerTpc < typeArguments.Count; i++) { |
||||||
|
if (i > 0) b.Append(','); |
||||||
|
AppendTypeName(b, typeArguments[i + outerTpc], context); |
||||||
|
} |
||||||
|
b.Append('}'); |
||||||
|
} |
||||||
|
return outerTpc + ntr.AdditionalTypeParameterCount; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue