¿Herramientas para encontrar encabezados incluidos que no se utilizan?

Sé que PC-Lint puede informarle sobre los encabezados que se incluyen pero no se usan. ¿Hay alguna otra herramienta que pueda hacer esto, preferiblemente en Linux?

Tenemos una gran base de código que a lo largo de los últimos 15 años ha visto una gran cantidad de funcionalidades moverse, pero rara vez se eliminan las directivas #include sobrantes cuando la funcionalidad se mueve de un archivo de implementación a otro, dejándonos con bastante confusión en este punto. Obviamente, puedo hacer la laboriosa tarea de eliminar todas las directivas #include y dejar que el comstackdor me diga cuáles incluir, pero prefiero resolver el problema a la inversa, encontrar las que no se utilizaron, en lugar de reconstruir una lista de las usadas.

DESCARGO DE RESPONSABILIDAD: Mi trabajo diario está funcionando para una empresa que desarrolla herramientas de análisis estático.

Me sorprendería que la mayoría de las herramientas de análisis estático (si no todas) no tuvieran algún tipo de verificación de uso del encabezado. Puede usar esta página de wikipedia para obtener una lista de las herramientas disponibles y luego enviarlas por correo electrónico a las empresas para que las consulten.

Algunos puntos que puede considerar al evaluar una herramienta:

Para las sobrecargas de funciones, desea que todos los encabezados que contienen sobrecargas estén visibles, no solo el encabezado que contiene la función que se seleccionó mediante la resolución de sobrecarga:

// 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 adoptas el enfoque de la fuerza bruta, primero quita todos los encabezados y luego vuelve a agregarlos hasta que se compile, si primero se agrega ‘f1.h’, el código se comstackrá pero la semántica del progtwig se habrá modificado.

Una regla similar se aplica cuando tienes parcializaciones y especializaciones. No importa si la especialización está seleccionada o no, debe asegurarse de que todas las especializaciones estén 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 cuanto al ejemplo de sobrecarga, el enfoque de fuerza bruta puede dar como resultado un progtwig que aún comstack pero tiene un comportamiento diferente.

Otro tipo de análisis relacionado que puede tener en cuenta es verificar si los tipos pueden declararse hacia adelante. Considera lo siguiente:

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

En el ejemplo anterior, la definición de ‘A’ no es necesaria, por lo que el archivo de encabezado ‘foo.h’ se puede cambiar para que tenga una statement directa solo para ‘A’:

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

Este tipo de control también reduce las dependencias del encabezado.

Aquí hay un script que lo hace:

 #!/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 

Eche un vistazo a Dehydra .

Desde el sitio web:

Dehydra es una herramienta de análisis estático, liviana, progtwigble y de uso general, capaz de análisis específicos de la aplicación del código C ++. En el sentido más simple, se puede pensar en Dehydra como una herramienta semántica de grep.

Debería ser posible encontrar un script que verifique los archivos #include no utilizados.

El cppclean de Google parece hacer un trabajo decente al encontrar archivos de encabezado sin usar. Solo comencé a usarlo. Produce algunos falsos positivos. A menudo encontrará inclusiones innecesarias en los archivos de encabezado, pero lo que no le dirá es que necesita una statement directa de la clase asociada, y la inclusión debe moverse al archivo fuente asociado.

Si está utilizando Eclipse CDT, puede probar el Includator, que es gratuito para los beta testers (en el momento de escribir esto) y elimina automáticamente #includes superfluos o agrega los que faltan.

Descargo de responsabilidad: trabajo para la compañía que desarrolla el Includator y lo he usado durante los últimos meses. Funciona bastante bien para mí, así que pruébalo 🙂

Por lo que yo sé, no hay uno (que no sea PC-Lint), lo cual es una pena y sorprendente. He visto la sugerencia de hacer este tipo de pseudocódigo (que básicamente es la automatización de su “proceso minucioso”:

por cada archivo cpp
por cada encabezado incluido
comentar el incluir
comstackr el archivo cpp
if (compile_errors)
des-comentar el encabezado
más
eliminar encabezado incluir desde cpp

Ponlo en un cron nocturno, y debería hacer el trabajo, manteniendo el proyecto en cuestión libre de encabezados no utilizados (siempre puedes ejecutarlo manualmente, obviamente, pero llevará mucho tiempo ejecutarlo). El único problema es cuando no incluir un encabezado no genera un error, pero aún produce código.

He hecho esto manualmente y vale la pena en el corto plazo (Oh, ¿es el término a largo plazo? – Toma mucho tiempo) debido a un tiempo de comstackción reducido:

  1. Menos encabezados para analizar por cada archivo cpp.
  2. Menos dependencias: el mundo entero no necesita volver a comstackr después de un cambio en un encabezado.

También es un proceso recursivo: cada archivo de encabezado que permanece en las necesidades debe examinarse para ver si se puede eliminar cualquier archivo de encabezado que incluya. Además, a veces puede sustituir las declaraciones directas por encabezados.

Luego, todo el proceso debe repetirse cada pocos meses / año para mantenerse al tanto de los encabezados restantes.

En realidad, estoy un poco molesto con los comstackdores de C ++, deberían poder decirle lo que no se necesita: el comstackdor de Microsoft puede decirle cuándo un cambio en un archivo de encabezado puede ignorarse de manera segura durante la comstackción.

Si alguien está interesado, acabo de poner en sourceforge una pequeña herramienta Java línea de comando para hacer exactamente eso. Como está escrito en Java, obviamente es ejecutable en Linux.

El enlace para el proyecto es https://sourceforge.net/projects/chksem/files/chksem-1.0/

La mayoría de los enfoques para eliminar sin usar funcionan mejor si primero se asegura de que cada uno de sus archivos de encabezado se compile por sí mismo. Lo hice de forma relativamente rápida de la siguiente manera (disculpas por los errores tipográficos; estoy escribiendo esto en casa:

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

donde makeIncluder.sh contiene:

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

Para cada archivo ./subdir/classname.h , este enfoque crea un archivo llamado ./subdir/classname.h.cpp contiene la línea

 #include "./subdir/classname.h" 

Si su makefile en el. directorio comstack todos los archivos cpp y contiene -I. , entonces, al volver a comstackr, se probará que cada archivo incluido se puede comstackr por sí mismo. Comstack tu IDE favorito con goto-error y soluciona los errores.

Cuando termines, find . -name '*.h.cpp' -exec rm {} \; find . -name '*.h.cpp' -exec rm {} \;