Herramienta de análisis de código C++ estático: encontrar los diamantes en un gran código fuente

( Pregunta SO relacionada ).

Considere que hay una jerarquía de clases muy grande, de decenas o incluso cientos de clases. El diagrama de herencia también es muy complejo (doxygen no puede representarlo sin flechas de tamaño de media página :-)). Y aquí viene el temido problema de los diamantes. Estoy buscando una manera de encontrar todos los diamantes.

Alrededor así:

Las flechas de herencia dibujadas con lápiz rojo deben ser virtuales.  Encontrar los diamantes es fácil para el primer lugar.

Aquí, las flechas de herencia dibujadas con lápiz rojo deben ser virtuales. En una estructura tan sencilla es fácil encontrarlos todos, pero no en uno mucho más grande.

Encontrar todos los diamantes parece un problema de recorrido gráfico fácilmente automatizable. Me sorprendería si ya no existiera una solución para la tarea.

La pregunta es una herramienta que ya existe para una tarea?

Mi apuesta sería que es posible con CppDepend , pero trabajo en una nueva empresa y ya no tengo una licencia. Además, no tengo una base de código para probar. Ciertamente, no hay una función integrada para encontrar diamantes (lo escuché por primera vez), pero CppDepends es compatible con CQLinq , un lenguaje de consulta que hizo posible resolver cualquier tarea que tuviera. Obtenga la prueba de 14 días. Tal vez pregunte a support@cppdepend.com si tal consulta sería posible. Es comercial @ 500 USD.
¿Cómo se define un diamante en este contexto: una sola clase derivada de múltiples clases que a su vez se derivan de una sola clase, a cuántas eliminaciones? ¿Puede también heredar de otras clases? Conceptualmente, todos los objetos de clase se derivan de una sola clase (es decir, clase u objeto).
@SteveBarnes El diagrama de herencia de clases es un DAG (gráfico acíclico dirigido). Un diamante es un subgráfico mínimo conexo múltiple de este DAG. Por ejemplo, BS-BCA-BCS-T4-BT4-BI4 es un diamante. En C ++, no existe una "clase más alta" (conceptualmente). Un objeto es en C++ una instancia de una clase, no están relacionados con este problema, solo se trata de las clases.

Respuestas (2)

Tienes dos problemas que resolver:

  • Obtener el gráfico de herencia en una gran aplicación de C++
  • Descubriendo los diamantes

La primera parte es compleja porque analizar C++ para obtener esta información de herencia con precisión es difícil (C++ en sí mismo es increíblemente difícil de analizar, luego tienes las complicaciones de los condicionales del preprocesador, los archivos incluidos, las macros y las plantillas). Necesita un front-end completo de C++ para hacer esto y un ataque organizado para recopilar la información de herencia.

Nuestro kit de herramientas de reingeniería de software DMS con su interfaz C++ se puede utilizar para extraer este tipo de información. Puede configurar DMS para analizar todas sus unidades de compilación y realizar una resolución de nombre/tipo; esto maneja todo el preprocesamiento/resolución de plantilla y produce, para cada unidad de compilación, tanto AST para el programa (que no necesita para esta tarea) como tablas de símbolos accesibles, que contienen declaraciones de clases y herencias A deseadas -desde-B información. Un simple escaneo de la tabla de símbolos puede producir la información de herencia para cada unidad de compilación.

Luego debe reunir esa información para obtener un gráfico de herencia para su sistema. Debería ser obvio que literalmente desea construir el gráfico de herencia.

Con ese gráfico, el descubrimiento de diamantes es básicamente fácil:

  1. Para cada nodo, cree un conjunto hash vacío de elementos secundarios que almacene la ruta al elemento secundario
  2. Enumerar y registrar todas las rutas de cada nodo a sus elementos secundarios mediante una enumeración ascendente de rutas de herencia (se implementa fácilmente mediante una búsqueda en profundidad)
  3. Cada vez que encuentre un hijo dos veces desde un nodo, el conjunto hash contendrá las rutas a ese hijo; dos caminos --> diamante
  4. Marque ese nodo como si tuviera un diamante para evitar volver a enumerar todas las rutas secundarias

Puede implementar ese buscador de diamantes usando un software que no sea DMS, pero también podría implementarlo usando el lenguaje de programación de procedimientos interno de DMS, lo que evitaría el paso que exporta la información heredada.

Resumen:

  • DMS con front-end C++ analiza el código con precisión
  • Se puede recopilar información de herencia sin procesar por unidad de compilación
  • Los conjuntos de tales datos proporcionan un gráfico de herencia
  • El algoritmo para encontrar diamantes es bastante fácil de codificar.

Dado que DMS es el producto de mi empresa, no lo tome como una recomendación, simplemente como una nota de que DMS existe y puede realizar la tarea de OP.

Creo que eres un buen hombre. El SO está haciendo esto porque si no lo hiciera, estarían invadidos por spam. Aunque soy un fanático del código abierto, no es contra los programadores que intentan vender sus productos realmente maravillosos , sino contra los abusos de poder de las grandes empresas. Espero que el softwarerecs SE sea más ligero en este sentido.
¿Alguna vez pensó en hacer complementos de eclipse/msvs/cualquier cosa a partir de sus herramientas?
@peterh: (Gracias por el voto de confianza). Con respecto a los complementos de eclipse: lo hacemos; actualmente están disponibles como complementos de análisis COBOL especializados en la versión doblada de eclipse de IBM llamada "RDz"; Hicimos esto por razones comerciales muy complicadas, incluida la llamada "compatibilidad con Eclipse", y no nos agradó mucho que IBM nos dijera en qué se diferenciaba RDz de Eclipse convencional. Esperamos algún día conectar el conjunto más amplio de maquinaria para eclipsar, pero no sucederá este año.

También puede probar CppDepend , que proporciona muchas funciones relacionadas con las dependencias y un lenguaje de consulta de código para crear fácilmente sus reglas de dependencias.