Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5901,4 +5901,26 @@ internal class Test
public int B { get; set; }
}
""", index: 1);

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49649")]
public Task TestInTopLevelProgram()
=> TestInRegularAndScriptAsync(
"""
var student = new [|Student|]("Youssef");
Console.WriteLine(student.Name);
""",
"""
var student = new Student("Youssef");
Console.WriteLine(student.Name);

internal class Student
{
private string v;

public Student(string v)
{
this.v = v;
}
}
""", index: 1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@
// 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
#if CODE_STYLE
extern alias CODESTYLE_UTILITIES;
#endif

using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Remote.Testing;
using Xunit.Abstractions;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;

public abstract partial class AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest : AbstractDiagnosticProviderBasedUserDiagnosticTest
{
protected AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest(ITestOutputHelper logger)
: base(logger)
{
}
#if CODE_STYLE
using OptionsCollectionAlias = CODESTYLE_UTILITIES::Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.OptionsCollection;
#else
using OptionsCollectionAlias = OptionsCollection;
#endif

public abstract partial class AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest(ITestOutputHelper? logger)
: AbstractDiagnosticProviderBasedUserDiagnosticTest(logger)
{
protected override ParseOptions GetScriptOptions() => Options.Script;

protected internal override string GetLanguage() => LanguageNames.CSharp;
Expand Down Expand Up @@ -158,8 +164,24 @@ public interface IAsyncEnumerator<out T> : IAsyncDisposable
[StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string initialMarkup,
[StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expectedMarkup,
int index = 0,
TestParameters parameters = null)
TestParameters? parameters = null)
{
return base.TestInRegularAndScript1Async(initialMarkup, expectedMarkup, index, parameters);
}

internal new Task TestInRegularAndScriptAsync(
[StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string initialMarkup,
[StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expectedMarkup,
int index = 0,
CodeActionPriority? priority = null,
CompilationOptions? compilationOptions = null,
OptionsCollectionAlias? options = null,
object? fixProviderData = null,
ParseOptions? parseOptions = null,
string? title = null,
TestHost testHost = TestHost.OutOfProcess)
{
return base.TestInRegularAndScriptAsync(
initialMarkup, expectedMarkup, index, priority, compilationOptions, options, fixProviderData, parseOptions, title, testHost);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.PooledObjects;
Expand Down Expand Up @@ -100,7 +101,7 @@ private ImmutableArray<CodeAction> GetActions(
State state,
CancellationToken cancellationToken)
{
using var _ = ArrayBuilder<CodeAction>.GetInstance(out var result);
using var result = TemporaryArray<CodeAction>.Empty;

var generateNewTypeInDialog = false;
if (state.NamespaceToGenerateInOpt != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,15 @@ public static SyntaxList<TDeclaration> Insert<TDeclaration>(
CSharpCodeGenerationContextInfo info,
IList<bool>? availableIndices,
Func<SyntaxList<TDeclaration>, TDeclaration?>? after = null,
Func<SyntaxList<TDeclaration>, TDeclaration?>? before = null)
Func<SyntaxList<TDeclaration>, TDeclaration?>? before = null,
Func<SyntaxList<TDeclaration>, int, bool>? canPlaceAtIndex = null)
where TDeclaration : SyntaxNode
{
var index = GetInsertionIndex(
declarationList, declaration, info, availableIndices,
CSharpDeclarationComparer.WithoutNamesInstance,
CSharpDeclarationComparer.WithNamesInstance,
after, before);
after, before, canPlaceAtIndex);

availableIndices?.Insert(index, true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ public static CompilationUnitSyntax AddNamedTypeTo(
CancellationToken cancellationToken)
{
var declaration = GenerateNamedTypeDeclaration(service, namedType, CodeGenerationDestination.CompilationUnit, info, cancellationToken);
var members = Insert(destination.Members, declaration, info, availableIndices);
var members = Insert(
destination.Members, declaration, info, availableIndices,
// We're adding a named type to a compilation unit. If there are any global statements, we must place it after them.
after: static members => members.LastOrDefault(m => m is GlobalStatementSyntax),
canPlaceAtIndex: static (members, index) => index >= members.Count || members[index] is not GlobalStatementSyntax);
return destination.WithMembers(members);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,14 @@ public static int GetInsertionIndex<TDeclaration>(
IComparer<TDeclaration> comparerWithoutNameCheck,
IComparer<TDeclaration> comparerWithNameCheck,
Func<SyntaxList<TDeclaration>, TDeclaration?>? after = null,
Func<SyntaxList<TDeclaration>, TDeclaration?>? before = null)
Func<SyntaxList<TDeclaration>, TDeclaration?>? before = null,
Func<SyntaxList<TDeclaration>, int, bool>? canPlaceAtIndex = null)
where TDeclaration : SyntaxNode
{
Contract.ThrowIfTrue(availableIndices != null && availableIndices.Count != declarationList.Count + 1);

canPlaceAtIndex ??= static (_, _) => true;

// Try to strictly obey the after option by inserting immediately after the member containing the location
if (info.Context.AfterThisLocation?.SourceTree is { } afterSourceTree &&
afterSourceTree.FilePath == declarationList.FirstOrDefault()?.SyntaxTree.FilePath)
Expand All @@ -207,10 +210,8 @@ public static int GetInsertionIndex<TDeclaration>(
{
var index = declarationList.IndexOf(afterMember);
index = GetPreferredIndex(index + 1, availableIndices, forward: true);
if (index != -1)
{
if (index != -1 && canPlaceAtIndex(declarationList, index))
return index;
}
}
}

Expand Down
Loading