diff --git a/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs b/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs index e8ea9e6..9d02678 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs +++ b/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs @@ -161,6 +161,12 @@ private void RenameProject(Project project, DTE2 dte) SourceFileService.UpdateUsingStatementsInSolution(dte.Solution, currentName, newName); }); + // Step 11: Update fully qualified type references across the solution + ExecuteStep(progressDialog, stepIndex++, () => + { + SourceFileService.UpdateFullyQualifiedReferencesInSolution(dte.Solution, currentName, newName); + }); + // Mark as complete and close after a brief delay progressDialog.Complete(); DoEvents(); diff --git a/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml b/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml index 7c94dc3..cfffd5b 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml +++ b/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Renaming Project" Width="400" - Height="340" + Height="360" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"> diff --git a/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml.cs b/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml.cs index 3613c3e..e0e561a 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml.cs +++ b/src/CodingWithCalvin.ProjectRenamifier/Dialogs/RenameProgressDialog.xaml.cs @@ -26,7 +26,8 @@ public RenameProgressDialog(string projectName) new ProgressStep("Renaming project directory"), new ProgressStep("Updating project references"), new ProgressStep("Re-adding project to solution"), - new ProgressStep("Updating using statements") + new ProgressStep("Updating using statements"), + new ProgressStep("Updating fully qualified references") }; StepsList.ItemsSource = Steps; diff --git a/src/CodingWithCalvin.ProjectRenamifier/Services/SourceFileService.cs b/src/CodingWithCalvin.ProjectRenamifier/Services/SourceFileService.cs index bfcd099..7828ef0 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/Services/SourceFileService.cs +++ b/src/CodingWithCalvin.ProjectRenamifier/Services/SourceFileService.cs @@ -10,6 +10,115 @@ namespace CodingWithCalvin.ProjectRenamifier.Services /// internal static class SourceFileService { + /// + /// Updates fully qualified type references in all .cs files across the entire solution. + /// For example: OldName.MyClass → NewName.MyClass + /// + /// The solution to scan. + /// The old namespace to find. + /// The new namespace to replace with. + /// The number of files modified. + public static int UpdateFullyQualifiedReferencesInSolution(Solution solution, string oldNamespace, string newNamespace) + { + ThreadHelper.ThrowIfNotOnUIThread(); + + var modifiedCount = 0; + + foreach (Project project in solution.Projects) + { + modifiedCount += UpdateFullyQualifiedReferencesInProjectTree(project, oldNamespace, newNamespace); + } + + return modifiedCount; + } + + /// + /// Recursively updates fully qualified references in a project (handles solution folders). + /// + private static int UpdateFullyQualifiedReferencesInProjectTree(Project project, string oldNamespace, string newNamespace) + { + ThreadHelper.ThrowIfNotOnUIThread(); + + if (project == null) + { + return 0; + } + + // Handle solution folders + if (project.Kind == EnvDTE.Constants.vsProjectKindSolutionItems) + { + var count = 0; + foreach (ProjectItem item in project.ProjectItems) + { + if (item.SubProject != null) + { + count += UpdateFullyQualifiedReferencesInProjectTree(item.SubProject, oldNamespace, newNamespace); + } + } + return count; + } + + // Process actual project + if (!string.IsNullOrEmpty(project.FullName) && File.Exists(project.FullName)) + { + var projectDirectory = Path.GetDirectoryName(project.FullName); + if (!string.IsNullOrEmpty(projectDirectory) && Directory.Exists(projectDirectory)) + { + return UpdateFullyQualifiedReferencesInDirectory(projectDirectory, oldNamespace, newNamespace); + } + } + + return 0; + } + + /// + /// Updates fully qualified references in all .cs files within a directory. + /// + private static int UpdateFullyQualifiedReferencesInDirectory(string directory, string oldNamespace, string newNamespace) + { + var csFiles = Directory.GetFiles(directory, "*.cs", SearchOption.AllDirectories); + var modifiedCount = 0; + + foreach (var filePath in csFiles) + { + if (UpdateFullyQualifiedReferencesInFile(filePath, oldNamespace, newNamespace)) + { + modifiedCount++; + } + } + + return modifiedCount; + } + + /// + /// Updates fully qualified type references in a single source file. + /// Matches patterns like OldName.MyClass, OldName.Sub.Type but not SomeOldName.Type + /// + /// Full path to the .cs file. + /// The old namespace to find. + /// The new namespace to replace with. + /// True if the file was modified, false otherwise. + public static bool UpdateFullyQualifiedReferencesInFile(string filePath, string oldNamespace, string newNamespace) + { + var encoding = DetectEncoding(filePath); + var content = File.ReadAllText(filePath, encoding); + var originalContent = content; + + // Pattern matches OldName followed by a dot and an identifier + // Uses word boundary \b to avoid matching partial names like SomeOldName + // Matches: OldName.Class, OldName.Sub.Class, etc. + var pattern = $@"\b{Regex.Escape(oldNamespace)}\."; + content = Regex.Replace(content, pattern, $"{newNamespace}."); + + if (content != originalContent) + { + File.WriteAllText(filePath, content, encoding); + return true; + } + + return false; + } + /// /// Updates using statements in all .cs files across the entire solution. ///