diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs
index 5e47c91..39d69f6 100644
--- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs
+++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs
@@ -224,7 +224,7 @@ public SolutionProjectModel AddProject(string filePath, string? projectTypeName
}
///
- /// Remove a solution folder from the solution model.
+ /// Remove a solution folder from the solution model. This includes any child folders and projects.
///
/// The folder to remove.
/// if the folder was found and removed.
@@ -232,18 +232,8 @@ public bool RemoveFolder(SolutionFolderModel folder)
{
Argument.ThrowIfNull(folder, nameof(folder));
this.ValidateInModel(folder);
- _ = this.solutionFolders.Remove(folder);
- // Remove any children of this folder.
- foreach (SolutionItemModel existingItem in this.SolutionItems)
- {
- if (ReferenceEquals(existingItem.Parent, folder))
- {
- existingItem.MoveToFolder(folder.Parent);
- }
- }
-
- return this.RemoveItem(folder);
+ return this.RemoveFolder(folder, this.SolutionItems.ToArray());
}
///
@@ -637,6 +627,29 @@ private SolutionFolderModel AddFolder(StringSpan name, string? parentItemRef)
return folder;
}
+ // Remove a solution folder from the solution model. This includes any child folders and projects.
+ // Recursive call reuses the solutionItems array to avoid creating a new array for each recursive call.
+ private bool RemoveFolder(SolutionFolderModel folder, SolutionItemModel[] solutionItems)
+ {
+ _ = this.solutionFolders.Remove(folder);
+
+ // Remove any children of this folder.
+ foreach (SolutionItemModel existingItem in solutionItems)
+ {
+ if (ReferenceEquals(existingItem.Parent, folder))
+ {
+ _ = existingItem switch
+ {
+ SolutionFolderModel childFolder => this.RemoveFolder(childFolder, solutionItems),
+ SolutionProjectModel childProject => this.RemoveProject(childProject),
+ _ => throw new InvalidOperationException(),
+ };
+ }
+ }
+
+ return this.RemoveItem(folder);
+ }
+
private bool RemoveItem(SolutionItemModel item)
{
_ = this.solutionItemsById.Remove(item.Id);
diff --git a/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs b/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs
index 810af52..894a8aa 100644
--- a/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs
+++ b/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs
@@ -28,6 +28,8 @@ public void RemoveFolder()
Assert.NotNull(folderNested);
Assert.NotNull(folderFolder);
+ SolutionProjectModel projectInIs = solution.AddProject("ProjectInThis.csproj", folder: folderIs);
+ Assert.NotNull(projectInIs);
SolutionProjectModel projectInA = solution.AddProject("ProjectInA.csproj", folder: folderA);
Assert.NotNull(projectInA);
SolutionProjectModel projectInFolder = solution.AddProject("ProjectInFolder.csproj", folder: folderFolder);
@@ -36,28 +38,31 @@ public void RemoveFolder()
// Remove the middle 'A' folder.
Assert.True(solution.RemoveFolder(folderA));
- // Make sure remaining folders have updated references.
+ // Make sure child folders were removed.
Assert.Equal("/This/", folderThis.ItemRef);
Assert.Equal("/This/Is/", folderIs.ItemRef);
- Assert.Equal("/This/Is/Nested/", folderNested.ItemRef);
- Assert.Equal("/This/Is/Nested/Folder/", folderFolder.ItemRef);
-
- // Make sure projects have updated references.
- Assert.NotNull(projectInA.Parent);
- Assert.Equal("/This/Is/", projectInA.Parent.ItemRef);
-
- Assert.NotNull(projectInFolder.Parent);
- Assert.Equal("/This/Is/Nested/Folder/", projectInFolder.Parent.ItemRef);
-
- // Remove all folders.
- Assert.True(solution.RemoveFolder(folderThis));
+ Assert.Null(solution.FindFolder(folderNested.ItemRef));
+ Assert.Null(solution.FindFolder(folderFolder.ItemRef));
+
+ // Make sure child projects were removed.
+ Assert.Null(solution.FindProject(projectInA.ItemRef));
+ Assert.Null(solution.FindProject(projectInFolder.ItemRef));
+
+ // Make sure project in 'Is' folder was not removed.
+ Assert.NotNull(projectInIs.Parent);
+ Assert.NotNull(solution.FindProject(projectInIs.ItemRef));
+ Assert.NotNull(projectInIs.Parent);
+ Assert.Equal("/This/Is/", projectInIs.Parent.ItemRef);
+
+ // Remove all folders in reverse.
+ Assert.False(solution.RemoveFolder(folderFolder));
+ Assert.False(solution.RemoveFolder(folderNested));
Assert.True(solution.RemoveFolder(folderIs));
- Assert.True(solution.RemoveFolder(folderNested));
- Assert.True(solution.RemoveFolder(folderFolder));
+ Assert.True(solution.RemoveFolder(folderThis));
- // Make sure projects are in root.
- Assert.Null(projectInA.Parent);
- Assert.Null(projectInFolder.Parent);
+ Assert.Empty(solution.SolutionItems);
+ Assert.Empty(solution.SolutionProjects);
+ Assert.Empty(solution.SolutionFolders);
}
///