Yesterday I announced the release of v1.0 of the DXCore plugin as described in this post. Almost immediately upon its release, someone pointed out a pretty embarrassing bug that I had apparently failed to test for: the plugin only replaced the portion of the existing namespace string that fell between pairs of periods (“.”) rather than the entire namespace declaration as had been intended. See this comment (and my response) for more details.
Oops 🙁 How embarrassing for me not to have caught that, but my (admittedly minimal) test-case consisted only of a class with a namespace that consisted of just one word rather than the much more common PartOne.PartTwo.PartThree kind of approach that most people use for namespaces in projects. Sure enough, the CodeRush.Selection.SelectWord() method that I was calling does indeed ‘respect’ the use of a ‘period’ (“.”) as a ‘word-delimiter’ rather than only using whitespace to parse ‘word boundaries’ so my overall implementation contained a giant flaw in that it relied on a method that didn’t do what I needed.
In fairness to Developer Express, their behavior for the CodeRush.Selection.SelectWord() method is actually much more ‘appropriate’ in its implementation anyway: more often than not, as a developer you want to select just the part of a so-called dotted-reference between the dots rather than the entire ‘whitespace-bounded string’ all at once.
And in fairness to me, this is yet another instance of why I am continually disappointed at Developer Express’ near-complete lack of documentation around the DXCore/Refactor!Pro/CodeRush API…a simple entry in some API reference could have easily told me that this was the expected behavior of the damned method and saved me both some time and some public embarrassment.
Another Great Suggestion
Proving that more heads are near-always better than one when it comes to evolving features for your products/projects, I also pretty quickly received this comment from an early adopter asking if it would be possible to have the plugin ‘respect’ the inclusion of solution folders in the namespaces it generates.
In its initial implementation, the plugin merely replaced whatever namespace you had with whatever the project default was set to (in Project Properties). But the way Visual Studio auto-assigns namespaces to new class files is by appending the names of each solution folder beneath the project level to the project’s default namespace setting. You can see this Visual Studio behavior clearly if you have an ASP.NET MVC project with a default project namespace set to MyMvcProject. When you create a class in the root of that project, Visual Studio will assign it the MyMvcProject namespace. But if you then add a class to the Controllers folder, Visual Studio will assign it the namespace MyMvcProject.Controllers, appending the name of the folder to the project’s default namespace.
And this pattern continues no matter how deep you make your solution folders. For example the path /Folder1/Folder2/Folder3 would result in the MyMvcProject.Folder1.Folder2.Folder3 namespace being assigned to any classes in the Folder3 solution folder in this case. Thanks to a quick modification, the Refactor_UpdateNamespace plugin has now been changed to behave this way also, properly inserting the full names of each solution folder into the namespace as it fixes them. Thanks for the great suggestion~!
Download
More good news is that I also have a report from a CodeRushXpress user that the plugin seems to work fine (well, as fine as it could with the bug in it!) under the freeware CodeRushXpress toolset so it would appear that you do NOT need the commercial CodeRush or Refactor! Pro products to make use of this plugin.
The updated binary of the plugin is available for download here. As before, if anyone has any comments, feedback, bug-reports, or ideas how to improve this thing, please post a comment here on my blog for the time being until I can get this project moved out to a more appropriate hosting location for it.
Happy coding~!
[…] Comments Unhandled Exceptions » Blog Archive » Refactor_UpdateNamespace v1.0 Updated with Bug-Fix on Refactor_UpdateNamespace v1.0 ReleasedMarc Scheuner on Refactor_UpdateNamespace v1.0 […]
Very useful plugin. One issue or future request:
When updating the namespace to default, fix existing references(using/import statement)from other objects to the class.
Cool plugin. Another feature requests:
*could you also add Code Issue that marks namespaces that need to be updated?
*Option to update all namespaces in whole folder / project / solution folder / solution would be awasome.
@Valdimar:
Thanks for the feedback — that WOULD be a great feature and would make the behavior of this plugin more like the the Developer Express-provided ‘Rename’ refactoring but applied to the ENTIRE namespace value.
Right now the Developer Express ‘Rename’ refactoring only lets you use it to rename the last ‘component’ of a namespace. For example, you can use the Rename refactoring to rename the ‘Folder3’ node in the following declarations…
namespace MyMvcProject.Folder1.Folder2.Folder3
{
…
}
…but you cannot apply the Rename refactoring to the entirety of the dotted namespace path at once, which is really more what you are suggesting here.
Either way, I *will* look into this capability but I think its actually more complex than you might think since I would have to actually search NOT just for ANY ‘using’ statements that reference the ‘old’ namespace but for ONLY those such statements where the ONLY classes in the target files to change are the classes in the file being changed, else this refactoring could easily introduce inadvertent breaking changes.
As an exmaple, consider this…
file class1.cs:
namespace ns1
{
public class Class1 {}
}
—
file class2.cs:
namespace ns1
{
public class Class2 {}
}
—
file SomeParent.cs:
using System;
using ns1;
namespace Parent
{
public class SomeParent
{
public SomeParentClass()
{
var a = new Class1();
var b = new Class2();
}
}
}
—
In the above collection of files, if you were to perform the ‘update namespace to default’ refactoring on the Class1 class in Class1.cs AND replace all references to ‘using’ statements, etc. in all other places in the solution, then the result would be that suddenly the code in SomeParent.cs would stop compiling (since all of a sudden Class2’s namespace would no longer be properly imported into the SomeParent.cs file and Class2 would become an ‘unknown type’ to the compiler).
The only way I could see to accomplish what you’re suggesting (which actually IS a very valuable suggestion BTW) would be to…
1) carefully interrogate ALL of the types in the file whose namespace you are ‘updating’
2) search the entire solution for all instances of those types (e.g., NOT search for namespaces, but search for TYPES in that namespace used elsewhere)
3) if you find one of these types in use elsewhere, check all other TYPES in use in the same file to see if there are any other types in the same namespace but NOT also in the source file with the namespace being updated
4) if there are other types in the same ‘source’ namespace, ADD the ‘target’ new namespace to the ‘using’ block
5) if there aren’t other types in the same ‘source’ namespace, REPLACE the existing ‘using’ statement with one that makes use of the new namespace
This is all ENTIRELY achievable using the DXCore/CodeRush API, but this is just an example to indicate that its probably non-trivial to implement this functionality. And it gets worse when you also realize that its NOT just ‘using’ statements that have to be updated but also explicit in-line fully-qualified references to the namespaces (e.g., var x = new ns.Class1(); statements) that would have to be searched for and resolved as well.
So….this is a long way of saying both “nice (and powerful) suggestion, but a lot more complex than I’m probably going to try to implement any time soon for all of the above reasons” but I *will* accept a patch from anyone wanting to take a stab at adding this really powerful capability to the plugin 🙂
Thanks for the suggestion, I *will* consider it for the future, but its non-trivial so probably won’t be happening anytime soon.
-Steve B.
@Przemyslaw:
Thanks for the feedback; I will investigate how to hook my plugin into the code-analysis capabilities of CodeRush; assuming there is some way to do this, it would be possible to at least have it show up as a file-level Code Issue, but for all the reasons I just listed in my response to @Valdimar above, providing a one-click ‘fix-this-issue’ implementation is decidedly non-trivial (despite being a really powerful capability) so its unlikley that I will be extending the plugin to provide anything more than a file-scoped ‘localized’ update capability in the near future.
Thanks again for the feedback and I hope you enjoy the plugin~!
-Steve B.
Steve, if there is possibility to chain refactorings, whole process would be:
1) Find all files containing calls to elements in scope of changed namespace
2) Add “using new namespace” directive
3) Invoke “optimize usings” refactoring
And another feature just crossed my mind:
After changed default namespace of project or renamed folder in project, optionally update all affected files. This could be optional.
>> Thanks again for the feedback and I hope you enjoy the plugin~!
Plugin is really cool. I really missed such functionality in VS. Keep up good work.
>> its unlikley that I will be extending the plugin to provide anything more than a file-scoped ‘localized’ update capability in the near future.
Care to post plugin to DX community plugins site? Maybe others could help here…
@Przemyslaw:
I think (in general) your 1-2-3 step is indeed the right process outline overall. I might quibble a bit with the invocation of the optimize-usings refactoring only because it would tend to violate the law-of-least-surprise for the user since performing that action is somewhat tangential to the act of changing a namespace declaration in one source file.
I agree that its pretty straightforward, just not trivial to implement:) There’s a ton of complexity buried in edge cases in even just that outline of yours, but I agree that’s more or less how it would need to work.
As for posting it to the dxcorecommunityplugins site, that’s my intent as soon as I get a minute or two to get in touch with Rory Becker and coordinate my getting access to that SVN repository.
After that, I’d be GLAD to consider a patch from anyone that wants to take a stab at implementing this suggested functionality — its easy to see how it would be valuable, but its also easy to see how its non-trivial to get all the edge cases right 🙂
Thanks again,
-Steve B.
Steve, the naming feature based on folder was exactly what I was looking for. Thanks.
[…] Recent Comments Unhandled Exceptions » Blog Archive » Refactor_UpdateNamespace now … on Refactor_UpdateNamespace now supports VB.NET too!Unhandled Exceptions » Blog Archive » Refactor_UpdateNamespace now supports VB.NET too! on Refactor_UpdateNamespace v1.0 Releasedsbohlen on On Open Source Software, Itches, and Documentationalwin on On Open Source Software, Itches, and DocumentationMike Wood on Refactor_UpdateNamespace v1.0 Updated with Bug-Fix […]