Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add records support to XmlDocCommentCompletion and ChangeSignature #53052

Merged
merged 22 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities.ChangeSignature;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ChangeSignature
Expand Down Expand Up @@ -412,5 +411,26 @@ public override int M(string x, int newIntegerParameter, int y)
}";
await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode);
}

[Fact(Skip = "https://github.com/dotnet/roslyn/issues/53091"), Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public async Task AddParameter_Cascade_Record()
{
var markup = @"
record $$BaseR(int A, int B);

record DerivedR() : BaseR(0, 1);";
var permutation = new AddedParameterOrExistingIndex[]
{
new(1),
new(new AddedParameter(null, "int", "C", CallSiteKind.Value, "3"), "int"),
new(0)
};
var updatedCode = @"
record BaseR(int B, int C, int A);

record DerivedR() : BaseR(1, 3, 0);";

await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1261,5 +1261,39 @@ public void M()
}";
await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode);
}

[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[WorkItem(44558, "https://github.com/dotnet/roslyn/issues/44558")]
public async Task AddParameters_Record()
{
var markup = @"
/// <param name=""First""></param>
/// <param name=""Second""></param>
/// <param name=""Third""></param>
record $$R(int First, int Second, int Third)
{
static R M() => new R(1, 2, 3);
}
";
var updatedSignature = new AddedParameterOrExistingIndex[]
{
new(0),
new(2),
new(1),
new(new AddedParameter(null, "int", "Forth", CallSiteKind.Value, "12345"), "System.Int32")
};
var updatedCode = @"
/// <param name=""First""></param>
/// <param name=""Third""></param>
/// <param name=""Second""></param>
/// <param name=""Forth""></param>
record R(int First, int Third, int Second, int Forth)
{
static R M() => new R(1, 3, 2, 12345);
}
";

await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -951,5 +951,29 @@ class D : C, I

await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode);
}

[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
public async Task ReorderParamTagsInDocComments_Record()
{
var markup = @"
/// <param name=""A""></param>
/// <param name=""B""></param>
/// <param name=""C""></param>
record $$R(int A, int B, int C)
{
public static R Instance = new(0, 1, 2);
}";
var permutation = new[] { 2, 1, 0 };
var updatedCode = @"
/// <param name=""C""></param>
/// <param name=""B""></param>
/// <param name=""A""></param>
record R(int C, int B, int A)
{
public static R Instance = new(2, 1, 0);
}";

await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: permutation, expectedUpdatedInvocationDocumentCode: updatedCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1012,5 +1012,27 @@ static void Goo()
await VerifyItemExistsAsync(text, "term");
await VerifyItemExistsAsync(text, "description");
}

[WorkItem(52738, "https://github.com/dotnet/roslyn/issues/52738")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task RecordParam()
{
await VerifyItemsExistAsync(@"
/// $$
public record Goo<T>(string MyParameter);
", "param name=\"MyParameter\"", "typeparam name=\"T\"");
}

[WorkItem(52738, "https://github.com/dotnet/roslyn/issues/52738")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task RecordParamRef()
{
await VerifyItemsExistAsync(@"
/// <summary>
/// $$
/// <summary>
public record Goo<T>(string MyParameter);
", "paramref name=\"MyParameter\"", "typeparamref name=\"T\"");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -785,5 +786,29 @@ public void Fizz(int i, int j, int k) {}

await TestAsync(initial, expected);
}

[WorkItem(52738, "https://github.com/dotnet/roslyn/issues/52738")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddDocCommentNodes)]
public async Task AddsParamTag_Record()
{
var initial = @"
/// <summary>
///
/// </summary>
/// <param name=""Second""></param>
record R(int [|First|], int Second, int Third);
";

var expected = @"
/// <summary>
///
/// </summary>
/// <param name=""First""></param>
/// <param name=""Second""></param>
/// <param name=""Third""></param>
record R(int First, int Second, int Third);
";
await TestAsync(initial, expected);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,25 @@ class c<T>
End Using
End Function

<WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CommitParam_Record(showCompletionInArgumentLists As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document><![CDATA[
/// <param$$
record R(int I);
]]></Document>, showCompletionInArgumentLists:=showCompletionInArgumentLists)

state.SendInvokeCompletionList()
Await state.AssertCompletionSession()
Await state.AssertSelectedCompletionItem(displayText:="param name=""I""")
state.SendReturn()
Await state.AssertNoCompletionSession()

' /// <param name="I"$$
Await state.AssertLineTextAroundCaret("/// <param name=""I""", "")
End Using
End Function

<WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CommitParamNoOpenAngle(showCompletionInArgumentLists As Boolean) As Task

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -825,5 +825,36 @@ End Class]]></Text>.NormalizedValue()

Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode)
End Function

<WorkItem(49941, "https://github.com/dotnet/roslyn/issues/49941")>
<Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)>
Public Async Function TestAddParameter_NoLastWhitespaceTrivia() As Task

Dim markup = <Text><![CDATA[
Class C
''' <summary>
''' </summary>
''' <param name="a"></param>
Sub $$M(a As Integer)
End Sub
End Class]]></Text>.NormalizedValue()
Dim permutation =
{
New AddedParameterOrExistingIndex(0),
New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "b", CallSiteKind.Value), "Integer")
}

Dim updatedCode = <Text><![CDATA[
Class C
''' <summary>
''' </summary>
''' <param name="a"></param>
''' <param name="b"></param>
Sub M(a As Integer, b As Integer)
End Sub
End Class]]></Text>.NormalizedValue()

Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode)
End Function
End Class
End Namespace
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -42,7 +43,9 @@ internal sealed class CSharpChangeSignatureService : AbstractChangeSignatureServ
SyntaxKind.DelegateDeclaration,
SyntaxKind.SimpleLambdaExpression,
SyntaxKind.ParenthesizedLambdaExpression,
SyntaxKind.LocalFunctionStatement);
SyntaxKind.LocalFunctionStatement,
SyntaxKind.RecordStructDeclaration,
SyntaxKind.RecordDeclaration);

private static readonly ImmutableArray<SyntaxKind> _declarationAndInvocableKinds =
_declarationKinds.Concat(ImmutableArray.Create(
Expand Down Expand Up @@ -85,7 +88,9 @@ internal sealed class CSharpChangeSignatureService : AbstractChangeSignatureServ
SyntaxKind.NameMemberCref,
SyntaxKind.AnonymousMethodExpression,
SyntaxKind.ParenthesizedLambdaExpression,
SyntaxKind.SimpleLambdaExpression);
SyntaxKind.SimpleLambdaExpression,
SyntaxKind.RecordStructDeclaration,
SyntaxKind.RecordDeclaration);

[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
Expand Down Expand Up @@ -270,7 +275,9 @@ public override async Task<SyntaxNode> ChangeSignatureAsync(
if (updatedNode.IsKind(SyntaxKind.MethodDeclaration) ||
updatedNode.IsKind(SyntaxKind.ConstructorDeclaration) ||
updatedNode.IsKind(SyntaxKind.IndexerDeclaration) ||
updatedNode.IsKind(SyntaxKind.DelegateDeclaration))
updatedNode.IsKind(SyntaxKind.DelegateDeclaration) ||
updatedNode.IsKind(SyntaxKind.RecordStructDeclaration) ||
updatedNode.IsKind(SyntaxKind.RecordDeclaration))
{
var updatedLeadingTrivia = UpdateParamTagsInLeadingTrivia(document, updatedNode, declarationSymbol, signaturePermutation);
if (updatedLeadingTrivia != default && !updatedLeadingTrivia.IsEmpty)
Expand All @@ -286,6 +293,12 @@ public override async Task<SyntaxNode> ChangeSignatureAsync(
return method.WithParameterList(method.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation));
}

if (updatedNode is RecordDeclarationSyntax { ParameterList: not null } record)
{
var updatedParameters = UpdateDeclaration(record.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax);
return record.WithParameterList(record.ParameterList.WithParameters(updatedParameters).WithAdditionalAnnotations(changeSignatureFormattingAnnotation));
}

if (updatedNode.IsKind(SyntaxKind.LocalFunctionStatement, out LocalFunctionStatementSyntax? localFunction))
{
var updatedParameters = UpdateDeclaration(localFunction.ParameterList.Parameters, signaturePermutation, CreateNewParameterSyntax);
Expand Down Expand Up @@ -745,13 +758,14 @@ private ImmutableArray<SyntaxTrivia> UpdateParamTagsInLeadingTrivia(Document doc
return GetPermutedDocCommentTrivia(document, node, permutedParamNodes);
}

private static ImmutableArray<SyntaxNode> VerifyAndPermuteParamNodes(IEnumerable<XmlElementSyntax> paramNodes, ISymbol declarationSymbol, SignatureChange updatedSignature)
private ImmutableArray<SyntaxNode> VerifyAndPermuteParamNodes(IEnumerable<XmlElementSyntax> paramNodes, ISymbol declarationSymbol, SignatureChange updatedSignature)
{
// Only reorder if count and order match originally.
var originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters();
var reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters();

var declaredParameters = declarationSymbol.GetParameters();
var declaredParameters = GetParameters(declarationSymbol);

if (paramNodes.Count() != declaredParameters.Length)
{
return ImmutableArray<SyntaxNode>.Empty;
Expand Down Expand Up @@ -875,5 +889,20 @@ protected override bool SupportsOptionalAndParamsArrayParametersSimultaneously()

protected override SyntaxToken CommaTokenWithElasticSpace()
=> Token(SyntaxKind.CommaToken).WithTrailingTrivia(ElasticSpace);

protected override bool TryGetRecordPrimaryConstructor(INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol? primaryConstructor)
=> typeSymbol.TryGetRecordPrimaryConstructor(out primaryConstructor);

protected override ImmutableArray<IParameterSymbol> GetParameters(ISymbol declarationSymbol)
{
var declaredParameters = declarationSymbol.GetParameters();
allisonchou marked this conversation as resolved.
Show resolved Hide resolved
if (declarationSymbol is INamedTypeSymbol namedTypeSymbol &&
namedTypeSymbol.TryGetRecordPrimaryConstructor(out var primaryConstructor))
{
declaredParameters = primaryConstructor.Parameters;
}

return declaredParameters;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -365,6 +366,18 @@ private string GetAttributeValue(XmlAttributeSyntax attribute)
}
}

protected override ImmutableArray<IParameterSymbol> GetParameters(ISymbol declarationSymbol)
{
var declaredParameters = declarationSymbol.GetParameters();
allisonchou marked this conversation as resolved.
Show resolved Hide resolved
if (declarationSymbol is INamedTypeSymbol namedTypeSymbol &&
namedTypeSymbol.TryGetRecordPrimaryConstructor(out var primaryConstructor))
{
declaredParameters = primaryConstructor.Parameters;
}

return declaredParameters;
}

private static readonly CompletionItemRules s_defaultRules =
CompletionItemRules.Create(
filterCharacterRules: FilterRules,
Expand Down
Loading