diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 629edf6934c73..e3d71b5799150 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -18,9 +18,9 @@
78da7776965b428ff31da8f1ff2cb073506212b7
-
+
https://github.com/dotnet/roslyn
- 03a07d1dd606ce11d62c9a595041c4c2d44c39e3
+ ca27d128f3533dc41a46b010b8e878916328f2e4
https://github.com/dotnet/arcade
diff --git a/eng/Versions.props b/eng/Versions.props
index 1b6de43e50b2a..a252ec69f85ca 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -23,7 +23,7 @@
- 4.0.0-2.21327.4
+ 4.0.0-2.21359.14
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs
index 8dc8d46656081..14f0a90213d07 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs
@@ -132,21 +132,24 @@ private BoundInterpolatedString BindUnconvertedInterpolatedStringToString(BoundU
{
// We have 4 possible lowering strategies, dependent on the contents of the string, in this order:
// 1. The string is a constant value. We can just use the final value.
- // 2. The WellKnownType DefaultInterpolatedStringHandler is available, and none of the interpolation holes contain an await expression.
+ // 2. The string is composed of 4 or fewer components that are all strings, we can lower to a call to string.Concat without a
+ // params array. This is very efficient as the runtime can allocate a buffer for the string with exactly the correct length and
+ // make no intermediate allocations.
+ // 3. The WellKnownType DefaultInterpolatedStringHandler is available, and none of the interpolation holes contain an await expression.
// The builder is a ref struct, and we can guarantee the lifetime won't outlive the stack if the string doesn't contain any
// awaits, but if it does we cannot use it. This builder is the only way that ref structs can be directly used as interpolation
// hole components, which means that ref structs components and await expressions cannot be combined. It is already illegal for
// the user to use ref structs in an async method today, but if that were to ever change, this would still need to be respected.
// We also cannot use this method if the interpolated string appears within a catch filter, as the builder is disposable and we
// cannot put a try/finally inside a filter block.
- // 3. The string is composed entirely of components that are strings themselves. We can turn this into a single call to string.Concat.
- // We prefer the builder over this because the builder can use pooling to avoid new allocations, while this call will potentially
- // need to allocate a param array.
- // 4. The string has heterogeneous data and either InterpolatedStringHandler is unavailable, or one of the holes contains an await
+ // 4. The string is composed of more than 4 components that are all strings themselves. We can turn this into a single
+ // call to string.Concat. We prefer the builder over this because the builder can use pooling to avoid new allocations, while this
+ // call will need to allocate a param array.
+ // 5. The string has heterogeneous data and either InterpolatedStringHandler is unavailable, or one of the holes contains an await
// expression. This is turned into a call to string.Format.
//
- // We need to do the determination of 1, 2, or 3/4 up front, rather than in lowering, as it affects diagnostics (ref structs not being
- // able to be used, for example). However, between 3 and 4, we don't need to know at this point, so that logic is deferred for lowering.
+ // We need to do the determination of 1, 2, 3, or 4/5 up front, rather than in lowering, as it affects diagnostics (ref structs not being
+ // able to be used, for example). However, between 4 and 5, we don't need to know at this point, so that logic is deferred for lowering.
if (unconvertedInterpolatedString.ConstantValue is not null)
{
@@ -155,13 +158,21 @@ private BoundInterpolatedString BindUnconvertedInterpolatedStringToString(BoundU
return constructWithData(BindInterpolatedStringParts(unconvertedInterpolatedString, diagnostics), data: null);
}
+ // Case 2. Attempt to see if all parts are strings.
+ if (unconvertedInterpolatedString.Parts.Length <= 4 &&
+ unconvertedInterpolatedString.Parts.All(p => p is BoundLiteral
+ or BoundStringInsert { Value: { Type: { SpecialType: SpecialType.System_String } }, Alignment: null, Format: null }))
+ {
+ return constructWithData(BindInterpolatedStringParts(unconvertedInterpolatedString, diagnostics), data: null);
+ }
+
if (tryBindAsHandlerType(out var result))
{
- // Case 2
+ // Case 3
return result;
}
- // The specifics of 3 vs 4 aren't necessary for this stage of binding. The only thing that matters is that every part needs to be convertible
+ // The specifics of 4 vs 5 aren't necessary for this stage of binding. The only thing that matters is that every part needs to be convertible
// object.
return constructWithData(BindInterpolatedStringParts(unconvertedInterpolatedString, diagnostics), data: null);
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs
index d9d88ab88e963..dc156979c39e3 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringInterpolation.cs
@@ -282,7 +282,10 @@ public override BoundNode VisitInterpolatedString(BoundInterpolatedString node)
_factory.Binary(BinaryOperatorKind.StringConcatenation, node.Type, result, part);
}
- if (length == 1)
+ // We need to ensure that the result of the interpolated string is not null. If the single part has a non-null constant value
+ // or is itself an interpolated string (which by proxy cannot be null), then there's nothing else that needs to be done. Otherwise,
+ // we need to test for null and ensure "" if it is.
+ if (length == 1 && result is not ({ Kind: BoundKind.InterpolatedString } or { ConstantValue: { IsString: true } }))
{
result = _factory.Coalesce(result!, _factory.StringLiteral(""));
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs
index 4159c6173ff92..1d37a8c5c1083 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs
@@ -213,6 +213,61 @@ static void Main(string[] args)
CompileAndVerify(source, expectedOutput: expectedOutput);
}
+ [Fact]
+ public void OneLiteral()
+ {
+ string source =
+@"using System;
+class Program
+{
+ static void Main(string[] args)
+ {
+ Console.WriteLine( $""Hello"" );
+ }
+}";
+ string expectedOutput = @"Hello";
+ var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
+ verifier.VerifyIL("Program.Main", @"
+{
+ // Code size 11 (0xb)
+ .maxstack 1
+ IL_0000: ldstr ""Hello""
+ IL_0005: call ""void System.Console.WriteLine(string)""
+ IL_000a: ret
+}
+");
+ }
+
+ [Fact]
+ public void OneInsert()
+ {
+ string source =
+@"using System;
+class Program
+{
+ static void Main(string[] args)
+ {
+ var hello = $""Hello"";
+ Console.WriteLine( $""{hello}"" );
+ }
+}";
+ string expectedOutput = @"Hello";
+ var verifier = CompileAndVerify(source, expectedOutput: expectedOutput);
+ verifier.VerifyIL("Program.Main", @"
+{
+ // Code size 20 (0x14)
+ .maxstack 2
+ IL_0000: ldstr ""Hello""
+ IL_0005: dup
+ IL_0006: brtrue.s IL_000e
+ IL_0008: pop
+ IL_0009: ldstr """"
+ IL_000e: call ""void System.Console.WriteLine(string)""
+ IL_0013: ret
+}
+");
+ }
+
[Fact]
public void TwoInserts()
{
@@ -1202,6 +1257,164 @@ static void Main()
);
}
+ [Fact, WorkItem(54702, "https://github.com/dotnet/roslyn/issues/54702")]
+ public void InterpolatedStringHandler_ConcatPreferencesForAllStringElements()
+ {
+ var code = @"
+using System;
+Console.WriteLine(TwoComponents());
+Console.WriteLine(ThreeComponents());
+Console.WriteLine(FourComponents());
+Console.WriteLine(FiveComponents());
+
+string TwoComponents()
+{
+ string s1 = ""1"";
+ string s2 = ""2"";
+ return $""{s1}{s2}"";
+}
+
+string ThreeComponents()
+{
+ string s1 = ""1"";
+ string s2 = ""2"";
+ string s3 = ""3"";
+ return $""{s1}{s2}{s3}"";
+}
+
+string FourComponents()
+{
+ string s1 = ""1"";
+ string s2 = ""2"";
+ string s3 = ""3"";
+ string s4 = ""4"";
+ return $""{s1}{s2}{s3}{s4}"";
+}
+
+string FiveComponents()
+{
+ string s1 = ""1"";
+ string s2 = ""2"";
+ string s3 = ""3"";
+ string s4 = ""4"";
+ string s5 = ""5"";
+ return $""{s1}{s2}{s3}{s4}{s5}"";
+}
+";
+
+ var handler = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
+
+ var verifier = CompileAndVerify(new[] { code, handler }, expectedOutput: @"
+12
+123
+1234
+value:1
+value:2
+value:3
+value:4
+value:5
+");
+
+ verifier.VerifyIL("$.<$>g__TwoComponents|0_0()", @"
+{
+ // Code size 18 (0x12)
+ .maxstack 2
+ .locals init (string V_0) //s2
+ IL_0000: ldstr ""1""
+ IL_0005: ldstr ""2""
+ IL_000a: stloc.0
+ IL_000b: ldloc.0
+ IL_000c: call ""string string.Concat(string, string)""
+ IL_0011: ret
+}
+");
+
+ verifier.VerifyIL("$.<$>g__ThreeComponents|0_1()", @"
+{
+ // Code size 25 (0x19)
+ .maxstack 3
+ .locals init (string V_0, //s2
+ string V_1) //s3
+ IL_0000: ldstr ""1""
+ IL_0005: ldstr ""2""
+ IL_000a: stloc.0
+ IL_000b: ldstr ""3""
+ IL_0010: stloc.1
+ IL_0011: ldloc.0
+ IL_0012: ldloc.1
+ IL_0013: call ""string string.Concat(string, string, string)""
+ IL_0018: ret
+}
+");
+
+ verifier.VerifyIL("$.<$>g__FourComponents|0_2()", @"
+{
+ // Code size 32 (0x20)
+ .maxstack 4
+ .locals init (string V_0, //s2
+ string V_1, //s3
+ string V_2) //s4
+ IL_0000: ldstr ""1""
+ IL_0005: ldstr ""2""
+ IL_000a: stloc.0
+ IL_000b: ldstr ""3""
+ IL_0010: stloc.1
+ IL_0011: ldstr ""4""
+ IL_0016: stloc.2
+ IL_0017: ldloc.0
+ IL_0018: ldloc.1
+ IL_0019: ldloc.2
+ IL_001a: call ""string string.Concat(string, string, string, string)""
+ IL_001f: ret
+}
+");
+
+ verifier.VerifyIL("$.<$>g__FiveComponents|0_3()", @"
+{
+ // Code size 89 (0x59)
+ .maxstack 3
+ .locals init (string V_0, //s1
+ string V_1, //s2
+ string V_2, //s3
+ string V_3, //s4
+ string V_4, //s5
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_5)
+ IL_0000: ldstr ""1""
+ IL_0005: stloc.0
+ IL_0006: ldstr ""2""
+ IL_000b: stloc.1
+ IL_000c: ldstr ""3""
+ IL_0011: stloc.2
+ IL_0012: ldstr ""4""
+ IL_0017: stloc.3
+ IL_0018: ldstr ""5""
+ IL_001d: stloc.s V_4
+ IL_001f: ldloca.s V_5
+ IL_0021: ldc.i4.0
+ IL_0022: ldc.i4.5
+ IL_0023: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
+ IL_0028: ldloca.s V_5
+ IL_002a: ldloc.0
+ IL_002b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
+ IL_0030: ldloca.s V_5
+ IL_0032: ldloc.1
+ IL_0033: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
+ IL_0038: ldloca.s V_5
+ IL_003a: ldloc.2
+ IL_003b: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
+ IL_0040: ldloca.s V_5
+ IL_0042: ldloc.3
+ IL_0043: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
+ IL_0048: ldloca.s V_5
+ IL_004a: ldloc.s V_4
+ IL_004c: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
+ IL_0051: ldloca.s V_5
+ IL_0053: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
+ IL_0058: ret
+}
+");
+ }
+
[Theory]
[CombinatorialData]
public void InterpolatedStringHandler_OverloadsAndBoolReturns(bool useDefaultParameters, bool useBoolReturns, bool constructorBoolArg)
@@ -2948,15 +3161,14 @@ public void NestedInterpolatedStrings()
var interpolatedStringBuilder = GetInterpolatedStringHandlerDefinition(includeSpanOverloads: false, useDefaultParameters: false, useBoolReturns: false);
- var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"value:value:1");
+ var verifier = CompileAndVerify(new[] { source, interpolatedStringBuilder }, expectedOutput: @"value:1");
verifier.VerifyIL("", @"
{
- // Code size 55 (0x37)
- .maxstack 4
+ // Code size 32 (0x20)
+ .maxstack 3
.locals init (int V_0, //i
- System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1,
- System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_2)
+ System.Runtime.CompilerServices.DefaultInterpolatedStringHandler V_1)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s V_1
@@ -2964,20 +3176,12 @@ .locals init (int V_0, //i
IL_0005: ldc.i4.1
IL_0006: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
IL_000b: ldloca.s V_1
- IL_000d: ldloca.s V_2
- IL_000f: ldc.i4.0
- IL_0010: ldc.i4.1
- IL_0011: call ""System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(int, int)""
- IL_0016: ldloca.s V_2
- IL_0018: ldloc.0
- IL_0019: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
- IL_001e: ldloca.s V_2
- IL_0020: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
- IL_0025: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(string)""
- IL_002a: ldloca.s V_1
- IL_002c: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
- IL_0031: call ""void System.Console.WriteLine(string)""
- IL_0036: ret
+ IL_000d: ldloc.0
+ IL_000e: call ""void System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendFormatted(int)""
+ IL_0013: ldloca.s V_1
+ IL_0015: call ""string System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.ToStringAndClear()""
+ IL_001a: call ""void System.Console.WriteLine(string)""
+ IL_001f: ret
}
");
}
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/VisualStudio/Core/Def/Implementation/Progression/GraphQueries/SearchGraphQuery.cs b/src/VisualStudio/Core/Def/Implementation/Progression/GraphQueries/SearchGraphQuery.cs
index 2a525df7db468..448311407c50b 100644
--- a/src/VisualStudio/Core/Def/Implementation/Progression/GraphQueries/SearchGraphQuery.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Progression/GraphQueries/SearchGraphQuery.cs
@@ -10,6 +10,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.NavigateTo;
using Microsoft.CodeAnalysis.PooledObjects;
@@ -38,8 +39,11 @@ public SearchGraphQuery(
public Task GetGraphAsync(Solution solution, IGraphContext context, CancellationToken cancellationToken)
{
+ var experimentationService = solution.Workspace.Services.GetService();
+ var forceLegacySearch = experimentationService?.IsExperimentEnabled(WellKnownExperimentNames.ProgressionForceLegacySearch) == true;
+
var option = solution.Options.GetOption(ProgressionOptions.SearchUsingNavigateToEngine);
- return option
+ return !forceLegacySearch && option
? SearchUsingNavigateToEngineAsync(solution, context, cancellationToken)
: SearchUsingSymbolsAsync(solution, context, cancellationToken);
}
diff --git a/src/VisualStudio/Core/Def/Implementation/Progression/ProgressionOptions.cs b/src/VisualStudio/Core/Def/Implementation/Progression/ProgressionOptions.cs
index 94a3c73b535cf..4e9eeb23cbae7 100644
--- a/src/VisualStudio/Core/Def/Implementation/Progression/ProgressionOptions.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Progression/ProgressionOptions.cs
@@ -13,7 +13,7 @@ internal static class ProgressionOptions
private const string LocalRegistryPath = @"Roslyn\Internal\OnOff\Components\Progression\";
public static readonly Option2 SearchUsingNavigateToEngine = new(
- nameof(ProgressionOptions), nameof(SearchUsingNavigateToEngine), defaultValue: false,
+ nameof(ProgressionOptions), nameof(SearchUsingNavigateToEngine), defaultValue: true,
storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + "SearchUsingNavigateToEngine"));
}
}
diff --git a/src/VisualStudio/Core/Test/Progression/SearchGraphQueryTests.vb b/src/VisualStudio/Core/Test/Progression/SearchGraphQueryTests.vb
index ff84d6ee40eb9..4641ed11ca716 100644
--- a/src/VisualStudio/Core/Test/Progression/SearchGraphQueryTests.vb
+++ b/src/VisualStudio/Core/Test/Progression/SearchGraphQueryTests.vb
@@ -25,6 +25,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Progression
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="C", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -59,6 +60,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Progression
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="F", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -95,6 +97,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Progression
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="M", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -144,6 +147,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="C", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -194,6 +198,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="Goo", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -243,6 +248,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="Z", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -284,6 +290,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="D.B", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -320,6 +327,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="C.B", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -344,6 +352,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="D.B", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -380,6 +389,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="A.D.B", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
@@ -416,6 +426,7 @@ End Namespace
)
+ testState.Workspace.SetOptions(testState.Workspace.Options.WithChangedOption(ProgressionOptions.SearchUsingNavigateToEngine, False))
Dim threadingContext = testState.Workspace.ExportProvider.GetExportedValue(Of IThreadingContext)
Dim outputContext = Await testState.GetGraphContextAfterQuery(
New Graph(), New SearchGraphQuery(searchPattern:="A.D.B", threadingContext, AsynchronousOperationListenerProvider.NullListener), GraphContextDirection.Custom)
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/Core/Portable/Experiments/IExperimentationService.cs b/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs
index 95cd7afd749c7..e4845a33961f1 100644
--- a/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs
+++ b/src/Workspaces/Core/Portable/Experiments/IExperimentationService.cs
@@ -45,5 +45,6 @@ internal static class WellKnownExperimentNames
public const string LspPullDiagnosticsFeatureFlag = "Lsp.PullDiagnostics";
public const string OOPCoreClr = "Roslyn.OOPCoreClr";
public const string DisableAsynchronousQuickActions = "Roslyn.DisableAsynchronousQuickActions";
+ public const string ProgressionForceLegacySearch = "Roslyn.ProgressionForceLegacySearch";
}
}
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