Skip to content

Commit

Permalink
Add nullable annotations to the "extract interface" dialog
Browse files Browse the repository at this point in the history
Fixes #37176
  • Loading branch information
jasonmalinowski committed Jul 17, 2019
1 parent 0a6d482 commit 651452e
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,17 @@
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox x:Uid="SelectableMemberCheckBox"
AutomationProperties.Name="{Binding MemberAutomationText}"
AutomationProperties.Name="{Binding SymbolAutomationText}"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
Width="Auto"
Focusable="False"
AutomationProperties.AutomationId="{Binding MemberName}">
AutomationProperties.AutomationId="{Binding SymbolName}">
</CheckBox>
<Image x:Uid="SelectableMemberGlyph"
Margin="8,0,0,0"
Source="{Binding Glyph}"/>
<TextBlock x:Uid="SelectableMemberName"
Text="{Binding MemberName}"/>
Text="{Binding SymbolName}"/>
</StackPanel>
</DataTemplate>
</u:AutomationDelegatingListView.ItemTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Media;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Microsoft.VisualStudio.LanguageServices.Utilities;
using Roslyn.Utilities;

namespace Microsoft.VisualStudio.LanguageServices.Implementation.ExtractInterface
Expand Down Expand Up @@ -55,7 +51,7 @@ internal ExtractInterfaceDialogViewModel(
_generatedNameTypeParameterSuffix = generatedNameTypeParameterSuffix;
_languageName = languageName;

MemberContainers = extractableMembers.Select(m => new MemberSymbolViewModel(m, glyphService)).OrderBy(s => s.MemberName).ToList();
MemberContainers = extractableMembers.Select(m => new MemberSymbolViewModel(m, glyphService)).OrderBy(s => s.SymbolName).ToList();
}

internal bool TrySubmit()
Expand Down Expand Up @@ -173,45 +169,10 @@ public InterfaceDestination Destination

public bool FileNameEnabled => Destination == InterfaceDestination.NewFile;

internal class MemberSymbolViewModel : AbstractNotifyPropertyChanged
internal class MemberSymbolViewModel : SymbolViewModel<ISymbol>
{
private readonly IGlyphService _glyphService;

public ISymbol MemberSymbol { get; }

private static readonly SymbolDisplayFormat s_memberDisplayFormat = new SymbolDisplayFormat(
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
memberOptions: SymbolDisplayMemberOptions.IncludeParameters,
parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut | SymbolDisplayParameterOptions.IncludeOptionalBrackets,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes);

public MemberSymbolViewModel(ISymbol symbol, IGlyphService glyphService)
{
MemberSymbol = symbol;
_glyphService = glyphService;
_isChecked = true;
}

private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set { SetProperty(ref _isChecked, value); }
}

public string MemberName
{
get { return MemberSymbol.ToDisplayString(s_memberDisplayFormat); }
}

public ImageSource Glyph
{
get { return MemberSymbol.GetGlyph().GetImageSource(_glyphService); }
}

public string MemberAutomationText
public MemberSymbolViewModel(ISymbol symbol, IGlyphService glyphService) : base(symbol, glyphService)
{
get { return MemberSymbol.Kind + " " + MemberName; }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public async Task<ExtractInterfaceOptionsResult> GetExtractInterfaceOptionsAsync

if (result.HasValue && result.Value)
{
var includedMembers = viewModel.MemberContainers.Where(c => c.IsChecked).Select(c => c.MemberSymbol);
var includedMembers = viewModel.MemberContainers.Where(c => c.IsChecked).Select(c => c.Symbol);

return new ExtractInterfaceOptionsResult(
isCancelled: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ class $$MyClass
}"]]></Text>

Dim viewModel = Await GetViewModelAsync(markup, LanguageNames.CSharp, "IMyClass")
Assert.Equal("Goo<T>(T, CorrelationManager, ref int, [int?], [string], params int[])", viewModel.MemberContainers.Single().MemberName)
Assert.Equal("Goo<T>(T, CorrelationManager, ref int, [int?], [string], params int[])", viewModel.MemberContainers.Single().SymbolName)
End Function

<Fact, Trait(Traits.Feature, Traits.Features.ExtractInterface)>
Expand All @@ -411,7 +411,7 @@ class $$MyClass
}"]]></Text>

Dim viewModel = Await GetViewModelAsync(markup, LanguageNames.CSharp, "IMyClass")
Assert.Equal("Goo", viewModel.MemberContainers.Where(Function(c) c.MemberSymbol.IsKind(SymbolKind.Property)).Single().MemberName)
Assert.Equal("Goo", viewModel.MemberContainers.Where(Function(c) c.Symbol.IsKind(SymbolKind.Property)).Single().SymbolName)
End Function

<Fact, Trait(Traits.Feature, Traits.Features.ExtractInterface)>
Expand All @@ -424,7 +424,22 @@ class $$MyClass
}"]]></Text>

Dim viewModel = Await GetViewModelAsync(markup, LanguageNames.CSharp, "IMyClass")
Assert.Equal("this[int?, [string]]", viewModel.MemberContainers.Where(Function(c) c.MemberSymbol.IsKind(SymbolKind.Property)).Single().MemberName)
Assert.Equal("this[int?, [string]]", viewModel.MemberContainers.Where(Function(c) c.Symbol.IsKind(SymbolKind.Property)).Single().SymbolName)
End Function

<Fact, Trait(Traits.Feature, Traits.Features.ExtractInterface)>
<WorkItem(37176, "https://github.com/dotnet/roslyn/issues/37176")>
Public Async Function TestExtractInterface_MemberDisplay_NullableReferenceType() As Task
Dim markup = <Text><![CDATA[
#nullable enable
using System.Collections.Generic;
class $$MyClass
{
public void M(string? s, IEnumerable<string?> e) { }
}"]]></Text>

Dim viewModel = Await GetViewModelAsync(markup, LanguageNames.CSharp, "IMyClass")
Assert.Equal("M(string?, IEnumerable<string?>)", viewModel.MemberContainers.Single(Function(c) c.Symbol.IsKind(SymbolKind.Method)).SymbolName)
End Function

<Fact, Trait(Traits.Feature, Traits.Features.ExtractInterface)>
Expand All @@ -441,11 +456,11 @@ public class $$MyClass

Dim viewModel = Await GetViewModelAsync(markup, LanguageNames.CSharp, "IMyClass")
Assert.Equal(5, viewModel.MemberContainers.Count)
Assert.Equal("Goo()", viewModel.MemberContainers.ElementAt(0).MemberName)
Assert.Equal("Goo(int)", viewModel.MemberContainers.ElementAt(1).MemberName)
Assert.Equal("Goo(int, int)", viewModel.MemberContainers.ElementAt(2).MemberName)
Assert.Equal("Goo(int, string)", viewModel.MemberContainers.ElementAt(3).MemberName)
Assert.Equal("Goo(string)", viewModel.MemberContainers.ElementAt(4).MemberName)
Assert.Equal("Goo()", viewModel.MemberContainers.ElementAt(0).SymbolName)
Assert.Equal("Goo(int)", viewModel.MemberContainers.ElementAt(1).SymbolName)
Assert.Equal("Goo(int, int)", viewModel.MemberContainers.ElementAt(2).SymbolName)
Assert.Equal("Goo(int, string)", viewModel.MemberContainers.ElementAt(3).SymbolName)
Assert.Equal("Goo(string)", viewModel.MemberContainers.ElementAt(4).SymbolName)
End Function

Private Async Function GetViewModelAsync(markup As XElement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public string[] GetSelectedItems()

return listItems.Cast<ExtractInterfaceDialogViewModel.MemberSymbolViewModel>()
.Where(viewModel => viewModel.IsChecked)
.Select(viewModel => viewModel.MemberName)
.Select(viewModel => viewModel.SymbolName)
.ToArray();
});
}
Expand All @@ -142,7 +142,7 @@ public void ToggleItem(string item)

var memberSelectionList = dialog.GetTestAccessor().Members;
var items = memberSelectionList.Items.Cast<ExtractInterfaceDialogViewModel.MemberSymbolViewModel>().ToArray();
var itemViewModel = items.Single(x => x.MemberName == item);
var itemViewModel = items.Single(x => x.SymbolName == item);
itemViewModel.IsChecked = !itemViewModel.IsChecked;

// Wait for changes to propagate
Expand Down

0 comments on commit 651452e

Please sign in to comment.