Browse Source

C# XML documentation support.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
2bebee46a1
  1. 20
      ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
  2. 5
      ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs
  3. 117
      ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs
  4. 1
      ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs
  5. 10
      ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs
  6. 2
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  7. 47
      ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  8. 5
      ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs
  9. 10
      ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs
  10. 7
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  11. 43
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs
  12. 46
      ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpParsedFile.cs
  13. 32
      ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
  14. 21
      ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs
  15. 185
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs
  16. 264
      ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs
  17. 62
      ICSharpCode.NRefactory.Tests/Documentation/CSharpDocumentationTests.cs
  18. 80
      ICSharpCode.NRefactory.Tests/Documentation/IDStringTests.cs
  19. 3
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  20. 5
      ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs
  21. 32
      ICSharpCode.NRefactory/Documentation/DocumentationComment.cs
  22. 18
      ICSharpCode.NRefactory/Documentation/IDocumentationProvider.cs
  23. 26
      ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs
  24. 13
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs
  25. 8
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs
  26. 23
      ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleTypeResolveContext.cs

20
ICSharpCode.NRefactory.CSharp/Ast/AstType.cs

@ -153,6 +153,26 @@ namespace ICSharpCode.NRefactory.CSharp @@ -153,6 +153,26 @@ namespace ICSharpCode.NRefactory.CSharp
return new TypeReferenceExpression { Type = this }.Member(memberName);
}
/// <summary>
/// Builds an expression that can be used to access a static member on this type.
/// </summary>
public MemberType MemberType(string memberName, params AstType[] typeArguments)
{
var memberType = new MemberType(this, memberName);
memberType.TypeArguments.AddRange(typeArguments);
return memberType;
}
/// <summary>
/// Builds an expression that can be used to access a static member on this type.
/// </summary>
public MemberType MemberType(string memberName, IEnumerable<AstType> typeArguments)
{
var memberType = new MemberType(this, memberName);
memberType.TypeArguments.AddRange(typeArguments);
return memberType;
}
/// <summary>
/// Builds an invocation expression using this type as target.
/// </summary>

5
ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs

@ -55,6 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -55,6 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (comment, data);
}
public virtual S VisitDocumentationReference (DocumentationReference documentationReference, T data)
{
return VisitChildren (documentationReference, data);
}
public virtual S VisitPreProcessorDirective (PreProcessorDirective preProcessorDirective, T data)
{
return VisitChildren (preProcessorDirective, data);

117
ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
// 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.CSharp
{
/// <summary>
/// Represents a 'cref' reference in XML documentation.
/// </summary>
public class DocumentationReference : AstNode
{
public static readonly Role<AstType> DeclaringTypeRole = new Role<AstType>("DeclaringType", AstType.Null);
public static readonly Role<AstType> ConversionOperatorReturnTypeRole = new Role<AstType>("ConversionOperatorReturnType", AstType.Null);
/// <summary>
/// Gets/Sets the entity type.
/// Possible values are:
/// <c>EntityType.Operator</c> for operators,
/// <c>EntityType.Indexer</c> for indexers,
/// <c>EntityType.TypeDefinition</c> for references to primitive types,
/// and <c>EntityType.None</c> for everything else.
/// </summary>
public EntityType EntityType { get; set; }
/// <summary>
/// Gets/Sets the operator type.
/// This property is only used when EntityType==Operator.
/// </summary>
public OperatorType OperatorType { get; set; }
/// <summary>
/// Gets/Sets whether a parameter list was provided.
/// </summary>
public bool HasParameterList { get; set; }
public override NodeType NodeType {
get { return NodeType.Unknown; }
}
/// <summary>
/// Gets/Sets the declaring type.
/// </summary>
public AstType DeclaringType {
get { return GetChildByRole(DeclaringTypeRole); }
set { SetChildByRole(DeclaringTypeRole, value); }
}
/// <summary>
/// Gets/sets the member name.
/// This property is only used when EntityType==None.
/// </summary>
public string MemberName {
get { return GetChildByRole(Roles.Identifier).Name; }
set { SetChildByRole(Roles.Identifier, Identifier.Create(value)); }
}
/// <summary>
/// Gets/Sets the return type of conversion operators.
/// This property is only used when EntityType==Operator and OperatorType is explicit or implicit.
/// </summary>
public AstType ConversionOperatorReturnType {
get { return GetChildByRole(ConversionOperatorReturnTypeRole); }
set { SetChildByRole(ConversionOperatorReturnTypeRole, value); }
}
public AstNodeCollection<AstType> TypeArguments {
get { return GetChildrenByRole (Roles.TypeArgument); }
}
public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); }
}
protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.PatternMatching.Match match)
{
DocumentationReference o = other as DocumentationReference;
if (!(o != null && this.EntityType == o.EntityType && this.HasParameterList == o.HasParameterList))
return false;
if (this.EntityType == EntityType.Operator) {
if (this.OperatorType != o.OperatorType)
return false;
if (this.OperatorType == OperatorType.Implicit || this.OperatorType == OperatorType.Explicit) {
if (!this.ConversionOperatorReturnType.DoMatch(o.ConversionOperatorReturnType, match))
return false;
}
} else if (this.EntityType == EntityType.None) {
if (!MatchString(this.MemberName, o.MemberName))
return false;
if (!this.TypeArguments.DoMatch(o.TypeArguments, match))
return false;
}
return this.Parameters.DoMatch(o.Parameters, match);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitDocumentationReference(this, data);
}
}
}

1
ICSharpCode.NRefactory.CSharp/Ast/IAstVisitor.cs

@ -138,6 +138,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -138,6 +138,7 @@ namespace ICSharpCode.NRefactory.CSharp
S VisitComment(Comment comment, T data);
S VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective, T data);
S VisitDocumentationReference(DocumentationReference documentationReference, T data);
S VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration, T data);
S VisitConstraint(Constraint constraint, T data);

10
ICSharpCode.NRefactory.CSharp/Ast/ObservableAstVisitor.cs

@ -71,6 +71,16 @@ namespace ICSharpCode.NRefactory.CSharp @@ -71,6 +71,16 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (preProcessorDirective, data);
}
public event Action<DocumentationReference, T> DocumentationReferenceVisited;
S IAstVisitor<T, S>.VisitDocumentationReference (DocumentationReference documentationReference, T data)
{
var handler = DocumentationReferenceVisited;
if (handler != null)
handler (documentationReference, data);
return VisitChildren (documentationReference, data);
}
public event Action<Identifier, T> IdentifierVisited;
S IAstVisitor<T, S>.VisitIdentifier (Identifier identifier, T data)

2
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -62,6 +62,7 @@ @@ -62,6 +62,7 @@
<Compile Include="Ast\AstNode.cs" />
<Compile Include="Ast\AstNodeCollection.cs" />
<Compile Include="Ast\AstType.cs" />
<Compile Include="Ast\DocumentationReference.cs" />
<Compile Include="Ast\IdentifierExpressionBackreference.cs" />
<Compile Include="Ast\CompilationUnit.cs" />
<Compile Include="Ast\ComposedType.cs" />
@ -299,6 +300,7 @@ @@ -299,6 +300,7 @@
<Compile Include="TypeSystem\ConstantValues.cs" />
<Compile Include="TypeSystem\CSharpAssembly.cs" />
<Compile Include="TypeSystem\CSharpAttribute.cs" />
<Compile Include="TypeSystem\CSharpDocumentationComment.cs" />
<Compile Include="TypeSystem\CSharpParsedFile.cs" />
<Compile Include="TypeSystem\CSharpUnresolvedTypeDefinition.cs" />
<Compile Include="TypeSystem\CSharpTypeResolveContext.cs" />

47
ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -2459,5 +2459,52 @@ namespace ICSharpCode.NRefactory.CSharp @@ -2459,5 +2459,52 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
#endregion
#region Documentation Reference
public object VisitDocumentationReference(DocumentationReference documentationReference, object data)
{
StartNode(documentationReference);
if (!documentationReference.DeclaringType.IsNull) {
documentationReference.DeclaringType.AcceptVisitor(this, data);
if (documentationReference.EntityType != EntityType.TypeDefinition)
WriteToken(".", AstNode.Roles.Dot);
}
switch (documentationReference.EntityType) {
case EntityType.TypeDefinition:
// we already printed the DeclaringType
break;
case EntityType.Indexer:
WriteKeyword("this");
break;
case EntityType.Operator:
var opType = documentationReference.OperatorType;
if (opType == OperatorType.Explicit) {
WriteKeyword ("explicit", OperatorDeclaration.OperatorTypeRole);
} else if (opType == OperatorType.Implicit) {
WriteKeyword ("implicit", OperatorDeclaration.OperatorTypeRole);
}
WriteKeyword ("operator", OperatorDeclaration.OperatorKeywordRole);
Space ();
if (opType == OperatorType.Explicit || opType == OperatorType.Implicit) {
documentationReference.ConversionOperatorReturnType.AcceptVisitor (this, data);
} else {
WriteToken (OperatorDeclaration.GetToken (opType), OperatorDeclaration.OperatorTypeRole);
}
break;
default:
WriteIdentifier(documentationReference.MemberName);
break;
}
WriteTypeArguments(documentationReference.TypeArguments);
if (documentationReference.HasParameterList) {
Space(policy.SpaceBeforeMethodDeclarationParentheses);
if (documentationReference.EntityType == EntityType.Indexer)
WriteCommaSeparatedListInBrackets(documentationReference.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
else
WriteCommaSeparatedListInParenthesis(documentationReference.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
}
return EndNode(documentationReference);
}
#endregion
}
}

5
ICSharpCode.NRefactory.CSharp/OutputVisitor/CodeDomConvertVisitor.cs

@ -1298,5 +1298,10 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1298,5 +1298,10 @@ namespace ICSharpCode.NRefactory.CSharp
{
return null;
}
CodeObject IAstVisitor<object, CodeObject>.VisitDocumentationReference(DocumentationReference documentationReference, object data)
{
return null;
}
}
}

10
ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs

@ -3726,5 +3726,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -3726,5 +3726,15 @@ namespace ICSharpCode.NRefactory.CSharp
// TODO: add support for parsing a part of a file
throw new NotImplementedException();
}
public DocumentationReference ParseDocumentationReference(string cref)
{
if (cref == null)
throw new ArgumentNullException("cref");
cref = cref.Replace('{', '<').Replace('}', '>');
// TODO: add support for parsing cref attributes
// (documentation_parsing production, see DocumentationBuilder.HandleXrefCommon)
throw new NotImplementedException();
}
}
}

7
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -3559,5 +3559,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3559,5 +3559,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return voidResult;
}
#endregion
#region Documentation Reference
ResolveResult IAstVisitor<object, ResolveResult>.VisitDocumentationReference(DocumentationReference documentationReference, object data)
{
throw new NotImplementedException();
}
#endregion
}
}

43
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpDocumentationComment.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// 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.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.TypeSystem
{
/// <summary>
/// DocumentationComment with C# cref lookup.
/// </summary>
sealed class CSharpDocumentationComment : DocumentationComment
{
public CSharpDocumentationComment(string xmlDoc, ITypeResolveContext context) : base(xmlDoc, context)
{
}
public override IEntity ResolveCref(string cref)
{
if (cref.Length > 2 && cref[1] == ':') {
// resolve ID string
return base.ResolveCref(cref);
}
return null;
}
}
}

46
ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpParsedFile.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using System.Linq;
@ -28,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -28,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
/// Represents a file that was parsed and converted for the type system.
/// </summary>
[Serializable]
public sealed class CSharpParsedFile : AbstractFreezable, IParsedFile
public sealed class CSharpParsedFile : AbstractFreezable, IParsedFile, IUnresolvedDocumentationProvider
{
readonly string fileName;
readonly UsingScope rootUsingScope;
@ -37,6 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -37,6 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
IList<IUnresolvedAttribute> moduleAttributes = new List<IUnresolvedAttribute>();
IList<UsingScope> usingScopes = new List<UsingScope>();
IList<Error> errors = new List<Error> ();
Dictionary<IUnresolvedEntity, string> documentation;
protected override void FreezeInternal()
{
@ -105,6 +107,14 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -105,6 +107,14 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
get { return moduleAttributes; }
}
public void AddDocumentation(IUnresolvedEntity entity, string xmlDocumentation)
{
FreezableHelper.ThrowIfFrozen(this);
if (documentation == null)
documentation = new Dictionary<IUnresolvedEntity, string>();
documentation.Add(entity, xmlDocumentation);
}
public UsingScope GetUsingScope(TextLocation location)
{
foreach (UsingScope scope in usingScopes) {
@ -176,5 +186,39 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -176,5 +186,39 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
{
return new ICSharpCode.NRefactory.CSharp.Resolver.CSharpResolver (GetTypeResolveContext (compilation, loc));
}
public string GetDocumentation(IUnresolvedEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
if (documentation == null)
return null;
string xmlDoc;
if (documentation.TryGetValue(entity, out xmlDoc))
return xmlDoc;
else
return null;
}
public DocumentationComment GetDocumentation(IUnresolvedEntity entity, IEntity resolvedEntity)
{
if (entity == null)
throw new ArgumentNullException("entity");
if (resolvedEntity == null)
throw new ArgumentNullException("resolvedEntity");
string xmlDoc = GetDocumentation(entity);
if (xmlDoc == null)
return null;
var unresolvedTypeDef = entity as IUnresolvedTypeDefinition ?? entity.DeclaringTypeDefinition;
var resolvedTypeDef = resolvedEntity as ITypeDefinition ?? resolvedEntity.DeclaringTypeDefinition;
if (unresolvedTypeDef != null && resolvedTypeDef != null) {
var context = unresolvedTypeDef.CreateResolveContext(new SimpleTypeResolveContext(resolvedTypeDef));
if (resolvedEntity is IMember)
context = context.WithCurrentMember((IMember)resolvedEntity);
return new CSharpDocumentationComment(xmlDoc, context);
} else {
return new DocumentationComment(xmlDoc, new SimpleTypeResolveContext(resolvedEntity));
}
}
}
}

32
ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.CSharp.Analysis;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
@ -181,6 +182,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -181,6 +182,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
var td = currentTypeDefinition = CreateTypeDefinition(typeDeclaration.Name);
td.Region = MakeRegion(typeDeclaration);
td.BodyRegion = MakeBraceRegion(typeDeclaration);
AddXmlDocumentation(td, typeDeclaration);
ApplyModifiers(td, typeDeclaration.Modifiers);
switch (typeDeclaration.ClassType) {
@ -222,6 +224,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -222,6 +224,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
td.Kind = TypeKind.Delegate;
td.Region = MakeRegion(delegateDeclaration);
td.BaseTypes.Add(KnownTypeReference.MulticastDelegate);
AddXmlDocumentation(td, delegateDeclaration);
ApplyModifiers(td, delegateDeclaration.Modifiers);
td.IsSealed = true; // delegates are implicitly sealed
@ -334,6 +337,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -334,6 +337,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
field.Region = isSingleField ? MakeRegion(fieldDeclaration) : MakeRegion(vi);
field.BodyRegion = MakeRegion(vi);
ConvertAttributes(field.Attributes, fieldDeclaration.Attributes);
AddXmlDocumentation(field, fieldDeclaration);
ApplyModifiers(field, modifiers);
field.IsVolatile = (modifiers & Modifiers.Volatile) != 0;
@ -364,6 +368,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -364,6 +368,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
DefaultUnresolvedField field = new DefaultUnresolvedField(currentTypeDefinition, enumMemberDeclaration.Name);
field.Region = field.BodyRegion = MakeRegion(enumMemberDeclaration);
ConvertAttributes(field.Attributes, enumMemberDeclaration.Attributes);
AddXmlDocumentation(field, enumMemberDeclaration);
if (currentTypeDefinition.TypeParameters.Count == 0) {
field.ReturnType = currentTypeDefinition;
@ -402,6 +407,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -402,6 +407,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
currentMethod = m; // required for resolving type parameters
m.Region = MakeRegion(methodDeclaration);
m.BodyRegion = MakeRegion(methodDeclaration.Body);
AddXmlDocumentation(m, methodDeclaration);
if (InheritsConstraints(methodDeclaration) && methodDeclaration.Constraints.Count == 0) {
int index = 0;
@ -526,6 +532,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -526,6 +532,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
m.EntityType = EntityType.Operator;
m.Region = MakeRegion(operatorDeclaration);
m.BodyRegion = MakeRegion(operatorDeclaration.Body);
AddXmlDocumentation(m, operatorDeclaration);
m.ReturnType = operatorDeclaration.ReturnType.ToTypeReference();
ConvertAttributes(m.Attributes, operatorDeclaration.Attributes.Where(s => s.AttributeTarget != "return"));
@ -560,6 +567,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -560,6 +567,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
ConvertAttributes(ctor.Attributes, constructorDeclaration.Attributes);
ConvertParameters(ctor.Parameters, constructorDeclaration.Parameters);
AddXmlDocumentation(ctor, constructorDeclaration);
if (isStatic)
ctor.IsStatic = true;
@ -586,6 +594,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -586,6 +594,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
dtor.ReturnType = KnownTypeReference.Void;
ConvertAttributes(dtor.Attributes, destructorDeclaration.Attributes);
AddXmlDocumentation(dtor, destructorDeclaration);
currentTypeDefinition.Members.Add(dtor);
if (interningProvider != null) {
@ -604,6 +613,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -604,6 +613,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
ApplyModifiers(p, propertyDeclaration.Modifiers);
p.ReturnType = propertyDeclaration.ReturnType.ToTypeReference();
ConvertAttributes(p.Attributes, propertyDeclaration.Attributes);
AddXmlDocumentation(p, propertyDeclaration);
if (!propertyDeclaration.PrivateImplementationType.IsNull) {
p.Accessibility = Accessibility.None;
p.IsExplicitInterfaceImplementation = true;
@ -628,6 +638,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -628,6 +638,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
ApplyModifiers(p, indexerDeclaration.Modifiers);
p.ReturnType = indexerDeclaration.ReturnType.ToTypeReference();
ConvertAttributes(p.Attributes, indexerDeclaration.Attributes);
AddXmlDocumentation(p, indexerDeclaration);
ConvertParameters(p.Parameters, indexerDeclaration.Parameters);
p.Getter = ConvertAccessor(indexerDeclaration.Getter, p, "get_");
@ -692,6 +703,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -692,6 +703,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
ev.BodyRegion = MakeRegion(vi);
ApplyModifiers(ev, modifiers);
AddXmlDocumentation(ev, eventDeclaration);
ev.ReturnType = eventDeclaration.ReturnType.ToTypeReference();
@ -738,6 +750,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -738,6 +750,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
ApplyModifiers(e, eventDeclaration.Modifiers);
e.ReturnType = eventDeclaration.ReturnType.ToTypeReference();
ConvertAttributes(e.Attributes, eventDeclaration.Attributes);
AddXmlDocumentation(e, eventDeclaration);
if (!eventDeclaration.PrivateImplementationType.IsNull) {
e.Accessibility = Accessibility.None;
@ -1100,5 +1113,24 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -1100,5 +1113,24 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
}
}
#endregion
#region XML Documentation
void AddXmlDocumentation(IUnresolvedEntity entity, AstNode entityDeclaration)
{
List<string> documentation = null;
for (AstNode node = entityDeclaration.PrevSibling; node != null && node.NodeType == NodeType.Whitespace; node = node.PrevSibling) {
Comment c = node as Comment;
if (c != null && c.CommentType == CommentType.Documentation) {
if (documentation == null)
documentation = new List<string>();
documentation.Add(c.Content);
}
}
if (documentation != null) {
documentation.Reverse(); // bring docu in correct order
parsedFile.AddDocumentation(entity, string.Join(Environment.NewLine, documentation));
}
}
#endregion
}
}

21
ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs

@ -121,6 +121,27 @@ namespace ICSharpCode.NRefactory.CSharp.Parser @@ -121,6 +121,27 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
}
}
public static DocumentationReference ParseDocumentationReference(string cref, bool expectErrors = false)
{
CSharpParser parser = new CSharpParser();
var parsedExpression = parser.ParseDocumentationReference(cref);
if (parser.HasErrors)
parser.ErrorPrinter.Errors.ForEach (err => Console.WriteLine (err.Message));
Assert.AreEqual(expectErrors, parser.HasErrors, "HasErrors");
if (expectErrors && parsedExpression == null)
return null;
return parsedExpression;
}
public static void AssertDocumentationReference(string cref, CSharp.DocumentationReference expectedExpr)
{
var expr = ParseDocumentationReference(cref);
if (!expectedExpr.IsMatch(expr)) {
Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedExpr), ToCSharp(expr));
}
}
static string ToCSharp(AstNode node)
{
StringWriter w = new StringWriter();

185
ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefLookupTests.cs

@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
// 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.IO;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation
{
[TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefLookupTests
{
IEntity Lookup(string cref)
{
string program = @"using System;
using System.Collections.Generic;
/// <summary/>
class Test {
int @int;
void M(int a) {}
void Overloaded(int a) {}
void Overloaded(string a) {}
void Overloaded(ref int a) {}
public int this[int index] { get { return 0; } }
public static int operator +(Test a, int b) { return 0; }
public static implicit operator Test(int a) { return 0; }
public static implicit operator int(Test a) { return 0; }
}
interface IGeneric<A, B> {
void Test<T>(ref T[,] a);
}
class Impl<T> : IGeneric<List<string>[,], T> {
void IGeneric<List<string>[,], T>.Test<X>(ref X[,] a) {}
}";
var pc = new CSharpProjectContent().AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib });
var cu = new CSharpParser().Parse(new StringReader(program), "program.cs");
var compilation = pc.UpdateProjectContent(null, cu.ToTypeSystem()).CreateCompilation();
var typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.Single();
IEntity entity = typeDefinition.Documentation.ResolveCref(cref);
Assert.IsNotNull(entity, "ResolveCref() returned null.");
return entity;
}
[Test]
public void String()
{
Assert.AreEqual("System.String",
Lookup("string").ReflectionName);
}
[Test]
public void IntParse()
{
Assert.AreEqual("M:System.Int32.Parse(System.String)",
IDStringProvider.GetIDString(Lookup("int.Parse(string)")));
}
[Test]
public void IntField()
{
Assert.AreEqual("Test.int",
Lookup("@int").ReflectionName);
}
[Test]
public void ListOfT()
{
Assert.AreEqual("System.Collections.Generic.List`1",
Lookup("List{T}").ReflectionName);
}
[Test]
public void ListOfTEnumerator()
{
Assert.AreEqual("System.Collections.Generic.List`1+Enumerator",
Lookup("List{T}.Enumerator").ReflectionName);
}
[Test]
public void IDString()
{
Assert.AreEqual("System.Collections.Generic.List`1+Enumerator",
Lookup("T:System.Collections.Generic.List`1.Enumerator").ReflectionName);
}
[Test]
public void M()
{
Assert.AreEqual("M:Test.M(System.String[0:,0:])",
IDStringProvider.GetIDString(Lookup("M")));
}
[Test]
public void CurrentType()
{
Assert.AreEqual("T:Test",
IDStringProvider.GetIDString(Lookup("Test")));
}
[Test]
public void Constructor()
{
Assert.AreEqual("M:Test.#ctor",
IDStringProvider.GetIDString(Lookup("Test()")));
}
[Test]
public void Overloaded()
{
Assert.AreEqual("M:Test.Overloaded(System.Int32)",
IDStringProvider.GetIDString(Lookup("Overloaded(int)")));
Assert.AreEqual("M:Test.Overloaded(System.String)",
IDStringProvider.GetIDString(Lookup("Overloaded(string)")));
Assert.AreEqual("M:Test.Overloaded(System.Int32@)",
IDStringProvider.GetIDString(Lookup("Overloaded(ref int)")));
}
[Test]
public void MethodInGenericInterface()
{
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)",
IDStringProvider.GetIDString(Lookup("IGeneric{X, Y}.Test")));
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)",
IDStringProvider.GetIDString(Lookup("IGeneric{X, Y}.Test{Z}")));
Assert.AreEqual("M:XmlDocTest.IGeneric`2.Test``1(``0[0:,0:]@)",
IDStringProvider.GetIDString(Lookup("IGeneric{X, Y}.Test{Z}(ref Z[,])")));
}
[Test]
public void Indexer()
{
Assert.AreEqual("P:Test.Item(System.Int32)",
IDStringProvider.GetIDString(Lookup("this")));
Assert.AreEqual("P:Test.Item(System.Int32)",
IDStringProvider.GetIDString(Lookup("Test.this")));
Assert.AreEqual("P:Test.Item(System.Int32)",
IDStringProvider.GetIDString(Lookup("Test.this[int]")));
}
[Test]
public void OperatorPlus()
{
Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)",
IDStringProvider.GetIDString(Lookup("operator +")));
Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)",
IDStringProvider.GetIDString(Lookup("operator +(Test, int)")));
Assert.AreEqual("M:Test.op_Addition(Test,System.Int32)",
IDStringProvider.GetIDString(Lookup("Test.operator +(Test, int)")));
}
[Test]
public void ImplicitOperator()
{
Assert.AreEqual("M:Test.op_Implicit(Test)~System.Int32",
IDStringProvider.GetIDString(Lookup("implicit operator int(Test)")));
Assert.AreEqual("M:Test.op_Implicit(System.Int32)~Test",
IDStringProvider.GetIDString(Lookup("implicit operator Test(int)")));
Assert.AreEqual("M:Test.op_Implicit(System.Int32)~Test",
IDStringProvider.GetIDString(Lookup("Test.implicit operator Test(int)")));
}
}
}

264
ICSharpCode.NRefactory.Tests/Documentation/CSharpCrefParserTests.cs

@ -0,0 +1,264 @@ @@ -0,0 +1,264 @@
// 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.CSharp;
using ICSharpCode.NRefactory.CSharp.Parser;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation
{
[TestFixture]
[Ignore("Cref parsing not yet implemented")]
public class CSharpCrefParserTests
{
[Test]
public void M()
{
ParseUtilCSharp.AssertDocumentationReference(
"M",
new DocumentationReference {
MemberName = "M"
});
}
[Test]
public void This()
{
ParseUtilCSharp.AssertDocumentationReference(
"this",
new DocumentationReference {
EntityType = EntityType.Indexer
});
}
[Test]
public void ThisWithParameter()
{
ParseUtilCSharp.AssertDocumentationReference(
"this[int]",
new DocumentationReference {
EntityType = EntityType.Indexer,
HasParameterList = true,
Parameters = { new ParameterDeclaration { Type = new PrimitiveType("int") } }
});
}
[Test]
public void ThisWithDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(
"List{T}.this",
new DocumentationReference {
EntityType = EntityType.Indexer,
DeclaringType = new SimpleType("List", new SimpleType("T"))
});
}
[Test]
public void NestedTypeInGenericType()
{
ParseUtilCSharp.AssertDocumentationReference(
"List{T}.Enumerator",
new DocumentationReference {
DeclaringType = new SimpleType("List", new SimpleType("T")),
MemberName = "Enumerator"
});
}
[Test]
public void GenericTypeWithFullNamespace()
{
ParseUtilCSharp.AssertDocumentationReference(
"System.Collections.Generic.List{T}",
new DocumentationReference {
DeclaringType = new SimpleType("System").MemberType("Collections").MemberType("Generic"),
MemberName = "List",
TypeArguments = { new SimpleType("T") }
});
}
[Test]
public void PrimitiveType()
{
ParseUtilCSharp.AssertDocumentationReference(
"int",
new DocumentationReference {
EntityType = EntityType.TypeDefinition,
DeclaringType = new PrimitiveType("int")
});
}
[Test]
public void VerbatimIdentifier()
{
ParseUtilCSharp.AssertDocumentationReference(
"@int",
new DocumentationReference {
MemberName = "int"
});
}
[Test]
public void Generic()
{
ParseUtilCSharp.AssertDocumentationReference(
"IGeneric{X, Y}",
new DocumentationReference {
MemberName = "IGeneric",
TypeArguments = { new SimpleType("X"), new SimpleType("Y") }
});
}
[Test]
public void MethodInGeneric()
{
ParseUtilCSharp.AssertDocumentationReference(
"IGeneric{X, Y}.Test",
new DocumentationReference {
DeclaringType = new SimpleType("IGeneric", new SimpleType("X"), new SimpleType("Y")),
MemberName = "Test"
});
}
[Test]
public void GenericMethodInGeneric()
{
ParseUtilCSharp.AssertDocumentationReference(
"IGeneric{X, Y}.Test{Z}",
new DocumentationReference {
DeclaringType = new SimpleType("IGeneric", new SimpleType("X"), new SimpleType("Y")),
MemberName = "Test",
TypeArguments = { new SimpleType("Z") }
});
}
[Test]
public void GenericMethodInGenericWithParameterList()
{
ParseUtilCSharp.AssertDocumentationReference(
"IGeneric{X, Y}.Test{Z}(ref Z[,])",
new DocumentationReference {
DeclaringType = new SimpleType("IGeneric", new SimpleType("X"), new SimpleType("Y")),
MemberName = "Test",
TypeArguments = { new SimpleType("Z") },
HasParameterList = true,
Parameters = {
new ParameterDeclaration {
ParameterModifier = ParameterModifier.Ref,
Type = new SimpleType("Z").MakeArrayType(2)
}
}});
}
[Test]
public void EmptyParameterList()
{
ParseUtilCSharp.AssertDocumentationReference(
"Window1()",
new DocumentationReference {
MemberName = "Window1",
HasParameterList = true
});
}
[Test]
public void OperatorPlus()
{
ParseUtilCSharp.AssertDocumentationReference(
"operator +",
new DocumentationReference {
EntityType = EntityType.Operator,
OperatorType = OperatorType.Addition
});
}
[Test]
public void OperatorPlusWithDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(
"Test.operator +",
new DocumentationReference {
DeclaringType = new SimpleType("Test"),
EntityType = EntityType.Operator,
OperatorType = OperatorType.Addition
});
}
[Test]
public void OperatorPlusWithParameterList()
{
ParseUtilCSharp.AssertDocumentationReference(
"operator +(Test, int)",
new DocumentationReference {
EntityType = EntityType.Operator,
OperatorType = OperatorType.Addition,
HasParameterList = true,
Parameters = {
new ParameterDeclaration { Type = new SimpleType("Test") },
new ParameterDeclaration { Type = new PrimitiveType("int") }
}});
}
[Test]
public void ImplicitOperator()
{
ParseUtilCSharp.AssertDocumentationReference(
"implicit operator int",
new DocumentationReference {
EntityType = EntityType.Operator,
OperatorType = OperatorType.Implicit,
ConversionOperatorReturnType = new PrimitiveType("int")
});
}
[Test]
public void ExplicitOperatorWithParameterList()
{
ParseUtilCSharp.AssertDocumentationReference(
"explicit operator int(Test)",
new DocumentationReference {
EntityType = EntityType.Operator,
OperatorType = OperatorType.Explicit,
ConversionOperatorReturnType = new PrimitiveType("int"),
HasParameterList = true,
Parameters = {
new ParameterDeclaration { Type = new SimpleType("Test") },
}
});
}
[Test]
public void ExplicitOperatorWithParameterListAndDeclaringType()
{
ParseUtilCSharp.AssertDocumentationReference(
"Test.explicit operator int(Test)",
new DocumentationReference {
EntityType = EntityType.Operator,
OperatorType = OperatorType.Explicit,
DeclaringType = new SimpleType("Test"),
ConversionOperatorReturnType = new PrimitiveType("int"),
HasParameterList = true,
Parameters = {
new ParameterDeclaration { Type = new SimpleType("Test") },
}
});
}
}
}

62
ICSharpCode.NRefactory.Tests/Documentation/CSharpDocumentationTests.cs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
// 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.IO;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.Documentation
{
[TestFixture]
public class CSharpDocumentationTests
{
ICompilation compilation;
ITypeDefinition typeDefinition;
void Init(string program)
{
var pc = new CSharpProjectContent().AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib });
var cu = new CSharpParser().Parse(new StringReader(program), "program.cs");
compilation = pc.UpdateProjectContent(null, cu.ToTypeSystem()).CreateCompilation();
typeDefinition = compilation.MainAssembly.TopLevelTypeDefinitions.FirstOrDefault();
}
[Test]
public void TypeDocumentationLookup()
{
Init(@"using System;
/// <summary/>
class Test { }");
Assert.AreEqual(" <summary/>", typeDefinition.Documentation.Xml);
}
[Test]
public void MultilineTypeDocumentationLookup()
{
Init(@"using System;
/// <summary>
/// Documentation
/// </summary>
class Test { }");
Assert.AreEqual(" <summary>" + Environment.NewLine + " Documentation" + Environment.NewLine + " </summary>", typeDefinition.Documentation.Xml);
}
}
}

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

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

3
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -169,6 +169,9 @@ @@ -169,6 +169,9 @@
<Compile Include="CSharp\Resolver\ResolverTestBase.cs" />
<Compile Include="CSharp\Resolver\UnaryOperatorTests.cs" />
<Compile Include="CSharp\Resolver\UnsafeCodeTests.cs" />
<Compile Include="Documentation\CSharpCrefLookupTests.cs" />
<Compile Include="Documentation\CSharpCrefParserTests.cs" />
<Compile Include="Documentation\CSharpDocumentationTests.cs" />
<Compile Include="Documentation\IDStringTests.cs" />
<Compile Include="FormattingTests\TestBraceStlye.cs" />
<Compile Include="FormattingTests\TestFormattingBugs.cs" />

5
ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs

@ -2215,5 +2215,10 @@ namespace ICSharpCode.NRefactory.VB.Visitors @@ -2215,5 +2215,10 @@ namespace ICSharpCode.NRefactory.VB.Visitors
foundAttribute = null;
return false;
}
public AstNode VisitDocumentationReference(CSharp.DocumentationReference documentationReference, object data)
{
throw new NotImplementedException();
}
}
}

32
ICSharpCode.NRefactory/Documentation/DocumentationComment.cs

@ -24,32 +24,44 @@ namespace ICSharpCode.NRefactory.Documentation @@ -24,32 +24,44 @@ namespace ICSharpCode.NRefactory.Documentation
/// <summary>
/// Represents a documentation comment.
/// </summary>
[Serializable]
public class DocumentationComment
{
string xmlText;
string xml;
protected readonly ITypeResolveContext context;
/// <summary>
/// Gets the XML code for this documentation comment.
/// </summary>
public string XmlText {
get { return xmlText; }
public string Xml {
get { return xml; }
}
public DocumentationComment(string xmlText)
/// <summary>
/// Creates a new DocumentationComment.
/// </summary>
/// <param name="xml">The XML text.</param>
/// <param name="context">Context for resolving cref attributes.</param>
public DocumentationComment(string xml, ITypeResolveContext context)
{
if (xmlText == null)
throw new ArgumentNullException("xmlText");
this.xmlText = xmlText;
if (xml == null)
throw new ArgumentNullException("xml");
if (context == null)
throw new ArgumentNullException("context");
this.xml = xml;
this.context = context;
}
/// <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)
public virtual IEntity ResolveCref(string cref)
{
return null;
try {
return IDStringProvider.FindEntity(cref, context);
} catch (ReflectionNameParseException) {
return null;
}
}
}
}

18
ICSharpCode.NRefactory/Documentation/IDocumentationProvider.cs

@ -23,7 +23,7 @@ using ICSharpCode.NRefactory.TypeSystem; @@ -23,7 +23,7 @@ using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.Documentation
{
/// <summary>
/// Provides XML documentation for members.
/// Provides XML documentation for entities.
/// </summary>
public interface IDocumentationProvider
{
@ -32,4 +32,20 @@ namespace ICSharpCode.NRefactory.Documentation @@ -32,4 +32,20 @@ namespace ICSharpCode.NRefactory.Documentation
/// </summary>
DocumentationComment GetDocumentation(IEntity entity);
}
/// <summary>
/// Provides XML documentation for entities.
/// </summary>
public interface IUnresolvedDocumentationProvider
{
/// <summary>
/// Gets the XML documentation for the specified entity.
/// </summary>
string GetDocumentation(IUnresolvedEntity entity);
/// <summary>
/// Gets the XML documentation for the specified entity.
/// </summary>
DocumentationComment GetDocumentation(IUnresolvedEntity entity, IEntity resolvedEntity);
}
}

26
ICSharpCode.NRefactory/Documentation/XmlDocumentationProvider.cs

@ -307,35 +307,11 @@ namespace ICSharpCode.NRefactory.Documentation @@ -307,35 +307,11 @@ namespace ICSharpCode.NRefactory.Documentation
{
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));
return new DocumentationComment(xmlDoc, new SimpleTypeResolveContext(entity));
} 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

13
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Documentation;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.TypeSystem.Implementation
@ -65,6 +66,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -65,6 +66,18 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
}
public override DocumentationComment Documentation {
get {
IUnresolvedDocumentationProvider docProvider = unresolved.ParsedFile as IUnresolvedDocumentationProvider;
if (docProvider != null) {
var doc = docProvider.GetDocumentation(unresolved, this);
if (doc != null)
return doc;
}
return base.Documentation;
}
}
IList<IMember> FindInterfaceImplementations()
{
if (unresolved.IsExplicitInterfaceImplementation) {

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

@ -388,6 +388,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -388,6 +388,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public virtual DocumentationComment Documentation {
get {
foreach (var part in parts) {
var unresolvedProvider = part.ParsedFile as IUnresolvedDocumentationProvider;
if (unresolvedProvider != null) {
var doc = unresolvedProvider.GetDocumentation(part, this);
if (doc != null)
return doc;
}
}
IDocumentationProvider provider = AbstractResolvedEntity.FindDocumentation(parentContext);
if (provider != null)
return provider.GetDocumentation(this);

23
ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleTypeResolveContext.cs

@ -45,23 +45,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -45,23 +45,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
this.currentAssembly = assembly;
}
public SimpleTypeResolveContext(ITypeDefinition typeDefinition)
public SimpleTypeResolveContext(IEntity entity)
{
if (typeDefinition == null)
throw new ArgumentNullException("typeDefinition");
this.compilation = typeDefinition.Compilation;
this.currentAssembly = typeDefinition.ParentAssembly;
this.currentTypeDefinition = typeDefinition;
}
public SimpleTypeResolveContext(IMember member)
{
if (member == null)
throw new ArgumentNullException("member");
this.compilation = member.Compilation;
this.currentAssembly = member.ParentAssembly;
this.currentTypeDefinition = member.DeclaringTypeDefinition;
this.currentMember = member;
if (entity == null)
throw new ArgumentNullException("entity");
this.compilation = entity.Compilation;
this.currentAssembly = entity.ParentAssembly;
this.currentTypeDefinition = (entity as ITypeDefinition) ?? entity.DeclaringTypeDefinition;
this.currentMember = entity as IMember;
}
private SimpleTypeResolveContext(ICompilation compilation, IAssembly currentAssembly, ITypeDefinition currentTypeDefinition, IMember currentMember)

Loading…
Cancel
Save