File: ImplementInterface\AbstractImplementInterfaceService.CodeAction_Property.cs
Web Access
Project: ..\..\..\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.ImplementType;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.ImplementInterface
{
    internal abstract partial class AbstractImplementInterfaceService
    {
        internal partial class ImplementInterfaceCodeAction
        {
            private IEnumerable<ISymbol?> GeneratePropertyMembers(
                Compilation compilation,
                IPropertySymbol property,
                Accessibility accessibility,
                DeclarationModifiers modifiers,
                bool generateAbstractly,
                bool useExplicitInterfaceSymbol,
                string memberName,
                ImplementTypePropertyGenerationBehavior propertyGenerationBehavior)
            {
                var factory = Document.GetLanguageService<SyntaxGenerator>();
                var attributesToRemove = AttributesToRemove(compilation);
 
                var getAccessor = GenerateGetAccessor(
                    compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
                    propertyGenerationBehavior, attributesToRemove);
 
                var setAccessor = GenerateSetAccessor(
                    compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
                    propertyGenerationBehavior, attributesToRemove);
 
                var syntaxFacts = Document.GetRequiredLanguageService<ISyntaxFactsService>();
                var semanticFacts = Document.GetRequiredLanguageService<ISemanticFactsService>();
 
                if (property is { IsIndexer: false, Parameters.Length: > 0 } &&
                    !semanticFacts.SupportsParameterizedProperties)
                {
                    yield return getAccessor;
                    yield return setAccessor;
                    yield break;
                }
 
                var parameterNames = NameGenerator.EnsureUniqueness(
                    property.Parameters.SelectAsArray(p => p.Name),
                    isCaseSensitive: syntaxFacts.IsCaseSensitive);
 
                var updatedProperty = property.RenameParameters(parameterNames);
 
                updatedProperty = updatedProperty.RemoveInaccessibleAttributesAndAttributesOfTypes(compilation.Assembly, attributesToRemove);
 
                yield return CodeGenerationSymbolFactory.CreatePropertySymbol(
                    updatedProperty,
                    accessibility: accessibility,
                    modifiers: modifiers,
                    explicitInterfaceImplementations: useExplicitInterfaceSymbol ? ImmutableArray.Create(property) : default,
                    name: memberName,
                    getMethod: getAccessor,
                    setMethod: setAccessor);
            }
 
            /// <summary>
            /// Lists compiler attributes that we want to remove.
            /// The TupleElementNames attribute is compiler generated (it is used for naming tuple element names).
            /// We never want to place it in source code.
            /// Same thing for the Dynamic attribute.
            /// </summary>
            private static INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
            {
                return new[] { compilation.ComAliasNameAttributeType(), compilation.TupleElementNamesAttributeType(),
                    compilation.DynamicAttributeType(), compilation.NativeIntegerAttributeType() }.WhereNotNull().ToArray()!;
            }
 
            private IMethodSymbol? GenerateSetAccessor(
                Compilation compilation,
                IPropertySymbol property,
                Accessibility accessibility,
                bool generateAbstractly,
                bool useExplicitInterfaceSymbol,
                ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
                INamedTypeSymbol[] attributesToRemove)
            {
                if (property.SetMethod == null)
                {
                    return null;
                }
 
                if (property.GetMethod == null)
                {
                    // Can't have an auto-prop with just a setter.
                    propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
                }
 
                var setMethod = property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(
                     State.ClassOrStructType,
                     attributesToRemove);
 
                return CodeGenerationSymbolFactory.CreateAccessorSymbol(
                    setMethod,
                    attributes: default,
                    accessibility: accessibility,
                    explicitInterfaceImplementations: useExplicitInterfaceSymbol ? ImmutableArray.Create(property.SetMethod) : default,
                    statements: GetSetAccessorStatements(
                        compilation, property, generateAbstractly, propertyGenerationBehavior));
            }
 
            private IMethodSymbol? GenerateGetAccessor(
                Compilation compilation,
                IPropertySymbol property,
                Accessibility accessibility,
                bool generateAbstractly,
                bool useExplicitInterfaceSymbol,
                ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
                INamedTypeSymbol[] attributesToRemove)
            {
                if (property.GetMethod == null)
                {
                    return null;
                }
 
                var getMethod = property.GetMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(
                     State.ClassOrStructType,
                     attributesToRemove);
 
                return CodeGenerationSymbolFactory.CreateAccessorSymbol(
                    getMethod,
                    attributes: default,
                    accessibility: accessibility,
                    explicitInterfaceImplementations: useExplicitInterfaceSymbol ? ImmutableArray.Create(property.GetMethod) : default,
                    statements: GetGetAccessorStatements(
                        compilation, property, generateAbstractly, propertyGenerationBehavior));
            }
 
            private ImmutableArray<SyntaxNode> GetSetAccessorStatements(
                Compilation compilation,
                IPropertySymbol property,
                bool generateAbstractly,
                ImplementTypePropertyGenerationBehavior propertyGenerationBehavior)
            {
                if (generateAbstractly)
                    return default;
 
                var generator = Document.GetRequiredLanguageService<SyntaxGenerator>();
                return generator.GetSetAccessorStatements(compilation, property, ThroughMember,
                    propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties);
            }
 
            private ImmutableArray<SyntaxNode> GetGetAccessorStatements(
                Compilation compilation,
                IPropertySymbol property,
                bool generateAbstractly,
                ImplementTypePropertyGenerationBehavior propertyGenerationBehavior)
            {
                if (generateAbstractly)
                    return default;
 
                var generator = Document.Project.Services.GetRequiredService<SyntaxGenerator>();
                return generator.GetGetAccessorStatements(compilation, property, ThroughMember,
                    propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties);
            }
        }
    }
}