Question

I've recently inherited C# console application that is in need of some pruning and clean up. Long story short, the app consists of a single class containing over 110,000 lines of code. Yup, over 110,000 lines in a single class. And, of course, the app is core to our business, running 'round the clock updating data used on a dynamic website. Although I'm told my predecessor was "a really good programmer", it obvious he was not at all into OOP (or version control).

Anyway... while familiarizing myself with the code I've found plenty of methods that are declared, but never referenced. It looks as if copy/paste was used to version the code, for example say I have a method called getSomethingImportant(), chances are there is another method called getSomethingImortant_July2007() (the pattern is functionName_[datestamp] in most cases). It looks like when the programmer was asked to make a change to getSomethingImportant() he would copy/paste then rename to getSomethingImortant_Date, make changes to getSomethingImortant_Date, then change any method calls in the code to the new method name, leaving the old method in the code but never referenced.

I'd like to write a simple console app that crawls through the one huge class and returns a list of all methods with the number of times each method was referenced. By my estimates there are well over 1000 methods, so doing this by hand would take a while.

Are there classes within the .NET framework that I can use to examine this code? Or any other usefull tools that may help identify methods that are declared but never referenced?

(Side question: Has anyone else ever seen a C# app like this, one reeeealy big class? It's more or less one huge procedural process, I know this is the first I've seen, at least of this size.)

Was it helpful?

Solution

You could try to use NDepend if you just need to extract some stats about your class. Note that this tool relies on Mono.Cecil internally to inspect assemblies.

OTHER TIPS

Download the free trial of Resharper. Use the Resharper->Search->Find Usages in File (Ctrl-Shift-F7) to have all usages highlighted. Also, a count will appear in the status bar. If you want to search across multiple files, you can do that too using Ctrl-Alt-F7.

If you don't like that, do text search for the function name in Visual Studio (Ctrl-Shift-F), this should tell you how many occurrences were found in the solution, and where they are.

To complete the Romain Verdier answer, lets dig a bit into what NDepend can bring to you here. (Disclaimer: I am a developer of the NDepend team)

NDepend lets query your .NET code with some LINQ queries. Knowing which methods call and is called by which others, is as simple as writing the following LINQ query:

from m in Application.Methods
select new { m, m.MethodsCalled, m.MethodsCallingMe }

The result of this query is presented in a way that makes easy to browse callers and callees (and its 100% integrated into Visual Studio).

NDepend methods callers and callees


There are many other NDepend capabilities that can help you. For example you can right click a method in Visual Studio > NDepend > Select methods... > that are using me (directly or indirectly) ...

NDepend Visual Studio method right click

The following code query is generated...

from m in Methods 
let depth0 = m.DepthOfIsUsing("NUnit.Framework.Constraints.ConstraintExpression.Property(String)")
where depth0  >= 0 orderby depth0
select new { m, depth0 }

... which matches direct and indirect callers, with the depth of calls (1 means direct caller, 2 means caller of direct callers and so on).

NDepend indirect method callers

And then by clicking the button Export to Graph, you get a call graph of your pivot method (of course it could be the other way around, i.e method called directly or indirectly by a particular pivot method).

NDepend call graph

I don't think you want to write this yourself - just buy NDepend and use its Code Query Language

FXCop has a rule that will identify unused private methods. So you could mark all the methods private and have it generate a list.

FXCop also has a language if you wanted to get fancier http://www.binarycoder.net/fxcop/

If you don't want to shell out for NDepend, since it sounds like there is just a single class in a single assembly - comment out the methods and compile. If it compiles, delete them - you aren't going to have any inheritance issues, virtual methods or anything like that. I know it sounds primitive, but sometimes refactoring is just grunt work like this. This is kind of assuming you have unit tests you run after each build until you've got the code cleaned up (Red/Green/Refactor).

The Analyzer window in Reflector can show you where a method is called (Used By).
Sounds like it would take a very long time to get the information that way though.
You might look at the API that Reflector provides for writing add-ins and see if you can get the grunt work of the analysis that way. I would expect that the source code for the code metrics add-in could tell you a bit about how to get information about methods from the reflector API.

Edit: Also the code model viewer add-in for Reflector could help too. It's a good way to explore the Reflector API.

I don't know of anything that's built to handle this specific case, but you could use Mono.Cecil. Reflect the assemblies and then count references in the IL. Shouldn't be too tough.

There is no easy tool to do that in .NET framework itself. However I don't think you really need a list of unused methods at once. As I see it, you'll just go through the code and for each method you'll check if it's unused and then delete it if so. I'd use Visual Studio "Find References" command to do that. Alternatively you can use Resharper with its "Analize" window. Or you can just use Visual Studio code analysis tool to find all unused private methods.

Try having the compiler emit assembler files, as in x86 instructions, not .NET assemblies.

Why? Because it's much easier to parse assembler code than it is C# code or .NET assemblies.

For instance, a function/method declaration looks something like this:

    .string "w+"
    .text
    .type   create_secure_tmpfile, @function
create_secure_tmpfile:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $-1, -8(%ebp)
    subl    $4, %esp

and function/method references will look something like this:

    subl    $12, %esp
    pushl   24(%ebp)
    call    create_secure_tmpfile
    addl    $16, %esp
    movl    20(%ebp), %edx
    movl    %eax, (%edx)

When you see "create_secure_tmpfile:" you know you have a function/method declaration, and when you see "call create_secure_tmpfile" you know you have a function/method reference. This may be good enough for your purposes, but if not it's just a few more steps before you can generate a very cute call-tree for your entire application.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top