Reputation: 7931
What I am trying to do:
Let's assume we have a class Class1
inside assembly OldAssembly
.
This assembly is referenced by a number of unknown projects.
I am going to move this class into a new assembly NewAssembly
, eventually name and namespace would also change. Now all usages must be adjusted.
I want to create a tool which will automate these code adjustments.
What I did so far:
I have played around with roslyn Renamer
:
var workspace = MSBuildWorkspace.Create();
var originalSln = workspace.OpenSolutionAsync(@"D:\spikes\ToBeFixed\ToBeFixed.sln").Result;
var project = originalSln.Projects.Single();
var compilation = project.GetCompilationAsync().Result;
var renameFrom = compilation.GetSymbolsWithName(s => s.Contains("Class1")).Single();
const string renameTo = "Class2";
var optionSet = originalSln.Workspace.Options;
var modifiedSln = Renamer.RenameSymbolAsync(originalSln, renameFrom, renameTo, optionSet).Result;
workspace.TryApplyChanges(modifiedSln);
but it renames also the source class. So I have looked into the Renamer
code and tried to adapt it for my use case, but failed due to some internals used in there.
Question: How can I automate code adjustments after moving a class from one assembly into another.
Upvotes: 2
Views: 2390
Reputation: 9426
You can achieve what you're looking for by:
Replacing the renamed class itself with its original self.
public async static Task TestingRenamer()
{
var code = @"
using System;
//We do not want to rename MyClass (we want to keep it the same)
public class MyClass
{
public MyClass()
{
}
}
public class Program
{
public static void Main()
{
//We want to rename this usage
var x = new MyClass();
}
}";
var newClassName = "MY_NEW_CLASS_NAME";
var document = getDocumentForCode(code);
var compilation = await document.Project.GetCompilationAsync();
var root = await document.GetSyntaxRootAsync();
var originalClass = root.DescendantNodesAndSelf().OfType<ClassDeclarationSyntax>().First();
var model = compilation.GetSemanticModel(root.SyntaxTree);
var originalSymbol = model.GetDeclaredSymbol(originalClass);
//Rename all
var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, originalSymbol, newClassName, document.Project.Solution.Workspace.Options);
//Revert the original class
var newDocument = newSolution.GetDocument(document.Id);
var newSyntaxRoot = await newDocument.GetSyntaxRootAsync();
var newClass = newSyntaxRoot.DescendantNodes().OfType<ClassDeclarationSyntax>().Where(n => n.Identifier.ToString() == newClassName).Single();
newSyntaxRoot = newSyntaxRoot.ReplaceNode(newClass, originalClass);
newDocument = newDocument.WithSyntaxRoot(newSyntaxRoot);
//We've now renamed all usages and reverted the class back to its original self.
var finalSolution = newDocument.Project.Solution;
}
//Helper method to build Document
private static Document getDocumentForCode(string code)
{
var ws = new AdhocWorkspace();
var Mscorlib = MetadataReference.CreateFromAssembly(typeof(object).Assembly);
var references = new List<MetadataReference>() { Mscorlib };
var projInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Default, "MyProject", "MyAssembly", "C#", metadataReferences: references);
var project = ws.AddProject(projInfo);
var text = SourceText.From(code);
var myDocument = ws.AddDocument(project.Id, "MyDocument.cs", text);
return myDocument;
}
Upvotes: 4