In this article I am going to explain about a small tool which I have developed as my personal project for a couple of weekends in between my busy schedules. This small tool, which I like to call it as BoxCop is basically a static analyzer just like FxCop. I conceived this idea when I was working with FxCop for a quite some time at work. I would not even claim that this tool is any where similar to FxCop in terms of supported feature.
A Bit History:
Basically I was working with FxCop for a week or so at work place because I am supposed to fix all the FxCop violations in our production code. While doing so, I found many codes which were doing a lot of boxing operations (confirmed by looking into IL most of the time). We already know that this operation is really a big pain if used extensively. So at that time I started to look if FxCop does support this rule so that we can refactor it so that boxing is minimized. But I did not find any, may be fxcop purpose is not for this? No idea.
You might have noticed from my past blog articles that I do spend a lot of time looking at IL for learning purposes. So I was doing the same and I got the idea of developing this small (tiny) tool which could save at least as small as 1% of a programmers/reviewers time.
Please download either of below packages:
Source code : BoxCop (Source code) – DotNET 3.5
Binaries: BoxCop DotNet 3.5 Binaries
Note: The source code package has been uploaded in .doc format due to wordpress issues. Please save it as .zip package or change the extension from .doc to .zip of the above files when downloaded.
I started to think of developing a small tool (tiny you may call) which could help me to find my mistakes itself in my code in the first place. So as said already boxing is one of those mistakes (not always though) I might do in my code.
You might argue now that boxing is not always harm. Yes it’s not, if you use it wisely. Many times it so happens that we programmer due to many reasons write code urgently and finish off the task but fail to see if what we did is really worthy. You might think that these flaws are easily caught when you ask your code to be reviewed by some body. But not always effective I would say. Because your reviewer is not the person who has written the code in the first place, the reviewer may try to understand your code as much as possible, but due to his/her reasons some things may be overlooked.
It’s always pain to review an old code which your suppose to do refactoring on it because it’s not documented properly? The original programmer is no more available? ,etc. But you got to do it.
Any ways, I do agree that boxing is not the only reason for refactoring a code. But it could be one of those pitfalls you might look for.
How it works:
The application analyses the assembly which is given as input and its associated PDB file in searching for boxing instructions in IL as well as related source code information in the PDB file. This tool searched for all the methods defined in each module or types in an assembly and for each of those methods collected, its equivalent pdb information is fetched. Once both of the data is collected, it aggregates the result as per required format which is displayed over UI.
Let me show you few screenshots of the application:
The above screenshot shows the basic UI window of this tool. First the user has to select an assembly by clicking the browse button.
Once the .NET assembly (exe or dll) is selected, the selected file path is shown on the UI. Hovering mouse on the path shows the complete path (if path is too long) as shown in the above image.
Once assembly is selected, you need to then press analyze button. Once it is clicked, the tool analyzes the assemblies for boxing instructions. The tool automatically tries to look for the pdb information for the selected assembly in the same location internally. In case of pdb is missing, the tool reports an error as shown:
Upon selecting correct assembly with valid pdb information, the tool successfully analyses the assembly for all the boxing instructions for each method in each module and type in an assembly. Once analyses are done, the UI list view displays all the information needed as shown:
As you can see from the above image, the list view component on the UI displays detailed information about boxing instructions usage in your C# code.
The first column simply displays a serial number, second displays Namespace.Class information, third column displays Method name and the last column displays information about source code path and line, column information appended to it.
You can export the above UI output to a csv format by right clicking on the listview component as shown in below image and selecting Export to CSV menu item:
Upon selecting the context menu, a save file dialog is displayed as shown:
When Save is clicked, the report is exported and a success message box is displayed to the user.
In case of any exceptions or crashes generated by this application, a log is created with file name BoxCop.log present in the same location as of this application.
As of now, it supports only target assemblies built for 32 bit .NET 3.5 or earlier frameworks. Any non compatible assemblies selected, the tools displays an error as shown below:
Before using this tool, please make sure following steps are taken care off:
- .NET 3.5 framework is installed but not 3.5 client profile
- All dependency assemblies for the targeted assemblies present in the same directory as the targeted assembly.
- All pdb files are present in the same directory as the assemblies and are updated.
This section explains in detail about the code parts which this tool uses internally. So if you are non-techie, it may no more interest you.
This tool has 3 parts in it:
BoxCop: This module is responsible for all the UI components associated with this tool.
This module has following components in it:
- BoxCopForm: UI form which is only responsible for displaying UI components and handling related events from the components.
- AnalyzeAssembly: This component is responsible for invoking all related methods for analyzing assemblies and getting pdb information from related modules.
- AnalyzedData: This component is just a helper component to hold all the collected data which is used to display in the UI.
ILCodeAnalyzerLib: This module is responsible for analyzing, reading all the IL instructions from the assembly.
This module has following components:
- AssemblyLoader: This component just loads the selected .NET assembly into memory via reflection. It also checks for availability of the pdb file associated with this assemblyThe above method loads the assembly into memory. If there is any problem related to it, an error is sent back. It also checks for pdb information in the same location as of assembly.
- AssemblyReader: This component just finds all the methods available in the assembly modules and types. Once it is collected a list is built to hold all the information for further analysis.The above code gets all the method in an assembly module and type wise. Once all methods are found, it builds up a MethodInfo list having all the details about a method. This list is later used to get further information about each method.
- ILInstructionFormat: This component is just a helper class which just holds all the required format of IL instructions.
- MethodBodyAnalyzer: As the name suggests, this component just analyzes all the method body having MSIL instructions. It reads the method body code as a byte array and then converts the byte array to an appropriate IL instruction sets.The above method reads and analyzes the IL byte array. Each opcode which is in byte value is identified from a standard dictionary of opcodes value based on singlebyte or double byte. Single byte instructions are like nop, break, ldarg, etc. where as double byte instructions are ceq, stloc, etc.
- OpCodesBuilder: This component is a singleton class which exposes 2 dictionary which holds single byte and double byte MSIL
PDBDataReader: This module is responsible for reading the program debug data base file (.pdb) of an assembly. It uses OLE32 native calls to read this file.
Following are the components in this module:
- PDBReader: This component is responsible for invoking ole32 native calls to fetch the source information from pdb file for specific method. This component collects all the data viz. Source Lines, Columns, End lines, Source code location, etc.
- NativePDBReaderWrapper: This component wraps all the native calls to ole32.dll. The native calls are used to get all the source information which is stored in the custom format file called .pdb (Program Database).
Hope you liked it. Your comments/votes are much appreciated.
Happy Coding. Thanks.
Following are few activities which I will be carrying it out in next couple of days if possible:
- Improve design of the classes where ever necessary.
- Add features if needed and if feasible
- Make it bug free ;)
- Central repositories of error strings either in app.config or resource.
- Unit test cases, although i have done few system tests to test the tool. Its working fine for all production code.
- Compiler warnings and FxCop fixes if any.
Feel free to:
- Submit bug via blog comments or email. Do not forget to provide as much details as possible.
- Improving the design/code. Kindly, keep me updated on the same.
- Fixing bug yourself. Again keep me updated.
- Any better ways to do? Add a comment.
Thanks to the following article authors which helped me alot in building this tool.