Browse Source

Add DocumentationComment class that allows looking up 'cref' attributes.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
7a76a805a0
  1. 2
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpOperators.cs
  2. 82
      ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs
  3. 55
      ICSharpCode.NRefactory/Documentation/DocumentationComment.cs
  4. 66
      ICSharpCode.NRefactory/Documentation/GetPotentiallyNestedClassTypeReference.cs
  5. 72
      ICSharpCode.NRefactory/Documentation/IDStringMemberReference.cs
  6. 207
      ICSharpCode.NRefactory/Documentation/IDStringProvider.cs
  7. 5
      ICSharpCode.NRefactory/Documentation/IDocumentationProvider.cs
  8. 44
      ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
  9. 5
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  10. 3
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  11. 1
      ICSharpCode.NRefactory/TypeSystem/ICompilation.cs
  12. 3
      ICSharpCode.NRefactory/TypeSystem/IEntity.cs
  13. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedEntity.cs
  14. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  15. 3
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs
  16. 7
      ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs

2
ICSharpCode.NRefactory.CSharp/Resolver/CSharpOperators.cs

@ -163,7 +163,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -163,7 +163,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
get { return EmptyList<IAttribute>.Instance; }
}
string IEntity.Documentation {
Documentation.DocumentationComment IEntity.Documentation {
get { return null; }
}

82
ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs

@ -34,12 +34,12 @@ namespace ICSharpCode.NRefactory.Documentation @@ -34,12 +34,12 @@ namespace ICSharpCode.NRefactory.Documentation
{
public IDStringTestProjectContent() : base("Test") {}
public string GetDocumentation(IEntity entity)
public DocumentationComment 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);
return new DocumentationComment(IDStringProvider.GetIDString(entity));
}
}
@ -87,18 +87,18 @@ namespace Acme @@ -87,18 +87,18 @@ namespace Acme
}
}";
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);
Assert.AreEqual("T:Color", GetTypeDefinition(string.Empty, "Color").Documentation.XmlText);
Assert.AreEqual("T:Acme.IProcess", GetTypeDefinition("Acme", "IProcess").Documentation.XmlText);
Assert.AreEqual("T:Acme.ValueType", GetTypeDefinition("Acme", "ValueType").Documentation.XmlText);
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);
Assert.AreEqual("T:Acme.Widget", widget.Documentation.XmlText);
Assert.AreEqual("T:Acme.Widget.NestedClass", widget.NestedTypes.Single(t => t.Name == "NestedClass").Documentation.XmlText);
Assert.AreEqual("T:Acme.Widget.IMenuItem", widget.NestedTypes.Single(t => t.Name == "IMenuItem").Documentation.XmlText);
Assert.AreEqual("T:Acme.Widget.Del", widget.NestedTypes.Single(t => t.Name == "Del").Documentation.XmlText);
Assert.AreEqual("T:Acme.Widget.Direction", widget.NestedTypes.Single(t => t.Name == "Direction").Documentation.XmlText);
Assert.AreEqual("T:Acme.MyList`1", GetTypeDefinition("Acme", "MyList", 1).Documentation.XmlText);
Assert.AreEqual("T:Acme.MyList`1.Helper`2", GetTypeDefinition("Acme", "MyList", 1).NestedTypes.Single().Documentation.XmlText);
}
[Test]
@ -121,10 +121,10 @@ namespace Acme @@ -121,10 +121,10 @@ namespace Acme
}";
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);
Assert.AreEqual("F:Acme.Widget.NestedClass.value", widget.NestedTypes.Single().Fields.Single().Documentation.XmlText);
Assert.AreEqual("F:Acme.Widget.message", widget.Fields.Single(f => f.Name == "message").Documentation.XmlText);
Assert.AreEqual("F:Acme.Widget.PI", widget.Fields.Single(f => f.Name == "PI").Documentation.XmlText);
Assert.AreEqual("F:Acme.Widget.ppValues", widget.Fields.Single(f => f.Name == "ppValues").Documentation.XmlText);
}
[Test]
@ -142,9 +142,9 @@ namespace Acme @@ -142,9 +142,9 @@ namespace Acme
}";
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);
Assert.AreEqual("M:Acme.Widget.#cctor", widget.Methods.Single(m => m.IsStatic).Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.#ctor", widget.Methods.Single(m => !m.IsStatic && m.Parameters.Count == 0).Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.#ctor(System.String)", widget.Methods.Single(m => m.Parameters.Count == 1).Documentation.XmlText);
}
[Test]
@ -160,7 +160,7 @@ namespace Acme @@ -160,7 +160,7 @@ namespace Acme
}";
Init(program);
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget");
Assert.AreEqual("M:Acme.Widget.Finalize", widget.Methods.Single(m => m.EntityType == EntityType.Destructor).Documentation);
Assert.AreEqual("M:Acme.Widget.Finalize", widget.Methods.Single(m => m.EntityType == EntityType.Destructor).Documentation.XmlText);
}
[Test]
@ -200,28 +200,28 @@ namespace Acme @@ -200,28 +200,28 @@ namespace Acme
}";
Init(program);
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget");
Assert.AreEqual("M:Acme.Widget.NestedClass.M(System.Int32)", widget.NestedTypes.Single().Methods.Single(m => m.EntityType == EntityType.Method).Documentation);
Assert.AreEqual("M:Acme.Widget.M0", widget.Methods.Single(m => m.Name == "M0").Documentation);
Assert.AreEqual("M:Acme.Widget.NestedClass.M(System.Int32)", widget.NestedTypes.Single().Methods.Single(m => m.EntityType == EntityType.Method).Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M0", widget.Methods.Single(m => m.Name == "M0").Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M1(System.Char,System.Single@,Acme.ValueType@)",
widget.Methods.Single(m => m.Name == "M1").Documentation);
widget.Methods.Single(m => m.Name == "M1").Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M2(System.Int16[],System.Int32[0:,0:],System.Int64[][])",
widget.Methods.Single(m => m.Name == "M2").Documentation);
widget.Methods.Single(m => m.Name == "M2").Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M3(System.Int64[][],Acme.Widget[0:,0:,0:][])",
widget.Methods.Single(m => m.Name == "M3").Documentation);
widget.Methods.Single(m => m.Name == "M3").Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M4(System.Char*,Color**)",
widget.Methods.Single(m => m.Name == "M4").Documentation);
widget.Methods.Single(m => m.Name == "M4").Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M5(System.Void*,System.Double*[0:,0:][])",
widget.Methods.Single(m => m.Name == "M5").Documentation);
widget.Methods.Single(m => m.Name == "M5").Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.M6(System.Nullable{System.Int32},System.Object[])",
widget.Methods.Single(m => m.Name == "M6").Documentation);
widget.Methods.Single(m => m.Name == "M6").Documentation.XmlText);
Assert.AreEqual("M:Acme.MyList`1.Test(`0)",
GetTypeDefinition("Acme", "MyList", 1).Methods.Single(m => m.Name == "Test").Documentation);
GetTypeDefinition("Acme", "MyList", 1).Methods.Single(m => m.Name == "Test").Documentation.XmlText);
Assert.AreEqual("M:Acme.UseList.Process(Acme.MyList{Color})",
GetTypeDefinition("Acme", "UseList").Methods.Single(m => m.Name == "Process").Documentation);
GetTypeDefinition("Acme", "UseList").Methods.Single(m => m.Name == "Process").Documentation.XmlText);
Assert.AreEqual("M:Acme.UseList.GetValues``1(``0)",
GetTypeDefinition("Acme", "UseList").Methods.Single(m => m.Name == "GetValues").Documentation);
GetTypeDefinition("Acme", "UseList").Methods.Single(m => m.Name == "GetValues").Documentation.XmlText);
}
[Test]
@ -229,8 +229,8 @@ namespace Acme @@ -229,8 +229,8 @@ namespace Acme
{
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(m => m.EntityType == EntityType.Method).Documentation);
Assert.AreEqual("T:A`1.B`1", b.Documentation.XmlText);
Assert.AreEqual("M:A`1.B`1.M(A{`1}.B{`0})", b.Methods.Single(m => m.EntityType == EntityType.Method).Documentation.XmlText);
}
[Test]
@ -248,11 +248,11 @@ namespace Acme @@ -248,11 +248,11 @@ namespace Acme
}";
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.Width", widget.Properties.Single(p => p.Parameters.Count == 0).Documentation.XmlText);
Assert.AreEqual("P:Acme.Widget.Item(System.Int32)",
widget.Properties.Single(p => p.Parameters.Count == 1).Documentation);
widget.Properties.Single(p => p.Parameters.Count == 1).Documentation.XmlText);
Assert.AreEqual("P:Acme.Widget.Item(System.String,System.Int32)",
widget.Properties.Single(p => p.Parameters.Count == 2).Documentation);
widget.Properties.Single(p => p.Parameters.Count == 2).Documentation.XmlText);
}
@ -269,7 +269,7 @@ namespace Acme @@ -269,7 +269,7 @@ namespace Acme
}";
Init(program);
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget");
Assert.AreEqual("E:Acme.Widget.AnEvent", widget.Events.Single().Documentation);
Assert.AreEqual("E:Acme.Widget.AnEvent", widget.Events.Single().Documentation.XmlText);
}
@ -286,7 +286,7 @@ namespace Acme @@ -286,7 +286,7 @@ namespace Acme
}";
Init(program);
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget");
Assert.AreEqual("M:Acme.Widget.op_UnaryPlus(Acme.Widget)", widget.Methods.Single(m => m.EntityType == EntityType.Operator).Documentation);
Assert.AreEqual("M:Acme.Widget.op_UnaryPlus(Acme.Widget)", widget.Methods.Single(m => m.EntityType == EntityType.Operator).Documentation.XmlText);
}
[Test]
@ -302,7 +302,7 @@ namespace Acme @@ -302,7 +302,7 @@ namespace Acme
}";
Init(program);
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget");
Assert.AreEqual("M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)", widget.Methods.Single(m => m.EntityType == EntityType.Operator).Documentation);
Assert.AreEqual("M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)", widget.Methods.Single(m => m.EntityType == EntityType.Operator).Documentation.XmlText);
}
[Test]
@ -319,8 +319,8 @@ namespace Acme @@ -319,8 +319,8 @@ namespace Acme
}";
Init(program);
ITypeDefinition widget = GetTypeDefinition("Acme", "Widget");
Assert.AreEqual("M:Acme.Widget.op_Explicit(Acme.Widget)~System.Int32", widget.Methods.First(m => m.EntityType == EntityType.Operator).Documentation);
Assert.AreEqual("M:Acme.Widget.op_Implicit(Acme.Widget)~System.Int64", widget.Methods.Last(m => m.EntityType == EntityType.Operator).Documentation);
Assert.AreEqual("M:Acme.Widget.op_Explicit(Acme.Widget)~System.Int32", widget.Methods.First(m => m.EntityType == EntityType.Operator).Documentation.XmlText);
Assert.AreEqual("M:Acme.Widget.op_Implicit(Acme.Widget)~System.Int64", widget.Methods.Last(m => m.EntityType == EntityType.Operator).Documentation.XmlText);
}
[Test]

55
ICSharpCode.NRefactory/Documentation/DocumentationComment.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// Copyright (c) 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.Documentation
{
/// <summary>
/// Represents a documentation comment.
/// </summary>
[Serializable]
public class DocumentationComment
{
string xmlText;
/// <summary>
/// Gets the XML code for this documentation comment.
/// </summary>
public string XmlText {
get { return xmlText; }
}
public DocumentationComment(string xmlText)
{
if (xmlText == null)
throw new ArgumentNullException("xmlText");
this.xmlText = xmlText;
}
/// <summary>
/// Resolves the given cref value to an entity.
/// Returns null if the entity is not found, or if the cref attribute is syntactically invalid.
/// </summary>
public virtual IEntity ResolveCRef(string cref)
{
return null;
}
}
}

66
ICSharpCode.NRefactory/Documentation/GetPotentiallyNestedClassTypeReference.cs

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
// Copyright (c) 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.Linq;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.Documentation
{
/// <summary>
/// A type reference of the form 'Some.Namespace.TopLevelType.NestedType`n'.
/// We do not know the boundary between namespace name and top level type, so we have to try
/// all possibilities.
/// The type parameter count only applies to the innermost type, all outer types must be non-generic.
/// </summary>
[Serializable]
class GetPotentiallyNestedClassTypeReference : ITypeReference
{
readonly string typeName;
readonly int typeParameterCount;
public GetPotentiallyNestedClassTypeReference(string typeName, int typeParameterCount)
{
this.typeName = typeName;
this.typeParameterCount = typeParameterCount;
}
public IType Resolve(ITypeResolveContext context)
{
string[] parts = typeName.Split('.');
var assemblies = new [] { context.CurrentAssembly, context.Compilation.MainAssembly }.Concat(context.Compilation.ReferencedAssemblies);
for (int i = parts.Length - 1; i >= 0; i++) {
string ns = string.Join(".", parts, 0, i);
string name = parts[i];
int topLevelTPC = (i == parts.Length - 1 ? typeParameterCount : 0);
foreach (var asm in assemblies) {
if (asm == null)
continue;
ITypeDefinition typeDef = asm.GetTypeDefinition(ns, name, topLevelTPC);
for (int j = i + 1; j < parts.Length && typeDef != null; j++) {
int tpc = (j == parts.Length - 1 ? typeParameterCount : 0);
typeDef = typeDef.NestedTypes.FirstOrDefault(n => n.Name == parts[j] && n.TypeParameterCount == tpc);
}
if (typeDef != null)
return typeDef;
}
}
return null;
}
}
}

72
ICSharpCode.NRefactory/Documentation/IDStringMemberReference.cs

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
// Copyright (c) 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.Documentation
{
[Serializable]
class IDStringMemberReference : IMemberReference
{
readonly ITypeReference declaringTypeReference;
readonly char memberType;
readonly string memberName;
readonly string memberIDString;
public IDStringMemberReference(ITypeReference declaringTypeReference, char memberType, string memberName, string memberIDString)
{
this.declaringTypeReference = declaringTypeReference;
this.memberType = memberType;
this.memberName = memberName;
this.memberIDString = memberIDString;
}
bool CanMatch(IUnresolvedMember member)
{
if (member.Name != memberName)
return false;
switch (member.EntityType) {
case EntityType.Field:
return memberType == 'F';
case EntityType.Property:
case EntityType.Indexer:
return memberType == 'P';
case EntityType.Event:
return memberType == 'E';
case EntityType.Method:
case EntityType.Operator:
case EntityType.Constructor:
case EntityType.Destructor:
return memberType == 'M';
default:
throw new NotSupportedException(member.EntityType.ToString());
}
}
public IMember Resolve(ITypeResolveContext context)
{
IType declaringType = declaringTypeReference.Resolve(context);
foreach (var member in declaringType.GetMembers(CanMatch, GetMemberOptions.IgnoreInheritedMembers)) {
if (IDStringProvider.GetIDString(member) == memberIDString)
return member;
}
return null;
}
}
}

207
ICSharpCode.NRefactory/Documentation/IDStringProvider.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.NRefactory.TypeSystem;
@ -30,6 +31,7 @@ namespace ICSharpCode.NRefactory.Documentation @@ -30,6 +31,7 @@ namespace ICSharpCode.NRefactory.Documentation
/// </summary>
public static class IDStringProvider
{
#region GetIDString
/// <summary>
/// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity.
/// </summary>
@ -80,7 +82,9 @@ namespace ICSharpCode.NRefactory.Documentation @@ -80,7 +82,9 @@ namespace ICSharpCode.NRefactory.Documentation
}
return b.ToString();
}
#endregion
#region GetTypeName
public static string GetTypeName(IType type)
{
if (type == null)
@ -157,5 +161,208 @@ namespace ICSharpCode.NRefactory.Documentation @@ -157,5 +161,208 @@ namespace ICSharpCode.NRefactory.Documentation
}
}
}
#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>
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('.', 0, parenPos);
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));
int memberTypeParameterCount;
memberName = ReflectionHelper.SplitTypeParameterCountFromReflectionName(memberName, out memberTypeParameterCount);
memberName = memberName.Replace('#', '.');
return new IDStringMemberReference(typeReference, typeChar, memberName, 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.CurrentAssembly"/> 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");
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);
return new TypeParameterReference(EntityType.Method, index);
} else {
// class type parameter reference
int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos);
return new TypeParameterReference(EntityType.TypeDefinition, index);
}
}
// 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);
ITypeReference 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 '}'");
}
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
}
}

5
ICSharpCode.NRefactory/TypeSystem/IDocumentationProvider.cs → ICSharpCode.NRefactory/Documentation/IDocumentationProvider.cs

@ -18,8 +18,9 @@ @@ -18,8 +18,9 @@
using System;
using System.IO;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.TypeSystem
namespace ICSharpCode.NRefactory.Documentation
{
/// <summary>
/// Provides XML documentation for members.
@ -29,6 +30,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -29,6 +30,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary>
/// Gets the XML documentation for the specified entity.
/// </summary>
string GetDocumentation(IEntity entity);
DocumentationComment GetDocumentation(IEntity entity);
}
}

44
ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs

@ -23,6 +23,7 @@ using System.IO; @@ -23,6 +23,7 @@ using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.Documentation
{
@ -262,12 +263,6 @@ namespace ICSharpCode.NRefactory.Documentation @@ -262,12 +263,6 @@ namespace ICSharpCode.NRefactory.Documentation
#endregion
#region GetDocumentation
/// <inheritdoc/>
public string GetDocumentation(IEntity entity)
{
return GetDocumentation(IDStringProvider.GetIDString(entity));
}
/// <summary>
/// Get the documentation for the member with the specified documentation key.
/// </summary>
@ -304,6 +299,43 @@ namespace ICSharpCode.NRefactory.Documentation @@ -304,6 +299,43 @@ namespace ICSharpCode.NRefactory.Documentation
}
#endregion
#region GetDocumentation for entity
/// <inheritdoc/>
public DocumentationComment GetDocumentation(IEntity entity)
{
string xmlDoc = GetDocumentation(IDStringProvider.GetIDString(entity));
if (xmlDoc != null) {
if (entity is IMember)
return new XmlDocumentationComment(xmlDoc, new SimpleTypeResolveContext((IMember)entity));
else if (entity is ITypeDefinition)
return new XmlDocumentationComment(xmlDoc, new SimpleTypeResolveContext((ITypeDefinition)entity));
else
return new XmlDocumentationComment(xmlDoc, new SimpleTypeResolveContext(entity.ParentAssembly));
} else {
return null;
}
}
sealed class XmlDocumentationComment : DocumentationComment
{
ITypeResolveContext context;
public XmlDocumentationComment(string xmlText, ITypeResolveContext context) : base(xmlText)
{
this.context = context;
}
public override IEntity ResolveCRef(string cref)
{
try {
return IDStringProvider.FindEntity(cref, context);
} catch (ReflectionNameParseException) {
return null;
}
}
}
#endregion
#region Load / Read XML
string LoadDocumentation(string key, int positionInFile)
{

5
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -53,6 +53,10 @@ @@ -53,6 +53,10 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="Documentation\DocumentationComment.cs" />
<Compile Include="Documentation\GetPotentiallyNestedClassTypeReference.cs" />
<Compile Include="Documentation\IDocumentationProvider.cs" />
<Compile Include="Documentation\IDStringMemberReference.cs" />
<Compile Include="Documentation\IDStringProvider.cs" />
<Compile Include="Editor\IDocument.cs" />
<Compile Include="Editor\IDocumentLine.cs" />
@ -108,7 +112,6 @@ @@ -108,7 +112,6 @@
<Compile Include="TypeSystem\IAttribute.cs" />
<Compile Include="TypeSystem\ICompilation.cs" />
<Compile Include="TypeSystem\IConstantValue.cs" />
<Compile Include="TypeSystem\IDocumentationProvider.cs" />
<Compile Include="TypeSystem\IEntity.cs" />
<Compile Include="TypeSystem\IEvent.cs" />
<Compile Include="TypeSystem\IField.cs" />

3
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -26,6 +26,7 @@ using System.Runtime.CompilerServices; @@ -26,6 +26,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Threading;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
@ -177,7 +178,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -177,7 +178,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
this.documentationProvider = documentationProvider;
}
string IDocumentationProvider.GetDocumentation(IEntity entity)
DocumentationComment IDocumentationProvider.GetDocumentation(IEntity entity)
{
if (documentationProvider != null)
return documentationProvider.GetDocumentation(entity);

1
ICSharpCode.NRefactory/TypeSystem/ICompilation.cs

@ -42,6 +42,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -42,6 +42,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary>
/// Gets the root namespace of this compilation.
/// This is a merged .
/// </summary>
INamespace RootNamespace { get; }

3
ICSharpCode.NRefactory/TypeSystem/IEntity.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using ICSharpCode.NRefactory.Documentation;
namespace ICSharpCode.NRefactory.TypeSystem
{
@ -137,7 +138,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -137,7 +138,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary>
/// Gets the documentation for this entity.
/// </summary>
string Documentation { get; }
DocumentationComment Documentation { get; }
/// <summary>
/// Gets whether this entity is static.

3
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedEntity.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Documentation;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
{
@ -66,7 +67,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -66,7 +67,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IList<IAttribute> Attributes { get; private set; }
public virtual string Documentation {
public virtual DocumentationComment Documentation {
get {
IDocumentationProvider provider = FindDocumentation(parentContext);
if (provider != null)

3
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -385,7 +386,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -385,7 +386,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return parentContext.CurrentAssembly; }
}
public virtual string Documentation {
public virtual DocumentationComment Documentation {
get {
IDocumentationProvider provider = AbstractResolvedEntity.FindDocumentation(parentContext);
if (provider != null)

3
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -159,7 +160,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -159,7 +160,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return memberDefinition.IsExplicitInterfaceImplementation; }
}
public string Documentation {
public DocumentationComment Documentation {
get { return memberDefinition.Documentation; }
}

7
ICSharpCode.NRefactory/TypeSystem/ReflectionHelper.cs

@ -206,8 +206,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -206,8 +206,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// Parses a reflection name into a type reference.
/// </summary>
/// <param name="reflectionTypeName">The reflection name of the type.</param>
/// <exception cref="ReflectionNameParseException">The syntax of the reflection type name is invalid</exception>
/// <returns>A type reference that represents the reflection name.</returns>
/// <exception cref="ReflectionNameParseException">The syntax of the reflection type name is invalid</exception>
/// <remarks>
/// If the type is open (contains type parameters '`0' or '``0'),
/// an <see cref="ITypeResolveContext"/> with the appropriate CurrentTypeDefinition/CurrentMember is required
@ -215,7 +215,8 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -215,7 +215,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// For looking up closed, assembly qualified type names, the root type resolve context for the compilation
/// is sufficient.
/// When looking up a type name that isn't assembly qualified, the type reference will look in
/// <see cref="ITypeResolveContext.CurrentAssembly"/> first, and .
/// <see cref="ITypeResolveContext.CurrentAssembly"/> first, and if the type is not found there,
/// it will look in all other assemblies of the compilation.
/// </remarks>
public static ITypeReference ParseReflectionName(string reflectionTypeName)
{
@ -411,7 +412,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -411,7 +412,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
return typeName;
}
static int ReadTypeParameterCount(string reflectionTypeName, ref int pos)
internal static int ReadTypeParameterCount(string reflectionTypeName, ref int pos)
{
int startPos = pos;
while (pos < reflectionTypeName.Length) {

Loading…
Cancel
Save