diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs
index a996a41288d50..72efbf595644d 100644
--- a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs
+++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.Cascading.cs
@@ -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
@@ -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);
+ }
}
}
diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs
index 136592635bd9a..11fecb5f73ea8 100644
--- a/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs
+++ b/src/EditorFeatures/CSharpTest/ChangeSignature/AddParameterTests.cs
@@ -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 = @"
+///
+///
+///
+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 = @"
+///
+///
+///
+///
+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);
+ }
}
}
diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.cs
index 90bf56923b963..0fb298efc3e11 100644
--- a/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.cs
+++ b/src/EditorFeatures/CSharpTest/ChangeSignature/ReorderParametersTests.cs
@@ -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 = @"
+///
+///
+///
+record $$R(int A, int B, int C)
+{
+ public static R Instance = new(0, 1, 2);
+}";
+ var permutation = new[] { 2, 1, 0 };
+ var updatedCode = @"
+///
+///
+///
+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);
+ }
}
}
diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs
index 8a0a6aa11c25a..52cbea5299e13 100644
--- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs
+++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs
@@ -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(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(@"
+///
+/// $$
+///
+public record Goo(string MyParameter);
+", "paramref name=\"MyParameter\"", "typeparamref name=\"T\"");
+ }
}
}
diff --git a/src/EditorFeatures/CSharpTest/DocumentationComments/CodeFixes/AddDocCommentNodesCodeFixProviderTests.cs b/src/EditorFeatures/CSharpTest/DocumentationComments/CodeFixes/AddDocCommentNodesCodeFixProviderTests.cs
index eebb1502ff7bc..9f9adf39a2826 100644
--- a/src/EditorFeatures/CSharpTest/DocumentationComments/CodeFixes/AddDocCommentNodesCodeFixProviderTests.cs
+++ b/src/EditorFeatures/CSharpTest/DocumentationComments/CodeFixes/AddDocCommentNodesCodeFixProviderTests.cs
@@ -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;
@@ -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 = @"
+///
+///
+///
+///
+record R(int [|First|], int Second, int Third);
+";
+
+ var expected = @"
+///
+///
+///
+///
+///
+///
+record R(int First, int Second, int Third);
+";
+ await TestAsync(initial, expected);
+ }
}
}
diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_XmlDoc.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_XmlDoc.vb
index ee1cc0729587b..c329a73fe8b35 100644
--- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_XmlDoc.vb
+++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests_XmlDoc.vb
@@ -765,6 +765,25 @@ class c
End Using
End Function
+
+ Public Async Function CommitParam_Record(showCompletionInArgumentLists As Boolean) As Task
+ Using state = TestStateFactory.CreateCSharpTestState(
+ , showCompletionInArgumentLists:=showCompletionInArgumentLists)
+
+ state.SendInvokeCompletionList()
+ Await state.AssertCompletionSession()
+ Await state.AssertSelectedCompletionItem(displayText:="param name=""I""")
+ state.SendReturn()
+ Await state.AssertNoCompletionSession()
+
+ ' ///
Public Async Function CommitParamNoOpenAngle(showCompletionInArgumentLists As Boolean) As Task
diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb
index 358f561f10ea0..0053746e98b52 100644
--- a/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb
+++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/AddParameterTests.vb
@@ -825,5 +825,36 @@ End Class]]>.NormalizedValue()
Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode)
End Function
+
+
+
+ Public Async Function TestAddParameter_NoLastWhitespaceTrivia() As Task
+
+ Dim markup =
+'''
+'''
+Sub $$M(a As Integer)
+End Sub
+End Class]]>.NormalizedValue()
+ Dim permutation =
+ {
+ New AddedParameterOrExistingIndex(0),
+ New AddedParameterOrExistingIndex(New AddedParameter(Nothing, "Integer", "b", CallSiteKind.Value), "Integer")
+ }
+
+ Dim updatedCode =
+ '''
+ '''
+ '''
+ Sub M(a As Integer, b As Integer)
+ End Sub
+End Class]]>.NormalizedValue()
+
+ Await TestChangeSignatureViaCommandAsync(LanguageNames.VisualBasic, markup, updatedSignature:=permutation, expectedUpdatedInvocationDocumentCode:=updatedCode)
+ End Function
End Class
End Namespace
diff --git a/src/Features/CSharp/Portable/ChangeSignature/CSharpChangeSignatureService.cs b/src/Features/CSharp/Portable/ChangeSignature/CSharpChangeSignatureService.cs
index 5ebd9cb87ab0b..e350faa680817 100644
--- a/src/Features/CSharp/Portable/ChangeSignature/CSharpChangeSignatureService.cs
+++ b/src/Features/CSharp/Portable/ChangeSignature/CSharpChangeSignatureService.cs
@@ -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;
@@ -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 _declarationAndInvocableKinds =
_declarationKinds.Concat(ImmutableArray.Create(
@@ -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)]
@@ -270,7 +275,9 @@ public override async Task 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)
@@ -286,6 +293,12 @@ public override async Task 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);
@@ -745,13 +758,14 @@ private ImmutableArray UpdateParamTagsInLeadingTrivia(Document doc
return GetPermutedDocCommentTrivia(document, node, permutedParamNodes);
}
- private static ImmutableArray VerifyAndPermuteParamNodes(IEnumerable paramNodes, ISymbol declarationSymbol, SignatureChange updatedSignature)
+ private ImmutableArray VerifyAndPermuteParamNodes(IEnumerable 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.Empty;
@@ -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 GetParameters(ISymbol declarationSymbol)
+ {
+ var declaredParameters = declarationSymbol.GetParameters();
+ if (declarationSymbol is INamedTypeSymbol namedTypeSymbol &&
+ namedTypeSymbol.TryGetRecordPrimaryConstructor(out var primaryConstructor))
+ {
+ declaredParameters = primaryConstructor.Parameters;
+ }
+
+ return declaredParameters;
+ }
}
}
diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs
index 57a8d38828ad3..f096d239f8fff 100644
--- a/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs
+++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs
@@ -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;
@@ -365,6 +366,18 @@ private string GetAttributeValue(XmlAttributeSyntax attribute)
}
}
+ protected override ImmutableArray GetParameters(ISymbol declarationSymbol)
+ {
+ var declaredParameters = declarationSymbol.GetParameters();
+ 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,
diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs
index 80ddbceb3bc97..dabab4bd296c8 100644
--- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs
+++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -74,6 +75,13 @@ public abstract Task ChangeSignatureAsync(
///
protected abstract bool SupportsOptionalAndParamsArrayParametersSimultaneously();
+ protected abstract bool TryGetRecordPrimaryConstructor(INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol? primaryConstructor);
+
+ ///
+ /// A temporarily hack that should be removed once/if https://github.com/dotnet/roslyn/issues/53092 is fixed.
+ ///
+ protected abstract ImmutableArray GetParameters(ISymbol declarationSymbol);
+
protected abstract SyntaxGenerator Generator { get; }
protected abstract ISyntaxFacts SyntaxFacts { get; }
@@ -124,6 +132,10 @@ internal async Task GetChangeSignatureContextAsy
{
symbol = typeSymbol.DelegateInvokeMethod;
}
+ else if (TryGetRecordPrimaryConstructor(typeSymbol, out var primaryConstructor))
+ {
+ symbol = primaryConstructor;
+ }
}
if (!symbol.MatchesKind(SymbolKind.Method, SymbolKind.Property))
@@ -164,7 +176,7 @@ internal async Task GetChangeSignatureContextAsy
}
var parameterConfiguration = ParameterConfiguration.Create(
- symbol.GetParameters().Select(p => new ExistingParameter(p)).ToImmutableArray(),
+ GetParameters(symbol).Select(p => new ExistingParameter(p)).ToImmutableArray(),
symbol.IsExtensionMethod(), selectedIndex);
return new ChangeSignatureAnalysisSucceededContext(
@@ -245,7 +257,7 @@ private static async Task> FindChangeSignatureR
var symbols = await FindChangeSignatureReferencesAsync(
declaredSymbol, context.Solution, cancellationToken).ConfigureAwait(false);
- var declaredSymbolParametersCount = declaredSymbol.GetParameters().Length;
+ var declaredSymbolParametersCount = GetParameters(declaredSymbol).Length;
var telemetryNumberOfDeclarationsToUpdate = 0;
var telemetryNumberOfReferencesToUpdate = 0;
@@ -441,14 +453,14 @@ private static bool TryGetNodeWithEditableSignatureOrAttributes(Location locatio
return nodeToUpdate != null;
}
- protected static ImmutableArray PermuteArguments(
+ protected ImmutableArray PermuteArguments(
ISymbol declarationSymbol,
ImmutableArray arguments,
SignatureChange updatedSignature,
bool isReducedExtensionMethod = false)
{
// 1. Determine which parameters are permutable
- var declarationParameters = declarationSymbol.GetParameters();
+ var declarationParameters = GetParameters(declarationSymbol);
var declarationParametersToPermute = GetParametersToPermute(arguments, declarationParameters, isReducedExtensionMethod);
var argumentsToPermute = arguments.Take(declarationParametersToPermute.Length).ToList();
@@ -552,14 +564,14 @@ protected static ImmutableArray PermuteArguments(
/// delegate Invoke methods (m) and delegate BeginInvoke methods (n = m + 2). This method adds on those extra parameters
/// to the base .
///
- private static SignatureChange UpdateSignatureChangeToIncludeExtraParametersFromTheDeclarationSymbol(ISymbol declarationSymbol, SignatureChange updatedSignature)
+ private SignatureChange UpdateSignatureChangeToIncludeExtraParametersFromTheDeclarationSymbol(ISymbol declarationSymbol, SignatureChange updatedSignature)
{
- if (declarationSymbol.GetParameters().Length > updatedSignature.OriginalConfiguration.ToListOfParameters().Length)
+ var realParameters = GetParameters(declarationSymbol);
+ if (realParameters.Length > updatedSignature.OriginalConfiguration.ToListOfParameters().Length)
{
var originalConfigurationParameters = updatedSignature.OriginalConfiguration.ToListOfParameters();
var updatedConfigurationParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters();
- var realParameters = declarationSymbol.GetParameters();
var bonusParameters = realParameters.Skip(originalConfigurationParameters.Length);
var originalConfigurationParametersWithExtraParameters = originalConfigurationParameters.AddRange(bonusParameters.Select(p => new ExistingParameter(p)));
@@ -759,13 +771,14 @@ protected virtual async Task> AddNewArgumentsToL
if (updatedParameters[i] != signaturePermutation.UpdatedConfiguration.ThisParameter
|| !isReducedExtensionMethod)
{
+ var parameters = GetParameters(declarationSymbol);
if (updatedParameters[i] is AddedParameter addedParameter)
{
// Omitting an argument only works in some languages, depending on whether
// there is a params array. We sometimes need to reinterpret an requested
// omitted parameter as one with a TODO requested.
var forcedCallsiteErrorDueToParamsArray = addedParameter.CallSiteKind == CallSiteKind.Omitted &&
- declarationSymbol.GetParameters().LastOrDefault()?.IsParams == true &&
+ parameters.LastOrDefault()?.IsParams == true &&
!SupportsOptionalAndParamsArrayParametersSimultaneously();
var isCallsiteActuallyOmitted = addedParameter.CallSiteKind == CallSiteKind.Omitted && !forcedCallsiteErrorDueToParamsArray;
@@ -808,7 +821,6 @@ protected virtual async Task> AddNewArgumentsToL
}
else
{
- var parameters = declarationSymbol.GetParameters();
if (indexInListOfPreexistingArguments == parameters.Length - 1 &&
parameters[indexInListOfPreexistingArguments].IsParams)
{
@@ -1001,7 +1013,6 @@ protected ImmutableArray GetPermutedDocCommentTrivia(Document docu
node.GetTrailingTrivia(),
lastWhiteSpaceTrivia,
document.Project.Solution.Options.GetOption(FormattingOptions.NewLine, document.Project.Language));
-
var newTrivia = Generator.Trivia(extraDocComments);
updatedLeadingTrivia.Add(newTrivia);
diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs
index 84866db580dd2..06471715b2b8b 100644
--- a/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs
+++ b/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs
@@ -97,6 +97,13 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
protected abstract IEnumerable GetExistingTopLevelAttributeValues(TSyntax syntax, string tagName, string attributeName);
+ protected abstract IEnumerable GetKeywordNames();
+
+ ///
+ /// A temporarily hack that should be removed once/if https://github.com/dotnet/roslyn/issues/53092 is fixed.
+ ///
+ protected abstract ImmutableArray GetParameters(ISymbol symbol);
+
private CompletionItem GetItem(string name)
{
if (s_tagMap.TryGetValue(name, out var values))
@@ -152,7 +159,7 @@ protected IEnumerable GetNestedItems(ISymbol symbol, bool includ
private IEnumerable GetParamRefItems(ISymbol symbol)
{
- var names = symbol.GetParameters().Select(p => p.Name);
+ var names = GetParameters(symbol).Select(p => p.Name);
return names.Select(p => CreateCompletionItem(
displayText: FormatParameter(ParameterReferenceElementName, p),
@@ -176,7 +183,7 @@ protected IEnumerable GetAttributeValueItems(ISymbol symbol, str
{
if (tagName is ParameterElementName or ParameterReferenceElementName)
{
- return symbol.GetParameters()
+ return GetParameters(symbol)
.Select(parameter => CreateCompletionItem(parameter.Name));
}
else if (tagName == TypeParameterElementName)
@@ -202,8 +209,6 @@ protected IEnumerable GetAttributeValueItems(ISymbol symbol, str
return SpecializedCollections.EmptyEnumerable();
}
- protected abstract IEnumerable GetKeywordNames();
-
protected ImmutableArray GetTopLevelItems(ISymbol symbol, TSyntax syntax)
{
using var _1 = ArrayBuilder.GetInstance(out var items);
@@ -216,7 +221,7 @@ protected ImmutableArray GetTopLevelItems(ISymbol symbol, TSynta
if (symbol != null)
{
- items.AddRange(GetParameterItems(symbol.GetParameters(), syntax, ParameterElementName));
+ items.AddRange(GetParameterItems(GetParameters(symbol), syntax, ParameterElementName));
items.AddRange(GetParameterItems(symbol.GetTypeParameters(), syntax, TypeParameterElementName));
if (symbol is IPropertySymbol && !existingTopLevelTags.Contains(ValueElementName))
diff --git a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb
index da9d187d8a6a3..ce65e2060dbc7 100644
--- a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb
+++ b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb
@@ -604,13 +604,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature
Return GetPermutedDocCommentTrivia(document, node, permutedParamNodes)
End Function
- Private Shared Function VerifyAndPermuteParamNodes(paramNodes As ImmutableArray(Of XmlElementSyntax), declarationSymbol As ISymbol, updatedSignature As SignatureChange) As ImmutableArray(Of SyntaxNode)
+ Private Function VerifyAndPermuteParamNodes(paramNodes As ImmutableArray(Of XmlElementSyntax), declarationSymbol As ISymbol, updatedSignature As SignatureChange) As ImmutableArray(Of SyntaxNode)
' Only reorder if count and order match originally.
Dim originalParameters = updatedSignature.OriginalConfiguration.ToListOfParameters()
Dim reorderedParameters = updatedSignature.UpdatedConfiguration.ToListOfParameters()
- Dim declaredParameters = declarationSymbol.GetParameters()
+ Dim declaredParameters = GetParameters(declarationSymbol)
If paramNodes.Length <> declaredParameters.Length Then
Return ImmutableArray(Of SyntaxNode).Empty
End If
@@ -755,5 +755,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature
Protected Overrides Function CommaTokenWithElasticSpace() As SyntaxToken
Return Token(SyntaxKind.CommaToken).WithTrailingTrivia(ElasticSpace)
End Function
+
+ Protected Overrides Function TryGetRecordPrimaryConstructor(typeSymbol As INamedTypeSymbol, ByRef primaryConstructor As IMethodSymbol) As Boolean
+ Return False
+ End Function
+
+ Protected Overrides Function GetParameters(declarationSymbol As ISymbol) As ImmutableArray(Of IParameterSymbol)
+ Return declarationSymbol.GetParameters()
+ End Function
End Class
End Namespace
diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb
index 29c5befe0a147..192e23a5d194a 100644
--- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb
+++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb
@@ -338,6 +338,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
Return nameSyntax?.LocalName.ValueText
End Function
+ Protected Overrides Function GetParameters(symbol As ISymbol) As ImmutableArray(Of IParameterSymbol)
+ Return symbol.GetParameters()
+ End Function
+
Private Shared ReadOnly s_defaultRules As CompletionItemRules =
CompletionItemRules.Create(
filterCharacterRules:=FilterRules,
diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs
index ceaff08c190dc..b0e04e3c7cfe1 100644
--- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs
+++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs
@@ -87,10 +87,13 @@ internal override SyntaxNode DocumentationCommentTrivia(IEnumerable
SyntaxFactory.List(nodes),
SyntaxFactory.Token(SyntaxKind.EndOfDocumentationCommentToken));
- return docTrivia
- .WithLeadingTrivia(SyntaxFactory.DocumentationCommentExterior("/// "))
- .WithTrailingTrivia(trailingTrivia)
- .WithTrailingTrivia(
+ docTrivia = docTrivia.WithLeadingTrivia(SyntaxFactory.DocumentationCommentExterior("/// "))
+ .WithTrailingTrivia(trailingTrivia);
+
+ if (lastWhitespaceTrivia == default)
+ return docTrivia.WithTrailingTrivia(SyntaxFactory.EndOfLine(endOfLineString));
+
+ return docTrivia.WithTrailingTrivia(
SyntaxFactory.EndOfLine(endOfLineString),
lastWhitespaceTrivia);
}
diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs
index 9b0cadc0c9d4c..73c1a9ff9649d 100644
--- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs
+++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs
@@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -177,5 +179,26 @@ public static bool IsIntrinsicType(this ITypeSymbol typeSymbol)
return false;
}
}
+
+ public static bool TryGetRecordPrimaryConstructor(this INamedTypeSymbol typeSymbol, [NotNullWhen(true)] out IMethodSymbol? primaryConstructor)
+ {
+ if (typeSymbol.IsRecord)
+ {
+ Debug.Assert(typeSymbol.GetParameters().IsDefaultOrEmpty, "If GetParameters extension handles record, we can remove the handling here.");
+
+ // A bit hacky to determine the parameters of primary constructor associated with a given record.
+ // Simplifying is tracked by: https://github.com/dotnet/roslyn/issues/53092.
+ // Note: When the issue is handled, we can remove the logic here and handle things in GetParameters extension. BUT
+ // if GetParameters extension method gets updated to handle records, we need to test EVERY usage
+ // of the extension method and make sure the change is applicable to all these usages.
+
+ primaryConstructor = typeSymbol.InstanceConstructors.FirstOrDefault(
+ c => c.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax() is RecordDeclarationSyntax);
+ return primaryConstructor is not null;
+ }
+
+ primaryConstructor = null;
+ return false;
+ }
}
}
diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb
index 9d1659d957012..4bf5bf06f207b 100644
--- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb
+++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb
@@ -67,9 +67,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Friend Overrides Function DocumentationCommentTrivia(nodes As IEnumerable(Of SyntaxNode), trailingTrivia As SyntaxTriviaList, lastWhitespaceTrivia As SyntaxTrivia, endOfLineString As String) As SyntaxNode
Dim node = SyntaxFactory.DocumentationCommentTrivia(SyntaxFactory.List(nodes))
- Return node.WithLeadingTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia("''' ")).
- WithTrailingTrivia(node.GetTrailingTrivia()).
- WithTrailingTrivia(SyntaxFactory.EndOfLine(endOfLineString), lastWhitespaceTrivia)
+ node = node.WithLeadingTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia("''' ")).
+ WithTrailingTrivia(node.GetTrailingTrivia())
+
+ If lastWhitespaceTrivia = Nothing Then
+ Return node.WithTrailingTrivia(SyntaxFactory.EndOfLine(endOfLineString))
+ End If
+
+ Return node.WithTrailingTrivia(SyntaxFactory.EndOfLine(endOfLineString), lastWhitespaceTrivia)
End Function
Friend Overrides Function DocumentationCommentTriviaWithUpdatedContent(trivia As SyntaxTrivia, content As IEnumerable(Of SyntaxNode)) As SyntaxNode