diff --git a/README.md b/README.md
index 6726a8f748261..7fa4b7a5624aa 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,12 @@
-## Welcome to the .NET Compiler Platform ("Roslyn")
+
+
+
-[![Join the chat at https://gitter.im/dotnet/roslyn](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dotnet/roslyn?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Chat on Discord](https://discordapp.com/api/guilds/143867839282020352/widget.png)](http://aka.ms/discord-csharp-roslyn)
+The .NET Compiler Platform
-Roslyn provides open-source C# and Visual Basic compilers with rich code analysis APIs. It enables building code analysis tools with the same APIs that are used by Visual Studio.
+
+
+Roslyn is the open-source implementation of both the C# and Visual Basic compilers with an API surface for building code analysis tools.
### C# and Visual Basic Language Feature Suggestions
@@ -11,50 +15,31 @@ If you want to suggest a new feature for the C# or Visual Basic languages go her
- [dotnet/vblang](https://github.com/dotnet/vblang) for VB-specific features
- [dotnet/csharplang](https://github.com/dotnet/csharplang) for features that affect both languages
-## Contribute!
+### Contributing
-Some of the best ways to contribute are to try things out, file bugs, and join in design conversations.
+All work on the C# and Visual Basic compiler happens directly on [GitHub](https://github.com/dotnet/roslyn). Both core team members and external contributors send pull requests which go through the same review process.
-### Questions
+If you are interested in fixing issues and contributing directly to the code base, a great way to get started is to ask some questions on [GitHub Discussions](https://github.com/dotnet/roslyn/discussions)! Then check out our [contributing guide](https://github.com/dotnet/roslyn/blob/master/docs/contributing/Building%2C%20Debugging%2C%20and%20Testing%20on%20Windows.md) which covers the following:
-A great way to get started is to ask some questions!
-- Start with a question on [discussions](https://github.com/dotnet/roslyn/discussions)
-- You can also join in on the design discussions on [gitter](https://gitter.im/dotnet/roslyn) or [discord](http://aka.ms/discord-csharp-roslyn)
+- [Coding guidelines](https://github.com/dotnet/roslyn/blob/master/docs/wiki/Contributing-Code.md)
+- [The development workflow, including debugging and running tests](https://github.com/dotnet/roslyn/blob/master/docs/contributing/Building%2C%20Debugging%2C%20and%20Testing%20on%20Windows.md)
+- [Submitting pull requests](https://github.com/dotnet/roslyn/blob/master/CONTRIBUTING.md)
+- Finding a bug to fix in the [IDE](https://aka.ms/roslyn-ide-bugs-help-wanted) or [Compiler](https://aka.ms/roslyn-compiler-bugs-help-wanted)
+- Finding a feature to implement in the [IDE](https://aka.ms/roslyn-ide-feature-help-wanted) or [Compiler](https://aka.ms/roslyn-compiler-feature-help-wanted)
-### See if your issue is already being worked on! (Add your own votes using the š reaction)
-- [IDE](https://aka.ms/roslyn-ide-in-progress)
-- [Compiler](https://aka.ms/roslyn-compiler-in-progress)
+### Community
-### Vote in the Backlog! (Add your own votes using the š reaction)
-- [IDE Bugs](https://aka.ms/roslyn-ide-bug-backlog)
-- [IDE Features](https://aka.ms/roslyn-ide-feature-backlog)
-- [Compiler Bugs](https://aka.ms/roslyn-compiler-bug-backlog)
-- [Compiler Features](https://aka.ms/roslyn-compiler-features-backlog)
+The Roslyn community can be found on [GitHub Discussions](https://github.com/dotnet/roslyn/discussions), where you can ask questions, voice ideas, and share your projects.
-### Find a bug to fix! (Add your own votes using the š reaction)
-- First read this guide: [How to Contribute](docs/wiki/Contributing-Code.md)
-- [Building, testing and debugging the sources](docs/wiki/Building-Testing-and-Debugging.md)
-- Top Bugs
- - [IDE](https://aka.ms/roslyn-ide-bugs-help-wanted)
- - [Compiler](https://aka.ms/roslyn-compiler-bugs-help-wanted)
+To chat with other community members, you can join the Roslyn [Discord](https://discord.com/invite/tGJvv88) or [Gitter](https://gitter.im/dotnet/roslyn).
-### Find a feature to implement! (Add your own votes using the š reaction)
-- [IDE](https://aka.ms/roslyn-ide-feature-help-wanted)
-- [Compiler](https://aka.ms/roslyn-compiler-feature-help-wanted)
+Our [Code of Conduct](CODE-OF-CONDUCT.md) applies to all Roslyn community channels and hasĀ adoptedĀ theĀ [.NETĀ FoundationĀ CodeĀ ofĀ Conduct](https://dotnetfoundation.org/code-of-conduct).
+### Documentation
-### Getting started with the Roslyn APIs
+Visit [Roslyn Architecture Overview](https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/compiler-api-model) to get started with Roslynās APIās.
-If you want to get started using Roslyn's APIs to analyzer your code take a look at these links:
-- [Roslyn Architecture Overview](https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/compiler-api-model)
- - [Syntax APIs](https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/work-with-syntax)
- - [Semantic APIs](https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/work-with-semantics)
- - [Workspace APIs](https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/work-with-workspace)
-- [Tutorial: Write your first analyzer and code fix](https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/tutorials/how-to-write-csharp-analyzer-code-fix)
-- Useful Tools
- - [Syntax Visualizer Tool](https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/syntax-visualizer)
- - [Syntax Quoter Tool](http://roslynquoter.azurewebsites.net)
- - Browse the source with the [enhanced source view](http://sourceroslyn.io/)
+### NuGet Feeds
**The latest pre-release builds** are available from the following public NuGet feeds:
- [Compiler](https://dev.azure.com/dnceng/public/_packaging?_a=feed&feed=dotnet-tools): `https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json`
@@ -102,8 +87,6 @@ If you want to get started using Roslyn's APIs to analyzer your code take a look
[//]: # (End current test results)
-This [project](CODE-OF-CONDUCT.md) has adopted the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
-
### .NET Foundation
This project is part of the [.NET Foundation](http://www.dotnetfoundation.org/projects) along with other
diff --git a/eng/build.ps1 b/eng/build.ps1
index c00338c30d482..37f78b3268e6f 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -417,10 +417,7 @@ function TestUsingRunTests() {
$args += " --include 'Microsoft.CodeAnalysis.Workspaces.MSBuild.UnitTests'"
if ($lspEditor) {
- $args += " --testfilter FullyQualifiedName~Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol|Editor=LanguageServerProtocol"
- }
- else {
- $args += " --testfilter FullyQualifiedName!~Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol"
+ $args += " --testfilter Editor=LanguageServerProtocol"
}
}
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/MatchResult.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/MatchResult.cs
index a6f0f0cf5d0ba..53e5159a601ea 100644
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/MatchResult.cs
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/MatchResult.cs
@@ -89,14 +89,14 @@ public int CompareTo(MatchResult other, string filterText)
ImmutableArray.Create>(
// Prefer the item that matches a longer prefix of the filter text.
(f, s) => f.RoslynCompletionItem.FilterText.GetCaseInsensitivePrefixLength(s),
+ // If there are "Abc" vs "abc", we should prefer the case typed by user.
+ (f, s) => f.RoslynCompletionItem.FilterText.GetCaseSensitivePrefixLength(s),
// If the lengths are the same, prefer the one with the higher match priority.
// But only if it's an item that would have been hard selected. We don't want
// to aggressively select an item that was only going to be softly offered.
(f, s) => f.RoslynCompletionItem.Rules.SelectionBehavior == CompletionItemSelectionBehavior.HardSelection
? f.RoslynCompletionItem.Rules.MatchPriority
: MatchPriority.Default,
- // If there are "Abc" vs "abc", we should prefer the case typed by user.
- (f, s) => f.RoslynCompletionItem.FilterText.GetCaseSensitivePrefixLength(s),
// Prefer Intellicode items.
(f, s) => f.RoslynCompletionItem.IsPreferredItem());
}
diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs
index 4de9239ba5e21..f05a6b0d60038 100644
--- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs
+++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs
@@ -1124,46 +1124,87 @@ public async Task BreakMode_RudeEdits()
{
var moduleId = Guid.NewGuid();
- using (var workspace = CreateWorkspace())
+ using var workspace = CreateWorkspace();
+ var project = AddDefaultTestProject(workspace, "class C1 { void M() { System.Console.WriteLine(1); } }");
+ _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(moduleId);
+
+ var service = CreateEditAndContinueService(workspace);
+
+ var debuggingSession = StartDebuggingSession(service);
+
+ StartEditSession(service);
+
+ // change the source (rude edit):
+ var document1 = workspace.CurrentSolution.Projects.Single().Documents.Single();
+ workspace.ChangeDocument(document1.Id, SourceText.From("class C1 { void M1() { System.Console.WriteLine(1); } }"));
+ var document2 = workspace.CurrentSolution.Projects.Single().Documents.Single();
+
+ var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noDocumentActiveSpans, CancellationToken.None).ConfigureAwait(false);
+ AssertEx.Equal(new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_will_prevent_the_debug_session_from_continuing, FeaturesResources.method) },
+ diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}"));
+
+ // validate solution update status and emit:
+ Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None).ConfigureAwait(false));
+
+ var (updates, emitDiagnostics) = await service.EmitSolutionUpdateAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, CancellationToken.None).ConfigureAwait(false);
+ Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status);
+ Assert.Empty(updates.Updates);
+ Assert.Empty(emitDiagnostics);
+
+ EndEditSession(service, documentsWithRudeEdits: ImmutableArray.Create(document2.Id));
+ EndDebuggingSession(service);
+
+ AssertEx.SetEqual(new[] { moduleId }, debuggingSession.Test_GetModulesPreparedForUpdate());
+
+ AssertEx.Equal(new[]
{
- var project = AddDefaultTestProject(workspace, "class C1 { void M() { System.Console.WriteLine(1); } }");
- _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(moduleId);
+ "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0",
+ "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0",
+ "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True"
+ }, _telemetryLog);
+ }
- var service = CreateEditAndContinueService(workspace);
+ [Fact]
+ public async Task BreakMode_RudeEdits_SourceGenerators()
+ {
+ var sourceV1 = @"
+// GENERATE: class G { int X1 => 1; }
- var debuggingSession = StartDebuggingSession(service);
+class C { int Y => 1; }
+";
+ var sourceV2 = @"
+// GENERATE: class G { int X2 => 1; }
- StartEditSession(service);
+class C { int Y => 2; }
+";
- // change the source (rude edit):
- var document1 = workspace.CurrentSolution.Projects.Single().Documents.Single();
- workspace.ChangeDocument(document1.Id, SourceText.From("class C1 { void M1() { System.Console.WriteLine(1); } }"));
- var document2 = workspace.CurrentSolution.Projects.Single().Documents.Single();
+ var generator = new TestSourceGenerator() { ExecuteImpl = GenerateSource };
- var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noDocumentActiveSpans, CancellationToken.None).ConfigureAwait(false);
- AssertEx.Equal(new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_will_prevent_the_debug_session_from_continuing, FeaturesResources.method) },
- diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}"));
+ using var workspace = CreateWorkspace();
+ var project = AddDefaultTestProject(workspace, sourceV1, generator: generator);
- // validate solution update status and emit:
- Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None).ConfigureAwait(false));
+ var service = CreateEditAndContinueService(workspace);
- var (updates, emitDiagnostics) = await service.EmitSolutionUpdateAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, CancellationToken.None).ConfigureAwait(false);
- Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status);
- Assert.Empty(updates.Updates);
- Assert.Empty(emitDiagnostics);
+ var debuggingSession = StartDebuggingSession(service);
+ StartEditSession(service);
- EndEditSession(service, documentsWithRudeEdits: ImmutableArray.Create(document2.Id));
- EndDebuggingSession(service);
+ // change the source:
+ var document1 = workspace.CurrentSolution.Projects.Single().Documents.Single();
+ workspace.ChangeDocument(document1.Id, SourceText.From(sourceV2, Encoding.UTF8));
- AssertEx.SetEqual(new[] { moduleId }, debuggingSession.Test_GetModulesPreparedForUpdate());
+ var generatedDocument = (await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync().ConfigureAwait(false)).Single();
- AssertEx.Equal(new[]
- {
- "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0",
- "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0",
- "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=20|RudeEditSyntaxKind=8875|RudeEditBlocking=True"
- }, _telemetryLog);
- }
+ var diagnostics1 = await service.GetDocumentDiagnosticsAsync(generatedDocument, s_noDocumentActiveSpans, CancellationToken.None).ConfigureAwait(false);
+ AssertEx.Equal(new[] { "ENC0020: " + string.Format(FeaturesResources.Renaming_0_will_prevent_the_debug_session_from_continuing, FeaturesResources.property_) },
+ diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}"));
+
+ var (updates, emitDiagnostics) = await service.EmitSolutionUpdateAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, CancellationToken.None).ConfigureAwait(false);
+ Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status);
+ Assert.Empty(updates.Updates);
+ Assert.Empty(emitDiagnostics);
+
+ EndEditSession(service, documentsWithRudeEdits: ImmutableArray.Create(generatedDocument.Id));
+ EndDebuggingSession(service);
}
[Fact]
@@ -1364,45 +1405,43 @@ public async Task BreakMode_SyntaxError()
{
var moduleId = Guid.NewGuid();
- using (var workspace = CreateWorkspace())
- {
- var project = AddDefaultTestProject(workspace, "class C1 { void M() { System.Console.WriteLine(1); } }");
- _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(moduleId);
+ using var workspace = CreateWorkspace();
+ var project = AddDefaultTestProject(workspace, "class C1 { void M() { System.Console.WriteLine(1); } }");
+ _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(moduleId);
- var service = CreateEditAndContinueService(workspace);
+ var service = CreateEditAndContinueService(workspace);
- var debuggingSession = StartDebuggingSession(service);
+ var debuggingSession = StartDebuggingSession(service);
- StartEditSession(service);
+ StartEditSession(service);
- // change the source (compilation error):
- var document1 = workspace.CurrentSolution.Projects.Single().Documents.Single();
- workspace.ChangeDocument(document1.Id, SourceText.From("class C1 { void M() { "));
- var document2 = workspace.CurrentSolution.Projects.Single().Documents.Single();
+ // change the source (compilation error):
+ var document1 = workspace.CurrentSolution.Projects.Single().Documents.Single();
+ workspace.ChangeDocument(document1.Id, SourceText.From("class C1 { void M() { "));
+ var document2 = workspace.CurrentSolution.Projects.Single().Documents.Single();
- // compilation errors are not reported via EnC diagnostic analyzer:
- var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noDocumentActiveSpans, CancellationToken.None).ConfigureAwait(false);
- AssertEx.Empty(diagnostics1);
+ // compilation errors are not reported via EnC diagnostic analyzer:
+ var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noDocumentActiveSpans, CancellationToken.None).ConfigureAwait(false);
+ AssertEx.Empty(diagnostics1);
- // validate solution update status and emit:
- Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None).ConfigureAwait(false));
+ // validate solution update status and emit:
+ Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None).ConfigureAwait(false));
- var (updates, emitDiagnostics) = await service.EmitSolutionUpdateAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, CancellationToken.None).ConfigureAwait(false);
- Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status);
- Assert.Empty(updates.Updates);
- Assert.Empty(emitDiagnostics);
+ var (updates, emitDiagnostics) = await service.EmitSolutionUpdateAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, CancellationToken.None).ConfigureAwait(false);
+ Assert.Equal(ManagedModuleUpdateStatus.Blocked, updates.Status);
+ Assert.Empty(updates.Updates);
+ Assert.Empty(emitDiagnostics);
- EndEditSession(service);
- EndDebuggingSession(service);
+ EndEditSession(service);
+ EndDebuggingSession(service);
- AssertEx.SetEqual(new[] { moduleId }, debuggingSession.Test_GetModulesPreparedForUpdate());
+ AssertEx.SetEqual(new[] { moduleId }, debuggingSession.Test_GetModulesPreparedForUpdate());
- AssertEx.Equal(new[]
- {
- "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0",
- "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=True|HadRudeEdits=False|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0"
- }, _telemetryLog);
- }
+ AssertEx.Equal(new[]
+ {
+ "Debugging_EncSession: SessionId=1|SessionCount=1|EmptySessionCount=0",
+ "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=True|HadRudeEdits=False|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0"
+ }, _telemetryLog);
}
[Fact]
@@ -1459,40 +1498,38 @@ public async Task BreakMode_SemanticError()
[Fact]
public async Task BreakMode_FileStatus_CompilationError()
{
- using (var workspace = CreateWorkspace())
- {
- workspace.ChangeSolution(workspace.CurrentSolution.
- AddProject("A", "A", "C#").
- AddDocument("A.cs", "class Program { void Main() { System.Console.WriteLine(1); } }", filePath: "A.cs").Project.Solution.
- AddProject("B", "B", "C#").
- AddDocument("Common.cs", "class Common {}", filePath: "Common.cs").Project.
- AddDocument("B.cs", "class B {}", filePath: "B.cs").Project.Solution.
- AddProject("C", "C", "C#").
- AddDocument("Common.cs", "class Common {}", filePath: "Common.cs").Project.
- AddDocument("C.cs", "class C {}", filePath: "C.cs").Project.Solution);
+ using var workspace = CreateWorkspace();
+ workspace.ChangeSolution(workspace.CurrentSolution.
+ AddProject("A", "A", "C#").
+ AddDocument("A.cs", "class Program { void Main() { System.Console.WriteLine(1); } }", filePath: "A.cs").Project.Solution.
+ AddProject("B", "B", "C#").
+ AddDocument("Common.cs", "class Common {}", filePath: "Common.cs").Project.
+ AddDocument("B.cs", "class B {}", filePath: "B.cs").Project.Solution.
+ AddProject("C", "C", "C#").
+ AddDocument("Common.cs", "class Common {}", filePath: "Common.cs").Project.
+ AddDocument("C.cs", "class C {}", filePath: "C.cs").Project.Solution);
- var service = CreateEditAndContinueService(workspace);
+ var service = CreateEditAndContinueService(workspace);
- StartDebuggingSession(service);
- StartEditSession(service);
+ StartDebuggingSession(service);
+ StartEditSession(service);
- // change C.cs to have a compilation error:
- var projectC = workspace.CurrentSolution.GetProjectsByName("C").Single();
- var documentC = projectC.Documents.Single(d => d.Name == "C.cs");
- workspace.ChangeDocument(documentC.Id, SourceText.From("class C { void M() { "));
+ // change C.cs to have a compilation error:
+ var projectC = workspace.CurrentSolution.GetProjectsByName("C").Single();
+ var documentC = projectC.Documents.Single(d => d.Name == "C.cs");
+ workspace.ChangeDocument(documentC.Id, SourceText.From("class C { void M() { "));
- // Common.cs is included in projects B and C. Both of these projects must have no errors, otherwise update is blocked.
- Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: "Common.cs", CancellationToken.None).ConfigureAwait(false));
+ // Common.cs is included in projects B and C. Both of these projects must have no errors, otherwise update is blocked.
+ Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: "Common.cs", CancellationToken.None).ConfigureAwait(false));
- // No changes in project containing file B.cs.
- Assert.False(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: "B.cs", CancellationToken.None).ConfigureAwait(false));
+ // No changes in project containing file B.cs.
+ Assert.False(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: "B.cs", CancellationToken.None).ConfigureAwait(false));
- // All projects must have no errors.
- Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None).ConfigureAwait(false));
+ // All projects must have no errors.
+ Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None).ConfigureAwait(false));
- EndEditSession(service);
- EndDebuggingSession(service);
- }
+ EndEditSession(service);
+ EndDebuggingSession(service);
}
[Fact]
diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb
index 46547f0187035..9983601aab8b1 100644
--- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb
+++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb
@@ -8521,5 +8521,72 @@ class C
context.AddItem(CompletionItem.Create(displayText:="ā
Length2", filterText:="Length"))
End Function
End Class
+
+
+
+
+ Public Async Function TestCaseSensitiveMatchWithLowerMatchPriority(showCompletionInArgumentLists As Boolean) As Task
+ ' PreselectionProvider will provide an item "ā
length" with filter text "length",
+ ' which is a case-insentive match to typed text "Length", but with higher match priority.
+ ' In this case, we need to make sure the case-sensitive match "Length" is selected.
+ Using state = TestStateFactory.CreateCSharpTestState(
+
+struct Range
+{
+ public (int Offset, int Length) GetOffsetAndLength(int length) => (0, 0);
+}
+
+class Repro
+{
+ public int Length { get; }
+
+ public void Test(Range x)
+ {
+ var (offset, length) = x.GetOffsetAndLength(Length$$);
+ }
+}
+ ,
+ extraExportedTypes:={GetType(PreselectionProvider)}.ToList(),
+ showCompletionInArgumentLists:=showCompletionInArgumentLists)
+
+ Dim workspace = state.Workspace
+ workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _
+ .WithChangedOption(CompletionOptions.TriggerOnDeletion, LanguageNames.CSharp, True)))
+
+ state.SendInvokeCompletionList()
+ Await state.AssertCompletionItemsContainAll({"ā
length", "length", "Length"})
+ Await state.AssertSelectedCompletionItem("Length", isHardSelected:=True)
+ state.SendEscape()
+ Await state.AssertNoCompletionSession()
+
+ state.SendBackspace()
+ Await state.AssertCompletionSession()
+ Await state.AssertCompletionItemsContainAll({"ā
length", "length", "Length"})
+ Await state.AssertSelectedCompletionItem("Length", isHardSelected:=True)
+ End Using
+ End Function
+
+ ' Simulate the situation that some provider (e.g. IntelliCode) provides items with higher match priority that only match case-insensitively.
+
+ <[Shared]>
+
+ Private Class PreselectionProvider
+ Inherits CommonCompletionProvider
+
+
+
+ Public Sub New()
+ End Sub
+
+ Public Overrides Function ProvideCompletionsAsync(context As CompletionContext) As Task
+ Dim rules = CompletionItemRules.Default.WithSelectionBehavior(CompletionItemSelectionBehavior.HardSelection).WithMatchPriority(MatchPriority.Preselect)
+ context.AddItem(CompletionItem.Create(displayText:="ā
length", filterText:="length", rules:=rules))
+ Return Task.CompletedTask
+ End Function
+
+ Public Overrides Function IsInsertionTrigger(text As SourceText, characterPosition As Integer, options As OptionSet) As Boolean
+ Return True
+ End Function
+ End Class
End Class
End Namespace
diff --git a/src/Features/Core/Portable/Completion/CompletionHelper.cs b/src/Features/Core/Portable/Completion/CompletionHelper.cs
index 0b13368f3ea47..a06e5d8669467 100644
--- a/src/Features/Core/Portable/Completion/CompletionHelper.cs
+++ b/src/Features/Core/Portable/Completion/CompletionHelper.cs
@@ -250,10 +250,18 @@ private int CompareMatches(PatternMatch match1, PatternMatch match2, CompletionI
return diff;
}
- var preselectionDiff = ComparePreselection(item1, item2);
- if (preselectionDiff != 0)
+ // If two items match in case-insensitive manner, and we are in a case-insensitive language,
+ // then the preselected one is considered better, otherwise we will prefer the one matches
+ // case-sensitively. This is to make sure common items in VB like `True` and `False` are prioritized
+ // for selection when user types `t` and `f`.
+ // More details can be found in comments of https://github.com/dotnet/roslyn/issues/4892
+ if (!_isCaseSensitive)
{
- return preselectionDiff;
+ var preselectionDiff = ComparePreselection(item1, item2);
+ if (preselectionDiff != 0)
+ {
+ return preselectionDiff;
+ }
}
// At this point we have two items which we're matching in a rather similar fashion.
diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs
index 63b605b2b6dd0..be8b57266d566 100644
--- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs
+++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs
@@ -458,7 +458,7 @@ public async Task AnalyzeDocumentAsync(
SyntaxNode oldRoot;
SourceText oldText;
- var oldDocument = oldProject.GetDocument(newDocument.Id);
+ var oldDocument = await oldProject.GetDocumentAsync(newDocument.Id, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false);
if (oldDocument != null)
{
oldTree = await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs
index 433e7b05d9ffd..23bd51b9c310d 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToDefinition.cs
@@ -26,7 +26,7 @@ public CSharpGoToDefinition(VisualStudioInstanceFactory instanceFactory)
{
}
- [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition)]
+ [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)]
public void GoToClassDeclaration()
{
var project = new ProjectUtils.Project(ProjectName);
@@ -49,7 +49,7 @@ public void GoToClassDeclaration()
Assert.False(VisualStudio.Shell.IsActiveTabProvisional());
}
- [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition)]
+ [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)]
public void GoToDefinitionOpensProvisionalTabIfDocumentNotAlreadyOpen()
{
var project = new ProjectUtils.Project(ProjectName);
@@ -74,19 +74,16 @@ public void GoToDefinitionOpensProvisionalTabIfDocumentNotAlreadyOpen()
Assert.True(VisualStudio.Shell.IsActiveTabProvisional());
}
- [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition)]
+ [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)]
public virtual void GoToDefinitionWithMultipleResults()
- {
- TestGoToDefinitionWithMultipleResults(declarationWindowName: "'PartialClass' declarations");
- }
-
- protected void TestGoToDefinitionWithMultipleResults(string declarationWindowName)
{
SetUpEditor(
@"partial class /*Marker*/ $$PartialClass { }
partial class PartialClass { int i = 0; }");
+ var declarationWindowName = VisualStudio.IsUsingLspEditor ? "'PartialClass' references" : "'PartialClass' declarations";
+
VisualStudio.Editor.GoToDefinition(declarationWindowName);
var results = VisualStudio.FindReferencesWindow.GetContents(declarationWindowName);
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs
deleted file mode 100644
index 5c16894e6082d..0000000000000
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/LanguageServerProtocol/LspGoToDefinition.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-ļ»æ// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Test.Utilities;
-using Microsoft.VisualStudio.IntegrationTest.Utilities;
-using Microsoft.VisualStudio.IntegrationTest.Utilities.Common;
-using Roslyn.Test.Utilities;
-using Roslyn.VisualStudio.IntegrationTests.CSharp;
-using Xunit;
-
-namespace Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol
-{
- ///
- /// A set of LSP specific goto definition tests.
- /// These tests test behavior that only applies to the LSP version of goto definition.
- ///
- [Collection(nameof(SharedIntegrationHostFixture))]
- [Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)]
- public class LspGoToDefinition : CSharpGoToDefinition
- {
- protected override string LanguageName => LanguageNames.CSharp;
-
- public LspGoToDefinition(VisualStudioInstanceFactory instanceFactory)
- : base(instanceFactory)
- {
- }
-
- ///
- /// We need to pass in a different window name to look for declarations in as the LSP client
- /// uses a different name to create the references window.
- /// https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1286575
- ///
- [WpfFact, Trait(Traits.Feature, Traits.Features.GoToDefinition), Trait(Traits.Editor, Traits.Editors.LanguageServerProtocol)]
- public override void GoToDefinitionWithMultipleResults()
- {
- TestGoToDefinitionWithMultipleResults(declarationWindowName: "'PartialClass' references");
- }
- }
-}
diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs
index 6918f32af99b9..b4b41f6c123e7 100644
--- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs
+++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs
@@ -91,12 +91,15 @@ public class VisualStudioInstance
///
public string InstallationPath { get; }
- public VisualStudioInstance(Process hostProcess, DTE dte, ImmutableHashSet supportedPackageIds, string installationPath)
+ public bool IsUsingLspEditor { get; }
+
+ public VisualStudioInstance(Process hostProcess, DTE dte, ImmutableHashSet supportedPackageIds, string installationPath, bool isUsingLspEditor)
{
HostProcess = hostProcess;
Dte = dte;
SupportedPackageIds = supportedPackageIds;
InstallationPath = installationPath;
+ IsUsingLspEditor = isUsingLspEditor;
if (System.Diagnostics.Debugger.IsAttached)
{
diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs
index db3d13b20ca34..0a54d6109baa8 100644
--- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs
+++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstanceFactory.cs
@@ -167,6 +167,8 @@ private async Task UpdateCurrentlyRunningInstanceAsync(ImmutableHashSet
ImmutableHashSet supportedPackageIds;
string installationPath;
+ var isUsingLspEditor = IsUsingLspEditor();
+
if (shouldStartNewInstance)
{
// We are starting a new instance, so ensure we close the currently running instance, if it exists
@@ -178,7 +180,7 @@ private async Task UpdateCurrentlyRunningInstanceAsync(ImmutableHashSet
var instanceVersion = instance.GetInstallationVersion();
var majorVersion = int.Parse(instanceVersion.Substring(0, instanceVersion.IndexOf('.')));
- hostProcess = StartNewVisualStudioProcess(installationPath, majorVersion);
+ hostProcess = StartNewVisualStudioProcess(installationPath, majorVersion, isUsingLspEditor);
var procDumpInfo = ProcDumpInfo.ReadFromEnvironment();
if (procDumpInfo != null)
@@ -208,7 +210,7 @@ private async Task UpdateCurrentlyRunningInstanceAsync(ImmutableHashSet
_currentlyRunningInstance.Close(exitHostProcess: false);
}
- _currentlyRunningInstance = new VisualStudioInstance(hostProcess, dte, supportedPackageIds, installationPath);
+ _currentlyRunningInstance = new VisualStudioInstance(hostProcess, dte, supportedPackageIds, installationPath, isUsingLspEditor);
}
private static IEnumerable EnumerateVisualStudioInstances()
@@ -308,13 +310,11 @@ private static ISetupInstance LocateVisualStudioInstance(ImmutableHashSet