Je travaille sur un grand projet C++ dans Visual Studio 2008, et il y a beaucoup de fichiers avec des #include inutiles. Parfois, les #include ne sont que des artefacts et tout se compile bien s'ils sont supprimés. Dans d'autres cas, les classes peuvent être déclarées de manière anticipée et le #include peut être déplacé vers le fichier .cpp. Existe-t-il de bons outils pour détecter ces deux cas de figure ?
Réponses
Trop de publicités?Bien qu'il ne révèle pas les fichiers inclus inutiles, Visual Studio dispose d'un paramètre "/showIncludes" (clic droit sur un fichier .cpp, Propriétés->C/C++->Avancé) qui affiche un arbre de tous les fichiers inclus au moment de la compilation. Cela peut aider à identifier les fichiers qui n'ont pas besoin d'être inclus.
Vous pouvez également jeter un coup d'œil à l'idiome pimpl, qui vous permet de réduire le nombre de dépendances des fichiers d'en-tête afin de mieux voir les éléments que vous pouvez supprimer.
Peluche de PC fonctionne très bien pour cela, et il trouve toutes sortes d'autres problèmes bizarres pour vous aussi. Il dispose d'options de ligne de commande qui peuvent être utilisées pour créer des outils externes dans Visual Studio, mais j'ai trouvé que l'option Visual Lint est plus facile à utiliser. Même la version gratuite de Visual Lint est utile. Mais donnez une chance à PC-Lint. Le configurer pour qu'il ne vous donne pas trop d'avertissements prend un peu de temps, mais vous serez étonné de ce qu'il trouve.
Il y a un nouvel outil basé sur Clang, incluez ce que vous voulez qui vise à faire cela.
AVIS DE NON-RESPONSABILITÉ ! Je travaille sur un outil commercial d'analyse statique (pas PC Lint). AVERTISSEMENT !
Une approche simple sans analyse syntaxique pose plusieurs problèmes :
1) Sets de surcharge :
Il est possible qu'une fonction surchargée ait des déclarations qui proviennent de différents fichiers. Il se peut que la suppression d'un fichier d'en-tête entraîne le choix d'une surcharge différente plutôt qu'une erreur de compilation ! Le résultat sera un changement silencieux de la sémantique qui peut être très difficile à retracer par la suite.
2) Spécialisations des modèles :
Comme dans l'exemple de la surcharge, si vous avez des spécialisations partielles ou explicites pour un modèle, vous voulez qu'elles soient toutes visibles lorsque le modèle est utilisé. Il se peut que les spécialisations pour le modèle principal se trouvent dans différents fichiers d'en-tête. La suppression de l'en-tête contenant la spécialisation ne provoquera pas d'erreur de compilation, mais peut entraîner un comportement indéfini si cette spécialisation avait été sélectionnée. (Voir : http://stackoverflow.com/questions/59331/visibility-of-template-specialization-of-c-function )
Comme l'a souligné 'msalters', une analyse complète du code permet également d'analyser l'utilisation des classes. En vérifiant comment une classe est utilisée à travers un chemin spécifique de fichiers, il est possible que la définition de la classe (et donc toutes ses dépendances) puisse être supprimée complètement ou au moins déplacée à un niveau plus proche de la source principale dans l'arbre d'inclusion.
Je ne connais pas d'outils de ce type, et j'ai pensé en écrire un par le passé, mais il s'avère que c'est un problème difficile à résoudre.
Disons que votre fichier source comprend a.h et b.h ; a.h contient #define USE_FEATURE_X
et b.h utilise #ifdef USE_FEATURE_X
. Si #include "a.h"
est commenté, votre fichier peut toujours compiler, mais peut ne pas faire ce que vous attendez. Détecter cela par programme est non trivial.
Quel que soit l'outil utilisé, il devra également connaître votre environnement de construction. Si a.h ressemble à :
#if defined( WINNT )
#define USE_FEATURE_X
#endif
Puis USE_FEATURE_X
n'est défini que si WINNT
est définie, l'outil doit donc savoir quelles directives sont générées par le compilateur lui-même et lesquelles sont spécifiées dans la commande de compilation plutôt que dans un fichier d'en-tête.