web-dev-qa-db-fra.com

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

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

Nous avons une grande base de code qui, au cours des 15 dernières années, a vu beaucoup de fonctionnalités bouger, mais les directives #include restantes sont rarement supprimées lorsqu'elles se déplacent d'un fichier d'implémentation à un autre, ce qui nous laisse un désordre total. Je peux évidemment faire le travail fastidieux de supprimer toutes les directives #include et de laisser le compilateur me dire lesquelles renvoyer, mais je préfère résoudre le problème à l'envers - trouver les inutilisées - plutôt que de reconstruire une liste de celles qui ont été utilisées.

69
Nick Bastin

AVERTISSEMENT: Mon travail consiste à travailler pour une entreprise qui développe des outils d’analyse statique.

Je serais surpris que la plupart (sinon la totalité) des outils d’analyse statique ne disposent pas d’une forme de vérification de l’utilisation de l’en-tête. Vous pouvez utiliser this wikipedia pour obtenir une liste des outils disponibles, puis envoyer un courrier électronique aux entreprises pour leur demander.

Quelques points à considérer lors de l’évaluation d’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 de la force brute, supprimez d'abord tous les en-têtes, puis rajoutez-les jusqu'à la compilation. Si 'f1.h' est ajouté, le code sera compilé mais la sémantique du programme a été modifiée.

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

// f1.h
template <typename T>
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>(int)'
}

En ce qui concerne l'exemple de surcharge, l'approche par force brute peut générer un programme qui compile toujours mais dont le comportement est différent.

Un autre type d'analyse connexe que vous pouvez rechercher consiste à vérifier si les types peuvent être déclarés en aval. Considérer ce qui suit:

// A.h
class A { };

// foo.h
#include "A.h"
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 obligatoire. Le fichier d'en-tête 'foo.h' peut donc être modifié de sorte qu'il ne possède une déclaration en aval que 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.

29
Richard Corden

Voici un script qui le fait:

#!/bin/bash
# Prune include files one at a time, recompile, and put them back if it doesn't compile
# 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 recompiles
        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
22
Andy C

Regardez Dehydra

Sur le site:

Dehydra est un outil d'analyse statique léger, scriptable et à usage général, capable d'analyser du code C++ spécifique à l'application. 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 recherche les fichiers #include inutilisés. 

5
Ton van den Heuvel

Le fichier cppclean de Google semble faire un travail décent en recherchant des fichiers d’en-tête inutilisés. Je viens de commencer à l'utiliser. Cela produit quelques faux positifs. Il y aura souvent des inclus inutiles dans les fichiers d’en-tête, mais cela ne vous dira pas qu’il faut une déclaration en aval de la classe associée et que l’inclusion doit être déplacé vers le fichier source associé. 

4
Chance

Si vous utilisez Eclipse CDT, vous pouvez essayer Includator qui est gratuit pour les bêta-testeurs (au moment de l'écriture de cette lettre) et supprime automatiquement les #includes superflus ou ajoute ceux qui sont manquants.

Disclaimer: Je travaille pour la société qui développe Includator et je l'utilise depuis quelques mois. Cela fonctionne assez bien pour moi, alors essayez-le :-)

3
Mirko Stocker

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 automatise fondamentalement votre "processus fastidieux":

pour chaque fichier cpp
pour chaque en-tête comprennent
commenter l'inclusion
compiler le fichier cpp
if (compile_errors)
commenter l'en-tête
autre
supprimer l'en-tête include de cpp

Mettez cela dans un cron nocturne, et il devrait faire le travail, en gardant le projet en question sans en-têtes inutilisés (vous pouvez toujours le lancer manuellement, évidemment, mais cela prendra beaucoup de temps). Le seul problème est que le fait de ne pas inclure d’en-tête ne génère pas d’erreur, mais produit toujours du code.

1
Cinder6

J'ai fait cela manuellement et ça en vaut la peine à court terme (Oh, est-ce le long terme? Cela prend beaucoup de temps) en raison du temps de compilation réduit: 

  1. Moins d'en-têtes à analyser pour chaque fichier cpp. 
  2. Moins de dépendances - le monde entier n'a pas besoin de recompiler après un changement En un en-tête.

C'est aussi un processus récursif - chaque fichier d'en-tête qui reste dans le fichier doit être examiné pour voir si des fichiers d'en-tête it includes peuvent être supprimés. De plus, vous pouvez parfois remplacer les déclarations en aval par les en-têtes.

Ensuite, tout le processus doit être répété tous les quelques mois/année pour rester au-dessus des en-têtes restants.

En fait, je suis un peu ennuyé 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 d'un fichier d'en-tête peut être ignorée en toute sécurité lors de la compilation.

1
quamrana

Si quelqu'un est intéressé, je viens de mettre sur sourceforge un petit outil en ligne de commande Java pour faire exactement cela .. .. Comme il est écrit en Java, il est évidemment utilisable sous Linux.

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

0
Arctica