diff --git a/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs b/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs index 160b935861b28..e3ed6efd59edb 100644 --- a/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs +++ b/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs @@ -476,11 +476,15 @@ private static async Task RefactorInitializersAsync( var symbolReferences = await SymbolFinder .FindReferencesAsync(type, solutionEditor.OriginalSolution, cancellationToken).ConfigureAwait(false); var referenceLocations = symbolReferences.SelectMany(reference => reference.Locations); - var documentLookup = referenceLocations.ToLookup(refLoc => refLoc.Document.Id); - foreach (var (documentID, documentLocations) in documentLookup) + var documentLookup = referenceLocations.ToLookup(refLoc => refLoc.Document); + foreach (var (document, documentLocations) in documentLookup) { + // We don't want to process source-generated documents. Make sure we can get back to a real document here. + if (document is SourceGeneratedDocument) + continue; + var documentEditor = await solutionEditor - .GetDocumentEditorAsync(documentID, cancellationToken).ConfigureAwait(false); + .GetDocumentEditorAsync(document.Id, cancellationToken).ConfigureAwait(false); if (documentEditor.OriginalDocument.Project.Language != LanguageNames.CSharp) { // since this is a CSharp-dependent file, we need to have specific VB support. diff --git a/src/Analyzers/CSharp/Tests/ConvertToRecord/ConvertToRecordCodeFixTests.cs b/src/Analyzers/CSharp/Tests/ConvertToRecord/ConvertToRecordCodeFixTests.cs index a09910d3e0a9a..63ad65169d356 100644 --- a/src/Analyzers/CSharp/Tests/ConvertToRecord/ConvertToRecordCodeFixTests.cs +++ b/src/Analyzers/CSharp/Tests/ConvertToRecord/ConvertToRecordCodeFixTests.cs @@ -2,8 +2,6 @@ // 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.Generic; using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; @@ -11,172 +9,169 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Testing; -using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord; + +[Trait(Traits.Feature, Traits.Features.CodeActionsConvertToRecord)] +public class ConvertToRecordCodeFixTests { - [Trait(Traits.Feature, Traits.Features.CodeActionsConvertToRecord)] - public class ConvertToRecordCodeFixTests + [Fact] + public async Task TestMovePropertySimpleRecordInheritance_CodeFix() { - [Fact] - public async Task TestMovePropertySimpleRecordInheritance_CodeFix() - { - var initialMarkup = """ - namespace N + var initialMarkup = """ + namespace N + { + public record B { - public record B - { - public int Foo { get; init; } - } + public int Foo { get; init; } + } - public class C : [|B|] - { - public int P { get; init; } - } + public class C : [|B|] + { + public int P { get; init; } } - """; - var changedMarkup = """ - namespace N + } + """; + var changedMarkup = """ + namespace N + { + public record B { - public record B - { - public int Foo { get; init; } - } - - public record C(int P) : B; + public int Foo { get; init; } } - """; - await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); - } - [Fact] - public async Task TestMovePropertyPositionalParameterRecordInheritance_CodeFix() - { - var initialMarkup = """ - namespace N - { - public record B(int Foo, int Bar); + public record C(int P) : B; + } + """; + await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); + } - public class {|CS1729:C|} : [|B|] - { - public int P { get; init; } - } - } - """; - var changedMarkup = """ - namespace N - { - public record B(int Foo, int Bar); + [Fact] + public async Task TestMovePropertyPositionalParameterRecordInheritance_CodeFix() + { + var initialMarkup = """ + namespace N + { + public record B(int Foo, int Bar); - public record C(int Foo, int Bar, int P) : B(Foo, Bar); + public class {|CS1729:C|} : [|B|] + { + public int P { get; init; } } - """; - await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); - } + } + """; + var changedMarkup = """ + namespace N + { + public record B(int Foo, int Bar); - [Fact] - public async Task TestMovePropertyPositionalParameterRecordInheritanceWithComments_CodeFix() - { - var initialMarkup = """ - namespace N - { - /// B - /// Foo is an int - /// Bar is an int as well - public record B(int Foo, int Bar); + public record C(int Foo, int Bar, int P) : B(Foo, Bar); + } + """; + await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); + } - /// C inherits from B - public class {|CS1729:C|} : [|B|] - { - /// P can be initialized - public int P { get; init; } - } - } - """; - var changedMarkup = """ - namespace N + [Fact] + public async Task TestMovePropertyPositionalParameterRecordInheritanceWithComments_CodeFix() + { + var initialMarkup = """ + namespace N + { + /// B + /// Foo is an int + /// Bar is an int as well + public record B(int Foo, int Bar); + + /// C inherits from B + public class {|CS1729:C|} : [|B|] { - /// B - /// Foo is an int - /// Bar is an int as well - public record B(int Foo, int Bar); - - /// C inherits from B - /// - /// - /// P can be initialized - public record C(int Foo, int Bar, int P) : B(Foo, Bar); + /// P can be initialized + public int P { get; init; } } - """; - await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); - } + } + """; + var changedMarkup = """ + namespace N + { + /// B + /// Foo is an int + /// Bar is an int as well + public record B(int Foo, int Bar); + + /// C inherits from B + /// + /// + /// P can be initialized + public record C(int Foo, int Bar, int P) : B(Foo, Bar); + } + """; + await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); + } - [Fact] - public async Task TestMovePropertyAndReorderWithPositionalParameterRecordInheritance_CodeFix() - { - var initialMarkup = """ - namespace N + [Fact] + public async Task TestMovePropertyAndReorderWithPositionalParameterRecordInheritance_CodeFix() + { + var initialMarkup = """ + namespace N + { + public record B(int Foo, int Bar); + + public class C : [|B|] { - public record B(int Foo, int Bar); + public int P { get; init; } - public class C : [|B|] + public {|CS1729:C|}(int p, int bar, int foo) { - public int P { get; init; } - - public {|CS1729:C|}(int p, int bar, int foo) - { - P = p; - Bar = bar; - Foo = foo; - } + P = p; + Bar = bar; + Foo = foo; } } - """; - var changedMarkup = """ - namespace N - { - public record B(int Foo, int Bar); + } + """; + var changedMarkup = """ + namespace N + { + public record B(int Foo, int Bar); - public record C(int P, int Bar, int Foo) : B(Foo, Bar); - } - """; - await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); - } + public record C(int P, int Bar, int Foo) : B(Foo, Bar); + } + """; + await TestCodeFixAsync(initialMarkup, changedMarkup).ConfigureAwait(false); + } - private class CodeFixTest : CSharpCodeFixVerifier.Test - { - } + private class CodeFixTest : CSharpCodeFixVerifier.Test + { + } - private static async Task TestCodeFixAsync(string initialMarkup, string fixedMarkup) + private static async Task TestCodeFixAsync(string initialMarkup, string fixedMarkup) + { + var test = new CodeFixTest() { - var test = new CodeFixTest() - { - TestCode = initialMarkup, - FixedCode = fixedMarkup, - LanguageVersion = LanguageVersion.CSharp10, - ReferenceAssemblies = Testing.ReferenceAssemblies.Net.Net60, - }; - await test.RunAsync().ConfigureAwait(false); - } + TestCode = initialMarkup, + FixedCode = fixedMarkup, + LanguageVersion = LanguageVersion.CSharp10, + ReferenceAssemblies = Testing.ReferenceAssemblies.Net.Net60, + }; + await test.RunAsync().ConfigureAwait(false); + } - private class TestAnalyzer : DiagnosticAnalyzer - { - public override ImmutableArray SupportedDiagnostics + private class TestAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics #pragma warning disable RS0030 // Do not used banned APIs - => ImmutableArray.Create(new DiagnosticDescriptor( - "CS8865", - "Only records may inherit from records.", - "Only records may inherit from records.", - "Compiler error", - DiagnosticSeverity.Error, - isEnabledByDefault: true)); + => ImmutableArray.Create(new DiagnosticDescriptor( + "CS8865", + "Only records may inherit from records.", + "Only records may inherit from records.", + "Compiler error", + DiagnosticSeverity.Error, + isEnabledByDefault: true)); #pragma warning restore RS0030 // Do not used banned APIs - public override void Initialize(AnalysisContext context) - { - } + public override void Initialize(AnalysisContext context) + { } } } diff --git a/src/Features/CSharpTest/ConvertToRecord/ConvertToRecordCodeRefactoringTests.cs b/src/Features/CSharpTest/ConvertToRecord/ConvertToRecordCodeRefactoringTests.cs index f0fe4191e33dc..105c39fc1c568 100644 --- a/src/Features/CSharpTest/ConvertToRecord/ConvertToRecordCodeRefactoringTests.cs +++ b/src/Features/CSharpTest/ConvertToRecord/ConvertToRecordCodeRefactoringTests.cs @@ -4480,6 +4480,68 @@ public record [|C|](int P) await TestRefactoringAsync(initialMarkup, fixedMarkup); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72067")] + public async Task TestMovePropertiesAndRefactorInitializer_SourceGeneratedDocuments() + { + await new RefactoringTestWithGenerator + { + TestCode = """ + namespace N + { + public class [|C|] + { + public int P { get; init; } + public bool B { get; init; } + } + } + """, + FixedState = + { + Sources = + { + """ + namespace N + { + public record C(int P, bool B); + } + """ + }, + ExpectedDiagnostics = + { + // Microsoft.CodeAnalysis.CSharp.Features.UnitTests\Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord.ConvertToRecordCodeRefactoringTests+ConvertToRecordTestGenerator\file.cs(7,24): error CS7036: There is no argument given that corresponds to the required parameter 'P' of 'C.C(int, bool)' + DiagnosticResult.CompilerError("CS7036").WithSpan(@"Microsoft.CodeAnalysis.CSharp.Features.UnitTests\Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord.ConvertToRecordCodeRefactoringTests+ConvertToRecordTestGenerator\file.cs", 7, 24, 7, 25).WithArguments("P", "N.C.C(int, bool)"), + } + } + }.RunAsync(); + } + + private sealed class ConvertToRecordTestGenerator : ISourceGenerator + { + public void Initialize(GeneratorInitializationContext context) { } + + public void Execute(GeneratorExecutionContext context) + { + context.AddSource( + "file.cs", + """ + namespace N + { + public static class D + { + public static C GetC() + { + return new C + { + P = 0, + B = false + }; + } + } + } + """); + } + } + #region selection [Fact] @@ -4654,6 +4716,14 @@ protected override Workspace CreateWorkspaceImpl() } } + private class RefactoringTestWithGenerator : RefactoringTest + { + protected override IEnumerable GetSourceGenerators() + { + yield return typeof(ConvertToRecordTestGenerator); + } + } + private static async Task TestRefactoringAsync( string initialMarkup, string changedMarkup)