319 votes

Comment puis-je savoir quelles parties du code ne sont jamais utilisées ?

J’ai hérité code C++ que je suis censé pour supprimer code inutilisé de. Le problème est que la base de code est grande.

J’aimerai trouver des code qui n’est jamais appelé/jamais utilisé ?

201voto

Matthieu M. Points 101624

Il existe deux variétés de code inutilisé:

  • le local, qui est, dans certaines fonctions, certains chemins ou les variables sont utilisées (ou utilisé mais pas de manière significative, comme écrit, mais jamais lu)
  • mondial: les fonctions qui ne sont jamais appelés, des objets globaux qui ne sont jamais accessibles

Pour le premier type, un bon compilateur peut aider:

  • -Wunused (GCC, Clang) devrait mettre en garde sur les variables, Clang inutilisés de l'analyseur a même été incrémenté pour avertir sur les variables qui ne sont jamais lire (même si utilisé).
  • -Wunreachable-code (âgés de GCC, supprimée en 2010) devrait mettre en garde sur les blocs qui ne sont jamais accessibles (ce qui arrive avec les premiers retours ou des conditions toujours true)
  • il n'y a pas d'option que je connaisse pour les avertir inutilisés catch blocs, parce que le compilateur ne peut généralement pas prouver qu'aucune exception n'est levée.

Pour le second type, c'est beaucoup plus difficile. Statiquement, il exige de tout programme d'analyse, et même si le lien à l'optimisation du temps peut effectivement supprimer le code mort, dans la pratique, le programme a été tellement transformé au moment où il est effectué, qu'il est presque impossible de transmettre des informations utiles à l'utilisateur.

Il y a donc deux approches:

  • La théorie est celle de l'utilisation d'un analyseur statique. Un morceau de logiciel qui examinera l'ensemble du code à la fois dans le détail et de trouver toutes les voies d'écoulement. Dans la pratique, je ne connais pas un qui serait à l'œuvre ici.
  • La pragmatique est l'utilisation d'une heuristique: l'utilisation d'un outil de couverture de code (dans la GNU chaîne c'est gcov. Notez que des indicateurs spécifiques devrait être adopté lors de la compilation pour que cela fonctionne correctement). Vous exécutez l'outil de couverture de code avec un bon ensemble de diverses entrées (votre unité de tests-ou non-des tests de régression), le code mort est nécessairement dans l'évangile de code... et donc vous pouvez commencer à partir d'ici.

Si vous êtes très intéressé par le sujet, et ont le temps et l'envie de travailler à un outil par vous-même, je vous recommande d'utiliser le Cliquetis des bibliothèques de construire un tel outil.

  1. Utiliser le Cliquetis de la bibliothèque pour obtenir un AST (abstract syntax tree)
  2. Effectuer un mark-and-sweep analyse à partir de l'entrée des points de correspondance

Parce que Clang va analyser le code pour vous, et d'effectuer la résolution de surcharge, vous n'aurez pas à traiter avec le C++ langages de règles, et vous serez en mesure de se concentrer sur le problème à portée de main.

Cependant ce genre de technique ne peut pas identifier le virtuel remplace qui ne sont pas utilisés, car ils pourraient être appelés par le code tiers vous ne pouvez pas raisonner sur.

41voto

olsner Points 546

Pour le cas de la fraction inutilisée du fonctionnement de l'ensemble (et non utilisés à des variables globales), GCC peut réellement faire la plupart du travail pour vous à condition que vous êtes en utilisant GCC et GNU ld.

Lors de la compilation de la source, utilisez -ffunction-sections et -fdata-sections, puis lors de la liaison utilisation -Wl,--gc-sections,--print-gc-sections. L'éditeur de liens maintenant la liste de toutes les fonctions qui pourraient être supprimés parce qu'ils n'ont jamais été appelés et toutes les variables globales qui n'ont jamais été référencé.

(Bien sûr, vous pouvez également passer l' --print-gc-sections de la partie et laisser l'éditeur de liens de supprimer les fonctions en silence, mais de les garder dans la source).

Remarque: ce ne trouverez inutilisés des fonctions complètes, il ne fera rien à propos de la mort de code à l'intérieur des fonctions. Les fonctions appelées à partir du code mort dans des fonctions en direct seront également conservés.

En C++caractéristiques spécifiques aussi causer des problèmes, en particulier:

  • Des fonctions virtuelles. Sans savoir qui les sous-classes existent et qui sont en fait des instanciée au moment de l'exécution, vous ne pouvez pas savoir qui des fonctions virtuelles, vous avez besoin d'exister dans le programme final. L'éditeur de liens n'a pas assez d'informations à ce sujet alors il aura à garder toutes les autour de.
  • Globals avec les constructeurs, et leurs constructeurs. En général, l'éditeur de liens ne peuvent pas savoir que le constructeur mondial n'a pas d'effets secondaires, de sorte qu'il doit exécuter. Évidemment, cela signifie que le mondial lui-même doit également être conservé.

Dans les deux cas, quoi que ce soit utilisé par une fonction virtuelle ou un mondial de la variable constructeur doit également être maintenu autour de.

Un inconvénient supplémentaire est que si vous êtes la construction d'une bibliothèque partagée, les paramètres par défaut de GCC permettra d'exporter toutes les fonctions de la bibliothèque partagée, à l'origine pour être "utilisé" aussi loin que l'éditeur de liens. Pour corriger cela, vous devez définir la valeur par défaut de cacher des symboles à la place de l'exportation (en utilisant par ex. -fvisibility=hidden), puis de choisir explicitement les fonctions exportées que vous avez besoin pour l'exportation.

26voto

UmmaGumma Points 3154

Eh bien, si vous à l'aide de g++, vous pouvez utiliser cet indicateur -Wunused

Selon la documentation:

Avertir à chaque fois qu'une variable est inutilisé à part sa déclaration, chaque fois que une fonction est déclarée statique, mais jamais défini, chaque fois que l'étiquette est déclarées mais non utilisées, et à chaque fois qu'un déclaration calcule un résultat pas explicitement utilisé.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

Edit: Voici d'autres utiles drapeau -Wunreachable-code Selon la documentation:

Cette option est destinée à avertir lorsque le compilateur détecte au moins un ensemble de ligne de code source ne sera jamais exécutée, parce que certaines condition n'est jamais remplie ou parce que c'est au terme d'une procédure ne retourne jamais.

Mise à jour: j'ai trouvé de sujet similaire détection du code Mort en héritage en C/C++ projet

18voto

Carlos V Points 1194

Je pense que vous cherchez un outil de couverture de code . Un outil de couverture de code analysera votre code en cours d'exécution et vous indiquera quelles lignes de code ont été exécutées et combien de fois, ainsi que celles qui ne l'ont pas été.

Vous pourriez tenter de donner une chance à cet outil de couverture de code open source: TestCocoon - outil de couverture de code pour C / C ++ et C #.

16voto

Justin Morgan Points 12853

La vraie réponse est ici: Vous ne pouvez jamais être vraiment sûr.

Au moins, pour les non négligeable de cas, vous ne pouvez pas être sûr que vous avez obtenu tout cela. Considérons la suite de l'article de Wikipedia sur le code inaccessible:

double x = sqrt(2);
if (x > 5)
{
  doStuff();
}

Comme Wikipedia correctement des notes, un savant compilateur peut être capable d'attraper quelque chose comme ça. Mais envisager une modification:

int y;
cin >> y;
double x = sqrt((double)y);

if (x != 0 && x < 1)
{
  doStuff();
}

Sera le compilateur attraper? Peut-être. Mais pour ce faire, il devra faire plus que de courir sqrt contre un scalaire constante de la valeur. Il devra comprendre qu' (double)y sera toujours un entier (facile), puis de comprendre les mathématiques de la gamme de sqrt pour l'ensemble des entiers (dur). Un système sophistiqué, le compilateur pourrait être en mesure de le faire pour l' sqrt de la fonction, ou pour chaque fonction math.h, ou pour toute fixe d'entrée de la fonction dont le domaine peut comprendre. Cela devient très, très complexe, et cette complexité est essentiellement illimitée. Vous pouvez continuer à ajouter des couches de sophistication à votre compilateur, mais il y aura toujours un moyen de se faufiler dans un code qui sera inaccessible pour un ensemble donné d'intrants.

Et puis il y a l'entrée des ensembles qui, tout simplement, de ne jamais entrer. D'entrée qui n'auraient pas de sens dans la vie réelle, ou bloqué par une logique de validation ailleurs. Il n'y a aucun moyen pour le compilateur de savoir à propos de ceux-ci.

Le résultat de ceci est que, bien que les outils logiciels d'autres ont mentionné sont extrêmement utiles, vous n'allez savoir pour sûr que vous avez pris tout à moins que vous passez par le code manuellement par la suite. Même alors, vous ne serez jamais être certain que vous ne manquiez de rien.

La seule vraie solution, à mon humble avis, est d'être aussi vigilants que possible, l'utilisation de l'automatisation à votre disposition, refactoriser où vous le pouvez, et de chercher constamment des moyens d'améliorer votre code. Bien sûr, c'est une bonne idée de le faire de toute façon.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X