La vera risposta qui è: non puoi mai saperlo con certezza.
Almeno, per i casi non banali, non puoi essere sicuro di averlo ottenuto tutto. Considera quanto segue dall'articolo di Wikipedia sul codice non raggiungibile :
double x = sqrt(2);
if (x > 5)
{
doStuff();
}
Come osserva correttamente Wikipedia, un compilatore intelligente potrebbe essere in grado di catturare qualcosa del genere. Ma considera una modifica:
int y;
cin >> y;
double x = sqrt((double)y);
if (x != 0 && x < 1)
{
doStuff();
}
Il compilatore lo prenderà? Può essere. Ma per farlo, dovrà fare di più che correre sqrt
contro un valore scalare costante. Dovrà capire che (double)y
sarà sempre un numero intero (facile) e quindi comprendere l'intervallo matematico di sqrt
per l'insieme di numeri interi (difficile). Un compilatore molto sofisticato potrebbe essere in grado di farlo per la sqrt
funzione, o per ogni funzione in math.h , o per qualsiasi funzione di input fisso di cui può capire il dominio. Questo diventa molto, molto complesso e la complessità è sostanzialmente illimitata. Puoi continuare ad aggiungere livelli di raffinatezza al tuo compilatore, ma ci sarà sempre un modo per intrufolarsi in un codice che sarà irraggiungibile per qualsiasi dato set di input.
E poi ci sono i set di input che semplicemente non vengono mai inseriti. Input che non avrebbero alcun senso nella vita reale o che sarebbero bloccati dalla logica di convalida altrove. Non c'è modo per il compilatore di conoscerli.
Il risultato finale di questo è che mentre gli strumenti software che altri hanno menzionato sono estremamente utili, non saprai mai con certezza che hai preso tutto a meno che non passi il codice manualmente in seguito. Anche allora, non sarai mai sicuro di non aver perso nulla.
L'unica vera soluzione, IMHO, è quella di essere il più vigile possibile, utilizzare l'automazione a tua disposizione, il refactor dove puoi e cercare costantemente modi per migliorare il tuo codice. Certo, è una buona idea farlo comunque.