As ferramentas de cobertura de código, como Emma, Cobertura e Clover, instrumentarão seu código e registrarão quais partes dele são invocadas executando um conjunto de testes. Isso é muito útil e deve ser parte integrante do seu processo de desenvolvimento. Isso o ajudará a identificar até que ponto sua suíte de testes cobre seu código.
No entanto, isso não é o mesmo que identificar código morto real. Ele identifica apenas o código coberto (ou não coberto) pelos testes. Isso pode fornecer falsos positivos (se seus testes não abrangem todos os cenários), bem como falsos negativos (se seus testes acessarem código que na verdade nunca é usado em um cenário do mundo real).
Eu imagino que a melhor maneira de realmente identificar o código morto seria instrumentá-lo com uma ferramenta de cobertura em um ambiente de execução ao vivo e analisar a cobertura do código por um longo período de tempo.
Se você estiver executando em um ambiente redundante com balanceamento de carga (e, se não, por que não?), Suponho que faria sentido instrumentar apenas uma instância do seu aplicativo e configurar seu balanceador de carga de forma que uma parte aleatória, mas pequena, do seus usuários executam em sua instância instrumentada. Se você fizer isso por um longo período de tempo (para se certificar de ter coberto todos os cenários de uso do mundo real - variações sazonais), poderá ver exatamente quais áreas do seu código são acessadas no uso do mundo real e quais partes nunca são realmente acessados e, portanto, código morto.
Eu nunca vi isso pessoalmente, e não sei como as ferramentas mencionadas podem ser usadas para instrumentar e analisar o código que não está sendo chamado por meio de um conjunto de testes - mas tenho certeza de que sim.