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); } }
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()); }
> 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()); }
private bool ShowWarningDialog(PullMembersUpOptions result) { var warningViewModel = new PullMemberUpWarningViewModel(result); var warningDialog = new PullMemberUpWarningDialog(warningViewModel); return(warningDialog.ShowModal().GetValueOrDefault()); }
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()); }
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()); }
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) =>