Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xamarin/NRefactory.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Grunwald <daniel@danielgrunwald.de>2012-02-24 00:55:50 +0400
committerDaniel Grunwald <daniel@danielgrunwald.de>2012-02-24 00:55:50 +0400
commit274fe417f5787d20b89658587566f4f89064447b (patch)
treed4c7e98bf076b3b3e26e177a0d39615267053c7a /ICSharpCode.NRefactory.Xml
parent18c96e089de48d03cce49146b8950283017bddc9 (diff)
Add "XmlDocumentationElement", a simplified tree for XML documentation comments that expands "<inheritdoc/>"
Diffstat (limited to 'ICSharpCode.NRefactory.Xml')
-rw-r--r--ICSharpCode.NRefactory.Xml/DocumentationElement.cs260
-rw-r--r--ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj1
2 files changed, 261 insertions, 0 deletions
diff --git a/ICSharpCode.NRefactory.Xml/DocumentationElement.cs b/ICSharpCode.NRefactory.Xml/DocumentationElement.cs
new file mode 100644
index 00000000..9dd2185a
--- /dev/null
+++ b/ICSharpCode.NRefactory.Xml/DocumentationElement.cs
@@ -0,0 +1,260 @@
+// 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using ICSharpCode.NRefactory.Documentation;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.NRefactory.Utils;
+
+namespace ICSharpCode.NRefactory.Xml
+{
+ /// <summary>
+ /// Represents an element in the XML documentation.
+ /// Any occurrences of "&lt;inheritdoc/>" are replaced with the inherited documentation.
+ /// </summary>
+ public class XmlDocumentationElement
+ {
+ /// <summary>
+ /// Gets the XML documentation element for the specified entity.
+ /// Returns null if no documentation is found.
+ /// </summary>
+ public static XmlDocumentationElement Get(IEntity entity, bool inheritDocIfMissing = true)
+ {
+ var documentationComment = entity.Documentation;
+ if (documentationComment != null) {
+ return Create(documentationComment, entity);
+ }
+
+ IMember member = entity as IMember;
+ if (inheritDocIfMissing && member != null) {
+ foreach (IMember baseMember in InheritanceHelper.GetBaseMembers(member, includeImplementedInterfaces: true)) {
+ documentationComment = baseMember.Documentation;
+ if (documentationComment != null)
+ return Create(documentationComment, baseMember);
+ }
+ }
+ return null;
+ }
+
+ static XmlDocumentationElement Create(DocumentationComment documentationComment, IEntity declaringEntity)
+ {
+ var doc = new AXmlParser().Parse(documentationComment.Xml);
+ return new XmlDocumentationElement(doc, declaringEntity, documentationComment.ResolveCref);
+ }
+
+ readonly AXmlObject xmlObject;
+ readonly AXmlElement element;
+ readonly IEntity declaringEntity;
+ readonly Func<string, IEntity> crefResolver;
+ volatile string textContent;
+
+ /// <summary>
+ /// Inheritance level; used to prevent cyclic doc inheritance.
+ /// </summary>
+ int nestingLevel;
+
+ /// <summary>
+ /// Creates a new documentation element.
+ /// </summary>
+ public XmlDocumentationElement(AXmlElement element, IEntity declaringEntity, Func<string, IEntity> crefResolver)
+ {
+ if (element == null)
+ throw new ArgumentNullException("element");
+ this.element = element;
+ this.xmlObject = element;
+ this.declaringEntity = declaringEntity;
+ this.crefResolver = crefResolver;
+ }
+
+ /// <summary>
+ /// Creates a new documentation element.
+ /// </summary>
+ public XmlDocumentationElement(AXmlDocument document, IEntity declaringEntity, Func<string, IEntity> crefResolver)
+ {
+ if (document == null)
+ throw new ArgumentNullException("document");
+ this.xmlObject = document;
+ this.declaringEntity = declaringEntity;
+ this.crefResolver = crefResolver;
+ }
+
+ /// <summary>
+ /// Creates a new documentation element.
+ /// </summary>
+ public XmlDocumentationElement(string text, IEntity declaringEntity)
+ {
+ if (text == null)
+ throw new ArgumentNullException("text");
+ this.textContent = text;
+ }
+
+ /// <summary>
+ /// Gets the entity on which this documentation was originally declared.
+ /// May return null.
+ /// </summary>
+ public IEntity DeclaringEntity {
+ get { return null; }
+ }
+
+ IEntity referencedEntity;
+ volatile bool referencedEntityInitialized;
+
+ /// <summary>
+ /// Gets the entity referenced by the 'cref' attribute.
+ /// May return null.
+ /// </summary>
+ public IEntity ReferencedEntity {
+ get {
+ if (!referencedEntityInitialized) {
+ string cref = GetAttribute("cref");
+ if (cref != null && crefResolver != null)
+ referencedEntity = crefResolver(cref);
+ referencedEntityInitialized = true;
+ }
+ return referencedEntity;
+ }
+ }
+
+ /// <summary>
+ /// Gets the element name.
+ /// </summary>
+ public string Name {
+ get {
+ return element != null ? element.Name : string.Empty;
+ }
+ }
+
+ /// <summary>
+ /// Gets the attribute value.
+ /// </summary>
+ public string GetAttribute(string name)
+ {
+ return element != null ? element.GetAttributeValue(name) : string.Empty;
+ }
+
+ /// <summary>
+ /// Gets whether this is a pure text node.
+ /// </summary>
+ public bool IsTextNode {
+ get { return element == null; }
+ }
+
+ /// <summary>
+ /// Gets the text content.
+ /// </summary>
+ public string TextContent {
+ get {
+ if (textContent == null) {
+ StringBuilder b = new StringBuilder();
+ foreach (var child in this.Children)
+ b.Append(child.TextContent);
+ textContent = b.ToString();
+ }
+ return textContent;
+ }
+ }
+
+ IList<XmlDocumentationElement> children;
+
+ /// <summary>
+ /// Gets the child elements.
+ /// </summary>
+ public IList<XmlDocumentationElement> Children {
+ get {
+ if (xmlObject == null)
+ return EmptyList<XmlDocumentationElement>.Instance;
+ return LazyInitializer.EnsureInitialized(
+ ref this.children,
+ () => CreateElements(xmlObject.Children, declaringEntity, crefResolver, nestingLevel));
+ }
+ }
+
+ static readonly string[] doNotInheritIfAlreadyPresent = {
+ "example", "exclude", "filterpriority", "preliminary", "summary",
+ "remarks", "returns", "threadsafety", "value"
+ };
+
+ static List<XmlDocumentationElement> CreateElements(IEnumerable<AXmlObject> childObjects, IEntity declaringEntity, Func<string, IEntity> crefResolver, int nestingLevel)
+ {
+ List<XmlDocumentationElement> list = new List<XmlDocumentationElement>();
+ foreach (var child in childObjects) {
+ var childText = child as AXmlText;
+ var childElement = child as AXmlElement;
+ if (childText != null) {
+ list.Add(new XmlDocumentationElement(childText.Value, declaringEntity));
+ } else if (childElement != null) {
+ if (nestingLevel < 5 && childElement.Name == "inheritdoc") {
+ string cref = childElement.GetAttributeValue("cref");
+ IEntity inheritedFrom = null;
+ DocumentationComment inheritedDocumentation = null;
+ if (cref != null) {
+ inheritedFrom = crefResolver(cref);
+ if (inheritedFrom != null)
+ inheritedDocumentation = inheritedFrom.Documentation;
+ } else {
+ foreach (IMember baseMember in InheritanceHelper.GetBaseMembers((IMember)declaringEntity, includeImplementedInterfaces: true)) {
+ inheritedDocumentation = baseMember.Documentation;
+ if (inheritedDocumentation != null) {
+ inheritedFrom = baseMember;
+ break;
+ }
+ }
+ }
+
+ if (inheritedDocumentation != null) {
+ var doc = new AXmlParser().Parse(inheritedDocumentation.Xml);
+
+ // XPath filter not yet implemented
+ if (childElement.Parent is AXmlDocument && childElement.GetAttributeValue("select") == null) {
+ // Inheriting documentation at the root level
+ List<string> doNotInherit = new List<string>();
+ doNotInherit.Add("overloads");
+ doNotInherit.AddRange(childObjects.OfType<AXmlElement>().Select(e => e.Name).Intersect(
+ doNotInheritIfAlreadyPresent));
+
+ var inheritedChildren = doc.Children.Where(
+ inheritedObject => {
+ AXmlElement inheritedElement = inheritedObject as AXmlElement;
+ return !(inheritedElement != null && doNotInherit.Contains(inheritedElement.Name));
+ });
+
+ list.AddRange(CreateElements(inheritedChildren, inheritedFrom, inheritedDocumentation.ResolveCref, nestingLevel + 1));
+ }
+ }
+ } else {
+ list.Add(new XmlDocumentationElement(childElement, declaringEntity, crefResolver) { nestingLevel = nestingLevel });
+ }
+ }
+ }
+ return list;
+ }
+
+ /// <inheritdoc/>
+ public override string ToString()
+ {
+ if (element != null)
+ return "<" + element.Name + ">";
+ else
+ return this.TextContent;
+ }
+ }
+}
diff --git a/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj b/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj
index c41c61cf..6ea7abad 100644
--- a/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj
+++ b/ICSharpCode.NRefactory.Xml/ICSharpCode.NRefactory.Xml.csproj
@@ -68,6 +68,7 @@
<Compile Include="AXmlReader.cs" />
<Compile Include="AXmlTag.cs" />
<Compile Include="AXmlText.cs" />
+ <Compile Include="DocumentationElement.cs" />
<Compile Include="IAXmlVisitor.cs" />
<Compile Include="IncrementalParserState.cs" />
<Compile Include="InternalDocument.cs" />