tags:

views:

582

answers:

14

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.)

A: 

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.

Cody Brocious
+1  A: 

I beleve you can do that with NDepend, but I've never used it.

Eric Haskins
+12  A: 

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.

Romain Verdier
+1  A: 

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

Steve Eisner
+1  A: 

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.

Hamish Smith
A: 

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.

Orlangur
Your suggestion to delete as I go through the code was my first thought too. I'll be using this method plus NDepend, as others suggested, to do further analysis.
Duffy
A: 

Can you get the money for ReSharper ? It's the ideal tool for refactoring.

+3  A: 

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.

Tobin Harris
A: 

To answer your "side question", have never seen one that bad, may be a good entry for The Daily WTF. Possibly call it "The ultimate copy/paste reuse".

Turnkey
A: 

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.

mbac32768
How is it "much easier" to parse assembler when .net includes reflection libraries? Not to mention 3rd party libraries like Mono.Cecil.
Wesley Wiser
Because there's a huge base of tools for processing line-based data in an ad hoc way. e.g. grep, sed, awk, etc.
mbac32768
+1  A: 

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/

A: 

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).

Cade Roux
+3  A: 

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.

What you really want is to know about the Afferent Coupling for method (MethodCa): The Afferent Coupling for a particular method is the number of methods that depends directly on it.

By using NDepend you just need to write this CQL query to list method ordered by afferent coupling descendant:
SELECT METHODS ORDER BY MethodCa DESC

You can also write queries such as:
SELECT METHODS WHERE MethodCa > 10

To know about popular methods, you might also be interested by the Method Rank metric: MethodRank values are computed by applying the Google PageRank algorithm on the graph of methods' dependencies.

And also by reading this blog post Code metrics on Coupling, Dead Code, Design flaws and Re-engineering

Patrick Smacchia - NDepend dev
A: 

I'm told my predecessor was "a really good programmer"

Whoever told you that is a poor judge of programmer ability. Is that person going to write your next performance review? Are you sure you want this job?

Jay Bazuzi