mirror of https://github.com/icsharpcode/ILSpy.git
5 changed files with 35 additions and 438 deletions
@ -1,392 +0,0 @@
@@ -1,392 +0,0 @@
|
||||
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.Decompiler.TypeSystem.Implementation; |
||||
|
||||
namespace ICSharpCode.Decompiler.Documentation |
||||
{ |
||||
/// <summary>
|
||||
/// Provides XML documentation tags.
|
||||
/// </summary>
|
||||
public static class XmlDocKeyProvider |
||||
{ |
||||
#region GetKey
|
||||
/// <summary>
|
||||
/// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity.
|
||||
/// </summary>
|
||||
public static string GetKey(IEntity entity) |
||||
{ |
||||
StringBuilder b = new StringBuilder(); |
||||
switch (entity.SymbolKind) { |
||||
case SymbolKind.TypeDefinition: |
||||
b.Append("T:"); |
||||
AppendTypeName(b, (ITypeDefinition)entity, false); |
||||
return b.ToString(); |
||||
case SymbolKind.Field: |
||||
b.Append("F:"); |
||||
break; |
||||
case SymbolKind.Property: |
||||
case SymbolKind.Indexer: |
||||
b.Append("P:"); |
||||
break; |
||||
case SymbolKind.Event: |
||||
b.Append("E:"); |
||||
break; |
||||
default: |
||||
b.Append("M:"); |
||||
break; |
||||
} |
||||
IMember member = (IMember)entity; |
||||
if (member.DeclaringType != null) { |
||||
AppendTypeName(b, member.DeclaringType, false); |
||||
b.Append('.'); |
||||
} |
||||
if (member.IsExplicitInterfaceImplementation && member.Name.IndexOf('.') < 0 && member.ExplicitlyImplementedInterfaceMembers.Count() == 1) { |
||||
AppendTypeName(b, member.ExplicitlyImplementedInterfaceMembers.First().DeclaringType, true); |
||||
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, false); |
||||
} |
||||
b.Append(')'); |
||||
} |
||||
if (member.SymbolKind == SymbolKind.Operator && (member.Name == "op_Implicit" || member.Name == "op_Explicit")) { |
||||
b.Append('~'); |
||||
AppendTypeName(b, member.ReturnType, false); |
||||
} |
||||
return b.ToString(); |
||||
} |
||||
#endregion
|
||||
|
||||
#region GetTypeName
|
||||
public static string GetTypeName(IType type) |
||||
{ |
||||
if (type == null) |
||||
throw new ArgumentNullException("type"); |
||||
StringBuilder b = new StringBuilder(); |
||||
AppendTypeName(b, type, false); |
||||
return b.ToString(); |
||||
} |
||||
|
||||
static void AppendTypeName(StringBuilder b, IType type, bool explicitInterfaceImpl) |
||||
{ |
||||
switch (type.Kind) { |
||||
case TypeKind.Dynamic: |
||||
b.Append(explicitInterfaceImpl ? "System#Object" : "System.Object"); |
||||
break; |
||||
case TypeKind.TypeParameter: |
||||
ITypeParameter tp = (ITypeParameter)type; |
||||
if (explicitInterfaceImpl) { |
||||
b.Append(tp.Name); |
||||
} else { |
||||
b.Append('`'); |
||||
if (tp.OwnerType == SymbolKind.Method) |
||||
b.Append('`'); |
||||
b.Append(tp.Index); |
||||
} |
||||
break; |
||||
case TypeKind.Array: |
||||
ArrayType array = (ArrayType)type; |
||||
AppendTypeName(b, array.ElementType, explicitInterfaceImpl); |
||||
b.Append('['); |
||||
if (array.Dimensions > 1) { |
||||
for (int i = 0; i < array.Dimensions; i++) { |
||||
if (i > 0) |
||||
b.Append(explicitInterfaceImpl ? '@' : ','); |
||||
if (!explicitInterfaceImpl) |
||||
b.Append("0:"); |
||||
} |
||||
} |
||||
b.Append(']'); |
||||
break; |
||||
case TypeKind.Pointer: |
||||
AppendTypeName(b, ((PointerType)type).ElementType, explicitInterfaceImpl); |
||||
b.Append('*'); |
||||
break; |
||||
case TypeKind.ByReference: |
||||
AppendTypeName(b, ((ByReferenceType)type).ElementType, explicitInterfaceImpl); |
||||
b.Append('@'); |
||||
break; |
||||
default: |
||||
IType declType = type.DeclaringType; |
||||
if (declType != null) { |
||||
AppendTypeName(b, declType, explicitInterfaceImpl); |
||||
b.Append(explicitInterfaceImpl ? '#' : '.'); |
||||
b.Append(type.Name); |
||||
AppendTypeParameters(b, type, declType.TypeParameterCount, explicitInterfaceImpl); |
||||
} else { |
||||
if (explicitInterfaceImpl) |
||||
b.Append(type.FullName.Replace('.', '#')); |
||||
else |
||||
b.Append(type.FullName); |
||||
AppendTypeParameters(b, type, 0, explicitInterfaceImpl); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static void AppendTypeParameters(StringBuilder b, IType type, int outerTypeParameterCount, bool explicitInterfaceImpl) |
||||
{ |
||||
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(explicitInterfaceImpl ? '@' : ','); |
||||
AppendTypeName(b, ta[i], explicitInterfaceImpl); |
||||
} |
||||
b.Append('}'); |
||||
} else { |
||||
b.Append('`'); |
||||
b.Append(tpc); |
||||
} |
||||
} |
||||
} |
||||
#endregion
|
||||
|
||||
#region ParseMemberName
|
||||
/// <summary>
|
||||
/// Parse the ID string into a member reference.
|
||||
/// </summary>
|
||||
/// <param name="memberIdString">The ID string representing the member (with "M:", "F:", "P:" or "E:" prefix).</param>
|
||||
/// <returns>A member reference that represents the ID string.</returns>
|
||||
/// <exception cref="ReflectionNameParseException">The syntax of the ID string is invalid</exception>
|
||||
/// <remarks>
|
||||
/// The member reference will look in <see cref="ITypeResolveContext.CurrentModule"/> first,
|
||||
/// and if the member is not found there,
|
||||
/// it will look in all other assemblies of the compilation.
|
||||
/// </remarks>
|
||||
public static IMemberReference ParseMemberIdString(string memberIdString) |
||||
{ |
||||
if (memberIdString == null) |
||||
throw new ArgumentNullException("memberIdString"); |
||||
if (memberIdString.Length < 2 || memberIdString[1] != ':') |
||||
throw new ReflectionNameParseException(0, "Missing type tag"); |
||||
char typeChar = memberIdString[0]; |
||||
int parenPos = memberIdString.IndexOf('('); |
||||
if (parenPos < 0) |
||||
parenPos = memberIdString.LastIndexOf('~'); |
||||
if (parenPos < 0) |
||||
parenPos = memberIdString.Length; |
||||
int dotPos = memberIdString.LastIndexOf('.', parenPos - 1); |
||||
if (dotPos < 0) |
||||
throw new ReflectionNameParseException(0, "Could not find '.' separating type name from member name"); |
||||
string typeName = memberIdString.Substring(0, dotPos); |
||||
int pos = 2; |
||||
ITypeReference typeReference = ParseTypeName(typeName, ref pos); |
||||
if (pos != typeName.Length) |
||||
throw new ReflectionNameParseException(pos, "Expected end of type name"); |
||||
// string memberName = memberIDString.Substring(dotPos + 1, parenPos - (dotPos + 1));
|
||||
// pos = memberName.LastIndexOf("``");
|
||||
// if (pos > 0)
|
||||
// memberName = memberName.Substring(0, pos);
|
||||
// memberName = memberName.Replace('#', '.');
|
||||
return new IdStringMemberReference(typeReference, typeChar, memberIdString); |
||||
} |
||||
#endregion
|
||||
|
||||
#region ParseTypeName
|
||||
/// <summary>
|
||||
/// Parse the ID string type name into a type reference.
|
||||
/// </summary>
|
||||
/// <param name="typeName">The ID string representing the type (the "T:" prefix is optional).</param>
|
||||
/// <returns>A type reference that represents the ID string.</returns>
|
||||
/// <exception cref="ReflectionNameParseException">The syntax of the ID string is invalid</exception>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The type reference will look in <see cref="ITypeResolveContext.CurrentModule"/> first,
|
||||
/// and if the type is not found there,
|
||||
/// it will look in all other assemblies of the compilation.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the type is open (contains type parameters '`0' or '``0'),
|
||||
/// an <see cref="ITypeResolveContext"/> with the appropriate CurrentTypeDefinition/CurrentMember is required
|
||||
/// to resolve the reference to the ITypeParameter.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static ITypeReference ParseTypeName(string typeName) |
||||
{ |
||||
if (typeName == null) |
||||
throw new ArgumentNullException("typeName"); |
||||
int pos = 0; |
||||
if (typeName.StartsWith("T:", StringComparison.Ordinal)) |
||||
pos = 2; |
||||
ITypeReference r = ParseTypeName(typeName, ref pos); |
||||
if (pos < typeName.Length) |
||||
throw new ReflectionNameParseException(pos, "Expected end of type name"); |
||||
return r; |
||||
} |
||||
|
||||
static bool IsIDStringSpecialCharacter(char c) |
||||
{ |
||||
switch (c) { |
||||
case ':': |
||||
case '{': |
||||
case '}': |
||||
case '[': |
||||
case ']': |
||||
case '(': |
||||
case ')': |
||||
case '`': |
||||
case '*': |
||||
case '@': |
||||
case ',': |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
static ITypeReference ParseTypeName(string typeName, ref int pos) |
||||
{ |
||||
string reflectionTypeName = typeName; |
||||
if (pos == typeName.Length) |
||||
throw new ReflectionNameParseException(pos, "Unexpected end"); |
||||
ITypeReference result; |
||||
if (reflectionTypeName[pos] == '`') { |
||||
// type parameter reference
|
||||
pos++; |
||||
if (pos == reflectionTypeName.Length) |
||||
throw new ReflectionNameParseException(pos, "Unexpected end"); |
||||
if (reflectionTypeName[pos] == '`') { |
||||
// method type parameter reference
|
||||
pos++; |
||||
int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos); |
||||
result = TypeParameterReference.Create(SymbolKind.Method, index); |
||||
} else { |
||||
// class type parameter reference
|
||||
int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos); |
||||
result = TypeParameterReference.Create(SymbolKind.TypeDefinition, index); |
||||
} |
||||
} else { |
||||
// not a type parameter reference: read the actual type name
|
||||
List<ITypeReference> typeArguments = new List<ITypeReference>(); |
||||
int typeParameterCount; |
||||
string typeNameWithoutSuffix = ReadTypeName(typeName, ref pos, true, out typeParameterCount, typeArguments); |
||||
result = new GetPotentiallyNestedClassTypeReference(typeNameWithoutSuffix, typeParameterCount); |
||||
while (pos < typeName.Length && typeName[pos] == '.') { |
||||
pos++; |
||||
string nestedTypeName = ReadTypeName(typeName, ref pos, false, out typeParameterCount, typeArguments); |
||||
result = new NestedTypeReference(result, nestedTypeName, typeParameterCount); |
||||
} |
||||
if (typeArguments.Count > 0) { |
||||
result = new ParameterizedTypeReference(result, typeArguments); |
||||
} |
||||
} |
||||
while (pos < typeName.Length) { |
||||
switch (typeName[pos]) { |
||||
case '[': |
||||
int dimensions = 1; |
||||
do { |
||||
pos++; |
||||
if (pos == typeName.Length) |
||||
throw new ReflectionNameParseException(pos, "Unexpected end"); |
||||
if (typeName[pos] == ',') |
||||
dimensions++; |
||||
} while (typeName[pos] != ']'); |
||||
result = new ArrayTypeReference(result, dimensions); |
||||
break; |
||||
case '*': |
||||
result = new PointerTypeReference(result); |
||||
break; |
||||
case '@': |
||||
result = new ByReferenceTypeReference(result); |
||||
break; |
||||
default: |
||||
return result; |
||||
} |
||||
pos++; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static string ReadTypeName(string typeName, ref int pos, bool allowDottedName, out int typeParameterCount, List<ITypeReference> typeArguments) |
||||
{ |
||||
int startPos = pos; |
||||
// skip the simple name portion:
|
||||
while (pos < typeName.Length && !IsIDStringSpecialCharacter(typeName[pos]) && (allowDottedName || typeName[pos] != '.')) |
||||
pos++; |
||||
if (pos == startPos) |
||||
throw new ReflectionNameParseException(pos, "Expected type name"); |
||||
string shortTypeName = typeName.Substring(startPos, pos - startPos); |
||||
// read type arguments:
|
||||
typeParameterCount = 0; |
||||
if (pos < typeName.Length && typeName[pos] == '`') { |
||||
// unbound generic type
|
||||
pos++; |
||||
typeParameterCount = ReflectionHelper.ReadTypeParameterCount(typeName, ref pos); |
||||
} else if (pos < typeName.Length && typeName[pos] == '{') { |
||||
// bound generic type
|
||||
typeArguments = new List<ITypeReference>(); |
||||
do { |
||||
pos++; |
||||
typeArguments.Add(ParseTypeName(typeName, ref pos)); |
||||
typeParameterCount++; |
||||
if (pos == typeName.Length) |
||||
throw new ReflectionNameParseException(pos, "Unexpected end"); |
||||
} while (typeName[pos] == ','); |
||||
if (typeName[pos] != '}') |
||||
throw new ReflectionNameParseException(pos, "Expected '}'"); |
||||
pos++; |
||||
} |
||||
return shortTypeName; |
||||
} |
||||
#endregion
|
||||
|
||||
#region FindEntity
|
||||
/// <summary>
|
||||
/// Finds the entity in the given type resolve context.
|
||||
/// </summary>
|
||||
/// <param name="idString">ID string of the entity.</param>
|
||||
/// <param name="context">Type resolve context</param>
|
||||
/// <returns>Returns the entity, or null if it is not found.</returns>
|
||||
/// <exception cref="ReflectionNameParseException">The syntax of the ID string is invalid</exception>
|
||||
public static IEntity FindEntity(string idString, ITypeResolveContext context) |
||||
{ |
||||
if (idString == null) |
||||
throw new ArgumentNullException("idString"); |
||||
if (context == null) |
||||
throw new ArgumentNullException("context"); |
||||
if (idString.StartsWith("T:", StringComparison.Ordinal)) { |
||||
return ParseTypeName(idString.Substring(2)).Resolve(context).GetDefinition(); |
||||
} else { |
||||
return ParseMemberIdString(idString).Resolve(context); |
||||
} |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
Loading…
Reference in new issue