A resposta real aqui é: você nunca pode realmente ter certeza.
Pelo menos, para casos não triviais, você não pode ter certeza de ter conseguido tudo isso. Considere o seguinte no artigo da Wikipedia sobre código inacessível :
double x = sqrt(2);
if (x > 5)
{
doStuff();
}
Como a Wikipedia observa corretamente, um compilador inteligente pode ser capaz de capturar algo assim. Mas considere uma modificação:
int y;
cin >> y;
double x = sqrt((double)y);
if (x != 0 && x < 1)
{
doStuff();
}
O compilador vai entender isso? Talvez. Mas, para fazer isso, será necessário fazer mais do que executarsqrt
contra um valor escalar constante. Ele terá que descobrir que (double)y
sempre será um número inteiro (fácil) e, em seguida, entender o intervalo matemático de sqrt
para o conjunto de números inteiros (difícil). Um compilador muito sofisticado pode fazer isso para a sqrt
função, ou para todas as funções em math.h , ou para qualquer função de entrada fixa cujo domínio ele possa descobrir. Isso fica muito, muito complexo, e a complexidade é basicamente ilimitada. Você pode continuar adicionando camadas de sofisticação ao seu compilador, mas sempre haverá uma maneira de ocultar algum código que será inacessível para qualquer conjunto de entradas.
E existem os conjuntos de entrada que simplesmente nunca são inseridos. Entrada que não faria sentido na vida real ou seria bloqueada pela lógica de validação em outro lugar. Não há como o compilador saber sobre isso.
O resultado final disso é que, embora as ferramentas de software mencionadas por outros sejam extremamente úteis, você nunca saberá com certeza que capturou tudo, a menos que repasse o código manualmente posteriormente. Mesmo assim, você nunca terá certeza de que não perdeu nada.
A única solução real, IMHO, é ser o mais vigilante possível, usar a automação à sua disposição, refatorar onde puder e procurar constantemente maneiras de melhorar seu código. Claro, é uma boa ideia fazer isso de qualquer maneira.