提交 419ca1f3 编写于 作者: C CyrusNajmabadi

Provide user with option to control how properties are generated.

上级 6a1f2fbb
......@@ -176,15 +176,15 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
var compilation = await result.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var isComImport = unimplementedMembers.Any(t => t.Item1.IsComImport);
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var propertyGenerationBehavior = options.GetOption(ImplementTypeOptions.PropertyGenerationBehavior);
var memberDefinitions = GenerateMembers(
compilation,
unimplementedMembers,
cancellationToken);
compilation, unimplementedMembers, propertyGenerationBehavior, cancellationToken);
// Only group the members in the destination if the user wants that *and*
// it's not a ComImport interface. Member ordering in ComImport interfaces
// matters, so we don't want to much with them.
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var insertionBehavior = options.GetOption(ImplementTypeOptions.InsertionBehavior);
var groupMembers = !isComImport &&
insertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind;
......@@ -203,6 +203,7 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
private ImmutableArray<ISymbol> GenerateMembers(
Compilation compilation,
ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> unimplementedMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
// As we go along generating members we may end up with conflicts. For example, say
......@@ -229,7 +230,9 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
foreach (var unimplementedInterfaceMember in unimplementedInterfaceMembers)
{
var member = GenerateMember(compilation, unimplementedInterfaceMember, implementedVisibleMembers, cancellationToken);
var member = GenerateMember(
compilation, unimplementedInterfaceMember, implementedVisibleMembers,
propertyGenerationBehavior, cancellationToken);
if (member != null)
{
implementedMembers.Add(member);
......@@ -272,6 +275,7 @@ private string DetermineMemberName(ISymbol member, List<ISymbol> implementedVisi
Compilation compilation,
ISymbol member,
List<ISymbol> implementedVisibleMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
// First check if we already generate a member that matches the member we want to
......@@ -308,7 +312,9 @@ private string DetermineMemberName(ISymbol member, List<ISymbol> implementedVisi
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
var addUnsafe = member.IsUnsafe() && !syntaxFacts.IsUnsafeContext(State.Location);
return GenerateMember(compilation, member, memberName, generateInvisibleMember, generateAbstractly, addNew, addUnsafe, cancellationToken);
return GenerateMember(
compilation, member, memberName, generateInvisibleMember, generateAbstractly,
addNew, addUnsafe, propertyGenerationBehavior, cancellationToken);
}
private bool GenerateInvisibleMember(ISymbol member, string memberName)
......@@ -376,6 +382,7 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
bool generateAbstractly,
bool addNew,
bool addUnsafe,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var factory = this.Document.GetLanguageService<SyntaxGenerator>();
......@@ -386,22 +393,16 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
? Accessibility.Public
: Accessibility.Private;
if (member.Kind == SymbolKind.Method)
if (member is IMethodSymbol method)
{
var method = (IMethodSymbol)member;
return GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
}
else if (member.Kind == SymbolKind.Property)
else if (member is IPropertySymbol property)
{
var property = (IPropertySymbol)member;
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, propertyGenerationBehavior, cancellationToken);
}
else if (member.Kind == SymbolKind.Event)
else if (member is IEventSymbol @event)
{
var @event = (IEventSymbol)member;
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default(ImmutableArray<AttributeData>),
accessibility: Accessibility.NotApplicable,
......
......@@ -7,6 +7,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.ImplementType;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -25,16 +26,19 @@ internal partial class ImplementInterfaceCodeAction
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
string memberName,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var factory = this.Document.GetLanguageService<SyntaxGenerator>();
var attributesToRemove = AttributesToRemove(compilation);
var getAccessor = GenerateGetAccessor(compilation, property, accessibility, generateAbstractly,
useExplicitInterfaceSymbol, attributesToRemove, cancellationToken);
var getAccessor = GenerateGetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
var setAccessor = GenerateSetAccessor(compilation, property, accessibility,
generateAbstractly, useExplicitInterfaceSymbol, attributesToRemove, cancellationToken);
var setAccessor = GenerateSetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
var parameterNames = NameGenerator.EnsureUniqueness(
......@@ -73,6 +77,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
Accessibility accessibility,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
{
......@@ -81,6 +86,12 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return null;
}
if (property.GetMethod == null)
{
// Can't have an auto-prop with just a setter.
propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
}
var setMethod = property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(
this.State.ClassOrStructType,
attributesToRemove);
......@@ -90,7 +101,8 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
attributes: default(ImmutableArray<AttributeData>),
accessibility: accessibility,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.SetMethod : null,
statements: GetSetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
statements: GetSetAccessorStatements(
compilation, property, generateAbstractly, propertyGenerationBehavior, cancellationToken));
}
private IMethodSymbol GenerateGetAccessor(
......@@ -99,6 +111,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
Accessibility accessibility,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
{
......@@ -116,13 +129,15 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
attributes: default(ImmutableArray<AttributeData>),
accessibility: accessibility,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.GetMethod : null,
statements: GetGetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
statements: GetGetAccessorStatements(
compilation, property, generateAbstractly, propertyGenerationBehavior, cancellationToken));
}
private ImmutableArray<SyntaxNode> GetSetAccessorStatements(
Compilation compilation,
IPropertySymbol property,
bool generateAbstractly,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (generateAbstractly)
......@@ -157,13 +172,16 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return ImmutableArray.Create(factory.ExpressionStatement(expression));
}
return factory.CreateThrowNotImplementedStatementBlock(compilation);
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: factory.CreateThrowNotImplementedStatementBlock(compilation);
}
private ImmutableArray<SyntaxNode> GetGetAccessorStatements(
Compilation compilation,
IPropertySymbol property,
bool generateAbstractly,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (generateAbstractly)
......@@ -196,8 +214,10 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return ImmutableArray.Create(factory.ReturnStatement(expression));
}
return factory.CreateThrowNotImplementedStatementBlock(compilation);
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: factory.CreateThrowNotImplementedStatementBlock(compilation);
}
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
......
......@@ -10,6 +10,12 @@ internal enum ImplementTypeInsertionBehavior
AtTheEnd = 1,
}
internal enum ImplementTypePropertyGenerationBehavior
{
PreferThrowingProperties = 0,
PreferAutoProperties = 1,
}
internal static class ImplementTypeOptions
{
public static readonly PerLanguageOption<ImplementTypeInsertionBehavior> InsertionBehavior =
......@@ -19,5 +25,14 @@ internal static class ImplementTypeOptions
defaultValue: ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind,
storageLocations: new RoamingProfileStorageLocation(
$"TextEditor.%LANGUAGE%.{nameof(ImplementTypeOptions)}.{nameof(InsertionBehavior)}"));
public static readonly PerLanguageOption<ImplementTypePropertyGenerationBehavior> PropertyGenerationBehavior =
new PerLanguageOption<ImplementTypePropertyGenerationBehavior>(
nameof(ImplementTypeOptions),
nameof(PropertyGenerationBehavior),
defaultValue: ImplementTypePropertyGenerationBehavior.PreferThrowingProperties,
storageLocations: new RoamingProfileStorageLocation(
$"TextEditor.%LANGUAGE%.{nameof(ImplementTypeOptions)}.{nameof(PropertyGenerationBehavior)}"));
}
}
\ No newline at end of file
......@@ -100,6 +100,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
</StackPanel>
<Label Content="{x:Static local:AdvancedOptionPageStrings.Option_When_generating_properties}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_throwing_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_throwing_properties}"/>
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_auto_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_auto_properties}"/>
</StackPanel>
</StackPanel>
</GroupBox>
</StackPanel>
......
......@@ -48,6 +48,9 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.CSharp);
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.CSharp);
BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.CSharp);
BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.CSharp);
}
}
}
\ No newline at end of file
......@@ -62,6 +62,15 @@ public static string Option_with_other_members_of_the_same_kind
public static string Option_at_the_end
=> ServicesVSResources.at_the_end;
public static string Option_When_generating_properties
=> ServicesVSResources.When_generating_properties;
public static string Option_prefer_auto_properties
=> ServicesVSResources.prefer_auto_properties;
public static string Option_prefer_throwing_properties
=> ServicesVSResources.prefer_throwing_properties;
public static string Option_GenerateXmlDocCommentsForTripleSlash
{
get { return CSharpVSResources.Generate_XML_documentation_comments_for; }
......
......@@ -1448,6 +1448,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer auto properties.
/// </summary>
internal static string prefer_auto_properties {
get {
return ResourceManager.GetString("prefer_auto_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Prefer braces.
/// </summary>
......@@ -1538,6 +1547,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer throwing properties.
/// </summary>
internal static string prefer_throwing_properties {
get {
return ResourceManager.GetString("prefer_throwing_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Preference.
/// </summary>
......@@ -2155,7 +2173,7 @@ internal class ServicesVSResources {
internal static string Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio {
get {
return ResourceManager.GetString("Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_er" +
"ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio", resourceCulture);
"ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio", resourceCulture);
}
}
......@@ -2323,6 +2341,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to When generating properties:.
/// </summary>
internal static string When_generating_properties {
get {
return ResourceManager.GetString("When_generating_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to When inserting properties, events and methods, place them:.
/// </summary>
......
......@@ -873,7 +873,7 @@ Additional information: {1}</value>
<data name="Pick_members" xml:space="preserve">
<value>Pick members</value>
</data>
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio" xml:space="preserve">
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio" xml:space="preserve">
<value>Unfortunately, a process used by Visual Studio has encountered an unrecoverable error. We recommend saving your work, and then closing and restarting Visual Studio.</value>
</data>
<data name="Add_a_symbol_specification" xml:space="preserve">
......@@ -900,4 +900,13 @@ Additional information: {1}</value>
<data name="VisualStudioWorkspace_TryApplyChanges_cannot_be_called_from_a_background_thread" xml:space="preserve">
<value>VisualStudioWorkspace.TryApplyChanges cannot be called from a background thread.</value>
</data>
<data name="prefer_auto_properties" xml:space="preserve">
<value>prefer auto properties</value>
</data>
<data name="prefer_throwing_properties" xml:space="preserve">
<value>prefer throwing properties</value>
</data>
<data name="When_generating_properties" xml:space="preserve">
<value>When generating properties:</value>
</data>
</root>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册