Skip to content

Commit

Permalink
Merge pull request #1085 from akshita31/sig_help_doc
Browse files Browse the repository at this point in the history
Using StructuredDocumentation for Signature Help and appropriate documentation for Parameter symbols
  • Loading branch information
Ravi Chande authored Jan 29, 2018
2 parents 759f062 + 43202ef commit ab289f5
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using OmniSharp.Models.TypeLookup;
using System.Collections.Generic;
using System.Linq;

Expand All @@ -13,6 +14,8 @@ public class SignatureHelpItem

public IEnumerable<SignatureHelpParameter> Parameters { get; set; }

public DocumentationComment StructuredDocumentation { get; set; }

public override bool Equals(object obj)
{
var other = obj as SignatureHelpItem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,31 @@ public class DocumentationComment
public string ValueText { get; }
public DocumentationItem[] Exception { get; }

private DocumentationComment(string summaryText, DocumentationItem[] typeParamElements, DocumentationItem[] paramElements, string returnsText, string remarksText, string exampleText, string valueText, DocumentationItem[ ] exception)
public DocumentationComment(
string summaryText = "",
DocumentationItem[] typeParamElements = null,
DocumentationItem[] paramElements = null,
string returnsText = "",
string remarksText = "",
string exampleText = "",
string valueText = "",
DocumentationItem[] exception = null)
{
SummaryText = summaryText;
TypeParamElements = typeParamElements;
ParamElements = paramElements;
TypeParamElements = typeParamElements ?? Array.Empty<DocumentationItem>();
ParamElements = paramElements ?? Array.Empty<DocumentationItem>();
ReturnsText = returnsText;
RemarksText = remarksText;
ExampleText = exampleText;
ValueText = valueText;
Exception = exception;
Exception = exception ?? Array.Empty<DocumentationItem>();
}

public static DocumentationComment From(string xmlDocumentation, string lineEnding)
{
if (string.IsNullOrEmpty(xmlDocumentation))
return Empty;

var reader = new StringReader("<docroot>" + xmlDocumentation + "</docroot>");
StringBuilder summaryText = new StringBuilder();
List<DocumentationItemBuilder> typeParamElements = new List<DocumentationItemBuilder>();
Expand Down Expand Up @@ -175,6 +186,14 @@ private static string TrimStartRetainingSingleLeadingSpace(string input)
return input;
return $" {input.TrimStart()}";
}

public string GetParameterText(string name)
=> Array.Find(ParamElements, parameter => parameter.Name == name)?.Documentation ?? string.Empty;

public string GetTypeParameterText(string name)
=> Array.Find(TypeParamElements, typeParam => typeParam.Name == name)?.Documentation ?? string.Empty;

public static readonly DocumentationComment Empty = new DocumentationComment();
}

class DocumentationItemBuilder
Expand Down
39 changes: 36 additions & 3 deletions src/OmniSharp.Roslyn.CSharp/Services/DocumentationConverter.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Microsoft.CodeAnalysis;
using OmniSharp.Models.TypeLookup;

namespace OmniSharp.Roslyn.CSharp.Services.Documentation
Expand Down Expand Up @@ -131,10 +131,43 @@ private static string GetCref(string cref)

public static DocumentationComment GetStructuredDocumentation(string xmlDocumentation, string lineEnding)
{
if (string.IsNullOrEmpty(xmlDocumentation))
return null;
return DocumentationComment.From(xmlDocumentation, lineEnding);
}

public static DocumentationComment GetStructuredDocumentation(ISymbol symbol, string lineEnding = "\n")
{
switch (symbol)
{
case IParameterSymbol parameter:
return new DocumentationComment(summaryText: GetParameterDocumentation(parameter, lineEnding));
case ITypeParameterSymbol typeParam:
return new DocumentationComment(summaryText: GetTypeParameterDocumentation(typeParam, lineEnding));
case IAliasSymbol alias:
return new DocumentationComment(summaryText: GetAliasDocumentation(alias, lineEnding));
default:
return GetStructuredDocumentation(symbol.GetDocumentationCommentXml(), lineEnding);
}
}

private static string GetParameterDocumentation(IParameterSymbol parameter, string lineEnding = "\n")
{
var contaningSymbolDef = parameter.ContainingSymbol.OriginalDefinition;
return GetStructuredDocumentation(contaningSymbolDef.GetDocumentationCommentXml(), lineEnding)
.GetParameterText(parameter.Name);
}

private static string GetTypeParameterDocumentation(ITypeParameterSymbol typeParam, string lineEnding = "\n")
{
var contaningSymbol = typeParam.ContainingSymbol;
return GetStructuredDocumentation(contaningSymbol.GetDocumentationCommentXml(), lineEnding)
.GetTypeParameterText(typeParam.Name);
}

private static string GetAliasDocumentation(IAliasSymbol alias, string lineEnding = "\n")
{
var target = alias.Target;
return GetStructuredDocumentation(target.GetDocumentationCommentXml(), lineEnding).SummaryText;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using OmniSharp.Mef;
using OmniSharp.Models;
using OmniSharp.Models.SignatureHelp;
using OmniSharp.Roslyn.CSharp.Services.Documentation;

namespace OmniSharp.Roslyn.CSharp.Services.Signatures
{
Expand Down Expand Up @@ -168,19 +169,19 @@ private static SignatureHelpItem BuildSignature(IMethodSymbol symbol)
signature.Documentation = symbol.GetDocumentationCommentXml();
signature.Name = symbol.MethodKind == MethodKind.Constructor ? symbol.ContainingType.Name : symbol.Name;
signature.Label = symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
signature.StructuredDocumentation = DocumentationConverter.GetStructuredDocumentation(symbol);

signature.Parameters = symbol.Parameters.Select(parameter =>
{
return new SignatureHelpParameter()
{
Name = parameter.Name,
Label = parameter.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
Documentation = parameter.GetDocumentationCommentXml()
Documentation = signature.StructuredDocumentation.GetParameterText(parameter.Name)
};
});

return signature;
}

}
}
2 changes: 1 addition & 1 deletion src/OmniSharp.Roslyn.CSharp/Services/Types/TypeLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task<TypeLookupResponse> Handle(TypeLookupRequest request)
if (request.IncludeDocumentation)
{
response.Documentation = DocumentationConverter.ConvertDocumentation(symbol.GetDocumentationCommentXml(), _formattingOptions.NewLine);
response.StructuredDocumentation = DocumentationConverter.GetStructuredDocumentation(symbol.GetDocumentationCommentXml(), _formattingOptions.NewLine);
response.StructuredDocumentation = DocumentationConverter.GetStructuredDocumentation(symbol, _formattingOptions.NewLine);
}
}
}
Expand Down
84 changes: 84 additions & 0 deletions tests/OmniSharp.Roslyn.CSharp.Tests/SignatureHelpFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,90 @@ bool LocalFunction(int i)
Assert.Equal("int i", signature.Parameters.ElementAt(0).Label);
}

[Fact]
public async Task ReturnsDocumentationForParameters()
{
const string source =
@"class Program
{
public static void Main()
{
var flag = Compare($$);
}
///<summary>Checks if object is tagged with the tag.</summary>
/// <param name=""gameObject"">The game object.</param>
/// <param name=""tagName"">Name of the tag.</param>
/// <returns>Returns <c> true</c> if object is tagged with tag.</returns>
public static bool Compare(GameObject gameObject, string tagName)
{
return true;
}
}";
var actual = await GetSignatureHelp(source);
Assert.Single(actual.Signatures);

var signature = actual.Signatures.ElementAt(0);
Assert.Equal(2, signature.Parameters.Count());
Assert.Equal("gameObject", signature.Parameters.ElementAt(0).Name);
Assert.Equal("The game object.", signature.Parameters.ElementAt(0).Documentation);
Assert.Equal("tagName", signature.Parameters.ElementAt(1).Name);
Assert.Equal("Name of the tag.", signature.Parameters.ElementAt(1).Documentation);
}

[Fact]
public async Task ReturnsDocumentationForParametersNestedTags()
{
const string source =
@"class Program
{
public static void Main()
{
var flag = Compare($$);
}
///<summary>Checks if object is tagged with the tag.</summary>
/// <param name=""gameObject"">The game object.</param>
/// <param name=""tagName"">Name of the tag.It has the default value as <c>null</c></param>
/// <returns>Returns <c> true</c> if object is tagged with tag.</returns>
public static bool Compare(GameObject gameObject, string tagName = null)
{
return true;
}
}";
var actual = await GetSignatureHelp(source);
Assert.Single(actual.Signatures);

var signature = actual.Signatures.ElementAt(0);
Assert.Equal(2, signature.Parameters.Count());
Assert.Equal("Name of the tag.It has the default value as null", signature.Parameters.ElementAt(1).Documentation);
}

[Fact]
public async Task ReturnsStructuredDocumentation()
{
const string source =
@"class Program
{
public static void Main()
{
var flag = Compare($$);
}
///<summary>Checks if object is tagged with the tag.</summary>
/// <param name=""gameObject"">The game object.</param>
/// <param name=""tagName"">Name of the tag.</param>
/// <returns>Returns <c>true</c> if object is tagged with tag.</returns>
public static bool Compare(GameObject gameObject, string tagName)
{
return true;
}
}";
var actual = await GetSignatureHelp(source);
Assert.Single(actual.Signatures);

var signature = actual.Signatures.ElementAt(0);
Assert.Equal("Checks if object is tagged with the tag.", signature.StructuredDocumentation.SummaryText);
Assert.Equal("Returns true if object is tagged with tag.", signature.StructuredDocumentation.ReturnsText);
}

[Fact]
public async Task SkipReceiverOfExtensionMethods()
{
Expand Down
32 changes: 32 additions & 0 deletions tests/OmniSharp.Roslyn.CSharp.Tests/TypeLookupFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -646,5 +646,37 @@ public class TestClass
@"DoWork is a method in the TestClass class.";
Assert.Equal(expected, response.StructuredDocumentation.SummaryText);
}

[Fact]
public async Task StructuredDocumentationForParameters1()
{
string content = @"
class testissue
{
/// <param name=""gameObject"">The game object.</param>
/// <param name=""tagName"">Name of the tag.</param>
public static bool Compare(int gam$$eObject, string tagName)
{
}
}";
var response = await GetTypeLookUpResponse(content);
Assert.Equal("The game object.", response.StructuredDocumentation.SummaryText);
}

[Fact]
public async Task StructuredDocumentationForParameters2()
{
string content = @"
class testissue
{
/// <param name=""gameObject"">The game object.</param>
/// <param name=""tagName"">Name of the tag.</param>
public static bool Compare(int gameObject, string tag$$Name)
{
}
}";
var response = await GetTypeLookUpResponse(content);
Assert.Equal("Name of the tag.", response.StructuredDocumentation.SummaryText);
}
}
}

0 comments on commit ab289f5

Please sign in to comment.