FindReferences of "N Order" - SharpDevelop Add-In





5.00/5 (7 votes)
Using ICSharpCode.SharpDevelop.Refactoring.RefactoringService.FindReferences to find all references in a given project
- Download ReferenceAnalysis - 25.88 KB
- Download source code - 1.16 MB
- Download sample classes - 4.83 KB to Run Tool on them
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 MethodC
calls MethodA
. You need to know if there is a relation between MethodZ
& 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:
Addon Part
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
& FindReferences.dll
. The FindReferences.addin
file contains information about the addin such as:
<addin name="""ReferenceList""" author="""Mohammad""
url="""""" description="""TODO:"">
<path name="""/Workspace/Tools""">
<menuitem class="""Addin1.ReferenceListToolCommand"""
id="""Reference"" label="""Reference"">
<addin name="""ReferenceList""" author="""Mohammad""
url="""""" description="""TODO:""><path name="""/Workspace/Tools""">
<menuitem class="""Addin1.ReferenceListToolCommand"""
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.">
<Runtime>
<Import assembly = "FindReferences.dll"> </Import>
</Runtime>
<Manifest>
<Identity name="FindReferences"/>
<Dependency addin="SharpDevelop" version="3.0"/>
</Manifest>
<Path name = "/Workspace/Tools">
<MenuItem id = "Reference Analysis" label = "Reference Analysis"
class = "SharpDevelopAddin.ReferenceListToolCommand" />
</Path>
</AddIn>
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.
// Retrieve Currently Open Solution.
ICSharpCode.SharpDevelop.Project.Solution Sol =
ICSharpCode.SharpDevelop.Project.ProjectService.OpenSolution;
// Enumerate on Projects
foreach (ICSharpCode.SharpDevelop.Project.IProject iProj in Sol.Projects)
{
System.Windows.Forms.ListViewItem lstProjectItem =
new System.Windows.Forms.ListViewItem();
// Extract Project Display Data in a ListView Item
lstProjectItem.Text = iProj.Name;
lstProjectItem.Tag = iProj;
lstProjectItem.SubItems.Add(iProj.Language);
lstProjectItem.SubItems.Add(iProj.AssemblyName);blyName);
// Add ListViewItem to ListView
lstProjects.Items.Add }
Property 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 ICSharpCode.SharpDevelop.Dom.IMethod
.
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:
// For Each Selected Project Get All Classes
foreach ( ICSharpCode.SharpDevelop.Project.IProject iProj in mSelectedProjects)
{
// Now Get Project Contents
ICSharpCode.SharpDevelop.Dom.IProjectContent ProjContent =
ICSharpCode.SharpDevelop.ParserService.GetProjectContent(iProj);
if (ProjContent != null)
{
// Look For Classes
foreach (ICSharpCode.SharpDevelop.Dom.IClass iClass in ProjContent.Classes)
{
//Get Classes Contents
Src.Gui.Dialogs.ReferenceDialog.DSReference.ClassRow ClassRow =
AddClassRow(iClass.Name, iClass.ProjectContent.Project.ToString () );
// Enumerate All Methods in the class
foreach (ICSharpCode.SharpDevelop.Dom.IMethod iMethod in iClass.Methods)
{
ICSharpCode.SharpDevelop.Dom.IMember Im =
(ICSharpCode.SharpDevelop.Dom.IMember)iMethod;
// Call ICSharpCode.SharpDevelop.Refactoring.
// RefactoringService.FindReferences to Find References.
List<ICSharpCode.SharpDevelop.Refactoring.Reference> Reff =
ICSharpCode.SharpDevelop.Refactoring.
RefactoringService.FindReferences(Im, null);
// Save Result in XML
Src.Gui.Dialogs.ReferenceDialog.DSReference.MethodRow MethodRowCalled =
AddMethodRow(iMethod.Name, ClassRow);
string CalledMethodFullName = iClass.Name + ":" + iMethod.Name;
foreach (ICSharpCode.SharpDevelop.Refactoring.Reference Ref in Reff)
{
AddMethodRelationRow(MethodRowCalled, Ref.ResolveResult );
}
}
}
}
Display Part
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.
Extra Enhancements
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.
History
- 1st March, 2009: Initial post