Para las herramientas de análisis estático , suelo utilizar CPD, PMD , FindBugs y Checkstyle .
CPD es la herramienta "Detector de copiar / pegar" de PMD. Estuve usando PMD por un tiempo antes de que me di cuenta del enlace "Encontrar código duplicado" en la página web de PMD .
Me gustaría señalar que estas herramientas a veces pueden extenderse más allá de su conjunto de reglas "listas para usar". Y no solo porque son de código abierto para que pueda reescribirlos. Algunas de estas herramientas vienen con aplicaciones o "ganchos" que permiten ampliarlas. Por ejemplo, PMD viene con la herramienta de "diseñador" que le permite crear nuevas reglas. Además, Checkstyle tiene el control DescendantToken que tiene propiedades que permiten una personalización sustancial.
Integro estas herramientas con una compilación basada en Ant . Puedes seguir el enlace para ver mi configuración comentada.
Además de la simple integración en la compilación, encuentro útil configurar las herramientas para que estén algo "integradas" en un par de otras formas. Es decir, uniformidad en la generación de informes y supresión de advertencias. Me gustaría agregar estos aspectos a esta discusión (que probablemente también debería tener la etiqueta "análisis estático"): ¿cómo está configurando la gente estas herramientas para crear una solución "unificada"? (He hecho esta pregunta por separado aquí )
Primero, para los informes de advertencia, transformo la salida para que cada advertencia tenga el formato simple:
/absolute-path/filename:line-number:column-number: warning(tool-name): message
Esto a menudo se denomina "formato de Emacs", pero incluso si no está utilizando Emacs, es un formato razonable para homogeneizar informes. Por ejemplo:
/project/src/com/example/Foo.java:425:9: warning(Checkstyle):Missing a Javadoc comment.
Mis transformaciones de formato de advertencia las realiza mi script Ant con cadenas de filtros Ant .
La segunda "integración" que hago es para la supresión de advertencias. De forma predeterminada, cada herramienta admite comentarios o una anotación (o ambos) que puede colocar en su código para silenciar una advertencia que desea ignorar. Pero estas diversas solicitudes de supresión de advertencias no tienen un aspecto coherente, lo que parece algo tonto. Cuando está suprimiendo una advertencia, está suprimiendo una advertencia, así que ¿por qué no escribir siempre " SuppressWarning
?"
Por ejemplo, la configuración predeterminada de PMD suprime la generación de advertencias en líneas de código con la cadena " NOPMD
" en un comentario. Además, PMD admite la @SuppressWarnings
anotación de Java . Configuro PMD para usar comentarios que contengan " SuppressWarning(PMD.
" en lugar de NOPMD
que las supresiones de PMD se vean iguales. Completo la regla particular que se viola cuando se usa la supresión de estilo de comentario:
// SuppressWarnings(PMD.PreserveStackTrace) justification: (false positive) exceptions are chained
Solo la parte " SuppressWarnings(PMD.
" es significativa para un comentario, pero es consistente con el apoyo de PMD a la @SuppressWarning
anotación que reconoce las violaciones de las reglas individuales por su nombre:
@SuppressWarnings("PMD.CompareObjectsWithEquals") // justification: identity comparision intended
De manera similar, Checkstyle suprime la generación de advertencias entre pares de comentarios (no se proporciona soporte de anotaciones). De forma predeterminada, los comentarios para activar y desactivar Checkstyle contienen las cadenas CHECKSTYLE:OFF
y CHECKSTYLE:ON
, respectivamente. Cambiar esta configuración (con "SuppressionCommentFilter" de Checkstyle) para usar las cadenas " BEGIN SuppressWarnings(CheckStyle.
" y " END SuppressWarnings(CheckStyle.
" hace que los controles se parezcan más a PMD:
// BEGIN SuppressWarnings(Checkstyle.HiddenField) justification: "Effective Java," 2nd ed., Bloch, Item 2
// END SuppressWarnings(Checkstyle.HiddenField)
Con los comentarios de estilo de verificación, la violación de verificación particular ( HiddenField
) es significativa porque cada verificación tiene su propio BEGIN/END
par de comentarios.
FindBugs también admite la supresión de la generación de advertencias con una @SuppressWarnings
anotación, por lo que no se requiere ninguna configuración adicional para lograr cierto nivel de uniformidad con otras herramientas. Desafortunadamente, Findbugs tiene que admitir una @SuppressWarnings
anotación personalizada porque la @SuppressWarnings
anotación Java incorporada tiene una SOURCE
política de retención que no es lo suficientemente sólida como para retener la anotación en el archivo de clase donde FindBugs la necesita. Califico completamente las supresiones de advertencias de FindBugs para evitar chocar con la @SuppressWarnings
anotación de Java :
@edu.umd.cs.findbugs.annotations.SuppressWarnings("UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR")
Estas técnicas hacen que las cosas parezcan razonablemente consistentes en todas las herramientas. Tenga en cuenta que hacer que cada supresión de advertencia contenga la cadena " SuppressWarnings
" facilita la ejecución de una búsqueda simple para encontrar todas las instancias de todas las herramientas en una base de código completa.