Skip to content

Commit 87ee8ea

Browse files
Merge pull request #81 from microsoft/users/richsta/removefolderrecursive
Change RemoveFolder behavior to recursively remove child items.
2 parents 47f9b31 + 0fa6109 commit 87ee8ea

2 files changed

Lines changed: 48 additions & 30 deletions

File tree

  • src/Microsoft.VisualStudio.SolutionPersistence/Model
  • test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization

src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,26 +224,16 @@ public SolutionProjectModel AddProject(string filePath, string? projectTypeName
224224
}
225225

226226
/// <summary>
227-
/// Remove a solution folder from the solution model.
227+
/// Remove a solution folder from the solution model. This includes any child folders and projects.
228228
/// </summary>
229229
/// <param name="folder">The folder to remove.</param>
230230
/// <returns><see langword="true"/> if the folder was found and removed.</returns>
231231
public bool RemoveFolder(SolutionFolderModel folder)
232232
{
233233
Argument.ThrowIfNull(folder, nameof(folder));
234234
this.ValidateInModel(folder);
235-
_ = this.solutionFolders.Remove(folder);
236235

237-
// Remove any children of this folder.
238-
foreach (SolutionItemModel existingItem in this.SolutionItems)
239-
{
240-
if (ReferenceEquals(existingItem.Parent, folder))
241-
{
242-
existingItem.MoveToFolder(folder.Parent);
243-
}
244-
}
245-
246-
return this.RemoveItem(folder);
236+
return this.RemoveFolder(folder, this.SolutionItems.ToArray());
247237
}
248238

249239
/// <summary>
@@ -637,6 +627,29 @@ private SolutionFolderModel AddFolder(StringSpan name, string? parentItemRef)
637627
return folder;
638628
}
639629

630+
// Remove a solution folder from the solution model. This includes any child folders and projects.
631+
// Recursive call reuses the solutionItems array to avoid creating a new array for each recursive call.
632+
private bool RemoveFolder(SolutionFolderModel folder, SolutionItemModel[] solutionItems)
633+
{
634+
_ = this.solutionFolders.Remove(folder);
635+
636+
// Remove any children of this folder.
637+
foreach (SolutionItemModel existingItem in solutionItems)
638+
{
639+
if (ReferenceEquals(existingItem.Parent, folder))
640+
{
641+
_ = existingItem switch
642+
{
643+
SolutionFolderModel childFolder => this.RemoveFolder(childFolder, solutionItems),
644+
SolutionProjectModel childProject => this.RemoveProject(childProject),
645+
_ => throw new InvalidOperationException(),
646+
};
647+
}
648+
}
649+
650+
return this.RemoveItem(folder);
651+
}
652+
640653
private bool RemoveItem(SolutionItemModel item)
641654
{
642655
_ = this.solutionItemsById.Remove(item.Id);

test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public void RemoveFolder()
2828
Assert.NotNull(folderNested);
2929
Assert.NotNull(folderFolder);
3030

31+
SolutionProjectModel projectInIs = solution.AddProject("ProjectInThis.csproj", folder: folderIs);
32+
Assert.NotNull(projectInIs);
3133
SolutionProjectModel projectInA = solution.AddProject("ProjectInA.csproj", folder: folderA);
3234
Assert.NotNull(projectInA);
3335
SolutionProjectModel projectInFolder = solution.AddProject("ProjectInFolder.csproj", folder: folderFolder);
@@ -36,28 +38,31 @@ public void RemoveFolder()
3638
// Remove the middle 'A' folder.
3739
Assert.True(solution.RemoveFolder(folderA));
3840

39-
// Make sure remaining folders have updated references.
41+
// Make sure child folders were removed.
4042
Assert.Equal("/This/", folderThis.ItemRef);
4143
Assert.Equal("/This/Is/", folderIs.ItemRef);
42-
Assert.Equal("/This/Is/Nested/", folderNested.ItemRef);
43-
Assert.Equal("/This/Is/Nested/Folder/", folderFolder.ItemRef);
44-
45-
// Make sure projects have updated references.
46-
Assert.NotNull(projectInA.Parent);
47-
Assert.Equal("/This/Is/", projectInA.Parent.ItemRef);
48-
49-
Assert.NotNull(projectInFolder.Parent);
50-
Assert.Equal("/This/Is/Nested/Folder/", projectInFolder.Parent.ItemRef);
51-
52-
// Remove all folders.
53-
Assert.True(solution.RemoveFolder(folderThis));
44+
Assert.Null(solution.FindFolder(folderNested.ItemRef));
45+
Assert.Null(solution.FindFolder(folderFolder.ItemRef));
46+
47+
// Make sure child projects were removed.
48+
Assert.Null(solution.FindProject(projectInA.ItemRef));
49+
Assert.Null(solution.FindProject(projectInFolder.ItemRef));
50+
51+
// Make sure project in 'Is' folder was not removed.
52+
Assert.NotNull(projectInIs.Parent);
53+
Assert.NotNull(solution.FindProject(projectInIs.ItemRef));
54+
Assert.NotNull(projectInIs.Parent);
55+
Assert.Equal("/This/Is/", projectInIs.Parent.ItemRef);
56+
57+
// Remove all folders in reverse.
58+
Assert.False(solution.RemoveFolder(folderFolder));
59+
Assert.False(solution.RemoveFolder(folderNested));
5460
Assert.True(solution.RemoveFolder(folderIs));
55-
Assert.True(solution.RemoveFolder(folderNested));
56-
Assert.True(solution.RemoveFolder(folderFolder));
61+
Assert.True(solution.RemoveFolder(folderThis));
5762

58-
// Make sure projects are in root.
59-
Assert.Null(projectInA.Parent);
60-
Assert.Null(projectInFolder.Parent);
63+
Assert.Empty(solution.SolutionItems);
64+
Assert.Empty(solution.SolutionProjects);
65+
Assert.Empty(solution.SolutionFolders);
6166
}
6267

6368
/// <summary>

0 commit comments

Comments
 (0)