Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove primary ctor when moving a type. #72695

Merged
merged 8 commits into from
Mar 24, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,34 @@ class Class2 { }
await TestMoveTypeToNewFileAsync(code, codeAfterMove, expectedDocumentName, destinationDocumentText, index: 1);
}

[WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72632")]
public async Task MoveNestedTypeToNewFile_Simple_DottedName_WithPrimaryConstructor()
{
var code =
@"internal class Outer()
{
private class Inner[||]
{
}
}";

var codeAfterMove =
@"internal partial class Outer()
{
}";

var expectedDocumentName = "Outer.Inner.cs";

var destinationDocumentText =
@"internal partial class Outer
{
private class Inner
{
}
}";
await TestMoveTypeToNewFileAsync(code, codeAfterMove, expectedDocumentName, destinationDocumentText, index: 1);
}

[WpfFact]
public async Task MoveNestedTypeToNewFile_ParentHasOtherMembers()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private async Task<Document> AddNewDocumentWithSingleTypeDeclarationAsync(Docume
// attributes from the containing partial types. We don't want to create
// duplicate attributes on things.
AddPartialModifiersToTypeChain(
documentEditor, removeAttributesAndComments: true, removeTypeInheritance: true);
documentEditor, removeAttributesAndComments: true, removeTypeInheritance: true, removePrimaryConstructor: true);

// remove things that are not being moved, from the forked document.
var membersToRemove = GetMembersToRemove(root);
Expand Down Expand Up @@ -193,7 +193,7 @@ private async Task<Solution> RemoveTypeFromSourceDocumentAsync(Document sourceDo
// However, keep all the attributes on these types as theses are the
// original attributes and we don't want to mess with them.
AddPartialModifiersToTypeChain(documentEditor,
removeAttributesAndComments: false, removeTypeInheritance: false);
removeAttributesAndComments: false, removeTypeInheritance: false, removePrimaryConstructor: false);
documentEditor.RemoveNode(State.TypeNode, SyntaxRemoveOptions.KeepUnbalancedDirectives);

var updatedDocument = documentEditor.GetChangedDocument();
Expand Down Expand Up @@ -258,7 +258,8 @@ TMemberDeclarationSyntax or
private void AddPartialModifiersToTypeChain(
DocumentEditor documentEditor,
bool removeAttributesAndComments,
bool removeTypeInheritance)
bool removeTypeInheritance,
bool removePrimaryConstructor)
{
var semanticFacts = State.SemanticDocument.Document.GetRequiredLanguageService<ISemanticFactsService>();
var typeChain = State.TypeNode.Ancestors().OfType<TTypeDeclarationSyntax>();
Expand All @@ -283,6 +284,11 @@ private void AddPartialModifiersToTypeChain(
{
documentEditor.RemoveAllTypeInheritance(node);
}

if (removePrimaryConstructor)
{
documentEditor.RemovePrimaryConstructor(node);
}
}

documentEditor.ReplaceNode(State.TypeNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,9 @@ private static SyntaxNode WithAttributeLists(SyntaxNode declaration, SyntaxList<
_ => declaration,
};

internal override SyntaxNode? GetPrimaryConstructorParameterList(SyntaxNode declaration)
=> declaration is TypeDeclarationSyntax { ParameterList: { } parameterList } ? parameterList : null;

internal override ImmutableArray<SyntaxNode> GetTypeInheritance(SyntaxNode declaration)
=> declaration is BaseTypeDeclarationSyntax baseType && baseType.BaseList != null
? [baseType.BaseList]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,7 @@ public static void AddInterfaceType(this SyntaxEditor editor, SyntaxNode declara

public static void AddBaseType(this SyntaxEditor editor, SyntaxNode declaration, SyntaxNode baseType)
=> editor.ReplaceNode(declaration, (d, g) => g.AddBaseType(d, baseType));

internal static void RemovePrimaryConstructor(this SyntaxEditor editor, SyntaxNode declaration)
=> editor.ReplaceNode(declaration, (d, g) => g.RemovePrimaryConstructor(d));
}
8 changes: 8 additions & 0 deletions src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,14 @@ public SyntaxNode RemoveAllAttributes(SyntaxNode declaration)
/// </summary>
internal abstract SyntaxNode RemoveAllComments(SyntaxNode node);

internal SyntaxNode RemovePrimaryConstructor(SyntaxNode declaration)
{
var node = GetPrimaryConstructorParameterList(declaration);
return RemoveNodes(declaration, node is not null ? [node] : []);
}

internal abstract SyntaxNode? GetPrimaryConstructorParameterList(SyntaxNode declaration);

internal SyntaxNode RemoveLeadingAndTrailingComments(SyntaxNode node)
{
return node.WithLeadingTrivia(RemoveCommentLines(node.GetLeadingTrivia()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Return attr.WithTarget(Nothing)
End Function

Friend Overrides Function GetPrimaryConstructorParameterList(declaration As SyntaxNode) As SyntaxNode
Return Nothing
End Function

Friend Overrides Function GetTypeInheritance(declaration As SyntaxNode) As ImmutableArray(Of SyntaxNode)
Dim typeDecl = TryCast(declaration, TypeBlockSyntax)
If typeDecl Is Nothing Then
Expand Down
Loading