Des outils pour trouver les en-têtes inclus qui ne sont pas utilisés?

Je sais que PC-Lint peut vous parler des en-têtes inclus mais non utilisés. Y a-t-il d’autres outils qui peuvent le faire, de préférence sous Linux?

Nous avons une base de code importante qui, au cours des 15 dernières années, a vu de nombreuses fonctionnalités évoluer, mais les directives #include restantes sont rarement supprimées lorsque la fonctionnalité passe d’un fichier d’implémentation à un autre. Je peux évidemment faire le travail pénible en supprimant toutes les directives #include et en laissant le compilateur me dire lesquelles renvoyer, mais je préfère résoudre le problème en sens inverse – trouver les inutilisées – plutôt que de reconstruire une liste de celles utilisées.

DISCLAIMER: Mon travail de jour travaille pour une entreprise qui développe des outils d’parsing statique.

Je serais surpris que la plupart (sinon tous) des outils d’parsing statique n’aient pas une forme de vérification de l’utilisation des en-têtes. Vous pouvez utiliser cette page wikipedia pour obtenir une liste des outils disponibles, puis envoyer un courrier électronique aux entresockets pour leur demander.

Quelques points à prendre en compte lorsque vous évaluez un outil:

Pour les surcharges de fonctions, vous souhaitez que tous les en-têtes contenant des surcharges soient visibles, pas seulement l’en-tête contenant la fonction sélectionnée par résolution de surcharge:

// f1.h void foo (char); // f2.h void foo (int); // bar.cc #include "f1.h" #include "f2.h" int main () { foo (0); // Calls 'foo(int)' but all functions were in overload set } 

Si vous adoptez l’approche par force brute, commencez par supprimer tous les en-têtes, puis rajoutez-les jusqu’à ce qu’ils soient compilés, si “f1.h” est ajouté en premier, le code sera compilé mais la sémantique du programme a été modifiée.

Une règle similaire s’applique lorsque vous avez des connaissances partielles et des spécialisations. Peu importe si la spécialisation est sélectionnée ou non, vous devez vous assurer que toutes les spécialisations sont visibles:

 // f1.h template  void foo (T); // f2.h template <> void foo (int); // bar.cc #include "f1.h" #include "f2.h" int main () { foo (0); // Calls specialization 'foo(int)' } 

En ce qui concerne l’exemple de surcharge, l’approche par force brute peut aboutir à un programme qui comstack encore mais a un comportement différent.

Un autre type d’parsing connexe que vous pouvez rechercher est de vérifier si les types peuvent être déclarés en avant. Considérer ce qui suit:

 // Ah class A { }; // foo.h #include "Ah" void foo (A const &); // bar.cc #include "foo.h" void bar (A const & a) { foo (a); } 

Dans l’exemple ci-dessus, la définition de ‘A’ n’est pas requirejse, et le fichier d’en-tête ‘foo.h’ peut donc être modifié pour n’avoir qu’une déclaration directe pour ‘A’:

 // foo.h class A; void foo (A const &); 

Ce type de vérification réduit également les dépendances d’en-tête.

Voici un script qui le fait:

 #!/bin/bash # prune include files one at a time, recomstack, and put them back if it doesn't comstack # arguments are list of files to check removeinclude() { file=$1 header=$2 perl -i -p -e 's+([ \t]*#include[ \t][ \t]*[\"\< ]'$2'[\"\>])+//REMOVEINCLUDE $1+' $1 } replaceinclude() { file=$1 perl -i -p -e 's+//REMOVEINCLUDE ++' $1 } for file in $* do includes=`grep "^[ \t]*#include" $file | awk '{print $2;}' | sed 's/[\"\< \>]//g'` echo $includes for i in $includes do touch $file # just to be sure it recomstacks removeinclude $file $i if make -j10 >/dev/null 2>&1; then grep -v REMOVEINCLUDE $file > tmp && mv tmp $file echo removed $i from $file else replaceinclude $file echo $i was needed in $file fi done done 

Jetez un coup d’œil à Dehydra .

Depuis le site:

Dehydra est un outil d’parsing statique léger, scriptable, à usage général, capable d’parsings spécifiques du code C ++. Dans le sens le plus simple, Dehydra peut être considéré comme un outil sémantique de grep.

Il devrait être possible de créer un script qui vérifie les fichiers #include inutilisés.

Cppclean de Google semble faire un travail décent pour trouver des fichiers d’en-tête inutilisés. Je viens de commencer à l’utiliser. Il produit quelques faux positifs. Il sera souvent inutile d’inclure des inclusions dans les fichiers d’en-tête, mais ce que cela ne vous dit pas, c’est que vous avez besoin d’une déclaration avancée de la classe associée et que l’inclusion doit être déplacée vers le fichier source associé.

Si vous utilisez Eclipse CDT, vous pouvez essayer Includator qui est gratuit pour les bêta-testeurs (au moment de la rédaction de ce document) et qui supprime automatiquement les #includes superflues ou ajoute celles qui manquent.

Disclaimer: Je travaille pour la société qui développe Includator et l’utilise depuis quelques mois. Ça marche plutôt bien pour moi, alors essayez-le 🙂

Pour autant que je sache, il n’y en a pas (ce n’est pas PC-Lint), ce qui est dommage et surprenant. J’ai vu la suggestion de faire ce morceau de pseudocode (qui consiste à automatiser fondamentalement votre “processus minutieux”:

pour chaque fichier cpp
pour chaque en-tête inclure
commenter l’inclusion
comstackr le fichier cpp
if (comstack_errors)
dés-commenter l’en-tête
autre
supprimer l’en-tête include de cpp

Mettez cela dans un cron nocturne, et cela devrait faire le travail, en gardant le projcet en question libre des en-têtes inutilisés (vous pouvez toujours l’exécuter manuellement, évidemment, mais cela prendra beaucoup de temps). Le seul problème est que lorsque ne pas inclure un en-tête ne génère pas une erreur, mais produit toujours du code.

Je l’ai fait manuellement et cela en vaut la peine (Oh, est-ce le long terme? – Cela prend du temps) en raison du temps de compilation réduit:

  1. Moins d’en-têtes à parsingr pour chaque fichier cpp.
  2. Moins de dépendances – le monde entier n’a pas besoin d’être recompilé après une modification d’un en-tête.

C’est également un processus récursif – chaque fichier d’en-tête qui rest dans doit être examiné pour voir si les fichiers d’en-tête qu’il inclut peuvent être supprimés. De plus, il est parfois possible de substituer des déclarations avancées pour les en-têtes inclus.

Ensuite, l’ensemble du processus doit être répété tous les quelques mois / an pour restr au fait des en-têtes restants.

En fait, je suis un peu contrarié par les compilateurs C ++, ils devraient pouvoir vous dire ce qui n’est pas nécessaire – le compilateur Microsoft peut vous dire quand une modification à un fichier d’en-tête peut être ignorée en toute sécurité lors de la compilation.

Si quelqu’un est intéressé, je viens de placer sur sourceforge un petit outil de commande Java pour faire exactement cela. Comme il est écrit en Java, il est évidemment exploitable sur Linux.

Le lien pour le projet est https://sourceforge.net/projects/chksem/files/chksem-1.0/

La plupart des approches pour supprimer les éléments inutilisés fonctionnent mieux si vous vous assurez d’abord que chaque fichier d’en-tête est compilé seul. Je l’ai fait relativement rapidement comme suit (excuses pour les fautes de frappe – je tape ceci à la maison:

 find . -name '*.h' -exec makeIncluder.sh {} \; 

makeIncluder.sh contient:

 #!/bin/sh echo "#include \"$1\"" > $1.cpp 

Pour chaque fichier ./subdir/classname.h , cette approche crée un fichier appelé ./subdir/classname.h.cpp contenant la ligne.

 #include "./subdir/classname.h" 

Si votre makefile dans le makefile . répertoire comstack tous les fichiers cpp et contient -I. , alors simplement recomstackr testera que chaque fichier d’inclusion peut se comstackr seul. Comstackz votre IDE préféré avec goto-error et corrigez les erreurs.

Lorsque vous avez terminé, find . -name '*.h.cpp' -exec rm {} \; find . -name '*.h.cpp' -exec rm {} \;