Skip to content

Commit

Permalink
Add cref attribute support and fix copying from templated sources
Browse files Browse the repository at this point in the history
  • Loading branch information
amirebrahimi committed Jan 15, 2020
1 parent 48a607c commit 1ae5ba1
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Documentation/spec/triple_slash_comments_spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Custom tags
-------
### inheritdoc
`docfx` supports a subset of the [inheritdoc functionality available in Sandcastle](https://ewsoftware.github.io/XMLCommentsGuide/html/86453FFB-B978-4A2A-9EB5-70E118CA8073.htm). Specifically, it implements most of the "Top-Level Inheritance Rules". It does not implement:
* Support for the `cref` or `select` attributes.
* Support for the `select` attribute.
* Automatic inheritance of documentation for explicit interface implementations.
* Support for inline `inheritdoc` tags (i.e., an `inheritdoc` tag inside of an `example` tag).

1 change: 1 addition & 0 deletions RELEASENOTE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Version Notes (Current Version: v2.49)

v2.49(Pre-release)
-----------
1. Add `cref` attribute support (#1306) for inheritdoc and fix copying from templated sources (#1516).

v2.48
-----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public class MetadataItem : ICloneable

[YamlIgnore]
[JsonIgnore]
public bool IsInheritDoc { get; set; }
public string InheritDoc { get; set; }

[YamlIgnore]
[JsonIgnore]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class TripleSlashCommentModel

public Dictionary<string, string> TypeParameters { get; private set; }

public bool IsInheritDoc { get; private set; }
public string InheritDoc { get; private set; }

private TripleSlashCommentModel(string xml, SyntaxLanguage language, ITripleSlashCommentParserContext context)
{
Expand All @@ -76,7 +76,7 @@ private TripleSlashCommentModel(string xml, SyntaxLanguage language, ITripleSlas
Examples = GetExamples(nav, context);
Parameters = GetParameters(nav, context);
TypeParameters = GetTypeParameters(nav, context);
IsInheritDoc = GetIsInheritDoc(nav, context);
InheritDoc = GetInheritDoc(nav, context);
}

public static TripleSlashCommentModel CreateModel(string xml, SyntaxLanguage language, ITripleSlashCommentParserContext context)
Expand Down Expand Up @@ -290,22 +290,48 @@ private List<string> GetExamples(XPathNavigator nav, ITripleSlashCommentParserCo
return GetMultipleExampleNodes(nav, "/member/example").ToList();
}

private bool GetIsInheritDoc(XPathNavigator nav, ITripleSlashCommentParserContext context)
private string GetInheritDoc(XPathNavigator nav, ITripleSlashCommentParserContext context)
{
var node = nav.SelectSingleNode("/member/inheritdoc");
if (node == null)
{
return false;
return null;
}

if (node.HasAttributes)
{
//The Sandcastle implementation of <inheritdoc /> supports two attributes: 'cref' and 'select'.
//These attributes allow changing the source of the inherited doc and controlling what is inherited.
//Until these attributes are supported, ignoring inheritdoc elements with attributes, so as not to misinterpret them.
Logger.LogWarning("Attributes on <inheritdoc /> elements are not supported; inheritdoc element will be ignored.");
return false;
// The Sandcastle implementation of <inheritdoc /> supports two attributes: 'cref' and 'select'.
// These attributes allow changing the source of the inherited doc and controlling what is inherited.
// Only cref is supported currently
var cRef = node.GetAttribute("cref", node.NamespaceURI);
if (!string.IsNullOrEmpty(cRef))
{
// Strict check is needed as value could be an invalid href,
// e.g. !:Dictionary&lt;TKey, string&gt; when user manually changed the intellisensed generic type
var match = CommentIdRegex.Match(cRef);
if (match.Success)
{
var id = match.Groups["id"].Value;
var type = match.Groups["type"].Value;

if (type == "Overload")
{
id += '*';
}

context.AddReferenceDelegate?.Invoke(id, cRef);
return id;
}
}
else
{
Logger.LogWarning("Unsupported attribute on <inheritdoc />; inheritdoc element will be ignored.");
return null;
}
}
return true;

// Default inheritdoc (no explicit reference)
return string.Empty;
}

private void ResolveCodeSource(XDocument doc, ITripleSlashCommentParserContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ type FSharpCompilation (compilation: FSharpCheckProjectResults, projPath: string
md.Sees <- cm.Sees
md.SeeAlsos <- cm.SeeAlsos
md.Examples <- cm.Examples
md.IsInheritDoc <- cm.IsInheritDoc
md.InheritDoc <- cm.InheritDoc
if not (isNull md.Syntax) then
if not (isNull md.Syntax.Parameters) then
for pmd in md.Syntax.Parameters do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static void FeedComments(MetadataItem item, ITripleSlashCommentParserCont
item.Sees = commentModel.Sees;
item.SeeAlsos = commentModel.SeeAlsos;
item.Examples = commentModel.Examples;
item.IsInheritDoc = commentModel.IsInheritDoc;
item.InheritDoc = commentModel.InheritDoc;
item.CommentModel = commentModel;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ private static void PatchViewModel(MetadataItem item, string comment)
}
}
}
item.IsInheritDoc = commentModel.IsInheritDoc;
item.InheritDoc = commentModel.InheritDoc;
// todo more.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,17 @@ public void Run(MetadataModel yaml, ResolverContext context)
s => s.IsInvalid ? null : s.Items,
(current, parent) =>
{
if (current.IsInheritDoc)
if (current.InheritDoc != null)
{
InheritDoc(current, context);
current.InheritDoc = null;
}
return true;
});
}

private static void InheritDoc(MetadataItem dest, ResolverContext context)
{
dest.IsInheritDoc = false;

switch (dest.Type)
{
case MemberType.Constructor:
Expand Down Expand Up @@ -126,22 +125,37 @@ private static void InheritDoc(MetadataItem dest, ResolverContext context)

private static void Copy(MetadataItem dest, string srcName, ResolverContext context)
{
if (string.IsNullOrEmpty(srcName) || !context.Members.TryGetValue(srcName, out MetadataItem src))
MetadataItem src = null;

// An explicit <inheritdoc/> (i.e. cref) overrides the default behavior
if (!string.IsNullOrEmpty(dest.InheritDoc) && context.Members.TryGetValue(dest.InheritDoc, out src))
{
srcName = dest.InheritDoc;
}

if (string.IsNullOrEmpty(srcName))
return;

if (src == null && !context.Members.TryGetValue(srcName, out src))
{
// Try to resolve any templated references before giving up
if (!context.References.TryGetValue(srcName, out var referenceItem) || !context.Members.TryGetValue(referenceItem.Definition, out src))
return;
}

Copy(dest, src, context);
}

private static void Copy(MetadataItem dest, MetadataItem src, ResolverContext context)
{
if (src.IsInheritDoc)
if (src.InheritDoc != null)
{
InheritDoc(src, context);
src.InheritDoc = null;
}

dest.CopyInheritedData(src);
dest.InheritDoc = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public int Main(string[] args)
string input = @"
<member name='T:TestClass1.Partial1'>
<summary>
Parital classes <see cref='T:System.AccessViolationException'/><see cref='T:System.AccessViolationException'/>can not cross assemblies, Test <see langword='null'/>
Partial classes <see cref='T:System.AccessViolationException'/><see cref='T:System.AccessViolationException'/>can not cross assemblies, Test <see langword='null'/>
```
Classes in assemblies are by definition complete.
Expand Down Expand Up @@ -134,11 +134,11 @@ Check empty code.
};

var commentModel = TripleSlashCommentModel.CreateModel(input, SyntaxLanguage.CSharp, context);
Assert.False(commentModel.IsInheritDoc, nameof(commentModel.IsInheritDoc));
Assert.True(commentModel.InheritDoc == null, nameof(commentModel.InheritDoc));

var summary = commentModel.Summary;
Assert.Equal(@"
Parital classes <xref href=""System.AccessViolationException"" data-throw-if-not-resolved=""false""></xref><xref href=""System.AccessViolationException"" data-throw-if-not-resolved=""false""></xref>can not cross assemblies, Test <xref uid=""langword_csharp_null"" name=""null"" href=""""></xref>
Partial classes <xref href=""System.AccessViolationException"" data-throw-if-not-resolved=""false""></xref><xref href=""System.AccessViolationException"" data-throw-if-not-resolved=""false""></xref>can not cross assemblies, Test <xref uid=""langword_csharp_null"" name=""null"" href=""""></xref>
```
Classes in assemblies are by definition complete.
Expand Down Expand Up @@ -242,7 +242,25 @@ public void InheritDoc()
};

var commentModel = TripleSlashCommentModel.CreateModel(input, SyntaxLanguage.CSharp, context);
Assert.True(commentModel.IsInheritDoc);
Assert.True(commentModel.InheritDoc != null, nameof(commentModel.InheritDoc));
}

[Trait("Related", "TripleSlashComments")]
[Fact]
public void InheritDocWithCref()
{
const string input = @"
<member name=""M:ClassLibrary1.MyClass.DoThing"">
<inheritdoc cref=""M:ClassLibrary1.MyClass.DoThing""/>
</member>";
var context = new TripleSlashCommentParserContext
{
AddReferenceDelegate = null,
PreserveRawInlineComments = false,
};

var commentModel = TripleSlashCommentModel.CreateModel(input, SyntaxLanguage.CSharp, context);
Assert.Equal("ClassLibrary1.MyClass.DoThing", commentModel.InheritDoc);
}

[Trait("Related", "TripleSlashComments")]
Expand Down

0 comments on commit 1ae5ba1

Please sign in to comment.