MethodWrappers

The most common approach here is to change a method by another one that does a particular job. More precisely, it means to change the CompiledMethod by another ordinary object. This object has to implement the method run: aSelector with: arguments in: aReceiver  that is call by the VM when that selector is called. Usually, this object also stores the original method for that selector so that then it can put it back and also to delegate during its own invocation. 

 To install the wrapper, you can do something simpler like "methodDict at: aSelector put: self"  where self is the wrapper. Another approach is to "self addSelector: self selector withMethod: self"  which basically does the same of the previous one but with all the notifications and so on.

To uninstall the wrapper you only need to put again the original CompiledMethod. 

The wrapper usually invokes the original method, but it can do something before and after such invocations. This actions can be to increment a variable, put statistics information somewhere, etc. 

The important thing here is that what is changed is the MethodDictionary of a class, not their instances. 

Suppose I want to know which methods where used, I need to do basically the same as the TestCoverage. This is, I replace all CM by a wrapper than just when it is called, it marks as "executed" and then put again the original. After running, you know which methods were invoked and which one were not. 

ProtocolCatcher

This a different approach to MethodWrappers. Basically, ProtocolCatcher extends from ProtoObject and implements the doesNotUndersand:
There it ask the class of the receiver and the selector and that information is stored in a class side variable.  What you have to do is to replace all the objects you want to analyze (using become:) by this objects of this class. One object of  ProtocolCatcher per object to be analyzed is created. 

This class variable is a dictionary where the key is the class and the value is a Set with the used selectors.

All the objects of ProtocolCatcher "work together" in the sense that they all store the information in a class side variable. Thus, there are class side methods to start, stop and reset the analysis. Once the analysis is done, you can ask the used classes and the selectors used for each class. 

However, as what I change are normal objects (not MethodDictionary), I can easily use this approach to detect used and unused objects, NO only code. For the same class, I can have a lot of objects, some that are used and some that are not. Of course that changing all the objects of an image by wrappers won't scale.

DynamicDeadCodeFinder

Is a tool mostly to detect unused code. The basic idea is to take a class, rename all methods to something like  NOTUSEDaMethod where aMethod is the name of the method. Then it implements the doesNotUnderstand:  and for the methods that were sent, they change them again to the original name.

After a while, it easy to detect the unused methods: those which names are NOTUSED* or have a particular category.

A little more in details, when you take a class and you want to analyze it, you do several things:
- Add to that class a implementation of the doesNotUnderstand: that what it does is to check if for the selector xxx there is a NOTUSEDxxx method. If there is, then that method is dynamically renamed to the original name (xxx) and then the message is resent. If it doesn't exist such method, it just send doesNotUnderstand: to super. 
- Add to that class a method called recompileNotSent: which is the one that does the mentioned rename. 
- Rename all existing methods to NOTUSED* 

A big problem with this approach is the following scenario: suppose you have the class B that implements the method foo and then the class A that subclass A and redefines the method foo. In this case, the doesNotUnderstand: is never sent for the message foo as the superclass DOES understand it. So...all the redefined messages are not taken into account. 

To solve this problem what is being done is to search (at the beginning) all the redefined methods. Then, we take the selector and we recompile it in the class (locally, not in super) but with an implementation that uses the method  recompileNotSent:  which does the conversion from NOTSEND to the original, as we already explained.