I'm trying to make my own Move to Resource refactoring (like the one found in ReSharper). In my CodeAction.GetChangedDocumentAsync
method I'm doing these 3 steps:
XmlDocument
SyntaxNode.ReplaceNode
Steps 1 & 2 are OK, but 3 does not work. If I remove the step 2, 3 is working.
I don't know if it is because I'm mixing Roslyn & DTE or if it's because step 2 generate new code in the solution and my cached context becomes invalid.
// Add the resource to the Resources.resx file
var xmlDoc = new XmlDocument();
xmlDoc.Load(resxPath);
XmlNode node = xmlDoc.SelectSingleNode($"//data[@name='{resourceIndentifierName}']");
if (node != null) return;
XmlElement dataElement = xmlDoc.CreateElement("data");
XmlAttribute nameAtt = xmlDoc.CreateAttribute("name");
nameAtt.Value = resourceIndentifierName;
dataElement.Attributes.Append(nameAtt);
XmlAttribute spaceAtt = xmlDoc.CreateAttribute("space", "xml");
spaceAtt.Value = "preserve";
dataElement.Attributes.Append(spaceAtt);
XmlElement valueElement = xmlDoc.CreateElement("value");
valueElement.InnerText = value;
dataElement.AppendChild(valueElement);
XmlNode rootNode = xmlDoc.SelectSingleNode("//root");
Debug.Assert(rootNode != null, "rootNode != null");
rootNode.AppendChild(dataElement);
xmlDoc.Save(resxPath);
// Update the Resources.Designer.cs file
var dte = (DTE2)Package.GetGlobalService(typeof(SDTE));
ProjectItem item = dte.Solution.FindProjectItem(resxPath);
((VSProjectItem) item.Object)?.RunCustomTool();
// Replace the node
SyntaxNode oldRoot = await context.Document.GetSyntaxRootAsync(cancellationToken)
.ConfigureAwait(false);
SyntaxNode newRoot = oldRoot.ReplaceNode(oldNode, newNode);
return context.Document.WithSyntaxRoot(newRoot);
it's because step 2 generate new code in the solution and my cached context becomes invalid
This is what is happening. When you call RunCustomTool
the visual studio file watcher api tells roslyn that the files have been updated and roslyn generates a new set of solution snapshots. When you attempt to apply your codefix, roslyn looks at the solution snapshot that your codefix came from, sees that it does not match the current snapshot, and fails to apply it.