|
// 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.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Completion.Providers;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.NamingStyles;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionSetSources;
using static SymbolSpecification;
[Trait(Traits.Feature, Traits.Features.Completion)]
public class DeclarationNameCompletionProviderTests : AbstractCSharpCompletionProviderTests
{
private const string Span = """
namespace System
{
public readonly ref struct Span<T>
{
private readonly T[] arr;
public ref T this[int i] => ref arr[i];
public override int GetHashCode() => 1;
public int Length { get; }
unsafe public Span(void* pointer, int length)
{
this.arr = Helpers.ToArray<T>(pointer, length);
this.Length = length;
}
public Span(T[] arr)
{
this.arr = arr;
this.Length = arr.Length;
}
public void CopyTo(Span<T> other) { }
/// <summary>Gets an enumerator for this span.</summary>
public Enumerator GetEnumerator() => new Enumerator(this);
/// <summary>Enumerates the elements of a <see cref="Span{T}"/>.</summary>
public ref struct Enumerator
{
/// <summary>The span being enumerated.</summary>
private readonly Span<T> _span;
/// <summary>The next index to yield.</summary>
private int _index;
/// <summary>Initialize the enumerator.</summary>
/// <param name="span">The span to enumerate.</param>
internal Enumerator(Span<T> span)
{
_span = span;
_index = -1;
}
/// <summary>Advances the enumerator to the next element of the span.</summary>
public bool MoveNext()
{
int index = _index + 1;
if (index < _span.Length)
{
_index = index;
return true;
}
return false;
}
/// <summary>Gets the element at the current position of the enumerator.</summary>
public ref T Current
{
get => ref _span[_index];
}
}
public static implicit operator Span<T>(T[] array) => new Span<T>(array);
public Span<T> Slice(int offset, int length)
{
var copy = new T[length];
Array.Copy(arr, offset, copy, 0, length);
return new Span<T>(copy);
}
}
public readonly ref struct ReadOnlySpan<T>
{
private readonly T[] arr;
public ref readonly T this[int i] => ref arr[i];
public override int GetHashCode() => 2;
public int Length { get; }
unsafe public ReadOnlySpan(void* pointer, int length)
{
this.arr = Helpers.ToArray<T>(pointer, length);
this.Length = length;
}
public ReadOnlySpan(T[] arr)
{
this.arr = arr;
this.Length = arr.Length;
}
public void CopyTo(Span<T> other) { }
/// <summary>Gets an enumerator for this span.</summary>
public Enumerator GetEnumerator() => new Enumerator(this);
/// <summary>Enumerates the elements of a <see cref="Span{T}"/>.</summary>
public ref struct Enumerator
{
/// <summary>The span being enumerated.</summary>
private readonly ReadOnlySpan<T> _span;
/// <summary>The next index to yield.</summary>
private int _index;
/// <summary>Initialize the enumerator.</summary>
/// <param name="span">The span to enumerate.</param>
internal Enumerator(ReadOnlySpan<T> span)
{
_span = span;
_index = -1;
}
/// <summary>Advances the enumerator to the next element of the span.</summary>
public bool MoveNext()
{
int index = _index + 1;
if (index < _span.Length)
{
_index = index;
return true;
}
return false;
}
/// <summary>Gets the element at the current position of the enumerator.</summary>
public ref readonly T Current
{
get => ref _span[_index];
}
}
public static implicit operator ReadOnlySpan<T>(T[] array) => array == null ? default : new ReadOnlySpan<T>(array);
public static implicit operator ReadOnlySpan<T>(string stringValue) => string.IsNullOrEmpty(stringValue) ? default : new ReadOnlySpan<T>((T[])(object)stringValue.ToCharArray());
public ReadOnlySpan<T> Slice(int offset, int length)
{
var copy = new T[length];
Array.Copy(arr, offset, copy, 0, length);
return new ReadOnlySpan<T>(copy);
}
}
public readonly ref struct SpanLike<T>
{
public readonly Span<T> field;
}
public enum Color: sbyte
{
Red,
Green,
Blue
}
public static unsafe class Helpers
{
public static T[] ToArray<T>(void* ptr, int count)
{
if (ptr == null)
{
return null;
}
if (typeof(T) == typeof(int))
{
var arr = new int[count];
for(int i = 0; i < count; i++)
{
arr[i] = ((int*)ptr)[i];
}
return (T[])(object)arr;
}
if (typeof(T) == typeof(byte))
{
var arr = new byte[count];
for(int i = 0; i < count; i++)
{
arr[i] = ((byte*)ptr)[i];
}
return (T[])(object)arr;
}
if (typeof(T) == typeof(char))
{
var arr = new char[count];
for(int i = 0; i < count; i++)
{
arr[i] = ((char*)ptr)[i];
}
return (T[])(object)arr;
}
if (typeof(T) == typeof(Color))
{
var arr = new Color[count];
for(int i = 0; i < count; i++)
{
arr[i] = ((Color*)ptr)[i];
}
return (T[])(object)arr;
}
throw new Exception("add a case for: " + typeof(T));
}
}
}
""";
private const string IAsyncEnumerable = """
namespace System
{
public interface IAsyncDisposable
{
System.Threading.Tasks.ValueTask DisposeAsync();
}
}
namespace System.Runtime.CompilerServices
{
using System.Threading.Tasks;
public sealed class AsyncMethodBuilderAttribute : Attribute
{
public AsyncMethodBuilderAttribute(Type builderType) { }
public Type BuilderType { get; }
}
public struct AsyncValueTaskMethodBuilder
{
public ValueTask Task => default;
public static AsyncValueTaskMethodBuilder Create() => default;
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine {}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine {}
public void SetException(Exception exception) {}
public void SetResult() {}
public void SetStateMachine(IAsyncStateMachine stateMachine) {}
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {}
}
public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
{
public bool IsCompleted => default;
public void GetResult() { }
public void OnCompleted(Action continuation) { }
public void UnsafeOnCompleted(Action continuation) { }
}
public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
{
public bool IsCompleted => default;
public TResult GetResult() => default;
public void OnCompleted(Action continuation) { }
public void UnsafeOnCompleted(Action continuation) { }
}
}
namespace System.Threading.Tasks
{
using System.Runtime.CompilerServices;
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
public readonly struct ValueTask : IEquatable<ValueTask>
{
public ValueTask(Task task) {}
public ValueTask(IValueTaskSource source, short token) {}
public bool IsCompleted => default;
public bool IsCompletedSuccessfully => default;
public bool IsFaulted => default;
public bool IsCanceled => default;
public Task AsTask() => default;
public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => default;
public override bool Equals(object obj) => default;
public bool Equals(ValueTask other) => default;
public ValueTaskAwaiter GetAwaiter() => default;
public override int GetHashCode() => default;
public ValueTask Preserve() => default;
public static bool operator ==(ValueTask left, ValueTask right) => default;
public static bool operator !=(ValueTask left, ValueTask right) => default;
}
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
{
public ValueTask(TResult result) {}
public ValueTask(Task<TResult> task) {}
public ValueTask(IValueTaskSource<TResult> source, short token) {}
public bool IsFaulted => default;
public bool IsCompletedSuccessfully => default;
public bool IsCompleted => default;
public bool IsCanceled => default;
public TResult Result => default;
public Task<TResult> AsTask() => default;
public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) => default;
public bool Equals(ValueTask<TResult> other) => default;
public override bool Equals(object obj) => default;
public ValueTaskAwaiter<TResult> GetAwaiter() => default;
public override int GetHashCode() => default;
public ValueTask<TResult> Preserve() => default;
public override string ToString() => default;
public static bool operator ==(ValueTask<TResult> left, ValueTask<TResult> right) => default;
public static bool operator !=(ValueTask<TResult> left, ValueTask<TResult> right) => default;
}
}
namespace System.Collections.Generic
{
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
T Current { get; }
}
}
""";
internal override Type GetCompletionProviderType()
=> typeof(DeclarationNameCompletionProvider);
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/48310")]
[InlineData("record")]
[InlineData("record class")]
[InlineData("record struct")]
public async Task TreatRecordPositionalParameterAsProperty(string record)
{
var markup = $@"
public class MyClass
{{
}}
public {record} R(MyClass $$
";
await VerifyItemExistsAsync(markup, "MyClass", glyph: (int)Glyph.PropertyPublic);
}
[Theory]
[InlineData("class")]
[InlineData("struct")]
public async Task DoNotTreatPrimaryConstructorParameterAsProperty(string record)
{
var markup = $@"
public class MyClass
{{
}}
public {record} R(MyClass $$
";
await VerifyItemIsAbsentAsync(markup, "MyClass");
}
[Fact]
public async Task NameWithOnlyType1()
{
var markup = """
public class MyClass
{
MyClass $$
}
""";
await VerifyItemExistsAsync(markup, "myClass", glyph: (int)Glyph.FieldPublic);
await VerifyItemExistsAsync(markup, "MyClass", glyph: (int)Glyph.PropertyPublic);
await VerifyItemExistsAsync(markup, "GetMyClass", glyph: (int)Glyph.MethodPublic);
}
[Fact]
public async Task AsyncTaskOfT()
{
var markup = """
using System.Threading.Tasks;
public class C
{
async Task<C> $$
}
""";
await VerifyItemExistsAsync(markup, "GetCAsync");
}
[Fact(Skip = "not yet implemented")]
public async Task NonAsyncTaskOfT()
{
var markup = """
public class C
{
Task<C> $$
}
""";
await VerifyItemExistsAsync(markup, "GetCAsync");
}
[Fact]
public async Task MethodDeclaration1()
{
var markup = """
public class C
{
virtual C $$
}
""";
await VerifyItemExistsAsync(markup, "GetC");
await VerifyItemIsAbsentAsync(markup, "C");
await VerifyItemIsAbsentAsync(markup, "c");
}
[Fact]
public async Task WordBreaking1()
{
var markup = """
using System.Threading;
public class C
{
CancellationToken $$
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "cancellation");
await VerifyItemExistsAsync(markup, "token");
}
[Fact]
public async Task WordBreaking2()
{
var markup = """
interface I {}
public class C
{
I $$
}
""";
await VerifyItemExistsAsync(markup, "GetI");
}
[Fact]
public async Task WordBreaking3()
{
var markup = """
interface II {}
public class C
{
II $$
}
""";
await VerifyItemExistsAsync(markup, "GetI");
}
[Fact]
public async Task WordBreaking4()
{
var markup = """
interface IGoo {}
public class C
{
IGoo $$
}
""";
await VerifyItemExistsAsync(markup, "Goo");
}
[Fact]
public async Task WordBreaking5()
{
var markup = """
class SomeWonderfullyLongClassName {}
public class C
{
SomeWonderfullyLongClassName $$
}
""";
await VerifyItemExistsAsync(markup, "Some");
await VerifyItemExistsAsync(markup, "SomeWonderfully");
await VerifyItemExistsAsync(markup, "SomeWonderfullyLong");
await VerifyItemExistsAsync(markup, "SomeWonderfullyLongClass");
await VerifyItemExistsAsync(markup, "Name");
await VerifyItemExistsAsync(markup, "ClassName");
await VerifyItemExistsAsync(markup, "LongClassName");
await VerifyItemExistsAsync(markup, "WonderfullyLongClassName");
await VerifyItemExistsAsync(markup, "SomeWonderfullyLongClassName");
}
[Fact]
public async Task Parameter1()
{
var markup = """
using System.Threading;
public class C
{
void Goo(CancellationToken $$
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact]
public async Task Parameter2()
{
var markup = """
using System.Threading;
public class C
{
void Goo(int x, CancellationToken c$$
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact]
public async Task Parameter3()
{
var markup = """
using System.Threading;
public class C
{
void Goo(CancellationToken c$$) {}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter4()
{
var markup = """
using System.Threading;
public class C
{
void Other(CancellationToken cancellationToken) {}
void Goo(CancellationToken c$$) {}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact]
public async Task Parameter5()
{
var markup = """
using System.Threading;
public class C
{
void Goo(CancellationToken cancellationToken, CancellationToken c$$) {}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken1", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter6()
{
var markup = """
using System.Threading;
void Other(CancellationToken cancellationToken) {}
void Goo(CancellationToken c$$) {}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact]
public async Task Parameter7()
{
var markup = """
using System.Threading;
void Goo(CancellationToken cancellationToken, CancellationToken c$$) {}
""";
await VerifyItemExistsAsync(markup, "cancellationToken1", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter8()
{
var markup = """
using System.Threading;
public class C
{
int this[CancellationToken cancellationToken] => throw null;
int this[CancellationToken c$$] => throw null;
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter9()
{
var markup = """
using System.Threading;
public class C
{
int this[CancellationToken cancellationToken] => throw null;
int this[CancellationToken cancellationToken, CancellationToken c$$] => throw null;
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken1", glyph: (int)Glyph.Parameter);
}
[InlineData(LanguageVersion.CSharp7)]
[InlineData(LanguageVersion.CSharp8)]
[InlineData(LanguageVersion.Latest)]
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/42049")]
[WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter10(LanguageVersion languageVersion)
{
var source = """
public class DbContext { }
public class C
{
void Goo(DbContext context) {
void InnerGoo(DbContext $$) { }
}
}
""";
var markup = GetMarkup(source, languageVersion);
await VerifyItemExistsAsync(markup, "dbContext", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "db", glyph: (int)Glyph.Parameter);
if (languageVersion.MapSpecifiedToEffectiveVersion() >= LanguageVersion.CSharp8)
{
await VerifyItemExistsAsync(markup, "context", glyph: (int)Glyph.Parameter);
}
else
{
await VerifyItemExistsAsync(markup, "context1", glyph: (int)Glyph.Parameter);
}
}
[InlineData(LanguageVersion.CSharp7)]
[InlineData(LanguageVersion.CSharp8)]
[InlineData(LanguageVersion.Latest)]
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/42049")]
[WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter11(LanguageVersion languageVersion)
{
var source = """
public class DbContext { }
public class C
{
void Goo() {
DbContext context;
void InnerGoo(DbContext $$) { }
}
}
""";
var markup = GetMarkup(source, languageVersion);
await VerifyItemExistsAsync(markup, "dbContext", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "db", glyph: (int)Glyph.Parameter);
if (languageVersion.MapSpecifiedToEffectiveVersion() >= LanguageVersion.CSharp8)
{
await VerifyItemExistsAsync(markup, "context", glyph: (int)Glyph.Parameter);
}
else
{
await VerifyItemExistsAsync(markup, "context1", glyph: (int)Glyph.Parameter);
}
}
[InlineData(LanguageVersion.CSharp7)]
[InlineData(LanguageVersion.CSharp8)]
[InlineData(LanguageVersion.Latest)]
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/42049")]
[WorkItem("https://github.com/dotnet/roslyn/issues/45492")]
public async Task Parameter12(LanguageVersion languageVersion)
{
var source = """
public class DbContext { }
public class C
{
DbContext dbContext;
void Goo(DbContext context) {
void InnerGoo(DbContext $$) { }
}
}
""";
var markup = GetMarkup(source, languageVersion);
await VerifyItemExistsAsync(markup, "dbContext", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "db", glyph: (int)Glyph.Parameter);
if (languageVersion.MapSpecifiedToEffectiveVersion() >= LanguageVersion.CSharp8)
{
await VerifyItemExistsAsync(markup, "context", glyph: (int)Glyph.Parameter);
}
else
{
await VerifyItemExistsAsync(markup, "context1", glyph: (int)Glyph.Parameter);
}
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36248")]
public async Task Parameter13()
{
using var workspaceFixture = GetOrCreateWorkspaceFixture();
var workspace = workspaceFixture.Target.GetWorkspace(GetComposition());
workspace.SetAnalyzerFallbackOptions(new OptionsCollection(LanguageNames.CSharp)
{
{ NamingStyleOptions.NamingPreferences, ParameterCamelCaseWithPascalCaseFallback() }
});
var markup = """
using System.Threading;
public class C
{
void Goo(CancellationToken $$
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
await VerifyItemIsAbsentAsync(markup, "CancellationToken");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52534")]
public async Task SuggestParameterNamesFromExistingOverloads()
{
var markup = """
using System.Threading;
public class C
{
void M(CancellationToken myTok) { }
void M(CancellationToken $$
}
""";
await VerifyItemExistsAsync(markup, "myTok", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52534")]
public async Task SuggestParameterNamesFromExistingOverloads_Constructor()
{
var markup = """
using System.Threading;
public class C
{
public C(string firstName, string middleName, string lastName) { }
public C(string firstName, string $$)
}
""";
await VerifyItemExistsAsync(markup, "middleName", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "lastName", glyph: (int)Glyph.Parameter);
await VerifyItemIsAbsentAsync(markup, "firstName");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52534")]
public async Task DoNotSuggestParameterNamesFromTheSameOverload()
{
var markup = """
public class C
{
void M(string name, string $$) { }
}
""";
await VerifyItemIsAbsentAsync(markup, "name");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52534")]
public async Task DoNotSuggestParameterNamesFromNonOverloads()
{
var markup = """
using System.Threading;
public class C
{
void M1(CancellationToken myTok) { }
void M2(CancellationToken $$
}
""";
await VerifyItemIsAbsentAsync(markup, "myTok");
await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52534")]
public async Task DoNotSuggestInGenericType()
{
var markup = """
using System.Collections.Generic;
public class C
{
void M(IEnumerable<int> numbers) { }
void M(List<$$>) { }
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/52534")]
public async Task DoNotSuggestInOptionalParameterDefaultValue()
{
var markup = """
using System.Collections.Generic;
public class C
{
private const int ZERO = 0;
void M(int num = ZERO) { }
void M(int x, int num = $$) { }
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19260")]
public async Task EscapeKeywords1()
{
var markup = """
using System.Text;
public class C
{
void Goo(StringBuilder $$) {}
}
""";
await VerifyItemExistsAsync(markup, "stringBuilder", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "@string", glyph: (int)Glyph.Parameter);
await VerifyItemExistsAsync(markup, "builder", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19260")]
public async Task EscapeKeywords2()
{
var markup = """
class For { }
public class C
{
void Goo(For $$) {}
}
""";
await VerifyItemExistsAsync(markup, "@for", glyph: (int)Glyph.Parameter);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19260")]
public async Task EscapeKeywords3()
{
var markup = """
class For { }
public class C
{
void goo()
{
For $$
}
}
""";
await VerifyItemExistsAsync(markup, "@for");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19260")]
public async Task EscapeKeywords4()
{
var markup = """
using System.Text;
public class C
{
void goo()
{
StringBuilder $$
}
}
""";
await VerifyItemExistsAsync(markup, "stringBuilder");
await VerifyItemExistsAsync(markup, "@string");
await VerifyItemExistsAsync(markup, "builder");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25214")]
public async Task TypeImplementsLazyOfType1()
{
var markup = """
using System;
using System.Collections.Generic;
internal class Example
{
public Lazy<Item> $$
}
public class Item { }
""";
await VerifyItemExistsAsync(markup, "item");
await VerifyItemExistsAsync(markup, "Item");
await VerifyItemExistsAsync(markup, "GetItem");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25214")]
public async Task TypeImplementsLazyOfType2()
{
var markup = """
using System;
using System.Collections.Generic;
internal class Example
{
public List<Lazy<Item>> $$
}
public class Item { }
""";
await VerifyItemExistsAsync(markup, "items");
await VerifyItemExistsAsync(markup, "Items");
await VerifyItemExistsAsync(markup, "GetItems");
}
[Fact]
public async Task NoSuggestionsForInt()
{
var markup = """
using System.Threading;
public class C
{
int $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForLong()
{
var markup = """
using System.Threading;
public class C
{
long $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForDouble()
{
var markup = """
using System.Threading;
public class C
{
double $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForFloat()
{
var markup = """
using System.Threading;
public class C
{
float $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForSbyte()
{
var markup = """
using System.Threading;
public class C
{
sbyte $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForShort()
{
var markup = """
using System.Threading;
public class C
{
short $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForUint()
{
var markup = """
using System.Threading;
public class C
{
uint $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForUlong()
{
var markup = """
using System.Threading;
public class C
{
ulong $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task SuggestionsForUShort()
{
var markup = """
using System.Threading;
public class C
{
ushort $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForBool()
{
var markup = """
using System.Threading;
public class C
{
bool $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForByte()
{
var markup = """
using System.Threading;
public class C
{
byte $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForChar()
{
var markup = """
using System.Threading;
public class C
{
char $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSuggestionsForString()
{
var markup = """
public class C
{
string $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NoSingleLetterClassNameSuggested()
{
var markup = """
public class C
{
C $$
}
""";
await VerifyItemIsAbsentAsync(markup, "C");
await VerifyItemIsAbsentAsync(markup, "c");
}
[Fact]
public async Task ArrayElementTypeSuggested()
{
var markup = """
using System.Threading;
public class MyClass
{
MyClass[] $$
}
""";
await VerifyItemExistsAsync(markup, "MyClasses");
await VerifyItemIsAbsentAsync(markup, "Array");
}
[Fact]
public async Task NotTriggeredByVar()
{
var markup = """
public class C
{
var $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task NotAfterVoid()
{
var markup = """
public class C
{
void $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task AfterGeneric()
{
var markup = """
public class C
{
System.Collections.Generic.IEnumerable<C> $$
}
""";
await VerifyItemExistsAsync(markup, "GetCs");
}
[Fact]
public async Task NothingAfterVar()
{
var markup = """
public class C
{
void goo()
{
var $$
}
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact]
public async Task TestCorrectOrder()
{
var markup = """
public class MyClass
{
MyClass $$
}
""";
var items = await GetCompletionItemsAsync(markup, SourceCodeKind.Regular);
Assert.Equal(
["myClass", "my", "@class", "MyClass", "My", "Class", "GetMyClass", "GetMy", "GetClass"],
items.Select(item => item.DisplayText));
}
[Fact]
public async Task TestDescriptionInsideClass()
{
var markup = """
public class MyClass
{
MyClass $$
}
""";
await VerifyItemExistsAsync(markup, "myClass", glyph: (int)Glyph.FieldPublic, expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemExistsAsync(markup, "MyClass", glyph: (int)Glyph.PropertyPublic, expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemExistsAsync(markup, "GetMyClass", glyph: (int)Glyph.MethodPublic, expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact]
public async Task TestDescriptionInsideMethod()
{
var markup = """
public class MyClass
{
void M()
{
MyClass $$
}
}
""";
await VerifyItemExistsAsync(markup, "myClass", glyph: (int)Glyph.Local, expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemIsAbsentAsync(markup, "MyClass");
await VerifyItemIsAbsentAsync(markup, "GetMyClass");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20273")]
public async Task Alias1()
{
var markup = """
using MyType = System.String;
public class C
{
MyType $$
}
""";
await VerifyItemExistsAsync(markup, "my");
await VerifyItemExistsAsync(markup, "type");
await VerifyItemExistsAsync(markup, "myType");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20273")]
public async Task AliasWithInterfacePattern()
{
var markup = """
using IMyType = System.String;
public class C
{
MyType $$
}
""";
await VerifyItemExistsAsync(markup, "my");
await VerifyItemExistsAsync(markup, "type");
await VerifyItemExistsAsync(markup, "myType");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20016")]
public async Task NotAfterExistingName1()
{
var markup = """
using IMyType = System.String;
public class C
{
MyType myType $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20016")]
public async Task NotAfterExistingName2()
{
var markup = """
using IMyType = System.String;
public class C
{
MyType myType, MyType $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19409")]
public async Task OutVarArgument()
{
var markup = """
class Test
{
void Do(out Test goo)
{
Do(out var $$
}
}
""";
await VerifyItemExistsAsync(markup, "test");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19409")]
public async Task OutArgument()
{
var markup = """
class Test
{
void Do(out Test goo)
{
Do(out Test $$
}
}
""";
await VerifyItemExistsAsync(markup, "test");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19409")]
public async Task OutGenericArgument()
{
var markup = """
class Test
{
void Do<T>(out T goo)
{
Do(out Test $$
}
}
""";
await VerifyItemExistsAsync(markup, "test");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleExpressionDeclaration1()
{
var markup = """
class Test
{
void Do()
{
(System.Array array, System.Action $$
}
}
""";
await VerifyItemExistsAsync(markup, "action");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleExpressionDeclaration2()
{
var markup = """
class Test
{
void Do()
{
(array, action $$
}
}
""";
await VerifyItemIsAbsentAsync(markup, "action");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleExpressionDeclaration_NestedTuples()
{
var markup = """
class Test
{
void Do()
{
((int i1, int i2), (System.Array array, System.Action $$
}
}
""";
await VerifyItemExistsAsync(markup, "action");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleExpressionDeclaration_NestedTuples_CompletionInTheMiddle()
{
var markup = """
class Test
{
void Do()
{
((System.Array array, System.Action $$), (int i1, int i2))
}
}
""";
await VerifyItemExistsAsync(markup, "action");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition1()
{
var markup = """
class Test
{
void Do()
{
(System.Array $$
}
}
""";
await VerifyItemExistsAsync(markup, "array");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition2()
{
var markup = """
class Test
{
(System.Array $$) Test() => default;
}
""";
await VerifyItemExistsAsync(markup, "array");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition3()
{
var markup = """
class Test
{
(System.Array array, System.Action $$) Test() => default;
}
""";
await VerifyItemExistsAsync(markup, "action");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition4()
{
var markup = """
class Test
{
(System.Array $$
}
""";
await VerifyItemExistsAsync(markup, "array");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition5()
{
var markup = """
class Test
{
void M((System.Array $$
}
""";
await VerifyItemExistsAsync(markup, "array");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition_NestedTuples()
{
var markup = """
class Test
{
void M(((int, int), (int, System.Array $$
}
""";
await VerifyItemExistsAsync(markup, "array");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementDefinition_InMiddleOfTuple()
{
var markup = """
class Test
{
void M((int, System.Array $$),int)
}
""";
await VerifyItemExistsAsync(markup, "array");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementTypeInference()
{
var markup = """
class Test
{
void Do()
{
(var accessViolationException, var $$) = (new AccessViolationException(), new Action(() => { }));
}
}
""";
// Currently not supported:
await VerifyItemIsAbsentAsync(markup, "action");
// see https://github.com/dotnet/roslyn/issues/27138
// after the issue ist fixed we expect this to work:
// await VerifyItemExistsAsync(markup, "action");
}
[Fact(Skip = "Not yet supported")]
[WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementInGenericTypeArgument()
{
var markup = """
class Test
{
void Do()
{
System.Func<(System.Action $$
}
}
""";
await VerifyItemExistsAsync(markup, "action");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22342")]
public async Task TupleElementInvocationInsideTuple()
{
var markup = """
class Test
{
void Do()
{
int M(int i1, int i2) => i1;
var t=(e1: 1, e2: M(1, $$));
}
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17987")]
public async Task Pluralize1()
{
var markup = """
using System.Collections.Generic;
class Index
{
IEnumerable<Index> $$
}
""";
await VerifyItemExistsAsync(markup, "Indices");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17987")]
public async Task Pluralize2()
{
var markup = """
using System.Collections.Generic;
class Test
{
IEnumerable<IEnumerable<Test>> $$
}
""";
await VerifyItemExistsAsync(markup, "tests");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17987")]
public async Task Pluralize3()
{
var markup = """
using System.Collections.Generic;
using System.Threading;
class Test
{
IEnumerable<CancellationToken> $$
}
""";
await VerifyItemExistsAsync(markup, "cancellationTokens");
await VerifyItemExistsAsync(markup, "cancellations");
await VerifyItemExistsAsync(markup, "tokens");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17987")]
public async Task PluralizeList()
{
var markup = """
using System.Collections.Generic;
using System.Threading;
class Test
{
List<CancellationToken> $$
}
""";
await VerifyItemExistsAsync(markup, "cancellationTokens");
await VerifyItemExistsAsync(markup, "cancellations");
await VerifyItemExistsAsync(markup, "tokens");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17987")]
public async Task PluralizeArray()
{
var markup = """
using System.Collections.Generic;
using System.Threading;
class Test
{
CancellationToken[] $$
}
""";
await VerifyItemExistsAsync(markup, "cancellationTokens");
await VerifyItemExistsAsync(markup, "cancellations");
await VerifyItemExistsAsync(markup, "tokens");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37366")]
public async Task PluralizeSpan()
{
var markup = """
using System;
class Test
{
void M(Span<Test> $$) { }
}
""" + Span;
await VerifyItemExistsAsync(markup, "tests");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37366")]
public async Task PluralizeValidGetEnumerator()
{
var markup = """
class MyClass
{
public void M(MyOwnCollection<MyClass> $$) { }
}
class MyOwnCollection<T>
{
public MyEnumerator GetEnumerator()
{
return new MyEnumerator();
}
public class MyEnumerator
{
public T Current { get; }
public bool MoveNext() { return false; }
}
}
""";
await VerifyItemExistsAsync(markup, "myClasses");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37366")]
public async Task PluralizeValidGetAsyncEnumerator()
{
var markup = """
using System.Threading.Tasks;
class MyClass
{
public void M(MyOwnCollection<MyClass> $$) { }
}
class MyOwnCollection<T>
{
public MyEnumerator GetAsyncEnumerator()
{
return new MyEnumerator();
}
public class MyEnumerator
{
public T Current { get; }
public Task<bool> MoveNextAsync() { return Task.FromResult(false); }
}
}
""";
await VerifyItemExistsAsync(markup, "myClasses");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37366")]
public async Task PluralizeForUnimplementedIEnumerable()
{
var markup = """
using System.Collections.Generic;
class MyClass
{
public void M(MyOwnCollection<MyClass> $$) { }
}
class MyOwnCollection<T> : IEnumerable<T>
{
}
""";
await VerifyItemExistsAsync(markup, "myClasses");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37366")]
public async Task PluralizeForUnimplementedIAsyncEnumerable()
{
var markup = """
using System.Collections.Generic;
class MyClass
{
public void M(MyOwnCollection<MyClass> $$) { }
}
class MyOwnCollection<T> : IAsyncEnumerable<T>
{
}
""" + IAsyncEnumerable;
await VerifyItemExistsAsync(markup, "myClasses");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23497")]
public async Task InPatternMatching1()
{
var markup = """
using System.Threading;
public class C
{
public static void Main()
{
object obj = null;
if (obj is CancellationToken $$) { }
}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "cancellation");
await VerifyItemExistsAsync(markup, "token");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23497")]
public async Task InPatternMatching2()
{
var markup = """
using System.Threading;
public class C
{
public static bool Foo()
{
object obj = null;
return obj is CancellationToken $$
}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "cancellation");
await VerifyItemExistsAsync(markup, "token");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23497")]
public async Task InPatternMatching3()
{
var markup = """
using System.Threading;
public class C
{
public static void Main()
{
object obj = null;
switch(obj)
{
case CancellationToken $$
}
}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "cancellation");
await VerifyItemExistsAsync(markup, "token");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23497")]
public async Task InPatternMatching4()
{
var markup = """
using System.Threading;
public class C
{
public static void Main()
{
object obj = null;
if (obj is CancellationToken ca$$) { }
}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "cancellation");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23497")]
public async Task InPatternMatching5()
{
var markup = """
using System.Threading;
public class C
{
public static bool Foo()
{
object obj = null;
return obj is CancellationToken to$$
}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "token");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23497")]
public async Task InPatternMatching6()
{
var markup = """
using System.Threading;
public class C
{
public static void Main()
{
object obj = null;
switch(obj)
{
case CancellationToken to$$
}
}
}
""";
await VerifyItemExistsAsync(markup, "cancellationToken");
await VerifyItemExistsAsync(markup, "token");
}
[Fact]
public async Task InUsingStatement1()
{
var markup = """
using System.IO;
class C
{
void M()
{
using (StreamReader s$$
}
}
""";
await VerifyItemExistsAsync(markup, "streamReader");
}
[Fact]
public async Task InUsingStatement2()
{
var markup = """
using System.IO;
class C
{
void M()
{
using (StreamReader s1, $$
}
}
""";
await VerifyItemExistsAsync(markup, "streamReader");
}
[Fact]
public async Task InUsingStatement_Var()
{
var markup = """
using System.IO;
class C
{
void M()
{
using (var m$$ = new MemoryStream())
}
}
""";
await VerifyItemExistsAsync(markup, "memoryStream");
}
[Fact]
public async Task InForStatement1()
{
var markup = """
using System.IO;
class C
{
void M()
{
for (StreamReader s$$
}
}
""";
await VerifyItemExistsAsync(markup, "streamReader");
}
[Fact]
public async Task InForStatement2()
{
var markup = """
using System.IO;
class C
{
void M()
{
for (StreamReader s1, $$
}
}
""";
await VerifyItemIsAbsentAsync(markup, "streamReader");
}
[Fact]
public async Task InForStatement_Var()
{
var markup = """
using System.IO;
class C
{
void M()
{
for (var m$$ = new MemoryStream();
}
}
""";
await VerifyItemExistsAsync(markup, "memoryStream");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/26021")]
public async Task InForEachStatement()
{
var markup = """
using System.IO;
class C
{
void M()
{
foreach (StreamReader $$
}
}
""";
await VerifyItemExistsAsync(markup, "streamReader");
}
[Fact]
public async Task InForEachStatement_Var()
{
var markup = """
using System.IO;
class C
{
void M()
{
foreach (var m$$ in new[] { new MemoryStream() })
}
}
""";
await VerifyItemExistsAsync(markup, "memoryStream");
}
[Fact]
public async Task DisabledByOption()
{
ShowNameSuggestions = false;
var markup = """
class Test
{
Test $$
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsIEnumerableOfType()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method()
{
Container $$
}
}
public class Container : ContainerBase { }
public class ContainerBase : IEnumerable<ContainerBase> { }
""";
await VerifyItemExistsAsync(markup, "container");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsIEnumerableOfType2()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method()
{
Container $$
}
}
public class ContainerBase : IEnumerable<Container> { }
public class Container : ContainerBase { }
""";
await VerifyItemExistsAsync(markup, "container");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsIEnumerableOfType3()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method()
{
Container $$
}
}
public class Container : IEnumerable<Container> { }
""";
await VerifyItemExistsAsync(markup, "container");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsIEnumerableOfType4()
{
var markup = """
using System.Collections.Generic;
using System.Threading.Tasks;
public class Class1
{
public void Method()
{
TaskType $$
}
}
public class ContainerBase : IEnumerable<Container> { }
public class Container : ContainerBase { }
public class TaskType : Task<Container> { }
""";
await VerifyItemExistsAsync(markup, "taskType");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsTaskOfType()
{
var markup = """
using System.Threading.Tasks;
public class Class1
{
public void Method()
{
Container $$
}
}
public class Container : ContainerBase { }
public class ContainerBase : Task<ContainerBase> { }
""";
await VerifyItemExistsAsync(markup, "container");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsTaskOfType2()
{
var markup = """
using System.Threading.Tasks;
public class Class1
{
public void Method()
{
Container $$
}
}
public class Container : Task<ContainerBase> { }
public class ContainerBase : Container { }
""";
await VerifyItemExistsAsync(markup, "container");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeImplementsTaskOfType3()
{
var markup = """
using System.Collections.Generic;
using System.Threading.Tasks;
public class Class1
{
public void Method()
{
EnumerableType $$
}
}
public class TaskType : TaskTypeBase { }
public class TaskTypeBase : Task<TaskTypeBase> { }
public class EnumerableType : IEnumerable<TaskType> { }
""";
await VerifyItemExistsAsync(markup, "taskTypes");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23590")]
public async Task TypeIsNullableOfNullable()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method()
{
// This code isn't legal, but we want to ensure we don't crash in this broken code scenario
IEnumerable<Nullable<int?>> $$
}
}
""";
await VerifyItemExistsAsync(markup, "nullables");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
[WorkItem("https://developercommunity2.visualstudio.com/t/Regression-from-1675-Suggested-varia/1220195")]
public async Task TypeIsNullableStructInLocalWithNullableTypeName()
{
var markup = """
using System;
public struct ImmutableArray<T> : System.Collections.Generic.IEnumerable<T> { }
public class Class1
{
public void Method()
{
Nullable<ImmutableArray<int>> $$
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
[WorkItem("https://developercommunity2.visualstudio.com/t/Regression-from-1675-Suggested-varia/1220195")]
public async Task TypeIsNullableStructInLocalWithQuestionMark()
{
var markup = """
using System.Collections.Immutable;
public struct ImmutableArray<T> : System.Collections.Generic.IEnumerable<T> { }
public class Class1
{
public void Method()
{
ImmutableArray<int>? $$
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
[WorkItem("https://developercommunity2.visualstudio.com/t/Regression-from-1675-Suggested-varia/1220195")]
public async Task TypeIsNullableReferenceInLocal()
{
var markup = """
#nullable enable
using System.Collections.Generic;
public class Class1
{
public void Method()
{
IEnumerable<int>? $$
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
[WorkItem("https://developercommunity2.visualstudio.com/t/Regression-from-1675-Suggested-varia/1220195")]
public async Task TypeIsNullableStructInParameterWithNullableTypeName()
{
var markup = """
using System;
public struct ImmutableArray<T> : System.Collections.Generic.IEnumerable<T> { }
public class Class1
{
public void Method(Nullable<ImmutableArray<int>> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
[WorkItem("https://developercommunity2.visualstudio.com/t/Regression-from-1675-Suggested-varia/1220195")]
public async Task TypeIsNullableStructInParameterWithQuestionMark()
{
var markup = """
public struct ImmutableArray<T> : System.Collections.Generic.IEnumerable<T> { }
public class Class1
{
public void Method(ImmutableArray<int>? $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
[WorkItem("https://developercommunity2.visualstudio.com/t/Regression-from-1675-Suggested-varia/1220195")]
public async Task TypeIsNullableReferenceInParameter()
{
var markup = """
#nullable enable
using System.Collections.Generic;
public class Class1
{
public void Method(IEnumerable<int>? $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableParameterOfUnmanagedType()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method(IEnumerable<int> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "ints");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableParameterOfObject()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method(IEnumerable<object> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "objects");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableParameterOfString()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method(IEnumerable<string> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "strings");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableGenericTParameter()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method<T>(IEnumerable<T> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "values");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableGenericTNameParameter()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method<TResult>(IEnumerable<TResult> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "results");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableGenericUnexpectedlyNamedParameter()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method<Arg>(IEnumerable<Arg> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "args");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36364")]
public async Task EnumerableGenericUnexpectedlyNamedParameterBeginsWithT()
{
var markup = """
using System.Collections.Generic;
public class Class1
{
public void Method<Type>(IEnumerable<Type> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "types");
}
[Fact]
public async Task CustomNamingStyleInsideClass()
{
using var workspaceFixture = GetOrCreateWorkspaceFixture();
var workspace = workspaceFixture.Target.GetWorkspace(GetComposition());
workspace.SetAnalyzerFallbackOptions(new OptionsCollection(LanguageNames.CSharp)
{
{ NamingStyleOptions.NamingPreferences, NamesEndWithSuffixPreferences() }
});
var markup = """
class Configuration
{
Configuration $$
}
""";
await VerifyItemExistsAsync(markup, "ConfigurationField", glyph: (int)Glyph.FieldPublic,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemExistsAsync(markup, "ConfigurationProperty", glyph: (int)Glyph.PropertyPublic,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemExistsAsync(markup, "ConfigurationMethod", glyph: (int)Glyph.MethodPublic,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemIsAbsentAsync(markup, "ConfigurationLocal");
await VerifyItemIsAbsentAsync(markup, "ConfigurationLocalFunction");
}
[Fact]
public async Task CustomNamingStyleInsideMethod()
{
using var workspaceFixture = GetOrCreateWorkspaceFixture();
var workspace = workspaceFixture.Target.GetWorkspace(GetComposition());
workspace.SetAnalyzerFallbackOptions(new OptionsCollection(LanguageNames.CSharp)
{
{ NamingStyleOptions.NamingPreferences, NamesEndWithSuffixPreferences() }
});
var markup = """
class Configuration
{
void M()
{
Configuration $$
}
}
""";
await VerifyItemExistsAsync(markup, "ConfigurationLocal", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemExistsAsync(markup, "ConfigurationLocalFunction", glyph: (int)Glyph.MethodPublic,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
await VerifyItemIsAbsentAsync(markup, "ConfigurationField");
await VerifyItemIsAbsentAsync(markup, "ConfigurationMethod");
await VerifyItemIsAbsentAsync(markup, "ConfigurationProperty");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionDoesNotUseForeachVariableName()
{
var markup = """
class ClassA
{
class ClassB {}
readonly List<ClassB> classBList;
void M()
{
foreach (var classB in classBList)
{
ClassB $$
}
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
await VerifyItemExistsAsync(markup, "classB1", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionDoesNotUseParameterName()
{
var markup = """
class ClassA
{
class ClassB { }
void M(ClassB classB)
{
ClassB $$
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
await VerifyItemExistsAsync(markup, "classB1", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionCanUsePropertyName()
{
var markup = """
class ClassA
{
class ClassB { }
ClassB classB { get; set; }
void M()
{
ClassB $$
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionCanUseFieldName()
{
var markup = """
class ClassA
{
class ClassB { }
ClassB classB;
void M()
{
ClassB $$
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionDoesNotUseLocalName()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
ClassB $$
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
await VerifyItemExistsAsync(markup, "classB1", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionDoesNotUseLocalNameMultiple()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
ClassB classB1 = new ClassB();
ClassB $$
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
await VerifyItemIsAbsentAsync(markup, "classB1");
await VerifyItemExistsAsync(markup, "classB2", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionDoesNotUseLocalInsideIf()
{
var markup = """
class ClassA
{
class ClassB { }
void M(bool flag)
{
ClassB $$
if (flag)
{
ClassB classB = new ClassB();
}
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
await VerifyItemExistsAsync(markup, "classB1", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionCanUseClassName()
{
var markup = """
class classA
{
void M()
{
classA $$
}
}
""";
await VerifyItemExistsAsync(markup, "classA", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31304")]
public async Task TestCompletionCanUseLocalInDifferentScope()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
}
void M2()
{
ClassB $$
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[InlineData(LanguageVersion.CSharp7)]
[InlineData(LanguageVersion.CSharp8)]
[InlineData(LanguageVersion.Latest)]
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
[WorkItem("https://github.com/dotnet/roslyn/issues/42049")]
public async Task TestUseLocalAsLocalFunctionParameter(LanguageVersion languageVersion)
{
var source = """
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
void LocalM1(ClassB $$) { }
}
}
""";
var markup = GetMarkup(source, languageVersion);
if (languageVersion.MapSpecifiedToEffectiveVersion() >= LanguageVersion.CSharp8)
{
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Parameter,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
else
{
await VerifyItemIsAbsentAsync(markup, "classB");
}
}
[InlineData(LanguageVersion.CSharp7)]
[InlineData(LanguageVersion.CSharp8)]
[InlineData(LanguageVersion.Latest)]
[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
[WorkItem("https://github.com/dotnet/roslyn/issues/42049")]
public async Task TestCompletionDoesNotUseLocalAsLocalFunctionVariable(LanguageVersion languageVersion)
{
var source = """
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
void LocalM1()
{
ClassB $$
}
}
}
""";
var markup = GetMarkup(source, languageVersion);
await VerifyItemIsAbsentAsync(markup, "classB");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
public async Task TestCompletionDoesNotUseLocalInNestedLocalFunction()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
ClassB classB = new ClassB();
void LocalM1()
{
void LocalM2()
{
ClassB $$
}
}
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
public async Task TestCompletionDoesNotUseLocalFunctionParameterInNestedLocalFunction()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
void LocalM1(ClassB classB)
{
void LocalM2()
{
ClassB $$
}
}
}
}
""";
await VerifyItemIsAbsentAsync(markup, "classB");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
public async Task TestCompletionCanUseLocalFunctionParameterAsParameter()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
void LocalM1(ClassB classB) { }
void LocalM2(ClassB $$) { }
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Parameter,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
public async Task TestCompletionCanUseLocalFunctionVariableAsParameter()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
void LocalM1()
{
ClassB classB
}
void LocalM2(ClassB $$) { }
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Parameter,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
public async Task TestCompletionCanUseLocalFunctionParameterAsVariable()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
void LocalM1(ClassB classB) { }
void LocalM2()
{
ClassB $$
}
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35891")]
public async Task TestCompletionCanUseLocalFunctionVariableAsVariable()
{
var markup = """
class ClassA
{
class ClassB { }
void M()
{
void LocalM1()
{
ClassB classB
}
void LocalM2()
{
ClassB $$
}
}
}
""";
await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local,
expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name);
}
[Fact]
public async Task TestNotForUnboundAsync()
{
var markup = """
class C
{
async $$
}
""";
await VerifyItemIsAbsentAsync(markup, "async");
await VerifyItemIsAbsentAsync(markup, "Async");
await VerifyItemIsAbsentAsync(markup, "GetAsync");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/pull/43816")]
public async Task ConflictingLocalVariable()
{
using var workspaceFixture = GetOrCreateWorkspaceFixture();
var workspace = workspaceFixture.Target.GetWorkspace(GetComposition());
workspace.SetAnalyzerFallbackOptions(new OptionsCollection(LanguageNames.CSharp)
{
{ NamingStyleOptions.NamingPreferences, MultipleCamelCaseLocalRules() }
});
var markup = """
public class MyClass
{
void M()
{
MyClass myClass;
MyClass $$
}
}
""";
await VerifyItemExistsAsync(markup, "myClass1", glyph: (int)Glyph.Local);
}
[Fact]
public async Task TestNotForNonTypeSymbol()
{
var markup = """
using System;
class C
{
Console.BackgroundColor $$
}
""";
await VerifyItemIsAbsentAsync(markup, "consoleColor");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/29487")]
public async Task TestForOutParam1()
{
var markup = """
using System.Threading;
class C
{
void Main()
{
Goo(out var $$)
}
void Goo(out CancellationToken interestingName)
{
}
}
""";
await VerifyItemExistsAsync(markup, "interestingName");
await VerifyItemExistsAsync(markup, "cancellationToken");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43602")]
public async Task TestForOutParam2()
{
var markup = """
class C
{
void Main()
{
int.TryParse("", out var $$)
}
}
""";
await VerifyItemExistsAsync(markup, "result");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49791")]
public async Task TestForErrorType1()
{
var markup = """
class C
{
void Main(string _rootPath)
{
_rootPath $$
_rootPath = null;
}
}
""";
await VerifyNoItemsExistAsync(markup);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49791")]
public async Task TestForErrorType2()
{
var markup = """
class C
{
void Main()
{
Goo $$
Goo = null;
}
}
""";
await VerifyItemExistsAsync(markup, "goo");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36352")]
public async Task InferCollectionInErrorCase1()
{
var markup = """
class Customer { }
class V
{
void M(IEnumerable<Customer> $$)
{
}
}
""";
await VerifyItemExistsAsync(markup, "customers");
}
private static NamingStylePreferences MultipleCamelCaseLocalRules()
{
var styles = new[]
{
SpecificationStyle(new SymbolKindOrTypeKind(SymbolKind.Local), name: "Local1"),
SpecificationStyle(new SymbolKindOrTypeKind(SymbolKind.Local), name: "Local1"),
};
return new NamingStylePreferences(
styles.Select(t => t.specification).ToImmutableArray(),
styles.Select(t => t.style).ToImmutableArray(),
styles.Select(t => CreateRule(t.specification, t.style)).ToImmutableArray());
// Local functions
static (SymbolSpecification specification, NamingStyle style) SpecificationStyle(SymbolKindOrTypeKind kind, string name)
{
var symbolSpecification = new SymbolSpecification(
Guid.NewGuid(),
name,
ImmutableArray.Create(kind));
var namingStyle = new NamingStyle(
Guid.NewGuid(),
name,
capitalizationScheme: Capitalization.CamelCase);
return (symbolSpecification, namingStyle);
}
}
private static NamingStylePreferences NamesEndWithSuffixPreferences()
{
var specificationStyles = new[]
{
SpecificationStyle(new SymbolKindOrTypeKind(SymbolKind.Field), "Field"),
SpecificationStyle(new SymbolKindOrTypeKind(SymbolKind.Property), "Property"),
SpecificationStyle(new SymbolKindOrTypeKind(MethodKind.Ordinary), "Method"),
SpecificationStyle(new SymbolKindOrTypeKind(SymbolKind.Local), "Local"),
SpecificationStyle(new SymbolKindOrTypeKind(MethodKind.LocalFunction), "LocalFunction"),
};
return new NamingStylePreferences(
specificationStyles.Select(t => t.specification).ToImmutableArray(),
specificationStyles.Select(t => t.style).ToImmutableArray(),
specificationStyles.Select(t => CreateRule(t.specification, t.style)).ToImmutableArray());
// Local functions
static (SymbolSpecification specification, NamingStyle style) SpecificationStyle(SymbolKindOrTypeKind kind, string suffix)
{
var symbolSpecification = new SymbolSpecification(
Guid.NewGuid(),
name: suffix,
ImmutableArray.Create(kind),
accessibilityList: default,
modifiers: default);
var namingStyle = new NamingStyle(
Guid.NewGuid(),
name: suffix,
capitalizationScheme: Capitalization.PascalCase,
prefix: "",
suffix: suffix,
wordSeparator: "");
return (symbolSpecification, namingStyle);
}
}
private static NamingStylePreferences ParameterCamelCaseWithPascalCaseFallback()
{
var symbolSpecifications = ImmutableArray.Create(
new SymbolSpecification(
id: Guid.NewGuid(),
name: "parameters",
ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter)),
accessibilityList: default,
modifiers: default),
new SymbolSpecification(
id: Guid.NewGuid(),
name: "fallback",
ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter), new SymbolKindOrTypeKind(SymbolKind.Local)),
accessibilityList: default,
modifiers: default));
var namingStyles = ImmutableArray.Create(
new NamingStyle(
Guid.NewGuid(),
name: "parameter",
capitalizationScheme: Capitalization.CamelCase,
prefix: "",
suffix: "",
wordSeparator: ""),
new NamingStyle(
Guid.NewGuid(),
name: "any_symbol",
capitalizationScheme: Capitalization.PascalCase,
prefix: "",
suffix: "",
wordSeparator: ""));
return new NamingStylePreferences(
symbolSpecifications,
namingStyles,
namingRules: ImmutableArray.Create(
CreateRule(symbolSpecifications[0], namingStyles[0]),
CreateRule(symbolSpecifications[1], namingStyles[1])));
}
private static SerializableNamingRule CreateRule(SymbolSpecification specification, NamingStyle style)
=> new()
{
SymbolSpecificationID = specification.ID,
NamingStyleID = style.ID,
EnforcementLevel = ReportDiagnostic.Error
};
}
|