提交 4fe8975b 编写于 作者: D David Poeschl

Disable Rename Tracking with "var" and "dynamic" in C#

Fixes #2605 "Lightbulb suggests renaming a type to 'var'"

This change disables using Rename Tracking to rename to/from "var" and "dynamic" in C#.
上级 c209de71
......@@ -201,6 +201,7 @@
<Compile Include="QuickInfo\SyntacticQuickInfoProvider.cs" />
<Compile Include="ReferenceHighlighting\ReferenceHighlightingAdditionalReferenceProvider.cs" />
<Compile Include="RenameTracking\CSharpRenameTrackingCodeFixProvider.cs" />
<Compile Include="RenameTracking\CSharpRenameTrackingLanguageHeuristicsService.cs" />
<Compile Include="SignatureHelp\AbstractCSharpSignatureHelpProvider.cs" />
<Compile Include="SignatureHelp\AttributeSignatureHelpProvider.cs" />
<Compile Include="SignatureHelp\ConstructorInitializerSignatureHelpProvider.cs" />
......@@ -275,4 +276,4 @@
<Import Project="..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
// 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.Editor.Implementation.RenameTracking;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Editor.CSharp.RenameTracking
{
[ExportLanguageService(typeof(IRenameTrackingLanguageHeuristicsService), LanguageNames.CSharp), Shared]
internal sealed class CSharpRenameTrackingLanguageHeuristicsService : IRenameTrackingLanguageHeuristicsService
{
public bool IsIdentifierValidForRenameTracking(string name)
{
return name != "var" && name != "dynamic";
}
}
}
......@@ -586,6 +586,7 @@
<Compile Include="Implementation\Peek\PeekHelpers.cs" />
<Compile Include="Implementation\ReferenceHighlighting\WrittenReferenceHighlightTag.cs" />
<Compile Include="Implementation\ReferenceHighlighting\WrittenReferenceHighlightTagDefinition.cs" />
<Compile Include="Implementation\RenameTracking\IRenameTrackingLanguageHeuristicsService.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingCancellationCommandHandler.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTagDefinition.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTag.cs" />
......
// 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.Editor.Implementation.RenameTracking
{
internal interface IRenameTrackingLanguageHeuristicsService : ILanguageService
{
bool IsIdentifierValidForRenameTracking(string name);
}
}
......@@ -253,8 +253,9 @@ public bool CanInvokeRename(out TrackingSession trackingSession, bool isSmartTag
}
ISyntaxFactsService syntaxFactsService;
return TryGetSyntaxFactsService(out syntaxFactsService) &&
trackingSession.CanInvokeRename(syntaxFactsService, isSmartTagCheck, waitForResult, cancellationToken);
IRenameTrackingLanguageHeuristicsService languageHeuristicsService;
return TryGetSyntaxFactsService(out syntaxFactsService) && TryGetLanguageHeuristicsService(out languageHeuristicsService) &&
trackingSession.CanInvokeRename(syntaxFactsService, languageHeuristicsService, isSmartTagCheck, waitForResult, cancellationToken);
}
internal async Task<IEnumerable<Diagnostic>> GetDiagnostic(SyntaxTree tree, DiagnosticDescriptor diagnosticDescriptor, CancellationToken cancellationToken)
......@@ -332,6 +333,20 @@ private bool TryGetSyntaxFactsService(out ISyntaxFactsService syntaxFactsService
return syntaxFactsService != null;
}
private bool TryGetLanguageHeuristicsService(out IRenameTrackingLanguageHeuristicsService languageHeuristicsService)
{
// Can be called on a background thread
languageHeuristicsService = null;
var document = _buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document != null)
{
languageHeuristicsService = document.Project.LanguageServices.GetService<IRenameTrackingLanguageHeuristicsService>();
}
return languageHeuristicsService != null;
}
public void Connect()
{
AssertIsForeground();
......
......@@ -159,7 +159,8 @@ private async Task<TriggerIdentifierKind> DetermineIfRenamableIdentifierAsync(Sn
return TriggerIdentifierKind.NotRenamable;
}
if (syntaxFactsService.IsIdentifier(token))
var languageHeuristicsService = document.Project.LanguageServices.GetService<IRenameTrackingLanguageHeuristicsService>();
if (syntaxFactsService.IsIdentifier(token) && languageHeuristicsService.IsIdentifierValidForRenameTracking(token.Text))
{
var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, _cancellationToken).ConfigureAwait(false);
var semanticFacts = document.GetLanguageService<ISemanticFactsService>();
......@@ -218,7 +219,12 @@ private async Task<TriggerIdentifierKind> DetermineIfRenamableSymbolAsync(ISymbo
: TriggerIdentifierKind.RenamableReference;
}
internal bool CanInvokeRename(ISyntaxFactsService syntaxFactsService, bool isSmartTagCheck, bool waitForResult, CancellationToken cancellationToken)
internal bool CanInvokeRename(
ISyntaxFactsService syntaxFactsService,
IRenameTrackingLanguageHeuristicsService languageHeuristicsService,
bool isSmartTagCheck,
bool waitForResult,
CancellationToken cancellationToken)
{
if (IsRenamableIdentifier(_isRenamableIdentifierTask, waitForResult, cancellationToken))
{
......@@ -227,7 +233,8 @@ internal bool CanInvokeRename(ISyntaxFactsService syntaxFactsService, bool isSma
var comparison = isRenamingDeclaration || syntaxFactsService.IsCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
if (!string.Equals(OriginalName, newName, comparison) &&
syntaxFactsService.IsValidIdentifier(newName))
syntaxFactsService.IsValidIdentifier(newName) &&
languageHeuristicsService.IsIdentifierValidForRenameTracking(newName))
{
// At this point, we want to allow renaming if the user invoked Ctrl+. explicitly, but we
// want to avoid showing a smart tag if we're renaming a reference that binds to an existing
......
......@@ -1090,5 +1090,109 @@ void M()
state.AssertNoTag();
}
}
[Fact]
[WorkItem(2605, "https://github.com/dotnet/roslyn/issues/2605")]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTracking_CannotRenameToVarInCSharp()
{
var code = @"
class C
{
void M()
{
C$$ c;
}
}";
using (var state = new RenameTrackingTestState(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.EditorOperations.InsertText("va");
state.AssertTag("C", "va");
Assert.NotEmpty(state.GetDocumentDiagnostics());
state.EditorOperations.InsertText("r");
state.AssertNoTag();
Assert.Empty(state.GetDocumentDiagnostics());
state.EditorOperations.InsertText("p");
state.AssertTag("C", "varp");
Assert.NotEmpty(state.GetDocumentDiagnostics());
}
}
[Fact]
[WorkItem(2605, "https://github.com/dotnet/roslyn/issues/2605")]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTracking_CannotRenameFromVarInCSharp()
{
var code = @"
class C
{
void M()
{
var$$ c = new C();
}
}";
using (var state = new RenameTrackingTestState(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.AssertNoTag();
Assert.Empty(state.GetDocumentDiagnostics());
}
}
[Fact]
[WorkItem(2605, "https://github.com/dotnet/roslyn/issues/2605")]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTracking_CanRenameToVarInVisualBasic()
{
var code = @"
Class C
Sub M()
Dim x as C$$
End Sub
End Class";
using (var state = new RenameTrackingTestState(code, LanguageNames.VisualBasic))
{
state.EditorOperations.Backspace();
state.EditorOperations.InsertText("var");
state.AssertTag("C", "var");
Assert.NotEmpty(state.GetDocumentDiagnostics());
}
}
[Fact]
[WorkItem(2605, "https://github.com/dotnet/roslyn/issues/2605")]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTracking_CannotRenameToDynamicInCSharp()
{
var code = @"
class C
{
void M()
{
C$$ c;
}
}";
using (var state = new RenameTrackingTestState(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.EditorOperations.InsertText("dynami");
state.AssertTag("C", "dynami");
Assert.NotEmpty(state.GetDocumentDiagnostics());
state.EditorOperations.InsertText("c");
state.AssertNoTag();
Assert.Empty(state.GetDocumentDiagnostics());
state.EditorOperations.InsertText("s");
state.AssertTag("C", "dynamics");
Assert.NotEmpty(state.GetDocumentDiagnostics());
}
}
}
}
......@@ -216,6 +216,7 @@
<Compile Include="Outlining\VisualBasicOutliningService.vb" />
<Compile Include="QuickInfo\SemanticQuickInfoProvider.vb" />
<Compile Include="ReferenceHighlighting\ReferenceHighlightingAdditionalReferenceProvider.vb" />
<Compile Include="RenameTracking\BasicRenameTrackingLanguageHeuristicsService.vb" />
<Compile Include="RenameTracking\RenameTrackingCodeFixProvider.vb" />
<Compile Include="SignatureHelp\AbstractIntrinsicOperatorSignatureHelpProvider.vb" />
<Compile Include="SignatureHelp\AbstractSignatureHelpProvider.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Composition
Imports Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking
Imports Microsoft.CodeAnalysis.Host.Mef
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.RenameTracking
<ExportLanguageService(GetType(IRenameTrackingLanguageHeuristicsService), LanguageNames.VisualBasic), [Shared]>
Friend NotInheritable Class BasicRenameTrackingLanguageHeuristicsService
Implements IRenameTrackingLanguageHeuristicsService
Public Function IsIdentifierValidForRenameTracking(name As String) As Boolean Implements IRenameTrackingLanguageHeuristicsService.IsIdentifierValidForRenameTracking
Return True
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册