未验证 提交 7569d8ee 编写于 作者: D David Poeschl 提交者: GitHub

Merge pull request #35672 from dotnet/merges/release/dev16.1-to-release/dev16.2-preview1

Merge release/dev16.1 to release/dev16.2-preview1
......@@ -49,8 +49,8 @@ internal class CompletionSource : ForegroundThreadAffinitizedObject, IAsyncCompl
private static readonly EditorOptionKey<bool> NonBlockingCompletionEditorOption = new EditorOptionKey<bool>(NonBlockingCompletion);
// Use CWT to cache data needed to create VSCompletionItem, so the table would be cleared when Roslyn completion item cache is cleared.
private static readonly ConditionalWeakTable<RoslynCompletionItem, VSCompletionItemData> s_roslynItemToVsItemData =
new ConditionalWeakTable<RoslynCompletionItem, VSCompletionItemData>();
private static readonly ConditionalWeakTable<RoslynCompletionItem, StrongBox<VSCompletionItemData>> s_roslynItemToVsItemData =
new ConditionalWeakTable<RoslynCompletionItem, StrongBox<VSCompletionItemData>>();
// Cache all the VS completion filters which essentially make them singletons.
// Because all items that should be filtered using the same filter button must
......@@ -322,7 +322,7 @@ public async Task<object> GetDescriptionAsync(IAsyncCompletionSession session, V
/// So as a compromise, we cache data that can be calculated from Roslyn completion item to avoid repeated
/// calculation cost for cached Roslyn completion items.
/// </summary>
private class VSCompletionItemData
private readonly struct VSCompletionItemData
{
public VSCompletionItemData(string displayText, ImageElement icon, ImmutableArray<AsyncCompletionData.CompletionFilter> filters, ImmutableArray<ImageElement> attributeIcons, string insertionText)
{
......@@ -348,55 +348,56 @@ public VSCompletionItemData(string displayText, ImageElement icon, ImmutableArra
Document document,
RoslynCompletionItem roslynItem)
{
if (roslynItem.IsCached && s_roslynItemToVsItemData.TryGetValue(roslynItem, out var itemData))
VSCompletionItemData itemData;
if (roslynItem.IsCached && s_roslynItemToVsItemData.TryGetValue(roslynItem, out var boxedItemData))
{
return new VSCompletionItem(
displayText: itemData.DisplayText,
source: this,
icon: itemData.Icon,
filters: itemData.Filters,
suffix: roslynItem.InlineDescription, // InlineDescription will be right-aligned in the selection popup
insertText: itemData.InsertionText,
sortText: roslynItem.SortText,
filterText: roslynItem.FilterText,
attributeIcons: itemData.AttributeIcons);
itemData = boxedItemData.Value;
}
else
{
var imageId = roslynItem.Tags.GetFirstGlyph().GetImageId();
var filters = GetFilters(roslynItem);
var imageId = roslynItem.Tags.GetFirstGlyph().GetImageId();
var filters = GetFilters(roslynItem);
// roslynItem generated by providers can contain an insertionText in a property bag.
// We will not use it but other providers may need it.
// We actually will calculate the insertion text once again when called TryCommit.
if (!roslynItem.Properties.TryGetValue(InsertionText, out var insertionText))
{
insertionText = roslynItem.DisplayText;
}
// roslynItem generated by providers can contain an insertionText in a property bag.
// We will not use it but other providers may need it.
// We actually will calculate the insertion text once again when called TryCommit.
if (!roslynItem.Properties.TryGetValue(InsertionText, out var insertionText))
{
insertionText = roslynItem.DisplayText;
}
var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(roslynItem, document.Project.Solution.Workspace);
var attributeImages = supportedPlatforms != null ? s_WarningImageAttributeImagesArray : ImmutableArray<ImageElement>.Empty;
var supportedPlatforms = SymbolCompletionItem.GetSupportedPlatforms(roslynItem, document.Project.Solution.Workspace);
var attributeImages = supportedPlatforms != null ? s_WarningImageAttributeImagesArray : ImmutableArray<ImageElement>.Empty;
itemData = new VSCompletionItemData(
displayText: roslynItem.GetEntireDisplayText(),
icon: new ImageElement(new ImageId(imageId.Guid, imageId.Id), roslynItem.DisplayText),
filters: filters,
attributeIcons: attributeImages,
insertionText: insertionText);
// It doesn't make sense to cache VS item data for those Roslyn items created from scratch for each session,
// since CWT uses object identity for comparison.
if (roslynItem.IsCached)
{
s_roslynItemToVsItemData.Add(roslynItem, new StrongBox<VSCompletionItemData>(itemData));
}
}
var item = new VSCompletionItem(
displayText: roslynItem.GetEntireDisplayText(),
displayText: itemData.DisplayText,
source: this,
icon: new ImageElement(new ImageId(imageId.Guid, imageId.Id), roslynItem.DisplayText),
filters: filters,
icon: itemData.Icon,
filters: itemData.Filters,
suffix: roslynItem.InlineDescription, // InlineDescription will be right-aligned in the selection popup
insertText: insertionText,
insertText: itemData.InsertionText,
sortText: roslynItem.SortText,
filterText: roslynItem.FilterText,
attributeIcons: attributeImages);
attributeIcons: itemData.AttributeIcons);
item.Properties.AddProperty(RoslynItem, roslynItem);
// It doesn't make sense to cache VS item data for those Roslyn items created from scratch for each session,
// since CWT uses object identity for comparison.
if (roslynItem.IsCached)
{
var data = new VSCompletionItemData(item.DisplayText, item.Icon, item.Filters, item.AttributeIcons, item.InsertText);
s_roslynItemToVsItemData.Add(roslynItem, data);
}
return item;
}
......
......@@ -4900,6 +4900,58 @@ class C
End Using
End Function
<WorkItem(35614, "https://github.com/dotnet/roslyn/issues/35614")>
<MemberData(NameOf(AllCompletionImplementations))>
<WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function TestTypeImportCompletion(completionImplementation As CompletionImplementation) As Task
Using state = TestStateFactory.CreateCSharpTestState(completionImplementation,
<Document><![CDATA[
namespace NS1
{
class C
{
public void Foo()
{
Bar$$
}
}
}
namespace NS2
{
public class Bar { }
}
]]></Document>)
Dim expectedText = "
using NS2;
namespace NS1
{
class C
{
public void Foo()
{
Bar
}
}
}
namespace NS2
{
public class Bar { }
}
"
state.Workspace.Options = state.Workspace.Options.WithChangedOption(CompletionOptions.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)
state.SendInvokeCompletionList()
Await state.AssertSelectedCompletionItem(displayText:="Bar", isHardSelected:=True, inlineDescription:="NS2")
state.SendTab()
Assert.Equal(expectedText, state.GetDocumentText())
End Using
End Function
Private Class MultipleChangeCompletionProvider
Inherits CompletionProvider
......
......@@ -109,8 +109,11 @@ public override void SaveSettingsToStorage()
// Save the changes that were accumulated in the option store.
var oldOptions = s_optionService.GetOptions();
var newOptions = s_optionStore.GetOptions();
s_optionService.SetOptions(newOptions);
// Must log the option change before setting the new option values via s_optionService,
// otherwise oldOptions and newOptions would be identical and nothing will be logged.
OptionLogger.Log(oldOptions, newOptions);
s_optionService.SetOptions(newOptions);
// Make sure we load the next time a page is activated, in case that options changed
// programmatically between now and the next time the page is activated
......
......@@ -1141,7 +1141,7 @@ public SolutionState AddDocuments(ImmutableArray<DocumentInfo> documentInfos)
{
return AddDocumentsToMultipleProjects(documentInfos,
(documentInfo, project) => project.CreateDocument(documentInfo, project.ParseOptions),
(project, documents) => (project.AddDocuments(documents), new CompilationTranslationAction.AddDocumentsAction(documents)));
(oldProject, documents) => (oldProject.AddDocuments(documents), new CompilationTranslationAction.AddDocumentsAction(documents)));
}
/// <summary>
......@@ -1209,7 +1209,11 @@ public SolutionState AddAnalyzerConfigDocuments(ImmutableArray<DocumentInfo> doc
// attached to them, so we'll just replace all syntax trees in that case.
return AddDocumentsToMultipleProjects(documentInfos,
(documentInfo, project) => new AnalyzerConfigDocumentState(documentInfo, _solutionServices),
(projectState, documents) => (projectState.AddAnalyzerConfigDocuments(documents), new CompilationTranslationAction.ReplaceAllSyntaxTreesAction(projectState)));
(oldProject, documents) =>
{
var newProject = oldProject.AddAnalyzerConfigDocuments(documents);
return (newProject, new CompilationTranslationAction.ReplaceAllSyntaxTreesAction(newProject));
});
}
public SolutionState RemoveAnalyzerConfigDocument(DocumentId documentId)
......
......@@ -1624,6 +1624,111 @@ public void TestUpdateDocumentsOrderExceptions()
Assert.Throws<ArgumentException>(() => solution = solution.WithProjectDocumentsOrder(pid, ImmutableList.CreateRange(new[] { did3, did2, did1 })));
}
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public async Task TestAddingEditorConfigFileWithDiagnosticSeverity()
{
var solution = CreateSolution();
var projectId = ProjectId.CreateNewId();
var sourceDocumentId = DocumentId.CreateNewId(projectId);
solution = solution.AddProject(projectId, "Test", "Test.dll", LanguageNames.CSharp);
solution = solution.AddDocument(sourceDocumentId, "Test.cs", "// Hello, world!", filePath: @"Z:\Test.cs");
var originalSyntaxTree = await solution.GetDocument(sourceDocumentId).GetSyntaxTreeAsync();
var originalCompilation = await solution.GetProject(projectId).GetCompilationAsync();
var editorConfigDocumentId = DocumentId.CreateNewId(projectId);
solution = solution.AddAnalyzerConfigDocuments(ImmutableArray.Create(
DocumentInfo.Create(
editorConfigDocumentId,
".editorconfig",
filePath: @"Z:\.editorconfig",
loader: TextLoader.From(TextAndVersion.Create(SourceText.From("[*.cs]\r\n\r\ndotnet_diagnostic.CA1234.severity = error"), VersionStamp.Default)))));
var newSyntaxTree = await solution.GetDocument(sourceDocumentId).GetSyntaxTreeAsync();
var newCompilation = await solution.GetProject(projectId).GetCompilationAsync();
Assert.NotSame(originalSyntaxTree, newSyntaxTree);
Assert.NotSame(originalCompilation, newCompilation);
Assert.True(newCompilation.ContainsSyntaxTree(newSyntaxTree));
Assert.Single(newSyntaxTree.DiagnosticOptions);
Assert.Equal(ReportDiagnostic.Error, newSyntaxTree.DiagnosticOptions["CA1234"]);
}
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public async Task TestAddingAndRemovingEditorConfigFileWithDiagnosticSeverity()
{
var solution = CreateSolution();
var projectId = ProjectId.CreateNewId();
var sourceDocumentId = DocumentId.CreateNewId(projectId);
solution = solution.AddProject(projectId, "Test", "Test.dll", LanguageNames.CSharp);
solution = solution.AddDocument(sourceDocumentId, "Test.cs", "// Hello, world!", filePath: @"Z:\Test.cs");
var editorConfigDocumentId = DocumentId.CreateNewId(projectId);
solution = solution.AddAnalyzerConfigDocuments(ImmutableArray.Create(
DocumentInfo.Create(
editorConfigDocumentId,
".editorconfig",
filePath: @"Z:\.editorconfig",
loader: TextLoader.From(TextAndVersion.Create(SourceText.From("[*.cs]\r\n\r\ndotnet_diagnostic.CA1234.severity = error"), VersionStamp.Default)))));
var syntaxTreeAfterAddingEditorConfig = await solution.GetDocument(sourceDocumentId).GetSyntaxTreeAsync();
Assert.Single(syntaxTreeAfterAddingEditorConfig.DiagnosticOptions);
Assert.Equal(ReportDiagnostic.Error, syntaxTreeAfterAddingEditorConfig.DiagnosticOptions["CA1234"]);
solution = solution.RemoveAnalyzerConfigDocument(editorConfigDocumentId);
var syntaxTreeAfterRemovingEditorConfig = await solution.GetDocument(sourceDocumentId).GetSyntaxTreeAsync();
Assert.Empty(syntaxTreeAfterRemovingEditorConfig.DiagnosticOptions);
var finalCompilation = await solution.GetProject(projectId).GetCompilationAsync();
Assert.True(finalCompilation.ContainsSyntaxTree(syntaxTreeAfterRemovingEditorConfig));
}
[Fact, Trait(Traits.Feature, Traits.Features.Workspace)]
public async Task TestChangingAnEditorConfigFile()
{
var solution = CreateSolution();
var projectId = ProjectId.CreateNewId();
var sourceDocumentId = DocumentId.CreateNewId(projectId);
solution = solution.AddProject(projectId, "Test", "Test.dll", LanguageNames.CSharp);
solution = solution.AddDocument(sourceDocumentId, "Test.cs", "// Hello, world!", filePath: @"Z:\Test.cs");
var editorConfigDocumentId = DocumentId.CreateNewId(projectId);
solution = solution.AddAnalyzerConfigDocuments(ImmutableArray.Create(
DocumentInfo.Create(
editorConfigDocumentId,
".editorconfig",
filePath: @"Z:\.editorconfig",
loader: TextLoader.From(TextAndVersion.Create(SourceText.From("[*.cs]\r\n\r\ndotnet_diagnostic.CA1234.severity = error"), VersionStamp.Default)))));
var syntaxTreeBeforeEditorConfigChange = await solution.GetDocument(sourceDocumentId).GetSyntaxTreeAsync();
Assert.Single(syntaxTreeBeforeEditorConfigChange.DiagnosticOptions);
Assert.Equal(ReportDiagnostic.Error, syntaxTreeBeforeEditorConfigChange.DiagnosticOptions["CA1234"]);
solution = solution.WithAnalyzerConfigDocumentTextLoader(
editorConfigDocumentId,
TextLoader.From(TextAndVersion.Create(SourceText.From("[*.cs]\r\n\r\ndotnet_diagnostic.CA6789.severity = error"), VersionStamp.Default)),
PreservationMode.PreserveValue);
var syntaxTreeAfterEditorConfigChange = await solution.GetDocument(sourceDocumentId).GetSyntaxTreeAsync();
Assert.Single(syntaxTreeAfterEditorConfigChange.DiagnosticOptions);
Assert.Equal(ReportDiagnostic.Error, syntaxTreeAfterEditorConfigChange.DiagnosticOptions["CA6789"]);
var finalCompilation = await solution.GetProject(projectId).GetCompilationAsync();
Assert.True(finalCompilation.ContainsSyntaxTree(syntaxTreeAfterEditorConfigChange));
}
private static void GetMultipleProjects(
out Project csBrokenProject,
out Project vbNormalProject,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册