Skip to content

Commit

Permalink
Merge pull request #18693 from dpoeschl/NamingStylesUpdateXAML
Browse files Browse the repository at this point in the history
Notify XAML of renames caused by Naming Rule fixes
  • Loading branch information
dpoeschl authored May 8, 2017
2 parents f9b1f75 + 6c6b25e commit 2a6c6d0
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeFixes.NamingStyles;
using Microsoft.CodeAnalysis.CSharp.Diagnostics.NamingStyles;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Roslyn.Test.Utilities;
using Xunit;

Expand Down Expand Up @@ -306,5 +308,28 @@ class D : C
internal override void [|m|]() { }
}", new TestParameters(options: MethodNamesArePascalCase));
}

[Fact, Trait(Traits.Feature, Traits.Features.NamingStyle)]
[WorkItem(16562, "https://github.com/dotnet/roslyn/issues/16562")]
public async Task TestRefactorNotify()
{
var markup = @"public class [|c|] { }";
var testParameters = new TestParameters(options: ClassNamesArePascalCase);

using (var workspace = CreateWorkspaceFromOptions(markup, testParameters))
{
var actions = await GetCodeActionsAsync(workspace, testParameters);

var previewOperations = await actions[0].GetPreviewOperationsAsync(CancellationToken.None);
Assert.Empty(previewOperations.OfType<TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation>());

var commitOperations = await actions[0].GetOperationsAsync(CancellationToken.None);
Assert.Equal(2, commitOperations.Length);

var symbolRenamedOperation = (TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.Operation)commitOperations[1];
Assert.Equal("c", symbolRenamedOperation._symbol.Name);
Assert.Equal("C", symbolRenamedOperation._newName);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@
<Compile Include="Workspaces\TestHostDocument.cs" />
<Compile Include="Workspaces\TestHostProject.cs" />
<Compile Include="Workspaces\TestHostSolution.cs" />
<Compile Include="Workspaces\TestSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs" />
<Compile Include="Workspaces\TestWorkspace.cs" />
<Compile Include="Workspaces\TestWorkspaceFixture.cs" />
<Compile Include="Workspaces\TestWorkspace_Create.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Composition;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeActions.WorkspaceServices;
using Microsoft.CodeAnalysis.Host.Mef;

namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
{
[ExportWorkspaceService(typeof(ISymbolRenamedCodeActionOperationFactoryWorkspaceService), TestWorkspace.WorkspaceName), Shared]
public class TestSymbolRenamedCodeActionOperationFactoryWorkspaceService : ISymbolRenamedCodeActionOperationFactoryWorkspaceService
{
public CodeActionOperation CreateSymbolRenamedOperation(ISymbol symbol, string newName, Solution startingSolution, Solution updatedSolution)
{
return new Operation(symbol, newName, startingSolution, updatedSolution);
}

public class Operation : CodeActionOperation
{
public ISymbol _symbol;
public string _newName;
public Solution _startingSolution;
public Solution _updatedSolution;

public Operation(ISymbol symbol, string newName, Solution startingSolution, Solution updatedSolution)
{
_symbol = symbol;
_newName = newName;
_startingSolution = startingSolution;
_updatedSolution = updatedSolution;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeActions.WorkspaceServices;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.NamingStyles;
using Microsoft.CodeAnalysis.Rename;
Expand Down Expand Up @@ -52,9 +54,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
var solution = context.Document.Project.Solution;
context.RegisterCodeFix(
new FixNameCodeAction(
solution,
symbol,
fixedName,
string.Format(FeaturesResources.Fix_Name_Violation_colon_0, fixedName),
c => FixAsync(document, symbol, fixedName, c),
nameof(NamingStyleCodeFixProvider)),
equivalenceKey: nameof(NamingStyleCodeFixProvider)),
diagnostic);
}
}
Expand All @@ -68,12 +73,51 @@ await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false),
cancellationToken).ConfigureAwait(false);
}

private class FixNameCodeAction : CodeAction.SolutionChangeAction
private class FixNameCodeAction : CodeAction
{
public FixNameCodeAction(string title, Func<CancellationToken, Task<Solution>> createChangedSolution, string equivalenceKey)
: base(title, createChangedSolution, equivalenceKey)
private readonly Solution _startingSolution;
private readonly ISymbol _symbol;
private readonly string _newName;
private readonly string _title;
private readonly Func<CancellationToken, Task<Solution>> _createChangedSolutionAsync;
private readonly string _equivalenceKey;

public FixNameCodeAction(
Solution startingSolution,
ISymbol symbol,
string newName,
string title,
Func<CancellationToken, Task<Solution>> createChangedSolutionAsync,
string equivalenceKey)
{
_startingSolution = startingSolution;
_symbol = symbol;
_newName = newName;
_title = title;
_createChangedSolutionAsync = createChangedSolutionAsync;
_equivalenceKey = equivalenceKey;
}

protected override async Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken)
{
return SpecializedCollections.SingletonEnumerable(
new ApplyChangesOperation(await _createChangedSolutionAsync(cancellationToken).ConfigureAwait(false)));
}

protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
{
var factory =_startingSolution.Workspace.Services.GetService<ISymbolRenamedCodeActionOperationFactoryWorkspaceService>();
var newSolution = await _createChangedSolutionAsync(cancellationToken).ConfigureAwait(false);
return new CodeActionOperation[]
{
new ApplyChangesOperation(newSolution),
factory.CreateSymbolRenamedOperation(_symbol, _newName, _startingSolution, newSolution)
}.AsEnumerable();
}

public override string Title => _title;

public override string EquivalenceKey => _equivalenceKey;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.CodeAnalysis.Host;

namespace Microsoft.CodeAnalysis.CodeActions.WorkspaceServices
{
internal interface ISymbolRenamedCodeActionOperationFactoryWorkspaceService : IWorkspaceService
{
CodeActionOperation CreateSymbolRenamedOperation(ISymbol symbol, string newName, Solution startingSolution, Solution updatedSolution);
}
}
1 change: 1 addition & 0 deletions src/Features/Core/Portable/Features.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<Compile Include="AddPackage\InstallPackageParentCodeAction.cs" />
<Compile Include="AddParameter\AbstractAddParameterCodeFixProvider.cs" />
<Compile Include="CodeFixes\RemoveUnusedVariable\AbstractRemoveUnusedVariableCodeFixProvider.cs" />
<Compile Include="CodeRefactorings\WorkspaceServices\ISymbolRenamedCodeActionOperationFactoryWorkspaceService.cs" />
<Compile Include="Completion\FileSystemCompletionHelper.cs" />
<Compile Include="ConvertIfToSwitch\AbstractConvertIfToSwitchCodeRefactoringProvider.cs" />
<Compile Include="ConvertNumericLiteral\AbstractConvertNumericLiteralCodeRefactoringProvider.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeActions.WorkspaceServices;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Host.Mef;

namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
[ExportWorkspaceService(typeof(ISymbolRenamedCodeActionOperationFactoryWorkspaceService), ServiceLayer.Host), Shared]
internal sealed class VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService : ISymbolRenamedCodeActionOperationFactoryWorkspaceService
{
private readonly IEnumerable<IRefactorNotifyService> _refactorNotifyServices;

[ImportingConstructor]
public VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService(
[ImportMany] IEnumerable<IRefactorNotifyService> refactorNotifyServices)
{
_refactorNotifyServices = refactorNotifyServices;
}

public CodeActionOperation CreateSymbolRenamedOperation(ISymbol symbol, string newName, Solution startingSolution, Solution updatedSolution)
{
return new RenameSymbolOperation(
_refactorNotifyServices,
symbol ?? throw new ArgumentNullException(nameof(symbol)),
newName ?? throw new ArgumentNullException(nameof(newName)),
startingSolution ?? throw new ArgumentNullException(nameof(startingSolution)),
updatedSolution ?? throw new ArgumentNullException(nameof(updatedSolution)));
}

private class RenameSymbolOperation : CodeActionOperation
{
private readonly IEnumerable<IRefactorNotifyService> _refactorNotifyServices;
private readonly ISymbol _symbol;
private readonly string _newName;
private readonly Solution _startingSolution;
private readonly Solution _updatedSolution;

public RenameSymbolOperation(
IEnumerable<IRefactorNotifyService> refactorNotifyServices,
ISymbol symbol,
string newName,
Solution startingSolution,
Solution updatedSolution)
{
_refactorNotifyServices = refactorNotifyServices;
_symbol = symbol;
_newName = newName;
_startingSolution = startingSolution;
_updatedSolution = updatedSolution;
}

public override void Apply(Workspace workspace, CancellationToken cancellationToken = default(CancellationToken))
{
var updatedDocumentIds = _updatedSolution.GetChanges(_startingSolution).GetProjectChanges().SelectMany(p => p.GetChangedDocuments());

foreach (var refactorNotifyService in _refactorNotifyServices)
{
// If something goes wrong and some language service rejects the rename, we
// can't really do anything about it because we're potentially in the middle of
// some unknown set of CodeActionOperations. This is a best effort approach.

if (refactorNotifyService.TryOnBeforeGlobalSymbolRenamed(workspace, updatedDocumentIds, _symbol, _newName, throwOnFailure: false))
{
refactorNotifyService.TryOnAfterGlobalSymbolRenamed(workspace, updatedDocumentIds, _symbol, _newName, throwOnFailure: false);
}
}
}

public override string Title => string.Format(EditorFeaturesResources.Rename_0_to_1, _symbol.Name, _newName);
}
}
}
1 change: 1 addition & 0 deletions src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@
<Compile Include="Implementation\Workspace\GlobalUndoServiceFactory.NoOpUndoPrimitive.cs" />
<Compile Include="Implementation\Workspace\GlobalUndoServiceFactory.WorkspaceGlobalUndoTransaction.cs" />
<Compile Include="Implementation\Workspace\VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs" />
<Compile Include="Implementation\Workspace\VisualStudioSymbolRenamedCodeActionOperationFactoryWorkspaceService.cs" />
<Compile Include="Implementation\Workspace\VisualStudioFormattingRuleFactoryServiceFactory.cs" />
<Compile Include="Implementation\Workspace\VisualStudioDocumentNavigationService.cs" />
<Compile Include="Implementation\Workspace\VisualStudioDocumentNavigationServiceFactory.cs" />
Expand Down

0 comments on commit 2a6c6d0

Please sign in to comment.