Introduction "What is the Problem?"
Using Visual Studio, you can easily right-click on a method and choose "
FindAllReferences" to list all methods that call your method as in the following image. You can only see what I call "First Order Reference" which are methods that directly call your method. In many situations, you need "N Order Reference", i.e. you need to know that caller of caller methods, ...etc.
In very large projects, you need a deeper view. It is not always enough to know that
MethodA. You need to know if there is a relation between
MethodA through a series of calls, e.g. Z->y->X-> ......... C->B->A ?! It is important to know this information to decide whether you need to re-test
MethodZ or not.
Idea & Implementation "How Can We Solve It?"
Our utility "Reference Analysis" is a SharpDevelop Add-In that is installed on SharpDevelop 3.0. It uses SharpDevelop library to walk over all methods in all classes of all projects in an open solution and get all direct caller methods "First Order Caller". This information is stored in XML file using the following schema:.
As we can see, there are three main tables, Projects - Classes & Methods. There is a one-to-many relation that exists between Project and Classes. Another one-to-many relation exists between Classes & Methods. Finally there is a many-to-many relationship between Methods and themselves.
If we navigate on all methods in a solution and store callers using the above schema, we can easily query to get list of "N Order Callers".
Using the Code
The code has three main parts:
This is the code that enables SharpDevelop to recognize the utility as a Add-In module.
A SharpDevelop Add-in can consist of a zip file with two files inside; DLL file & Addin file. The DLL contains all code & logic, while the .addin file is an XML based format file that defines attributes of the plug-in to SharpDevelop IDE. Our Reference Analysis addin is a zip file of
FindReferences.addin file contains information about the addin such as:
<addin name="""ReferenceList""" author="""Mohammad""
<addin name="""ReferenceList""" author="""Mohammad""
url="""""" description="""TODO:""><path name="""/Workspace/Tools""">
id="""Reference"" label="""Reference""><AddIn name = "ReferenceList"
author = "Mohammad Said Hefny"
url = ""
description = "TODO: List all callers of a given project.
can be used in an impact analysis.">
<Import assembly = "FindReferences.dll"> </Import>
<Dependency addin="SharpDevelop" version="3.0"/>
<Path name = "/Workspace/Tools">
<MenuItem id = "Reference Analysis" label = "Reference Analysis"
class = "SharpDevelopAddin.ReferenceListToolCommand" />
The file provides description and points to class
SharpDevelopAddin.ReferenceListToolCommand where SharpDevelop expects to find a Method called
Run() to call. In the
Run() method, you can either use SharpDevelop GUI control that as View Control or you can use normal dialog controls as the one used for this utility. Please refer to "Line Counter - Writing a SharpDevelop Add-In" for more detailed information about how to make an Add-in.
Code Analysis Part
This is the core of this tool. It is where all data is extracted. Generated data can be saved as XML for future use.
First the tool extracts the project from the solution to enable the user to select only projects he/she needs to analyze.
ICSharpCode.SharpDevelop.Project.Solution Sol =
foreach (ICSharpCode.SharpDevelop.Project.IProject iProj in Sol.Projects)
System.Windows.Forms.ListViewItem lstProjectItem =
lstProjectItem.Text = iProj.Name;
lstProjectItem.Tag = iProj;
ICSharpCode.SharpDevelop.Project.ProjectService.OpenSolution returns the current open solution. It contains a list of
ICSharpCode.SharpDevelop.Project.IProject that we enumerate on them to retrieve projects of the solution. Then we will a listview of these projects to enable the user to select them for analysis.
After the user selects the projects as in the image below:
The project starts analyzing each method in these projects and traces the calls into all projects in the solution. The following code explains this technically:
First we get enumerate on selected projects that the user selected in the last image. A call to
ICSharpCode.SharpDevelop.ParserService.GetProjectContent(iProj) returns all information for a given project. The information is that we need now is classes of the project
ProjContent.Classes. This property returns a list of
ICSharpCode.SharpDevelop.Dom.IClass. Now we enumerate on classes to retrieve Methods by using property
iClass.Methods that returns a list of
Now we can get all Methods in a given solution. The second important part is to
FindReference these methods. This is done by calling
ICSharpCode.SharpDevelop.Refactoring.RefactoringService.FindReferences(Im, null). This function takes
IMethod as a parameter and returns a list of all methods that call this function even if these methods are in other projects.
The following code explains the above approach:
foreach ( ICSharpCode.SharpDevelop.Project.IProject iProj in mSelectedProjects)
ICSharpCode.SharpDevelop.Dom.IProjectContent ProjContent =
if (ProjContent != null)
foreach (ICSharpCode.SharpDevelop.Dom.IClass iClass in ProjContent.Classes)
Src.Gui.Dialogs.ReferenceDialog.DSReference.ClassRow ClassRow =
AddClassRow(iClass.Name, iClass.ProjectContent.Project.ToString () );
foreach (ICSharpCode.SharpDevelop.Dom.IMethod iMethod in iClass.Methods)
ICSharpCode.SharpDevelop.Dom.IMember Im =
List<ICSharpCode.SharpDevelop.Refactoring.Reference> Reff =
Src.Gui.Dialogs.ReferenceDialog.DSReference.MethodRow MethodRowCalled =
string CalledMethodFullName = iClass.Name + ":" + iMethod.Name;
foreach (ICSharpCode.SharpDevelop.Refactoring.Reference Ref in Reff)
AddMethodRelationRow(MethodRowCalled, Ref.ResolveResult );
This module has a standalone version that uses XML saved data and displays it.
Although the tool works fast for small projects, generating call reference method of all Methods in a large project can take a very long time. We are talking here about many hous or even couple of days!! This is a very time consuming task, so to avoid running this task very often, the results can be stored in XML format and can be retrieved later or distributed on different developers who are interested in seeing the result. The XML structure represents a simple database with three tables References - Classes - Methods. You can work on that XML to extract more information if you need.
How to Make It Work
- Installing & Running Reference Analysis Add-In:
- Download ReferenceAnalysis.zip
- Open SharpDevelop, goto Tools\AddinManager
- Select the zip file as an addin and restart SharpDev.
- Now download SampleClasses.zip and extract it. And open the solution in SharpDevelop.
- Goto "Tools\Reference Analysis" and click it.
- Select FindReference and you will see only one project reference that you need to click on to select.
- Results will be displayed in the main dialog and you can save the results in XML file.
Running Reference Analysis Desktop Version:
- Download Desktop.zip
- Run DeskTopTool.exe
- Press Open File & Select "SampleResult.xml" found in the zip file.
- Now you can see the result sample.
Why is this Data Useful?
Well, the data retrieved from this utility gives a complete view of "what calls what" in a given solution. This can be used in an impact analysis study of a code refactoring. The utility will allow you to tell which methods, classes & projects are affected or should be re-tested as a result of refactoring a given method.
You can extend this project to draw reference dependency diagram or a class dependency diagram represents which classes are called by which classes.You can extract more information such as the weight of each method depending on the number or callers. If you need to enhance a code response, this data will help you to select which method you should enhance first and which methods will have impact when changed.
- 1st March, 2009: Initial post