Skip to content
Merged
1 change: 1 addition & 0 deletions samples/ReadmeSample/ReadmeSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\EntityFrameworkCore.Projectables.Generator\EntityFrameworkCore.Projectables.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\EntityFrameworkCore.Projectables.CodeFixes\EntityFrameworkCore.Projectables.CodeFixes.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\EntityFrameworkCore.Projectables\EntityFrameworkCore.Projectables.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;

namespace EntityFrameworkCore.Projectables.CodeFixes;

/// <summary>
/// Code refactoring provider that converts a <c>[Projectable]</c> factory method whose body is
/// an object-initializer expression (<c>=> new T { … }</c>) into a <c>[Projectable]</c>
/// constructor of the same class.
/// <para>
/// Two refactoring actions are offered:
/// <list type="number">
/// <item><description>Convert the factory method to a constructor (current document only).</description></item>
/// <item><description>Convert the factory method to a constructor <em>and</em> replace all
/// callers throughout the solution with <c>new T(…)</c> invocations.</description></item>
/// </list>
/// </para>
/// <para>
/// This provider is complementary to <see cref="FactoryMethodToCtorCodeFixProvider"/>,
/// which fixes the <c>EFP0012</c> diagnostic. The refactoring provider remains useful when
/// the diagnostic is suppressed.
/// </para>
/// <para>
/// A public parameterless constructor is automatically inserted when the class does not already
/// have one, preserving the implicit default constructor that would otherwise be lost.
/// </para>
/// </summary>
[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = nameof(FactoryMethodToConstructorCodeRefactoringProvider))]
[Shared]
public sealed class FactoryMethodToConstructorCodeRefactoringProvider : CodeRefactoringProvider
{
/// <inheritdoc />
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root is null)
{
return;
}

var node = root.FindNode(context.Span);

if (!ProjectableCodeFixHelper.TryGetFixableFactoryMethodPattern(node, out var containingType, out var method))
{
return;
}

context.RegisterRefactoring(
CodeAction.Create(
title: "Convert [Projectable] factory method to constructor",
createChangedDocument: ct =>
FactoryMethodTransformationHelper.ConvertToConstructorAsync(
context.Document, method!, containingType!, ct),
equivalenceKey: "EFP_FactoryToConstructor"));

context.RegisterRefactoring(
CodeAction.Create(
title: "Convert [Projectable] factory method to constructor (and update callers)",
createChangedSolution: ct =>
FactoryMethodTransformationHelper.ConvertToConstructorAndUpdateCallersAsync(
context.Document, method!, containingType!, ct),
equivalenceKey: "EFP_FactoryToConstructorWithCallers"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;

namespace EntityFrameworkCore.Projectables.CodeFixes;

/// <summary>
/// Code fix provider for <c>EFP0012</c>.
/// Offers two fixes on a <c>[Projectable]</c> factory method that can be a constructor:
/// <list type="number">
/// <item><description>Convert the factory method to a constructor (current document).</description></item>
/// <item><description>Convert the factory method to a constructor <em>and</em> update all
/// callers throughout the solution.</description></item>
/// </list>
/// </summary>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(FactoryMethodToCtorCodeFixProvider))]
[Shared]
public sealed class FactoryMethodToCtorCodeFixProvider : CodeFixProvider
{
/// <inheritdoc />
public override ImmutableArray<string> FixableDiagnosticIds => ["EFP0012"];

/// <inheritdoc />
public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

/// <inheritdoc />
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root is null)
{
return;
}

var node = root.FindNode(context.Span);

if (!ProjectableCodeFixHelper.TryGetFixableFactoryMethodPattern(node, out var containingType, out var method))
{
return;
}

context.RegisterCodeFix(
CodeAction.Create(
title: "Convert [Projectable] factory method to constructor",
createChangedDocument: ct =>
FactoryMethodTransformationHelper.ConvertToConstructorAsync(
context.Document, method!, containingType!, ct),
equivalenceKey: "EFP0012_FactoryToConstructor"),
context.Diagnostics[0]);

context.RegisterCodeFix(
CodeAction.Create(
title: "Convert [Projectable] factory method to constructor (and update callers)",
createChangedSolution: ct =>
FactoryMethodTransformationHelper.ConvertToConstructorAndUpdateCallersAsync(
context.Document, method!, containingType!, ct),
equivalenceKey: "EFP0012_FactoryToConstructorWithCallers"),
context.Diagnostics[0]);
}
}

Loading
Loading