Esempio n. 1
0
 public static Task <Solution> PullMembersUpAsync(
     Document document,
     PullMembersUpOptions pullMembersUpOptions,
     CancellationToken cancellationToken
     )
 {
     if (pullMembersUpOptions.Destination.TypeKind == TypeKind.Interface)
     {
         return(PullMembersIntoInterfaceAsync(
                    document,
                    pullMembersUpOptions,
                    document.Project.Solution,
                    cancellationToken
                    ));
     }
     else if (pullMembersUpOptions.Destination.TypeKind == TypeKind.Class)
     {
         return(PullMembersIntoClassAsync(
                    document,
                    pullMembersUpOptions,
                    document.Project.Solution,
                    cancellationToken
                    ));
     }
     else
     {
         throw ExceptionUtilities.UnexpectedValue(pullMembersUpOptions.Destination);
     }
 }
Esempio n. 2
0
        private ImmutableArray <string> GenerateMessage(PullMembersUpOptions options)
        {
            var warningMessagesBuilder = ImmutableArray.CreateBuilder <string>();

            if (!options.Destination.IsAbstract &&
                options.MemberAnalysisResults.Any(result => result.ChangeDestinationTypeToAbstract))
            {
                Logger.Log(FunctionId.PullMembersUpWarning_ChangeTargetToAbstract);
                warningMessagesBuilder.Add(string.Format(ServicesVSResources._0_will_be_changed_to_abstract, options.Destination.Name));
            }

            foreach (var result in options.MemberAnalysisResults)
            {
                if (result.ChangeOriginalToPublic)
                {
                    Logger.Log(FunctionId.PullMembersUpWarning_ChangeOriginToPublic);
                    warningMessagesBuilder.Add(string.Format(ServicesVSResources._0_will_be_changed_to_public, result.Member.Name));
                }

                if (result.ChangeOriginalToNonStatic)
                {
                    Logger.Log(FunctionId.PullMembersUpWarning_ChangeOriginToNonStatic);
                    warningMessagesBuilder.Add(string.Format(ServicesVSResources._0_will_be_changed_to_non_static, result.Member.Name));
                }
            }

            return(warningMessagesBuilder.ToImmutableArray());
        }
Esempio n. 3
0
            > InitializeSymbolToDeclarationsMapAsync(
            PullMembersUpOptions result,
            CancellationToken cancellationToken
            )
        {
            // One member may have multiple syntax nodes (e.g partial method).
            // Create a map from ISymbol to SyntaxNode find them more easily.
            var symbolToDeclarationsBuilder = ImmutableDictionary.CreateBuilder <
                ISymbol,
                ImmutableArray <SyntaxNode>
                >();

            foreach (var memberAnalysisResult in result.MemberAnalysisResults)
            {
                var tasks = memberAnalysisResult.Member.DeclaringSyntaxReferences.SelectAsArray(
                    @ref => @ref.GetSyntaxAsync(cancellationToken)
                    );
                var allSyntaxes = await Task.WhenAll(tasks).ConfigureAwait(false);

                symbolToDeclarationsBuilder.Add(
                    memberAnalysisResult.Member,
                    allSyntaxes.ToImmutableArray()
                    );
            }

            return(symbolToDeclarationsBuilder.ToImmutableDictionary());
        }
Esempio n. 4
0
        private bool ShowWarningDialog(PullMembersUpOptions result)
        {
            var warningViewModel = new PullMemberUpWarningViewModel(result);
            var warningDialog    = new PullMemberUpWarningDialog(warningViewModel);

            return(warningDialog.ShowModal().GetValueOrDefault());
        }
Esempio n. 5
0
        private static async Task <Solution> PullMembersIntoInterfaceAsync(
            Document document,
            PullMembersUpOptions pullMemberUpOptions,
            Solution solution,
            CancellationToken cancellationToken)
        {
            var solutionEditor        = new SolutionEditor(solution);
            var codeGenerationService = document.Project.LanguageServices.GetRequiredService <ICodeGenerationService>();
            var destinationSyntaxNode = await codeGenerationService.FindMostRelevantNameSpaceOrTypeDeclarationAsync(
                solution, pullMemberUpOptions.Destination, options : null, cancellationToken).ConfigureAwait(false);

            var symbolToDeclarationsMap = await InitializeSymbolToDeclarationsMapAsync(pullMemberUpOptions, cancellationToken).ConfigureAwait(false);

            var symbolsToPullUp = pullMemberUpOptions.MemberAnalysisResults.
                                  SelectAsArray(analysisResult => GetSymbolsToPullUp(analysisResult));

            // Add members to interface
            var codeGenerationOptions = new CodeGenerationOptions(
                generateMethodBodies: false,
                generateMembers: false,
                options: await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false));
            var destinationWithMembersAdded = codeGenerationService.AddMembers(destinationSyntaxNode, symbolsToPullUp, options: codeGenerationOptions, cancellationToken: cancellationToken);
            var destinationEditor           = await solutionEditor.GetDocumentEditorAsync(
                solution.GetDocumentId(destinationSyntaxNode.SyntaxTree),
                cancellationToken).ConfigureAwait(false);

            destinationEditor.ReplaceNode(destinationSyntaxNode, (syntaxNode, generator) => destinationWithMembersAdded);

            // Change original members
            foreach (var analysisResult in pullMemberUpOptions.MemberAnalysisResults)
            {
                foreach (var declaration in symbolToDeclarationsMap[analysisResult.Member])
                {
                    var originalMemberEditor = await solutionEditor.GetDocumentEditorAsync(
                        solution.GetDocumentId(declaration.SyntaxTree),
                        cancellationToken).ConfigureAwait(false);

                    if (analysisResult.Member.ContainingType.TypeKind == TypeKind.Interface)
                    {
                        // If we are pulling member from interface to interface, the original member should be removed.
                        // Also don't need to worry about other changes since the member is removed
                        originalMemberEditor.RemoveNode(originalMemberEditor.Generator.GetDeclaration(declaration));
                    }
                    else
                    {
                        if (analysisResult.ChangeOriginalToNonStatic || analysisResult.ChangeOriginalToPublic)
                        {
                            ChangeMemberToPublicAndNonStatic(
                                codeGenerationService, originalMemberEditor,
                                declaration, analysisResult.Member);
                        }
                    }
                }
            }

            return(solutionEditor.GetChangedSolution());
        }
Esempio n. 6
0
        private static async Task <Solution> PullMembersIntoClassAsync(
            Document document,
            PullMembersUpOptions result,
            Solution solution,
            CancellationToken cancellationToken)
        {
            var solutionEditor        = new SolutionEditor(solution);
            var codeGenerationService = document.Project.LanguageServices.GetRequiredService <ICodeGenerationService>();
            var destinationSyntaxNode = await codeGenerationService.FindMostRelevantNameSpaceOrTypeDeclarationAsync(
                solution, result.Destination, options : null, cancellationToken).ConfigureAwait(false);

            var symbolToDeclarations = await InitializeSymbolToDeclarationsMapAsync(result, cancellationToken).ConfigureAwait(false);

            // Add members to destination
            var pullUpMembersSymbols = result.MemberAnalysisResults.SelectAsArray(
                memberResult =>
            {
                if (memberResult.MakeMemberDeclarationAbstract && !memberResult.Member.IsKind(SymbolKind.Field))
                {
                    // Change the member to abstract if user choose to make them abstract
                    return(MakeAbstractVersion(memberResult.Member));
                }
                else
                {
                    return(memberResult.Member);
                }
            });
            var options = new CodeGenerationOptions(
                reuseSyntax: true,
                generateMethodBodies: false,
                options: await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false));
            var newDestination = codeGenerationService.AddMembers(destinationSyntaxNode, pullUpMembersSymbols, options: options, cancellationToken: cancellationToken);

            // Remove some original members since we are pulling members into class.
            // Note: If the user chooses to make the member abstract, then the original member will be changed to an override,
            // and it will pull an abstract declaration up to the destination.
            // But if the member is abstract itself, it will still be removed.
            foreach (var analysisResult in result.MemberAnalysisResults)
            {
                foreach (var syntax in symbolToDeclarations[analysisResult.Member])
                {
                    var originalMemberEditor = await solutionEditor.GetDocumentEditorAsync(
                        solution.GetDocumentId(syntax.SyntaxTree),
                        cancellationToken).ConfigureAwait(false);

                    if (!analysisResult.MakeMemberDeclarationAbstract || analysisResult.Member.IsAbstract)
                    {
                        originalMemberEditor.RemoveNode(originalMemberEditor.Generator.GetDeclaration(syntax));
                    }
                    else
                    {
                        var declarationSyntax = originalMemberEditor.Generator.GetDeclaration(syntax);
                        originalMemberEditor.ReplaceNode(declarationSyntax, (node, generator) => generator.WithModifiers(node, DeclarationModifiers.Override));
                    }
                }
            }

            // Change the destination to abstract class if needed.
            var destinationEditor = await solutionEditor.GetDocumentEditorAsync(
                solution.GetDocumentId(destinationSyntaxNode.SyntaxTree),
                cancellationToken).ConfigureAwait(false);

            if (!result.Destination.IsAbstract &&
                result.MemberAnalysisResults.Any(analysis => analysis.Member.IsAbstract || analysis.MakeMemberDeclarationAbstract))
            {
                var modifiers = DeclarationModifiers.From(result.Destination).WithIsAbstract(true);
                newDestination = destinationEditor.Generator.WithModifiers(newDestination, modifiers);
            }

            destinationEditor.ReplaceNode(destinationSyntaxNode, (syntaxNode, generator) => newDestination);
            return(solutionEditor.GetChangedSolution());
        }
Esempio n. 7
0
 public PullMemberUpWarningViewModel(PullMembersUpOptions options)
 {
     WarningMessageContainer = GenerateMessage(options);
 }
        private static ImmutableArray <string> GenerateMessage(PullMembersUpOptions options)
        {
            var warningMessagesBuilder = ImmutableArray.CreateBuilder <string>();

            if (!options.Destination.IsAbstract &&
                options.MemberAnalysisResults.Any(static result => result.ChangeDestinationTypeToAbstract))
 public PullMemberUpWarningViewModel(PullMembersUpOptions options) =>