|
// 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 file in the project root for more information.
#nullable disable
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Text;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.RenameTracking;
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public sealed class RenameTrackingTaggerProviderTests
{
[WpfFact]
public async Task RenameTrackingNotOnCreation()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingNotInBlankFile()
{
var code = @"$$";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("d");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingTypingAtEnd()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("C", "Cat");
}
[WpfFact]
public async Task RenameTrackingTypingAtBeginning()
{
var code = """
class $$C
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("AB");
await state.AssertTag("C", "ABC");
}
[WpfFact]
public async Task RenameTrackingTypingInMiddle()
{
var code = """
class AB$$CD
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("ZZ");
await state.AssertTag("ABCD", "ABZZCD");
}
[WpfFact]
public async Task RenameTrackingDeleteFromEnd()
{
var code = """
class ABC$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
await state.AssertTag("ABC", "AB");
}
[WpfFact]
public async Task RenameTrackingDeleteFromBeginning()
{
var code = """
class $$ABC
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Delete();
await state.AssertTag("ABC", "BC");
}
[WpfFact]
public async Task RenameTrackingDeleteFromMiddle()
{
var code = """
class AB$$C
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
await state.AssertTag("ABC", "AC");
}
[WpfFact]
public async Task RenameTrackingNotOnClassKeyword()
{
var code = """
class$$ ABCD
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("d");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingNotAtMethodArgument()
{
var code = """
class ABCD
{
void Goo(int x)
{
int abc = 3;
Goo($$
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("a");
await state.AssertNoTag();
state.EditorOperations.InsertText("b");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingSessionContinuesAfterViewingTag()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("C", "Cat");
state.EditorOperations.InsertText("s");
await state.AssertTag("C", "Cats");
}
[WpfFact]
public async Task RenameTrackingNotInString()
{
var code = """
class C
{
void Goo()
{
string s = "abc$$"
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("d");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingHandlesAtSignAsCSharpEscape()
{
var code = """
class $$C
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("@");
await state.AssertTag("C", "@C");
}
[WpfFact]
public async Task RenameTrackingHandlesSquareBracketsAsVisualBasicEscape()
{
var code = """
Class $$C
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText("[");
await state.AssertNoTag();
state.MoveCaret(1);
state.EditorOperations.InsertText("]");
await state.AssertTag("C", "[C]");
}
[WpfFact]
public async Task RenameTrackingNotOnSquareBracketsInCSharp()
{
var code = """
class $$C
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("[");
await state.AssertNoTag();
state.MoveCaret(1);
state.EditorOperations.InsertText("]");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingHandlesUnicode()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("\u0414\u046E\u046A\u00DB\u00CA\u00DB\u00C4\u00C1\u00CD\u00E4\u00E1\u0152\u0178\u00F5\u00E0\u0178\u00FC\u00C4\u00B5\u00C1i\u00DBE\u00EA\u00E0\u00EA\u00E8\u00E4\u00E5\u00ED\u00F2\u00E8\u00F4\u00E8\u00EA\u00E0\u00F2\u00EE\u00F0\u00F1\u00EB\u00EE\u00E2\u00EE");
await state.AssertTag("C", "C\u0414\u046E\u046A\u00DB\u00CA\u00DB\u00C4\u00C1\u00CD\u00E4\u00E1\u0152\u0178\u00F5\u00E0\u0178\u00FC\u00C4\u00B5\u00C1i\u00DBE\u00EA\u00E0\u00EA\u00E8\u00E4\u00E5\u00ED\u00F2\u00E8\u00F4\u00E8\u00EA\u00E0\u00F2\u00EE\u00F0\u00F1\u00EB\u00EE\u00E2\u00EE");
}
[WpfFact]
public async Task RenameTrackingThroughKeyword()
{
var code = """
class i$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("n");
await state.AssertNoTag();
state.EditorOperations.InsertText("t");
await state.AssertNoTag();
state.EditorOperations.InsertText("s");
await state.AssertTag("i", "ints");
}
[WpfFact]
public async Task RenameTrackingThroughIllegalStartCharacter()
{
var code = """
class $$abc
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("9");
await state.AssertNoTag();
state.MoveCaret(-1);
state.EditorOperations.InsertText("t");
await state.AssertTag("abc", "t9abc");
}
[WpfFact]
public async Task RenameTrackingOnBothSidesOfIdentifier()
{
var code = """
class $$Def
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("Abc");
await state.AssertTag("Def", "AbcDef");
state.MoveCaret(3);
state.EditorOperations.InsertText("Ghi");
await state.AssertTag("Def", "AbcDefGhi");
}
[WpfFact]
public async Task RenameTrackingThroughSameIdentifier()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("s");
await state.AssertTag("C", "Cs");
state.EditorOperations.Backspace();
await state.AssertNoTag();
state.EditorOperations.InsertText("s");
await state.AssertTag("C", "Cs");
}
[WpfFact]
public async Task RenameTrackingThroughEmptyString()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
await state.AssertNoTag();
state.EditorOperations.InsertText("D");
await state.AssertTag("C", "D");
}
[WpfFact]
public async Task RenameTrackingThroughEmptyStringWithCaretMove()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.MoveCaret(-4);
state.MoveCaret(4);
await state.AssertNoTag();
state.EditorOperations.InsertText("D");
await state.AssertTag("C", "D");
}
[WpfFact]
public async Task RenameTrackingNotThroughEmptyStringResumeOnDifferentSpace()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
// Move to previous space
state.MoveCaret(-1);
state.EditorOperations.InsertText("D");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingReplaceIdentifierSuffix()
{
var code = """
class Identifi[|er|]$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
var textSpan = state.HostDocument.SelectedSpans.Single();
state.EditorOperations.ReplaceText(new Span(textSpan.Start, textSpan.Length), "cation");
await state.AssertTag("Identifier", "Identification");
}
[WpfFact]
public async Task RenameTrackingReplaceIdentifierPrefix()
{
var code = """
class $$[|Ident|]ifier
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
var textSpan = state.HostDocument.SelectedSpans.Single();
state.EditorOperations.ReplaceText(new Span(textSpan.Start, textSpan.Length), "Complex");
await state.AssertTag("Identifier", "Complexifier");
}
[WpfFact]
public async Task RenameTrackingReplaceIdentifierCompletely()
{
var code = """
class [|Cat|]$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
var textSpan = state.HostDocument.SelectedSpans.Single();
state.EditorOperations.ReplaceText(new Span(textSpan.Start, textSpan.Length), "Dog");
await state.AssertTag("Cat", "Dog");
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/34280")]
public async Task RenameTrackingReplaceIdentifierWithDiscard()
{
var code = """
class Class
{
int Method()
{
int i;
[|i|]$$ = Method();
rteurn 0;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
var textSpan = state.HostDocument.SelectedSpans.Single();
state.EditorOperations.ReplaceText(new Span(textSpan.Start, textSpan.Length), "_");
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingNotAfterInvoke()
{
var code = """
class Cat$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingInvokeAndChangeBackToOriginal()
{
var code = """
class Cat$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
await state.AssertNoTag();
state.EditorOperations.Backspace();
await state.AssertTag("Cats", "Cat");
}
[WpfFact]
public async Task RenameTrackingUndoOnceAndStartNewSession()
{
var code = """
class Cat$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("abc");
await state.AssertTag("Cat", "Catabc", invokeAction: true);
await state.AssertNoTag();
// Back to original
state.Undo();
await state.AssertNoTag();
state.EditorOperations.InsertText("xyz");
await state.AssertTag("Cat", "Catxyz");
}
[WpfFact]
public async Task RenameTrackingUndoTwiceAndContinueSession()
{
var code = """
class Cat$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("abc");
await state.AssertTag("Cat", "Catabc", invokeAction: true);
await state.AssertNoTag();
// Resume rename tracking session
state.Undo(2);
await state.AssertTag("Cat", "Catabc");
state.EditorOperations.InsertText("xyz");
await state.AssertTag("Cat", "Catabcxyz");
}
[WpfFact]
public async Task RenameTrackingRedoAlwaysClearsState()
{
var code = """
class Cat$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
await state.AssertNoTag();
// Resume rename tracking session
state.Undo(2);
await state.AssertTag("Cat", "Cats");
state.Redo();
await state.AssertNoTag();
state.Redo();
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingUndoTwiceRedoTwiceUndoStillWorks()
{
var code = """
class Cat$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
await state.AssertNoTag();
// Resume rename tracking session
state.Undo(2);
await state.AssertTag("Cat", "Cats");
state.Redo(2);
await state.AssertNoTag();
// Back to original
state.Undo();
await state.AssertNoTag();
// Resume rename tracking session
state.Undo();
await state.AssertTag("Cat", "Cats");
}
[WpfFact]
public async Task RenameTrackingOnReference_ParameterAsArgument()
{
var code = """
class C
{
void M(int x)
{
M(x$$);
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("yz");
await state.AssertTag("x", "xyz");
}
[WpfFact]
public async Task RenameTrackingOnReference_ParameterAsNamedArgument()
{
var code = """
class C
{
void M(int x)
{
M(x$$: x);
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("yz");
await state.AssertTag("x", "xyz");
}
[WpfFact]
public async Task RenameTrackingOnReference_Namespace()
{
var code = """
namespace NS
{
class C
{
static void M()
{
NS$$.C.M();
}
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("A");
await state.AssertTag("NS", "NSA");
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/21657")]
public async Task RenameTrackingOnReference_Attribute_CSharp()
{
var code = """
using System;
class [|$$ustom|]Attribute : Attribute
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("C");
await state.AssertTag("ustomAttribute", "CustomAttribute", invokeAction: true);
var expectedCode = """
using System;
class CustomAttribute : Attribute
{
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/21657")]
public async Task RenameTrackingOnReference_Attribute_VB()
{
var code = """
Import System;
Public Class [|$$ustom|]Attribute
Inherits Attribute
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText("C");
await state.AssertTag("ustomAttribute", "CustomAttribute", invokeAction: true);
var expectedCode = """
Import System;
Public Class CustomAttribute
Inherits Attribute
End Class
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/21657")]
public async Task RenameTrackingOnReference_Capitalized_Attribute_VB()
{
var code = """
Import System;
Public Class [|$$ustom|]ATTRIBUTE
Inherits Attribute
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText("C");
await state.AssertTag("ustomATTRIBUTE", "CustomATTRIBUTE", invokeAction: true);
var expectedCode = """
Import System;
Public Class CustomATTRIBUTE
Inherits Attribute
End Class
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/21657")]
public async Task RenameTrackingOnReference_Not_Capitalized_Attribute_VB()
{
var code = """
Import System;
Public Class [|$$ustom|]attribute
Inherits Attribute
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText("C");
await state.AssertTag("ustomattribute", "Customattribute", invokeAction: true);
var expectedCode = """
Import System;
Public Class Customattribute
Inherits Attribute
End Class
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
}
[WpfFact]
public async Task RenameTrackingNotifiesThirdPartiesOfRenameOperation()
{
var code = """
class Cat$$
{
public Cat()
{
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
Assert.Equal(1, state.RefactorNotifyService.OnBeforeSymbolRenamedCount);
Assert.Equal(1, state.RefactorNotifyService.OnAfterSymbolRenamedCount);
var expectedCode = """
class Cats
{
public Cats()
{
}
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
state.AssertNoNotificationMessage();
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingHonorsThirdPartyRequestsForCancellationBeforeRename()
{
var code = """
class Cat$$
{
public Cat()
{
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp, onBeforeGlobalSymbolRenamedReturnValue: false);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
Assert.Equal(1, state.RefactorNotifyService.OnBeforeSymbolRenamedCount);
// Make sure the rename didn't proceed
Assert.Equal(0, state.RefactorNotifyService.OnAfterSymbolRenamedCount);
await state.AssertNoTag();
var expectedCode = """
class Cat
{
public Cat()
{
}
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
state.AssertNotificationMessage();
}
[WpfFact]
public async Task RenameTrackingAlertsAboutThirdPartyRequestsForCancellationAfterRename()
{
var code = """
class Cat$$
{
public Cat()
{
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp, onAfterGlobalSymbolRenamedReturnValue: false);
state.EditorOperations.InsertText("s");
await state.AssertTag("Cat", "Cats", invokeAction: true);
Assert.Equal(1, state.RefactorNotifyService.OnBeforeSymbolRenamedCount);
Assert.Equal(1, state.RefactorNotifyService.OnAfterSymbolRenamedCount);
state.AssertNotificationMessage();
// Make sure the rename completed
var expectedCode = """
class Cats
{
public Cats()
{
}
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
await state.AssertNoTag();
}
[WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530469")]
public async Task RenameTrackingNotWhenStartedFromTextualWordInTrivia()
{
var code = """
Module Program
Sub Main()
Dim [x$$ = 1
End Sub
End Module
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText("]");
await state.AssertNoTag();
}
[WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530495")]
public async Task RenameTrackingNotWhenCaseCorrectingReference()
{
var code = """
Module Program
Sub Main()
$$main()
End Sub
End Module
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.Delete();
await state.AssertTag("main", "ain");
state.EditorOperations.InsertText("M");
await state.AssertNoTag();
}
[WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/599508")]
public async Task RenameTrackingNotWhenNewIdentifierReferenceBinds()
{
var code = """
Module Program
Sub Main()
$$[|main|]()
End Sub
Sub Goo()
End Sub
End Module
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
var textSpan = state.HostDocument.SelectedSpans.Single();
state.EditorOperations.ReplaceText(new Span(textSpan.Start, textSpan.Length), "Go");
await state.AssertTag("main", "Go");
state.EditorOperations.InsertText("o");
await state.AssertNoTag();
}
[WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530400")]
public async Task RenameTrackingNotWhenDeclaringEnumMembers()
{
var code = """
Enum E
$$
End Enum
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText(" a");
state.EditorOperations.InsertText("b");
await state.AssertNoTag();
}
[WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1028072")]
public void RenameTrackingDoesNotThrowAggregateException()
{
var waitForResult = false;
var notRenamable = Task.FromResult(RenameTrackingTaggerProvider.TriggerIdentifierKind.NotRenamable);
Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(notRenamable, waitForResult, CancellationToken.None));
var source = new TaskCompletionSource<RenameTrackingTaggerProvider.TriggerIdentifierKind>();
Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None));
source.TrySetResult(RenameTrackingTaggerProvider.TriggerIdentifierKind.RenamableReference);
Assert.True(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None));
source = new TaskCompletionSource<RenameTrackingTaggerProvider.TriggerIdentifierKind>();
source.TrySetCanceled();
Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None));
Assert.False(RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, CancellationToken.None));
source = new TaskCompletionSource<RenameTrackingTaggerProvider.TriggerIdentifierKind>();
source.TrySetException(new OperationCanceledException());
Assert.False(RenameTrackingTaggerProvider.IsRenamableIdentifier(source.Task, waitForResult, CancellationToken.None));
Assert.False(RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, CancellationToken.None));
Assert.False(RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, new CancellationTokenSource().Token));
source = new TaskCompletionSource<RenameTrackingTaggerProvider.TriggerIdentifierKind>();
Assert.Throws<OperationCanceledException>(() => RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, new CancellationToken(canceled: true)));
var thrownException = new Exception();
source.TrySetException(thrownException);
var caughtException = Assert.Throws<Exception>(() => RenameTrackingTaggerProvider.WaitForIsRenamableIdentifier(source.Task, CancellationToken.None));
Assert.Same(thrownException, caughtException);
}
[WpfFact]
[WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1063943")]
[WorkItem("https://github.com/dotnet/roslyn/issues/10914")]
public async Task RenameTrackingOnReferenceWithWrongNumberOfArguments()
{
var code = """
class C
{
void M(int x)
{
M$$();
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("eow");
await state.AssertTag("M", "Meow");
}
[WpfFact]
[WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1063943")]
[WorkItem("https://github.com/dotnet/roslyn/issues/10914")]
public async Task RenameTrackingOnReferenceWithWrongNumberOfArguments_Overloads()
{
var code = """
class C
{
void M(int x)
{
M$$();
}
void M(bool x)
{
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("eow");
await state.AssertNoTag();
}
[WpfFact]
public async Task CancelRenameTracking()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("C", "Cat");
state.SendEscape();
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTrackingNotWhenDeclaringEnumMembersEvenAfterCancellation()
{
var code = """
Enum E
$$
End Enum
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText(" a");
state.EditorOperations.InsertText("b");
await state.AssertNoTag();
state.SendEscape();
state.EditorOperations.InsertText("c");
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/540")]
public async Task RenameTrackingDoesNotProvideDiagnosticAfterCancellation()
{
var code = """
class C$$
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("C", "Cat");
Assert.NotNull(await state.TryGetCodeActionAsync());
state.SendEscape();
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
}
[WpfFact]
public async Task RenameTracking_Nameof_FromMethodGroupReference()
{
var code = """
class C
{
void M()
{
nameof(M$$).ToString();
}
void M(int x)
{
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("M", "Mat", invokeAction: true);
// Make sure the rename completed
var expectedCode = """
class C
{
void Mat()
{
nameof(Mat).ToString();
}
void Mat(int x)
{
}
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTracking_Nameof_FromMethodDefinition_NoOverloads()
{
var code = """
class C
{
void M$$()
{
nameof(M).ToString();
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("M", "Mat", invokeAction: true);
// Make sure the rename completed
var expectedCode = """
class C
{
void Mat()
{
nameof(Mat).ToString();
}
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTracking_Nameof_FromMethodDefinition_WithOverloads()
{
var code = """
class C
{
void M$$()
{
nameof(M).ToString();
}
void M(int x)
{
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("at");
await state.AssertTag("M", "Mat", invokeAction: true);
// Make sure the rename completed
var expectedCode = """
class C
{
void Mat()
{
nameof(M).ToString();
}
void M(int x)
{
}
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTracking_Nameof_FromReferenceToMetadata_NoTag()
{
var code = """
class C
{
void M()
{
var x = nameof(ToString$$);
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("z");
await state.AssertNoTag();
}
[WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/762964")]
public async Task RenameTracking_NoTagWhenFirstEditChangesReferenceToAnotherSymbol()
{
var code = """
class C
{
void M()
{
int abc = 7;
int ab = 8;
int z = abc$$;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/2605")]
public async Task RenameTracking_CannotRenameToVarInCSharp()
{
var code = """
class C
{
void M()
{
C$$ c;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.EditorOperations.InsertText("va");
await state.AssertTag("C", "va");
Assert.NotNull(await state.TryGetCodeActionAsync());
state.EditorOperations.InsertText("r");
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
state.EditorOperations.InsertText("p");
await state.AssertTag("C", "varp");
Assert.NotNull(await state.TryGetCodeActionAsync());
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/2605")]
public async Task RenameTracking_CannotRenameFromVarInCSharp()
{
var code = """
class C
{
void M()
{
var$$ c = new C();
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/2605")]
public async Task RenameTracking_CanRenameToVarInVisualBasic()
{
var code = """
Class C
Sub M()
Dim x as C$$
End Sub
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.Backspace();
state.EditorOperations.InsertText("var");
await state.AssertTag("C", "var");
Assert.NotNull(await state.TryGetCodeActionAsync());
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/2605")]
public async Task RenameTracking_CannotRenameToDynamicInCSharp()
{
var code = """
class C
{
void M()
{
C$$ c;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.EditorOperations.InsertText("dynami");
await state.AssertTag("C", "dynami");
Assert.NotNull(await state.TryGetCodeActionAsync());
state.EditorOperations.InsertText("c");
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
state.EditorOperations.InsertText("s");
await state.AssertTag("C", "dynamics");
Assert.NotNull(await state.TryGetCodeActionAsync());
}
[WpfFact]
public async Task RenameImplicitTupleField()
{
var code = """
class C
{
void M()
{
(int, int) x = (1, 2);
var y = x.Item1$$;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
}
[WpfFact]
public async Task RenameImplicitTupleFieldVB()
{
var code = """
class C
Sub M()
Dim x as (Integer, Integer) = (1, 2)
Dim y = x.Item1$$
End Sub
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
}
[WpfFact]
public async Task RenameImplicitTupleFieldExtended()
{
var code = """
class C
{
void M()
{
(int, int, int, int, int, int, int, int, int, int) x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var y = x.Item9$$;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
}
[WpfFact]
public async Task RenameImplicitTupleFieldExtendedVB()
{
var code = """
Class C
Sub M()
Dim x as (Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer) = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Dim y = x.Item9$$
End Sub
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Null(await state.TryGetCodeActionAsync());
}
[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=371205")]
public async Task RenameTrackingNotOnExplicitTupleReturnDeclaration_CSharp()
{
var code = """
class C
{
void M()
{
(int abc$$, int) x = (1, 2);
var y = x.abc;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=371205")]
public async Task RenameTrackingNotOnExplicitTupleReturnDeclaration_VB()
{
var code = """
class C
Sub M()
Dim x as (abc$$ as integer, int Item2 as integer) = (1, 2)
Dim y = x.abc
End Sub
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=371205")]
public async Task RenameTrackingNotOnExplicitTupleFieldReference_CSharp()
{
var code = """
class C
{
void M()
{
(int abc, int) x = (1, 2);
var y = x.abc$$;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=371205")]
public async Task RenameTrackingNotOnExplicitTupleFieldReference_VB()
{
var code = """
class C
Sub M()
Dim x as (abc as integer, int Item2 as integer) = (1, 2)
Dim y = x.abc$$
End Sub
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=371205")]
public async Task RenameTrackingNotOnExplicitTupleElementsInDeclarations_CSharp()
{
var code = """
class C
{
void M()
{
var t = (x$$: 1, y: 2);
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("2");
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=371205")]
public async Task RenameTrackingNotOnExplicitTupleElementsInDeclarations_VB()
{
var code = """
Class C
Sub M()
Dim t = (x$$:=1, y:=2)
End Sub
End Class
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.VisualBasic);
state.EditorOperations.InsertText("2");
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/14159")]
public async Task RenameTrackingNotOnWellKnownValueTupleType()
{
var workspaceXml = """
<Workspace>
<Project Language="C#" CommonReferences="true" LanguageVersion="7">
<Document>
using System;
class C
{
void M()
{
var x = new ValueTuple$$<int>();
}
}
namespace System
{
public struct ValueTuple<T1>
{
public T1 Item1;
}
}
</Document>
</Project>
</Workspace>
""";
using var state = RenameTrackingTestState.CreateFromWorkspaceXml(workspaceXml, LanguageNames.CSharp);
state.EditorOperations.InsertText("2");
await state.AssertNoTag();
}
[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/14159")]
public async Task RenameTrackingOnThingsCalledValueTupleThatAreNotTheWellKnownType()
{
var workspaceXml = """
<Workspace>
<Project Language="C#" CommonReferences="true" LanguageVersion="7">
<Document>
class C
{
void M()
{
var x = new ValueTuple$$<int>();
}
}
public struct ValueTuple<T1>
{
public T1 Item1;
}
</Document>
</Project>
</Workspace>
""";
using var state = RenameTrackingTestState.CreateFromWorkspaceXml(workspaceXml, LanguageNames.CSharp);
state.EditorOperations.InsertText("2");
await state.AssertTag("ValueTuple", "ValueTuple2");
}
[WpfFact]
public async Task RenameTrackingOnDeconstruct()
{
var code = """
class C
{
void Deconstruct$$(out int x1, out int x2) { x1 = 1; x2 = 2; }
void M()
{
var (y1, y2) = this;
}
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("2");
await state.AssertTag("Deconstruct", "Deconstruct2");
}
[WpfFact]
public async Task RenameTracking_UnmanagedConstraint_Keyword()
{
var code = """
class C<T> where T : $$unmanaged
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
await state.AssertNoTag();
}
[WpfFact]
public async Task RenameTracking_UnmanagedConstraint_Type()
{
var code = """
interface unmanaged
{
}
class C<T> where T : $$unmanaged
{
}
""";
using var state = RenameTrackingTestState.Create(code, LanguageNames.CSharp);
state.EditorOperations.InsertText("my");
await state.AssertTag("unmanaged", "myunmanaged", invokeAction: true);
// Make sure the rename completed
var expectedCode = """
interface myunmanaged
{
}
class C<T> where T : myunmanaged
{
}
""";
Assert.Equal(expectedCode, state.HostDocument.GetTextBuffer().CurrentSnapshot.GetText());
await state.AssertNoTag();
}
}
|