protected override async Task <ImmutableArray <CodeAction> > GetRefactoringsForSingleParameterAsync(
            Document document,
            TParameterSyntax parameterSyntax,
            IParameterSymbol parameter,
            SyntaxNode constructorDeclaration,
            IMethodSymbol method,
            IBlockOperation?blockStatementOpt,
            CleanCodeGenerationOptionsProvider fallbackOptions,
            CancellationToken cancellationToken)
        {
            // Only supported for constructor parameters.
            if (method.MethodKind != MethodKind.Constructor)
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            var typeDeclaration = constructorDeclaration.GetAncestor <TTypeDeclarationSyntax>();

            if (typeDeclaration == null)
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            // See if we're already assigning this parameter to a field/property in this type. If so, there's nothing
            // more for us to do.
            var assignmentStatement = TryFindFieldOrPropertyAssignmentStatement(parameter, blockStatementOpt);

            if (assignmentStatement != null)
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            // Haven't initialized any fields/properties with this parameter.  Offer to assign
            // to an existing matching field/prop if we can find one, or add a new field/prop
            // if we can't.

            var rules = await document.GetNamingRulesAsync(fallbackOptions, cancellationToken).ConfigureAwait(false);

            var parameterNameParts = IdentifierNameParts.CreateIdentifierNameParts(parameter, rules);

            if (parameterNameParts.BaseName == "")
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            var fieldOrProperty = await TryFindMatchingUninitializedFieldOrPropertySymbolAsync(
                document, parameter, blockStatementOpt, rules, parameterNameParts.BaseNameParts, cancellationToken).ConfigureAwait(false);

            if (fieldOrProperty != null)
            {
                return(HandleExistingFieldOrProperty(
                           document, parameter, constructorDeclaration,
                           blockStatementOpt, fieldOrProperty, fallbackOptions));
            }

            return(await HandleNoExistingFieldOrPropertyAsync(
                       document, parameter, constructorDeclaration,
                       method, blockStatementOpt, rules, fallbackOptions, cancellationToken).ConfigureAwait(false));
        }
Beispiel #2
0
        /// <summary>
        /// Returns an array of parameter symbols that correspond to selected member symbols.
        /// If a selected member symbol has an empty base identifier name, the parameter symbol will not be added.
        /// </summary>
        /// <param name="selectedMembers"></param>
        /// <param name="rules"></param>
        /// <returns></returns>
        protected ImmutableArray <IParameterSymbol> DetermineParameters(
            ImmutableArray <ISymbol> selectedMembers, ImmutableArray <NamingRule> rules)
        {
            var parameters = ArrayBuilder <IParameterSymbol> .GetInstance();

            foreach (var symbol in selectedMembers)
            {
                var type = symbol.GetMemberType();

                var identifierNameParts = IdentifierNameParts.CreateIdentifierNameParts(symbol, rules);
                if (identifierNameParts.BaseName == "")
                {
                    continue;
                }

                var parameterNamingRule = rules.Where(rule => rule.SymbolSpecification.AppliesTo(SymbolKind.Parameter, Accessibility.NotApplicable)).First();
                var parameterName       = parameterNamingRule.NamingStyle.MakeCompliant(identifierNameParts.BaseName).First();

                parameters.Add(CodeGenerationSymbolFactory.CreateParameterSymbol(
                                   attributes: default,
        protected override async Task <ImmutableArray <CodeAction> > GetRefactoringsForSingleParameterAsync(
            Document document, IParameterSymbol parameter, SyntaxNode functionDeclaration, IMethodSymbol method,
            IBlockOperation blockStatementOpt, CancellationToken cancellationToken)
        {
            // Only supported for constructor parameters.
            if (method.MethodKind != MethodKind.Constructor)
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            var assignmentStatement = TryFindFieldOrPropertyAssignmentStatement(
                parameter, blockStatementOpt);

            if (assignmentStatement != null)
            {
                // We're already assigning this parameter to a field/property in this type.
                // So there's nothing more for us to do.
                return(ImmutableArray <CodeAction> .Empty);
            }

            // Haven't initialized any fields/properties with this parameter.  Offer to assign
            // to an existing matching field/prop if we can find one, or add a new field/prop
            // if we can't.

            var rules = await document.GetNamingRulesAsync(FallbackNamingRules.RefactoringMatchLookupRules, cancellationToken).ConfigureAwait(false);

            var parameterNameParts = IdentifierNameParts.CreateIdentifierNameParts(parameter, rules);

            if (parameterNameParts.BaseName == "")
            {
                return(ImmutableArray <CodeAction> .Empty);
            }

            var fieldOrProperty = await TryFindMatchingUninitializedFieldOrPropertySymbolAsync(
                document, parameter, blockStatementOpt, rules, parameterNameParts.BaseNameParts, cancellationToken).ConfigureAwait(false);

            if (fieldOrProperty != null)
            {
                // Found a field/property that this parameter should be assigned to.
                // Just offer the simple assignment to it.

                var resource = fieldOrProperty.Kind == SymbolKind.Field
                    ? FeaturesResources.Initialize_field_0
                    : FeaturesResources.Initialize_property_0;

                var title = string.Format(resource, fieldOrProperty.Name);

                return(ImmutableArray.Create <CodeAction>(new MyCodeAction(
                                                              title,
                                                              c => AddSymbolInitializationAsync(
                                                                  document, parameter, functionDeclaration, method, blockStatementOpt, fieldOrProperty, c))));
            }
            else
            {
                // Didn't find a field/prop that this parameter could be assigned to.
                // Offer to create new one and assign to that.
                var codeGenService = document.GetLanguageService <ICodeGenerationService>();

                var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

                var requireAccessibilityModifiers = options.GetOption(CodeStyleOptions.RequireAccessibilityModifiers);

                var field    = CreateField(requireAccessibilityModifiers, parameter, rules, parameterNameParts.BaseNameParts);
                var property = CreateProperty(requireAccessibilityModifiers, parameter, rules, parameterNameParts.BaseNameParts);

                // Offer to generate either a property or a field.  Currently we place the property
                // suggestion first (to help users with the immutable object+property pattern). But
                // we could consider swapping this if people prefer creating private fields more.
                return(ImmutableArray.Create <CodeAction>(
                           new MyCodeAction(string.Format(FeaturesResources.Create_and_initialize_property_0, property.Name),
                                            c => AddSymbolInitializationAsync(document, parameter, functionDeclaration, method, blockStatementOpt, property, c)),
                           new MyCodeAction(string.Format(FeaturesResources.Create_and_initialize_field_0, field.Name),
                                            c => AddSymbolInitializationAsync(document, parameter, functionDeclaration, method, blockStatementOpt, field, c))));
            }
        }
        protected override async Task<ImmutableArray<CodeAction>> GetRefactoringsForSingleParameterAsync(
            Document document, IParameterSymbol parameter, SyntaxNode functionDeclaration, IMethodSymbol method,
            IBlockOperation? blockStatementOpt, CancellationToken cancellationToken)
        {
            // Only supported for constructor parameters.
            if (method.MethodKind != MethodKind.Constructor)
                return ImmutableArray<CodeAction>.Empty;

            var typeDeclaration = functionDeclaration.GetAncestor<TTypeDeclarationSyntax>();
            if (typeDeclaration == null)
                return ImmutableArray<CodeAction>.Empty;

            var assignmentStatement = TryFindFieldOrPropertyAssignmentStatement(
                parameter, blockStatementOpt);
            if (assignmentStatement != null)
            {
                // We're already assigning this parameter to a field/property in this type.
                // So there's nothing more for us to do.
                return ImmutableArray<CodeAction>.Empty;
            }

            // Haven't initialized any fields/properties with this parameter.  Offer to assign
            // to an existing matching field/prop if we can find one, or add a new field/prop
            // if we can't.

            var rules = await document.GetNamingRulesAsync(cancellationToken).ConfigureAwait(false);
            var parameterNameParts = IdentifierNameParts.CreateIdentifierNameParts(parameter, rules);
            if (parameterNameParts.BaseName == "")
            {
                return ImmutableArray<CodeAction>.Empty;
            }

            var fieldOrProperty = await TryFindMatchingUninitializedFieldOrPropertySymbolAsync(
                document, parameter, blockStatementOpt, rules, parameterNameParts.BaseNameParts, cancellationToken).ConfigureAwait(false);

            if (fieldOrProperty != null)
            {
                // Found a field/property that this parameter should be assigned to.
                // Just offer the simple assignment to it.

                var resource = fieldOrProperty.Kind == SymbolKind.Field
                    ? FeaturesResources.Initialize_field_0
                    : FeaturesResources.Initialize_property_0;

                var title = string.Format(resource, fieldOrProperty.Name);

                return ImmutableArray.Create<CodeAction>(new MyCodeAction(
                    title,
                    c => AddSymbolInitializationAsync(
                        document, parameter, functionDeclaration, blockStatementOpt, fieldOrProperty, c)));
            }
            else
            {
                // Didn't find a field/prop that this parameter could be assigned to.
                // Offer to create new one and assign to that.
                var codeGenService = document.GetLanguageService<ICodeGenerationService>();

                var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
                var requireAccessibilityModifiers = options.GetOption(CodeStyleOptions2.RequireAccessibilityModifiers);

                var field = CreateField(requireAccessibilityModifiers, parameter, rules, parameterNameParts.BaseNameParts);
                var property = CreateProperty(requireAccessibilityModifiers, parameter, rules, parameterNameParts.BaseNameParts);

                var fieldAction = new MyCodeAction(string.Format(FeaturesResources.Create_and_initialize_field_0, field.Name),
                    c => AddSymbolInitializationAsync(document, parameter, functionDeclaration, blockStatementOpt, field, c));
                var propertyAction = new MyCodeAction(string.Format(FeaturesResources.Create_and_initialize_property_0, property.Name),
                    c => AddSymbolInitializationAsync(document, parameter, functionDeclaration, blockStatementOpt, property, c));

                // Check if the surrounding parameters are assigned to another field in this class.  If so, offer to
                // make this parameter into a field as well.  Otherwise, default to generating a property
                var siblingFieldOrProperty = TryFindSiblingFieldOrProperty(parameter, blockStatementOpt);
                return siblingFieldOrProperty is IFieldSymbol
                    ? ImmutableArray.Create<CodeAction>(fieldAction, propertyAction)
                    : ImmutableArray.Create<CodeAction>(propertyAction, fieldAction);
            }
        }