Skip to content

Commit

Permalink
Code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
ocalles committed May 13, 2020
1 parent d1909bf commit 14d1a90
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// 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.md file in the project root for more information.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Threading;
using System.Threading.Tasks;
using EnvDTE;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.ProjectSystem.Rename;
using Microsoft.VisualStudio.ProjectSystem.Waiting;
using Microsoft.VisualStudio.Shell.Interop;
using EnvDTE;

namespace Microsoft.VisualStudio.ProjectSystem.VS.Rename
{
Expand All @@ -30,8 +33,7 @@ internal class RenamerProjectTreeActionHandler : ProjectTreeActionHandlerBase, I
private readonly IWaitIndicator _waitService;
private readonly IRoslynServices _roslynServices;
private readonly Workspace _workspace;
private bool _isLanguageServiceDone;
private string _oldFilePath;
private Dictionary<(string, string), SemaphoreSlim> _languageServiceDone;

[ImportingConstructor]
public RenamerProjectTreeActionHandler(
Expand All @@ -56,75 +58,83 @@ public RenamerProjectTreeActionHandler(
_vsOnlineServices = vsOnlineServices;
_threadingService = threadingService;
_extensibility = extensibility;
_languageServiceDone = new Dictionary<(string, string), SemaphoreSlim>();
}

public void HandleRename(string oldFilePath, string newFilePath)
{
if (_oldFilePath == oldFilePath)
string newFileWithExtension = Path.GetFileName(newFilePath);
if (_languageServiceDone.TryGetValue((oldFilePath, newFileWithExtension), out SemaphoreSlim sem))
{
_isLanguageServiceDone = true;
sem.Release();
}
}

public override async Task RenameAsync(IProjectTreeActionHandlerContext context, IProjectTree node, string value)
{
Assumes.Present(context);
Assumes.Present(node);
Assumes.Present(value);
Requires.NotNull(context, nameof(Context));
Requires.NotNull(node, nameof(node));
Requires.NotNullOrEmpty(value, nameof(value));

_oldFilePath = node.FilePath;
string? newNameWithExtension = value;
// These variables are need to synchronize with Roslyn
_isLanguageServiceDone = false;
string oldFilePath = node.FilePath;
string newFileNameWithExtension = value;

// Do not offer to rename the file in VS Online scenarios.
if (_vsOnlineServices.ConnectedToVSOnline)
{
return;
}

if (await IsAutomationFunction() || node.IsFolder)
if (await IsAutomationFunctionAsync() || node.IsFolder)
{
// Do not display rename Prompt
await base.RenameAsync(context, node, value);
return;
}

// Get the list of possible actions to execute
string oldName = Path.GetFileNameWithoutExtension(_oldFilePath);
string oldName = Path.GetFileNameWithoutExtension(oldFilePath);
CodeAnalysis.Project? project = GetCurrentProject();
if (project is null)
{
return;
}

CodeAnalysis.Document? oldDocument = GetDocument(project, _oldFilePath);
CodeAnalysis.Document? oldDocument = GetDocument(project, oldFilePath);
if (oldDocument is null)
{
return;
}

var documentRenameResult = await CodeAnalysis.Rename.Renamer.RenameDocumentAsync(oldDocument, newNameWithExtension, oldDocument.Folders);
var documentRenameResult = await CodeAnalysis.Rename.Renamer.RenameDocumentAsync(oldDocument, newFileNameWithExtension);

bool errorsDetected = false;
foreach (var action in documentRenameResult.ApplicableActions)
{
foreach (var error in action.GetErrors())
{
errorsDetected = true;
break;
}
}

// Check errors before applying changes
if (errorsDetected)
{
string failureMessage = string.Format(CultureInfo.CurrentCulture, VSResources.RenameSymbolFailed, oldName);
string failureMessage = string.Format(CultureInfo.CurrentCulture, VSResources.CannotApplyRename, oldName);
_userNotificationServices.ShowWarning(failureMessage);
return;
}

if (_languageServiceDone.ContainsKey((oldFilePath, newFileNameWithExtension)))
{
return;
}
_languageServiceDone.Add((oldFilePath, newFileNameWithExtension), new SemaphoreSlim(0, 1));

// Rename the file
await base.RenameAsync(context, node, value); // Async process (1 of which updating Roslyn)
await base.RenameAsync(context, node, value);

//Check if there are any symbols that need to be renamed
if (documentRenameResult.ApplicableActions.IsEmpty)
Expand All @@ -143,7 +153,10 @@ public override async Task RenameAsync(IProjectTreeActionHandlerContext context,
//
// Because HandleRename() is called after Roslyn, we can set this
// flag when node.FilePath == HandlRename(FilePath)
while (_isLanguageServiceDone == false) ;
if (_languageServiceDone.TryGetValue((oldFilePath, newFileNameWithExtension), out SemaphoreSlim semLanguegeServiceDone)) {
await semLanguegeServiceDone.WaitAsync();
_languageServiceDone.Remove((node.FilePath, value));
}

// Apply actions and notify other VS features
CodeAnalysis.Solution currentSolution = GetCurrentProject().Solution;
Expand All @@ -154,14 +167,17 @@ public override async Task RenameAsync(IProjectTreeActionHandlerContext context,
allowCancel: true,
token => documentRenameResult.UpdateSolutionAsync(currentSolution, token));

_roslynServices.ApplyChangesToSolution(currentSolution.Workspace, renamedSolution);
if (!_roslynServices.ApplyChangesToSolution(currentSolution.Workspace, renamedSolution))
{
string failureMessage = string.Format(CultureInfo.CurrentCulture, VSResources.RenameSymbolFailed, oldName);
_userNotificationServices.ShowWarning(failureMessage);
}
return;

}, _unconfiguredProject);

}

private async Task<bool> IsAutomationFunction()
private async Task<bool> IsAutomationFunctionAsync()
{
await _threadingService.SwitchToUIThread();

Expand Down Expand Up @@ -193,7 +209,6 @@ private async Task<bool> CheckUserConfirmation(string oldFileName)
{
string renamePromptMessage = string.Format(CultureInfo.CurrentCulture, VSResources.RenameSymbolPrompt, oldFileName);

await _projectVsServices.ThreadingService.SwitchToUIThread();
return _userNotificationServices.Confirm(renamePromptMessage);
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,7 @@ In order to debug this project, add an executable project to this solution which
<data name="Renaming_Type_from_0_to_1" xml:space="preserve">
<value>Renaming Type from '{0}' to '{1}'</value>
</data>
<data name="CannotApplyRename" xml:space="preserve">
<value>Cannot apply rename</value>
</data>
</root>

0 comments on commit 14d1a90

Please sign in to comment.