When you write
void DoSomething( FAKE_DOC(shared_ptr<Button>, Button::Ptr button) );
the compiler sees the code like
void DoSomething( shared_ptr<Button> button )
and thus doesn't require the definition of Button, while Doxygen generates
void DoSomething( Button::Ptr button )
(if you add the macro also in Doxygen). As mentioned, ugly, but probably the only way
For the specific case of shared_ptr<X> vs. X::Ptr, you could even write a shorter macro:
#define PTR(Type) shared_ptr<Type>
void DoSomething( PTR(Button) );