未验证 提交 ba508d0c 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #41959 from CyrusNajmabadi/simplifyImplementAbstract

Share more code between Implement-Abstract-Class and Implement-Interface
......@@ -1822,5 +1822,29 @@ public override void M<T>()
}
}");
}
[Fact]
public async Task NothingOfferedWhenInheritanceIsPreventedByInternalAbstractMember()
{
await TestMissingAsync(
@"<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document>
public abstract class Base
{
internal abstract void Method();
}
</Document>
</Project>
<Project Language=""C#"" AssemblyName=""Assembly2"" CommonReferences=""true"">
<Document>
class [|Derived|] : Base
{
Base inner;
}
</Document>
</Project>
</Workspace>");
}
}
}
......@@ -1825,18 +1825,18 @@ public int Count
{
get
{
return ((IReadOnlyList<int>)field).Count;
return ((IReadOnlyCollection<int>)field).Count;
}
}
public IEnumerator<int> GetEnumerator()
{
return ((IReadOnlyList<int>)field).GetEnumerator();
return ((IEnumerable<int>)field).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IReadOnlyList<int>)field).GetEnumerator();
return field.GetEnumerator();
}
}",
index: 1);
......@@ -1870,7 +1870,7 @@ public int Count
{
get
{
return ((IReadOnlyList<int>)field).Count;
return ((IReadOnlyCollection<int>)field).Count;
}
}
......@@ -1878,12 +1878,12 @@ public int Count
public IEnumerator<int> GetEnumerator()
{
return ((IReadOnlyList<int>)field).GetEnumerator();
return ((IEnumerable<int>)field).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IReadOnlyList<int>)field).GetEnumerator();
return field.GetEnumerator();
}
}",
index: 1);
......@@ -6668,7 +6668,7 @@ public int Count
{
get
{
return ((IList<object>)innerList).Count;
return ((ICollection<object>)innerList).Count;
}
}
......@@ -6676,33 +6676,33 @@ public bool IsReadOnly
{
get
{
return ((IList<object>)innerList).IsReadOnly;
return ((ICollection<object>)innerList).IsReadOnly;
}
}
public void Add(object item)
{
((IList<object>)innerList).Add(item);
((ICollection<object>)innerList).Add(item);
}
public void Clear()
{
((IList<object>)innerList).Clear();
((ICollection<object>)innerList).Clear();
}
public bool Contains(object item)
{
return ((IList<object>)innerList).Contains(item);
return ((ICollection<object>)innerList).Contains(item);
}
public void CopyTo(object[] array, int arrayIndex)
{
((IList<object>)innerList).CopyTo(array, arrayIndex);
((ICollection<object>)innerList).CopyTo(array, arrayIndex);
}
public IEnumerator<object> GetEnumerator()
{
return ((IList<object>)innerList).GetEnumerator();
return ((IEnumerable<object>)innerList).GetEnumerator();
}
public int IndexOf(object item)
......@@ -6717,7 +6717,7 @@ public void Insert(int index, object item)
public bool Remove(object item)
{
return ((IList<object>)innerList).Remove(item);
return ((ICollection<object>)innerList).Remove(item);
}
public void RemoveAt(int index)
......@@ -6727,7 +6727,7 @@ public void RemoveAt(int index)
IEnumerator IEnumerable.GetEnumerator()
{
return ((IList<object>)innerList).GetEnumerator();
return ((IEnumerable)innerList).GetEnumerator();
}
}",
index: 1);
......
......@@ -967,16 +967,16 @@ Class A
Public ReadOnly Property Count As Integer Implements IReadOnlyCollection(Of Integer).Count
Get
Return DirectCast(field, IReadOnlyList(Of Integer)).Count
Return DirectCast(field, IReadOnlyCollection(Of Integer)).Count
End Get
End Property
Public Function GetEnumerator() As IEnumerator(Of Integer) Implements IEnumerable(Of Integer).GetEnumerator
Return DirectCast(field, IReadOnlyList(Of Integer)).GetEnumerator()
Return DirectCast(field, IEnumerable(Of Integer)).GetEnumerator()
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return DirectCast(field, IReadOnlyList(Of Integer)).GetEnumerator()
Return field.GetEnumerator()
End Function
End Class",
index:=1)
......@@ -1004,18 +1004,18 @@ Class A
Public ReadOnly Property Count As Integer Implements IReadOnlyCollection(Of Integer).Count
Get
Return DirectCast(field, IReadOnlyList(Of Integer)).Count
Return DirectCast(field, IReadOnlyCollection(Of Integer)).Count
End Get
End Property
Private Property field As Integer()
Public Function GetEnumerator() As IEnumerator(Of Integer) Implements IEnumerable(Of Integer).GetEnumerator
Return DirectCast(field, IReadOnlyList(Of Integer)).GetEnumerator()
Return DirectCast(field, IEnumerable(Of Integer)).GetEnumerator()
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return DirectCast(field, IReadOnlyList(Of Integer)).GetEnumerator()
Return field.GetEnumerator()
End Function
End Class",
index:=1)
......@@ -4483,13 +4483,13 @@ Class Program(Of T)
Public ReadOnly Property Count As Integer Implements ICollection(Of Object).Count
Get
Return DirectCast(innerList, IList(Of Object)).Count
Return DirectCast(innerList, ICollection(Of Object)).Count
End Get
End Property
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of Object).IsReadOnly
Get
Return DirectCast(innerList, IList(Of Object)).IsReadOnly
Return DirectCast(innerList, ICollection(Of Object)).IsReadOnly
End Get
End Property
......@@ -4502,15 +4502,15 @@ Class Program(Of T)
End Sub
Public Sub Add(item As Object) Implements ICollection(Of Object).Add
DirectCast(innerList, IList(Of Object)).Add(item)
DirectCast(innerList, ICollection(Of Object)).Add(item)
End Sub
Public Sub Clear() Implements ICollection(Of Object).Clear
DirectCast(innerList, IList(Of Object)).Clear()
DirectCast(innerList, ICollection(Of Object)).Clear()
End Sub
Public Sub CopyTo(array() As Object, arrayIndex As Integer) Implements ICollection(Of Object).CopyTo
DirectCast(innerList, IList(Of Object)).CopyTo(array, arrayIndex)
DirectCast(innerList, ICollection(Of Object)).CopyTo(array, arrayIndex)
End Sub
Public Function IndexOf(item As Object) As Integer Implements IList(Of Object).IndexOf
......@@ -4518,19 +4518,19 @@ Class Program(Of T)
End Function
Public Function Contains(item As Object) As Boolean Implements ICollection(Of Object).Contains
Return DirectCast(innerList, IList(Of Object)).Contains(item)
Return DirectCast(innerList, ICollection(Of Object)).Contains(item)
End Function
Public Function Remove(item As Object) As Boolean Implements ICollection(Of Object).Remove
Return DirectCast(innerList, IList(Of Object)).Remove(item)
Return DirectCast(innerList, ICollection(Of Object)).Remove(item)
End Function
Public Function GetEnumerator() As IEnumerator(Of Object) Implements IEnumerable(Of Object).GetEnumerator
Return DirectCast(innerList, IList(Of Object)).GetEnumerator()
Return DirectCast(innerList, IEnumerable(Of Object)).GetEnumerator()
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return DirectCast(innerList, IList(Of Object)).GetEnumerator()
Return DirectCast(innerList, IEnumerable).GetEnumerator()
End Function
End Class",
index:=1)
......
......@@ -1732,12 +1732,6 @@ This version used in: {2}</value>
<data name="Implement_implicitly" xml:space="preserve">
<value>Implement implicitly</value>
</data>
<data name="Implement all interfaces explicitly" xml:space="preserve">
<value>Implement all interfaces explicitly</value>
</data>
<data name="Implement explicitly" xml:space="preserve">
<value>Implement explicitly</value>
</data>
<data name="Implement_0_explicitly" xml:space="preserve">
<value>Implement '{0}' explicitly</value>
</data>
......@@ -1753,4 +1747,13 @@ This version used in: {2}</value>
<data name="Value_colon" xml:space="preserve">
<value>Value:</value>
</data>
<data name="Implement_through_0" xml:space="preserve">
<value>Implement through '{0}'</value>
</data>
<data name="Implement_all_interfaces_explicitly" xml:space="preserve">
<value>Implement all interfaces explicitly</value>
</data>
<data name="Implement_explicitly" xml:space="preserve">
<value>Implement explicitly</value>
</data>
</root>
\ No newline at end of file
......@@ -19,8 +19,8 @@ internal abstract class AbstractImplementAbstractClassCodeFixProvider<TClassNode
{
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; }
public sealed override FixAllProvider GetFixAllProvider() =>
WellKnownFixAllProviders.BatchFixer;
public sealed override FixAllProvider GetFixAllProvider()
=> WellKnownFixAllProviders.BatchFixer;
protected AbstractImplementAbstractClassCodeFixProvider(string diagnosticId)
=> FixableDiagnosticIds = ImmutableArray.Create(diagnosticId);
......@@ -44,10 +44,11 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
if (data == null)
return;
var abstractClassType = data.ClassType.BaseType!;
var abstractClassType = data.AbstractClassType;
var id = GetCodeActionId(abstractClassType.ContainingAssembly.Name, abstractClassType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
context.RegisterCodeFix(
new MyCodeAction(
FeaturesResources.Implement_abstract_class,
c => data.ImplementAbstractClassAsync(c), id),
context.Diagnostics);
}
......@@ -57,8 +58,8 @@ private static string GetCodeActionId(string assemblyName, string abstractTypeFu
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument, string id)
: base(FeaturesResources.Implement_abstract_class, createChangedDocument, id)
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument, string id)
: base(title, createChangedDocument, id)
{
}
}
......
......@@ -4,6 +4,8 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
......@@ -24,14 +26,16 @@ internal class ImplementAbstractClassData
private readonly ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> _unimplementedMembers;
public readonly INamedTypeSymbol ClassType;
public readonly INamedTypeSymbol AbstractClassType;
public ImplementAbstractClassData(
Document document, SyntaxNode classNode, INamedTypeSymbol classType,
Document document, SyntaxNode classNode, INamedTypeSymbol classType, INamedTypeSymbol abstractClassType,
ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> unimplementedMembers)
{
_document = document;
_classNode = classNode;
ClassType = classType;
AbstractClassType = abstractClassType;
_unimplementedMembers = unimplementedMembers;
}
......@@ -57,7 +61,7 @@ internal class ImplementAbstractClassData
if (unimplementedMembers.IsEmpty)
return null;
return new ImplementAbstractClassData(document, classNode, classType, unimplementedMembers);
return new ImplementAbstractClassData(document, classNode, classType, abstractClassType, unimplementedMembers);
}
public static async Task<Document?> TryImplementAbstractClassAsync(Document document, SyntaxNode classNode, CancellationToken cancellationToken)
......@@ -129,18 +133,18 @@ public async Task<Document> ImplementAbstractClassAsync(CancellationToken cancel
{
IMethodSymbol method => GenerateMethod(compilation, method, modifiers, accessibility),
IPropertySymbol property => GenerateProperty(compilation, property, modifiers, accessibility, propertyGenerationBehavior),
IEventSymbol @event => CodeGenerationSymbolFactory.CreateEventSymbol(
@event, accessibility: accessibility, modifiers: modifiers),
IEventSymbol @event => GenerateEvent(@event, accessibility, modifiers),
_ => null,
};
}
private ISymbol GenerateMethod(
Compilation compilation, IMethodSymbol method, DeclarationModifiers modifiers, Accessibility accessibility)
Compilation compilation, IMethodSymbol method,
DeclarationModifiers modifiers, Accessibility accessibility)
{
var syntaxFacts = _document.GetRequiredLanguageService<ISyntaxFactsService>();
var syntaxFactory = _document.GetRequiredLanguageService<SyntaxGenerator>();
var throwingBody = syntaxFactory.CreateThrowNotImplementedStatementBlock(compilation);
var generator = _document.GetRequiredLanguageService<SyntaxGenerator>();
var body = generator.CreateThrowNotImplementedStatement(compilation);
method = method.EnsureNonConflictingNames(this.ClassType, syntaxFacts);
......@@ -148,7 +152,7 @@ public async Task<Document> ImplementAbstractClassAsync(CancellationToken cancel
method,
accessibility: accessibility,
modifiers: modifiers,
statements: throwingBody);
statements: ImmutableArray.Create(body));
}
private IPropertySymbol GenerateProperty(
......@@ -164,18 +168,16 @@ public async Task<Document> ImplementAbstractClassAsync(CancellationToken cancel
propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
}
var syntaxFactory = _document.GetLanguageService<SyntaxGenerator>();
var accessorBody = propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default
: syntaxFactory.CreateThrowNotImplementedStatementBlock(compilation);
var generator = _document.GetRequiredLanguageService<SyntaxGenerator>();
var preferAutoProperties = propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties;
var getMethod = ShouldGenerateAccessor(property.GetMethod)
? CodeGenerationSymbolFactory.CreateAccessorSymbol(
property.GetMethod,
attributes: default,
accessibility: property.GetMethod.ComputeResultantAccessibility(this.ClassType),
statements: accessorBody)
statements: generator.GetGetAccessorStatements(
compilation, property, throughMember: null, preferAutoProperties))
: null;
var setMethod = ShouldGenerateAccessor(property.SetMethod)
......@@ -183,7 +185,8 @@ public async Task<Document> ImplementAbstractClassAsync(CancellationToken cancel
property.SetMethod,
attributes: default,
accessibility: property.SetMethod.ComputeResultantAccessibility(this.ClassType),
statements: accessorBody)
statements: generator.GetSetAccessorStatements(
compilation, property, throughMember: null, preferAutoProperties))
: null;
return CodeGenerationSymbolFactory.CreatePropertySymbol(
......@@ -194,6 +197,14 @@ public async Task<Document> ImplementAbstractClassAsync(CancellationToken cancel
setMethod: setMethod);
}
private IEventSymbol GenerateEvent(
IEventSymbol @event, Accessibility accessibility, DeclarationModifiers modifiers)
{
var generator = _document.GetRequiredLanguageService<SyntaxGenerator>();
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event, accessibility: accessibility, modifiers: modifiers);
}
private bool ShouldGenerateAccessor(IMethodSymbol? method)
=> method != null && this.ClassType.FindImplementationForAbstractMember(method) == null;
}
......
......@@ -99,7 +99,7 @@ public override string Title
}
else if (ThroughMember != null)
{
return string.Format(FeaturesResources.Implement_interface_through_0, GetDescription(ThroughMember));
return string.Format(FeaturesResources.Implement_interface_through_0, ThroughMember.Name);
}
else
{
......@@ -144,14 +144,6 @@ public override string Title
public override string EquivalenceKey => _equivalenceKey;
private static string GetDescription(ISymbol throughMember)
=> throughMember switch
{
IFieldSymbol field => field.Name,
IPropertySymbol property => property.Name,
_ => throw new InvalidOperationException(),
};
protected override Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
return GetUpdatedDocumentAsync(cancellationToken);
......@@ -390,44 +382,42 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
? Accessibility.Public
: Accessibility.Private;
switch (member)
return member switch
{
case IMethodSymbol method:
return GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
case IPropertySymbol property:
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, propertyGenerationBehavior, cancellationToken);
case IEventSymbol @event:
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default,
accessibility: Accessibility.NotApplicable,
statements: factory.CreateThrowNotImplementedStatementBlock(compilation));
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers,
explicitInterfaceImplementations: useExplicitInterfaceSymbol ? ImmutableArray.Create(@event) : default,
name: memberName,
addMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.AddEventHandler),
removeMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.RemoveEventHandler));
}
IMethodSymbol method => GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName),
IPropertySymbol property => GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, propertyGenerationBehavior, cancellationToken),
IEventSymbol @event => GenerateEvent(compilation, memberName, generateInvisibly, factory, modifiers, useExplicitInterfaceSymbol, accessibility, @event),
_ => null,
};
}
return null;
private ISymbol GenerateEvent(Compilation compilation, string memberName, bool generateInvisibly, SyntaxGenerator factory, DeclarationModifiers modifiers, bool useExplicitInterfaceSymbol, Accessibility accessibility, IEventSymbol @event)
{
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default,
accessibility: Accessibility.NotApplicable,
statements: factory.CreateThrowNotImplementedStatementBlock(compilation));
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers,
explicitInterfaceImplementations: useExplicitInterfaceSymbol ? ImmutableArray.Create(@event) : default,
name: memberName,
addMethod: GetAddOrRemoveMethod(@event, generateInvisibly, accessor, memberName, factory.AddEventHandler),
removeMethod: GetAddOrRemoveMethod(@event, generateInvisibly, accessor, memberName, factory.RemoveEventHandler));
}
private IMethodSymbol GetAddOrRemoveMethod(bool generateInvisibly,
IMethodSymbol accessor,
string memberName,
Func<SyntaxNode, SyntaxNode, SyntaxNode> createAddOrRemoveHandler)
private IMethodSymbol GetAddOrRemoveMethod(
IEventSymbol @event, bool generateInvisibly, IMethodSymbol accessor, string memberName,
Func<SyntaxNode, SyntaxNode, SyntaxNode> createAddOrRemoveHandler)
{
if (ThroughMember != null)
{
var factory = Document.GetLanguageService<SyntaxGenerator>();
var throughExpression = CreateThroughExpression(factory);
var statement = factory.ExpressionStatement(createAddOrRemoveHandler(
factory.MemberAccessExpression(throughExpression, memberName), factory.IdentifierName("value")));
var generator = Document.GetRequiredLanguageService<SyntaxGenerator>();
var throughExpression = generator.CreateDelegateThroughExpression(@event, ThroughMember);
var statement = generator.ExpressionStatement(createAddOrRemoveHandler(
generator.MemberAccessExpression(throughExpression, memberName), generator.IdentifierName("value")));
return CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default,
......@@ -438,80 +428,6 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
return generateInvisibly ? accessor : null;
}
private SyntaxNode CreateThroughExpression(SyntaxGenerator generator)
{
var through = ThroughMember.IsStatic
? GenerateName(generator, State.ClassOrStructType.IsGenericType)
: generator.ThisExpression();
through = generator.MemberAccessExpression(
through, generator.IdentifierName(ThroughMember.Name));
var throughMemberType = ThroughMember.GetMemberType();
if ((State.InterfaceTypes != null) && (throughMemberType != null))
{
// In the case of 'implement interface through field / property' , we need to know what
// interface we are implementing so that we can insert casts to this interface on every
// usage of the field in the generated code. Without these casts we would end up generating
// code that fails compilation in certain situations.
//
// For example consider the following code.
// class C : IReadOnlyList<int> { int[] field; }
// When applying the 'implement interface through field' code fix in the above example,
// we need to generate the following code to implement the Count property on IReadOnlyList<int>
// class C : IReadOnlyList<int> { int[] field; int Count { get { ((IReadOnlyList<int>)field).Count; } ...}
// as opposed to the following code which will fail to compile (because the array field
// doesn't have a property named .Count) -
// class C : IReadOnlyList<int> { int[] field; int Count { get { field.Count; } ...}
//
// The 'InterfaceTypes' property on the state object always contains only one item
// in the case of C# i.e. it will contain exactly the interface we are trying to implement.
// This is also the case most of the time in the case of VB, except in certain error conditions
// (recursive / circular cases) where the span of the squiggle for the corresponding
// diagnostic (BC30149) changes and 'InterfaceTypes' ends up including all interfaces
// in the Implements clause. For the purposes of inserting the above cast, we ignore the
// uncommon case and optimize for the common one - in other words, we only apply the cast
// in cases where we can unambiguously figure out which interface we are trying to implement.
var interfaceBeingImplemented = State.InterfaceTypes.SingleOrDefault();
if (interfaceBeingImplemented != null)
{
if (!throughMemberType.Equals(interfaceBeingImplemented))
{
through = generator.CastExpression(interfaceBeingImplemented,
through.WithAdditionalAnnotations(Simplifier.Annotation));
}
else if (!ThroughMember.IsStatic &&
ThroughMember is IPropertySymbol throughMemberProperty &&
throughMemberProperty.ExplicitInterfaceImplementations.Any())
{
// If we are implementing through an explicitly implemented property, we need to cast 'this' to
// the explicitly implemented interface type before calling the member, as in:
// ((IA)this).Prop.Member();
//
var explicitlyImplementedProperty = throughMemberProperty.ExplicitInterfaceImplementations[0];
var explicitImplementationCast = generator.CastExpression(
explicitlyImplementedProperty.ContainingType,
generator.ThisExpression());
through = generator.MemberAccessExpression(explicitImplementationCast,
generator.IdentifierName(explicitlyImplementedProperty.Name));
through = through.WithAdditionalAnnotations(Simplifier.Annotation);
}
}
}
return through.WithAdditionalAnnotations(Simplifier.Annotation);
}
private SyntaxNode GenerateName(SyntaxGenerator factory, bool isGenericType)
{
return isGenericType
? factory.GenericName(State.ClassOrStructType.Name, State.ClassOrStructType.TypeArguments)
: factory.IdentifierName(State.ClassOrStructType.Name);
}
private bool HasNameConflict(
ISymbol member,
string memberName,
......
......@@ -23,8 +23,7 @@ internal partial class ImplementInterfaceCodeAction
DeclarationModifiers modifiers,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
string memberName,
CancellationToken cancellationToken)
string memberName)
{
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
......@@ -46,37 +45,11 @@ internal partial class ImplementInterfaceCodeAction
}
private SyntaxNode CreateStatement(Compilation compilation, IMethodSymbol method)
{
if (ThroughMember == null)
{
var factory = Document.GetLanguageService<SyntaxGenerator>();
return factory.CreateThrowNotImplementedStatement(compilation);
}
else
{
return CreateDelegationStatement(method);
}
}
private SyntaxNode CreateDelegationStatement(
IMethodSymbol method)
{
var factory = Document.GetLanguageService<SyntaxGenerator>();
var through = CreateThroughExpression(factory);
var memberName = method.IsGenericMethod
? factory.GenericName(method.Name, method.TypeArguments.OfType<ITypeSymbol>().ToList())
: factory.IdentifierName(method.Name);
through = factory.MemberAccessExpression(
through, memberName);
var arguments = factory.CreateArguments(method.Parameters.As<IParameterSymbol>());
var invocationExpression = factory.InvocationExpression(through, arguments);
return method.ReturnsVoid
? factory.ExpressionStatement(invocationExpression)
: factory.ReturnStatement(invocationExpression);
return ThroughMember == null
? factory.CreateThrowNotImplementedStatement(compilation)
: factory.GenerateDelegateThroughMemberStatement(method, ThroughMember);
}
}
}
......
......@@ -38,11 +38,11 @@ internal partial class ImplementInterfaceCodeAction
var getAccessor = GenerateGetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
propertyGenerationBehavior, attributesToRemove);
var setAccessor = GenerateSetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
propertyGenerationBehavior, attributesToRemove);
var syntaxFacts = Document.Project.LanguageServices.GetRequiredService<ISyntaxFactsService>();
......@@ -54,7 +54,6 @@ internal partial class ImplementInterfaceCodeAction
updatedProperty = updatedProperty.RemoveInaccessibleAttributesAndAttributesOfTypes(compilation.Assembly, attributesToRemove);
// TODO(cyrusn): Delegate through throughMember if it's non-null.
return CodeGenerationSymbolFactory.CreatePropertySymbol(
updatedProperty,
accessibility: accessibility,
......@@ -84,8 +83,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
INamedTypeSymbol[] attributesToRemove)
{
if (property.SetMethod == null)
{
......@@ -118,8 +116,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
INamedTypeSymbol[] attributesToRemove)
{
if (property.GetMethod == null)
{
......@@ -146,40 +143,11 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior)
{
if (generateAbstractly)
{
return default;
}
var factory = Document.Project.LanguageServices.GetRequiredService<SyntaxGenerator>();
if (ThroughMember != null)
{
var throughExpression = CreateThroughExpression(factory);
SyntaxNode expression;
if (property.IsIndexer)
{
expression = throughExpression;
}
else
{
expression = factory.MemberAccessExpression(
throughExpression, factory.IdentifierName(property.Name));
}
if (property.Parameters.Length > 0)
{
var arguments = factory.CreateArguments(property.Parameters.As<IParameterSymbol>());
expression = factory.ElementAccessExpression(expression, arguments);
}
expression = factory.AssignmentStatement(expression, factory.IdentifierName("value"));
return ImmutableArray.Create(factory.ExpressionStatement(expression));
}
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default
: factory.CreateThrowNotImplementedStatementBlock(compilation);
var generator = Document.GetRequiredLanguageService<SyntaxGenerator>();
return generator.GetSetAccessorStatements(compilation, property, this.ThroughMember,
propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties);
}
private ImmutableArray<SyntaxNode> GetGetAccessorStatements(
......@@ -189,38 +157,11 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior)
{
if (generateAbstractly)
{
return default;
}
var factory = Document.Project.LanguageServices.GetRequiredService<SyntaxGenerator>();
if (ThroughMember != null)
{
var throughExpression = CreateThroughExpression(factory);
SyntaxNode expression;
if (property.IsIndexer)
{
expression = throughExpression;
}
else
{
expression = factory.MemberAccessExpression(
throughExpression, factory.IdentifierName(property.Name));
}
if (property.Parameters.Length > 0)
{
var arguments = factory.CreateArguments(property.Parameters.As<IParameterSymbol>());
expression = factory.ElementAccessExpression(expression, arguments);
}
return ImmutableArray.Create(factory.ReturnStatement(expression));
}
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default
: factory.CreateThrowNotImplementedStatementBlock(compilation);
var generator = Document.Project.LanguageServices.GetRequiredService<SyntaxGenerator>();
return generator.GetGetAccessorStatements(compilation, property, ThroughMember,
propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties);
}
}
}
......
......@@ -277,16 +277,6 @@
<target state="translated">Implementace GetHashCode se dá zjednodušit.</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Implementovat všechna rozhraní explicitně</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Implementovat explicitně</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Implementovat rozhraní {0} explicitně</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Implementovat všechna rozhraní implicitně</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Implementovat implicitně</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Odsadit všechny argumenty</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">Die Implementierung von "GetHashCode" kann vereinfacht werden.</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Alle Schnittstellen explizit implementieren</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Explizit implementieren</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">"{0}" explizit implementieren</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Alle Schnittstellen implizit implementieren</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Implizit implementieren</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Alle Argumente einrücken</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">La implementación de "GetHashCode" se puede simplificar.</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Implementar todas las interfaces de forma explícita</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Implementar de forma explícita</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Implementar "{0}" de forma explícita</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Implementar todas las interfaces de forma implícita</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Implementar de forma implícita</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Aplicar sangría a todos los argumentos</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">L'implémentation de 'GetHashCode' peut être simplifiée</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Implémenter toutes les interfaces explicitement</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Implémenter explicitement</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Implémenter '{0}' explicitement</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Implémenter toutes les interfaces implicitement</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Implémenter implicitement</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Mettre en retrait tous les arguments</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">L'implementazione di 'GetHashCode' può essere semplificata</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Implementa tutte le interfacce in modo esplicito</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Implementa in modo esplicito</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Implementa '{0}' in modo esplicito</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Implementa tutte le interfacce in modo implicito</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Implementa in modo implicito</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Imposta rientro per tutti gli argomenti</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">'GetHashCode' の実装を簡略化できます</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">すべてのインターフェイスを明示的に実装する</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">明示的に実装する</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">'{0}' を明示的に実装する</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">すべてのインターフェイスを暗黙的に実装する</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">暗黙的に実装する</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">すべての引数にインデントを設定します</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">'GetHashCode' 구현이 간소화될 수 있습니다.</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">모든 인터페이스를 명시적으로 구현</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">명시적으로 구현</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">'{0}'을(를) 명시적으로 구현</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">모든 인터페이스를 암시적으로 구현</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">암시적으로 구현</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">모든 인수 들여쓰기</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">Implementację „GetHashCode” można uprościć</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Jawnie zaimplementuj wszystkie interfejsy</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Zaimplementuj jawnie</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Jawnie zaimplementuj interfejs „{0}”</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Niejawnie zaimplementuj wszystkie interfejsy</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Zaimplementuj niejawnie</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Dodaj wcięcie dla wszystkich argumentów</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">A implementação de 'GetHashCode' pode ser simplificada</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Implementar todas as interfaces explicitamente</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Implementar explicitamente</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Implementar '{0}' explicitamente</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Implementar todas as interfaces implicitamente</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Implementar implicitamente</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Recuar todos os argumentos</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">Реализацию "GetHashCode" можно упростить.</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Реализовать все интерфейсы явно</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Реализовать явно</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">Реализовать "{0}" явно</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Реализовать все интерфейсы неявно</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Реализовать неявно</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Добавить отступы для всех аргументов</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">'GetHashCode' uygulaması basitleştirilebilir</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">Tüm arabirimleri açıkça uygula</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">Açıkça uygula</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">'{0}' öğesini açıkça uygula</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">Tüm arabirimleri örtük olarak uygula</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">Örtük olarak uygula</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">Tüm bağımsız değişkenleri girintile</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">可简化 "GetHashCode" 实现</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">显式实现所有接口</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">显式实现</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">显式实现 "{0}"</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">隐式实现所有接口</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">隐式实现</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">缩进所有参数</target>
......
......@@ -277,16 +277,6 @@
<target state="translated">'GetHashCode' 實作可簡化</target>
<note />
</trans-unit>
<trans-unit id="Implement all interfaces explicitly">
<source>Implement all interfaces explicitly</source>
<target state="translated">明確實作所有介面</target>
<note />
</trans-unit>
<trans-unit id="Implement explicitly">
<source>Implement explicitly</source>
<target state="translated">明確實作</target>
<note />
</trans-unit>
<trans-unit id="Implement_0_explicitly">
<source>Implement '{0}' explicitly</source>
<target state="translated">明確實作 '{0}'</target>
......@@ -302,16 +292,31 @@
<target state="new">Implement abstract class</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_explicitly">
<source>Implement all interfaces explicitly</source>
<target state="new">Implement all interfaces explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_all_interfaces_implicitly">
<source>Implement all interfaces implicitly</source>
<target state="translated">隱含實作所有介面</target>
<note />
</trans-unit>
<trans-unit id="Implement_explicitly">
<source>Implement explicitly</source>
<target state="new">Implement explicitly</target>
<note />
</trans-unit>
<trans-unit id="Implement_implicitly">
<source>Implement implicitly</source>
<target state="translated">隱含實作</target>
<note />
</trans-unit>
<trans-unit id="Implement_through_0">
<source>Implement through '{0}'</source>
<target state="new">Implement through '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Indent_all_arguments">
<source>Indent all arguments</source>
<target state="translated">將所有引數縮排</target>
......
......@@ -545,5 +545,155 @@ private static DeclarationModifiers GetOverrideModifiers(ISymbol symbol)
: ImmutableArray.Create(codeFactory.ReturnStatement(body)));
}
}
/// <summary>
/// Generates a call to a method *through* an existing field or property symbol.
/// </summary>
/// <returns></returns>
public static SyntaxNode GenerateDelegateThroughMemberStatement(
this SyntaxGenerator generator, IMethodSymbol method, ISymbol throughMember)
{
var through = CreateDelegateThroughExpression(generator, method, throughMember);
var memberName = method.IsGenericMethod
? generator.GenericName(method.Name, method.TypeArguments)
: generator.IdentifierName(method.Name);
through = generator.MemberAccessExpression(through, memberName);
var arguments = generator.CreateArguments(method.Parameters.As<IParameterSymbol>());
var invocationExpression = generator.InvocationExpression(through, arguments);
return method.ReturnsVoid
? generator.ExpressionStatement(invocationExpression)
: generator.ReturnStatement(invocationExpression);
}
public static SyntaxNode CreateDelegateThroughExpression(
this SyntaxGenerator generator, ISymbol member, ISymbol throughMember)
{
var through = throughMember.IsStatic
? GenerateContainerName(generator, throughMember)
: generator.ThisExpression();
through = generator.MemberAccessExpression(
through, generator.IdentifierName(throughMember.Name));
var throughMemberType = throughMember.GetMemberType();
if (member.ContainingType.IsInterfaceType() && throughMemberType != null)
{
// In the case of 'implement interface through field / property', we need to know what
// interface we are implementing so that we can insert casts to this interface on every
// usage of the field in the generated code. Without these casts we would end up generating
// code that fails compilation in certain situations.
//
// For example consider the following code.
// class C : IReadOnlyList<int> { int[] field; }
// When applying the 'implement interface through field' code fix in the above example,
// we need to generate the following code to implement the Count property on IReadOnlyList<int>
// class C : IReadOnlyList<int> { int[] field; int Count { get { ((IReadOnlyList<int>)field).Count; } ...}
// as opposed to the following code which will fail to compile (because the array field
// doesn't have a property named .Count) -
// class C : IReadOnlyList<int> { int[] field; int Count { get { field.Count; } ...}
//
// The 'InterfaceTypes' property on the state object always contains only one item
// in the case of C# i.e. it will contain exactly the interface we are trying to implement.
// This is also the case most of the time in the case of VB, except in certain error conditions
// (recursive / circular cases) where the span of the squiggle for the corresponding
// diagnostic (BC30149) changes and 'InterfaceTypes' ends up including all interfaces
// in the Implements clause. For the purposes of inserting the above cast, we ignore the
// uncommon case and optimize for the common one - in other words, we only apply the cast
// in cases where we can unambiguously figure out which interface we are trying to implement.
var interfaceBeingImplemented = member.ContainingType;
if (!throughMemberType.Equals(interfaceBeingImplemented))
{
through = generator.CastExpression(interfaceBeingImplemented,
through.WithAdditionalAnnotations(Simplifier.Annotation));
}
else if (!throughMember.IsStatic &&
throughMember is IPropertySymbol throughMemberProperty &&
throughMemberProperty.ExplicitInterfaceImplementations.Any())
{
// If we are implementing through an explicitly implemented property, we need to cast 'this' to
// the explicitly implemented interface type before calling the member, as in:
// ((IA)this).Prop.Member();
//
var explicitlyImplementedProperty = throughMemberProperty.ExplicitInterfaceImplementations[0];
var explicitImplementationCast = generator.CastExpression(
explicitlyImplementedProperty.ContainingType,
generator.ThisExpression());
through = generator.MemberAccessExpression(explicitImplementationCast,
generator.IdentifierName(explicitlyImplementedProperty.Name));
through = through.WithAdditionalAnnotations(Simplifier.Annotation);
}
}
return through.WithAdditionalAnnotations(Simplifier.Annotation);
// local functions
static SyntaxNode GenerateContainerName(SyntaxGenerator factory, ISymbol throughMember)
{
var classOrStructType = throughMember.ContainingType;
return classOrStructType.IsGenericType
? factory.GenericName(classOrStructType.Name, classOrStructType.TypeArguments)
: factory.IdentifierName(classOrStructType.Name);
}
}
public static ImmutableArray<SyntaxNode> GetGetAccessorStatements(
this SyntaxGenerator generator, Compilation compilation,
IPropertySymbol property, ISymbol throughMember, bool preferAutoProperties)
{
if (throughMember != null)
{
var throughExpression = CreateDelegateThroughExpression(generator, property, throughMember);
var expression = property.IsIndexer
? throughExpression
: generator.MemberAccessExpression(
throughExpression, generator.IdentifierName(property.Name));
if (property.Parameters.Length > 0)
{
var arguments = generator.CreateArguments(property.Parameters.As<IParameterSymbol>());
expression = generator.ElementAccessExpression(expression, arguments);
}
return ImmutableArray.Create(generator.ReturnStatement(expression));
}
return preferAutoProperties ? default : generator.CreateThrowNotImplementedStatementBlock(compilation);
}
public static ImmutableArray<SyntaxNode> GetSetAccessorStatements(
this SyntaxGenerator generator, Compilation compilation,
IPropertySymbol property, ISymbol throughMember, bool preferAutoProperties)
{
if (throughMember != null)
{
var throughExpression = CreateDelegateThroughExpression(generator, property, throughMember);
var expression = property.IsIndexer
? throughExpression
: generator.MemberAccessExpression(
throughExpression, generator.IdentifierName(property.Name));
if (property.Parameters.Length > 0)
{
var arguments = generator.CreateArguments(property.Parameters.As<IParameterSymbol>());
expression = generator.ElementAccessExpression(expression, arguments);
}
expression = generator.AssignmentStatement(expression, generator.IdentifierName("value"));
return ImmutableArray.Create(generator.ExpressionStatement(expression));
}
return preferAutoProperties
? default
: generator.CreateThrowNotImplementedStatementBlock(compilation);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册