How can I alter xml comments ?
Hello,
I want to alter the xml comments how can I do that ? I'm not familiar with the APIs.
I've attached the cleanup code module.
Attachment(s):
XmlCommentsCodeCleanupModule.cs.zip
Please sign in to leave a comment.
Hello,
I want to alter the xml comments how can I do that ? I'm not familiar with the APIs.
I've attached the cleanup code module.
Please sign in to leave a comment.
Take a look at the AgentSmith source in the R#6.1 branch. This is pretty much exactly what you're trying to do.
http://code.google.com/p/agentsmithplugin/source/browse/#svn%2Fbranches%2FR%236.1%2Fsrc%2FAgentSmith%2FComments%2FReflow
Thank you very much! :)
Also worth noting that the current Agent Smith beta may actually do what you were trying to write a plugin for...
The question is whether it will have the same level of customization.
I can't just copy/paste the code due to abstractions of the API there and permissions of the authors.
Can you please give me a small example based on the code I posted ? hopefully it's not much to ask. :)
The two interfaces that you're most interested in are:
IDocCommentBlockNode
IDocCommentBlockOwnerNode
The owner node is an item in the document tree that can own a comment. Alas pretty much the only way to work out what to do in the ReSharper API is to use Reflector or DotPeek to analyse derived types. If you look at the derived types on IDocCommentBlockOwnerNode then it's basically types, type members and enums and enum members.
From the "Process" method of your cleanup code, you can search through the current file and find things that could own doc comments by doing:
IFile file = sourceFile.GetPsiFile<CSharpLanguage>();
file.GetPsiServices().PsiManager.DoTransaction(
() =>
{
using (_shellLocks.UsingWriteLock())
file.ProcessChildren<IDocCommentBlockOwnerNode>(x => MyFunctionWhichProcessesOwners(x));
},
"My Cleanup Process Name");
...
public void MyFunctionWhichProcessesOwners(IDocCommentBlockOwnerNode owner) { ... }
Now your function will be called for every doc comment owner in the file. Once you've got the owner then you can call owner.GetDocCommentBlockNode() to get the actual comment (or null if there is no comment).
There are several ways you can then process the comments:
- Via XML
- Process the raw comment lines.
The first one is easy, you just call GetXML(null) on the comment block and you'll get back either an XML node containing the xml parsed comment text or null if the xml is malformed. This last part is the trick - GetXML only works if the comment is reasonably well constructed.
The second one is slightly trickier. You can iterate over the IDocCommentNodes (lines of the comment block) within the comment block by looking at the FirstChild of the IDocCommentBlockNode (to get the frst IDocCommentNode) and then calling NextSibling on that to go through the various lines (note the IDocCommentNode is a CSharp only construct - no idea how it works in VB).
Each IDocCommentNode has a CommentText property which will give you the text for that line.
Once you have applied whatever your logic is to transform/generate your new comment text, you need to generate a new IDocCommentBlockNode from it. You can do this in two ways:
- First (and easiest) is to create a new factory and use it to create the block node:
CSharpElementFactory factory = CSharpElementFactory.GetInstance(owner.GetPsiModule());
IDocCommentBlockNode comment = factory.CreateDocCommentBlock(newCommentText);
Unfortunately ReSharper feels the need to mess around with the whitespace in your text if you do it this way (empty lines are removed). The up side is that the text you pass only needs to be the actual content. ReSharper will add the /// and whitespace.
- Second way (which avoids the issues with whitespace) is to ask the factory to create a whole new code element with the given comment and then steal the block node that that created. You can see this in the AgentSmith code in the "SetDocComment" function in CommentReflowAction.cs. Note that, if you use this approach, you literally get what you asked for so you need to fully construct all the comment plumbiing.
Once you have the IDocCommentBlockNode then you can call SetDocCommentBlockNode on the IDocCommentBlockOwnerNode to actually apply the new comment.
So, the MyFunctionWhichProcessesOwners should look something like (completely untested :)) :
public void MyFunctionWhichProcessesOwners(IDocCommentBlockOwnerNode owner)
{
IDocCommentBlockNode oldComment = owner.GetDocCommentBlockNode();
// Get the XML
XmlNode memberXmlNode = oldComment.GetXML(null);
XmlElement memberElement = memberXmlNode as XmlElement;
// Get the "Summary" text.
XmlNodeList summaryNodes = memberElement.GetElementsByTagName("summary", "");
if (summaryNodes.Count == 0) return;
XmlNode summaryNode = summaryNodes[0];
string summaryText = summaryNode.InnerXML;
// Make some modifications
summaryNode.InnerXML = summaryText.Replace("hello", "hi");
// Create the new comment block
CSharpElementFactory factory = CSharpElementFactory.GetInstance(owner.GetPsiModule());
IDocCommentBlockNode comment = factory.CreateDocCommentBlock(memberElement.InnerXML);
// And update the comment on the owner
owner.SetDocCommentBlockNode(comment);
}
Hope this helps,
Chris
Btw, sorry for the terrible whitespace - the comment system seems to have its own ideas about how my text should be formatted.
wow! thank you for the detailed explanation, I think I got enough info to get started.;)
wow! thank you for the detailed explanation, I think I got enough info to get started.;)
You might want to check out the Comments section of the Plugin Development Guide, which specifically deals with the creation and manipulation of comments.
Is IDocCommentBlockOwnerNode available in the SDK still? I am having trouble finding this interface. How can I modify the xml comments on a method or class using ReSharper SDK 9.2?
IDocCommentBlockOwnerNode was renamed IDocCommentBlockOwner. It's the same, otherwise. A couple of other nodes were renamed like that, too.