2014-11-25

Resharper Code Cleanup Custom Type Member Layout that Works With StyleCop

I am a religious user of StyleCop to enforce coding standards in my C# code. It uses a coding standard that is fairly inflexible. You can turn rules on and off, but customizing the rules requires writing your own rule library, which is difficult. So you either buy into the way StyleCop does things or you don't. While I don't necessarily agree with every choice for how StyleCop does things, I feel StyleCop gets most things right, and the ones it gets wrong I can live with.

In some cases, I feel StyleCop doesn't go far enough. I wrote several additional rules that plug into StyleCop that enforces several coding standards that I use. One complains if members of a given type are not in alphabetical order. Another disallows multiple returns from inside a method: A method should have one exit point. I don't publish my rules since they have bugs in some cases.

I also use StyleCop+, which allows many additional rules. I do have to change a bunch of settings here to use it, because the defaults aren't right. Still, it does have a number of features I find useful when configured the right way.

One thing StyleCop enforces is the order of items in your code. It has a particular layout that it is looking for. I find it sometimes a little odd. For example, delegates and events come after the constructor...I would think putting them before the constructor makes more sense. However, knowing where things should be located in the file is much more important than exactly where that location is.

I just got a copy of Resharper. It seems many .NET programmers can't live without it, but I've gone 13 years so far. I think my rigid coding standards makes it less useful than it would be if I were more flexible. However, there are some things that I find useful. One thing it can do is reorder your code using the "Cleanup Code" command, which I have done by hand up until now. This is particularly useful when you acquire code from someone who doesn't use StyleCop. However, the default reordering in Resharper is incompatible with StyleCop.

Resharper has a way of customizing what Cleanup Code does. You can create custom rules using XML. I have produced a set of Custom Rules that is mostly compatible with StyleCop, shown at the end of this article.

There are a few issues with my rules. They do not order explicit interface implementations correctly: they will violate StyleCop rule SA1202. (Try implementing explicitly IConvertible, for example.) The ordering of overloaded operators is a little odd. Still, using Resharper with these rules is better than doing reordering by hand, as I can fix what it doesn't do right in few minutes.

Here are the rules. Let me know in the comments if you have any improvements. Be warned...I hate regions, and it will remove the region lines from your code. Change the RemoveAllRegions value to false if you want keep yours.

<?xml version="1.0" encoding="utf-8" ?>
<!-- StyleCop compatible custom rules by Greg Reddick, http://blog.xoc.net -->
<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns">
 <!--Do not reorder COM interfaces and structs marked by StructLayout attribute-->
 <Pattern RemoveAllRegions="true">
  <Match>
   <Or Weight="100">
    <And>
     <Kind Is="interface" />
     <Or>
      <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute" />
      <HasAttribute CLRName="System.Runtime.InteropServices.ComImport" />
     </Or>
    </And>
    <HasAttribute CLRName="System.Runtime.InteropServices.StructLayoutAttribute" />
   </Or>
  </Match>
 </Pattern>

 <Pattern RemoveAllRegions="true">

  <Entry>
   <Match>
    <Or>
     <Kind Is="constant" />
     <Kind Is="field" />
    </Or>
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Static />
    <Readonly />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="constructor" />
   </Match>
   <Sort>
    <Static />
    <Access Order="public internal protected-internal protected private" />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="destructor" />
   </Match>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="delegate" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="event" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Static />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="enum" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="interface" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="property" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Static />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="indexer" Weight="100" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Or>
     <Kind Is="method" />
     <Kind Is="operator" />
    </Or>
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Static />
    <Name IgnoreCase="false" />
   </Sort>
  </Entry>
 
  <Entry>
   <Match>
    <Kind Is="struct" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

  <Entry>
   <Match>
    <Kind Is="class" />
   </Match>
   <Sort>
    <Access Order="public internal protected-internal protected private" />
    <Static />
    <Name IgnoreCase="true" />
   </Sort>
  </Entry>

 </Pattern>
</Patterns>


No comments :

Post a Comment

Note: Only a member of this blog may post a comment.