Por contexto, soy un desarrollador de Clang que trabaja en Google. En Google, hemos implementado los diagnósticos de Clang (esencialmente) para todos nuestros desarrolladores de C ++, y también tratamos las advertencias de Clang como errores. Como desarrollador de Clang y uno de los usuarios más grandes de los diagnósticos de Clang, intentaré arrojar algo de luz sobre estos indicadores y cómo se pueden usar. Tenga en cuenta que todo lo que estoy describiendo es genéricamente aplicable a Clang, y no específico a C, C ++ u Objective-C.
TL; Versión DR: utilice -Wall
y -Werror
como mínimo en cualquier código nuevo que esté desarrollando. Nosotros (los desarrolladores del compilador) agregamos advertencias aquí por buenas razones: encuentran errores. Si encuentra una advertencia que detecta errores por usted, actívela también. Intenta -Wextra
con un montón de buenos candidatos aquí. Si uno de ellos es demasiado ruidoso para que lo use de manera rentable, presente un error . Si escribe código que contiene un error "obvio" pero el compilador no lo advirtió, presente un error.
Ahora para la versión larga. Primero algunos antecedentes sobre agrupaciones de banderas de advertencia. Hay muchas "agrupaciones" de advertencias en Clang (y hasta cierto punto en GCC). Algunos que son relevantes para esta discusión:
- Activado por defecto: estas advertencias siempre están activadas a menos que las desactive explícitamente.
-Wall
: Estas son advertencias de que los desarrolladores tienen una gran confianza tanto en su valor como en una baja tasa de falsos positivos.
-Wextra
: Estas son advertencias que se consideran valiosas y sólidas (es decir, no tienen errores), pero pueden tener altas tasas de falsos positivos u objeciones filosóficas comunes.
-Weverything
: Este es un grupo de locos que literalmente habilita todas las
advertencias en Clang. No uses esto en tu código. Está destinado estrictamente a los desarrolladores de Clang o para explorar qué advertencias existen .
Hay dos criterios principales mencionados anteriormente que guían dónde van las advertencias en Clang, y aclaremos lo que realmente significan. El primero es el valor potencial
de una ocurrencia particular de la advertencia. Este es el beneficio esperado para el usuario (desarrollador) cuando se activa la advertencia e
identifica correctamente un problema con el código.
El segundo criterio es la idea de informes falsos positivos . Estas son situaciones en las que la advertencia se activa en el código, pero el problema potencial que se cita no se produce de hecho debido al contexto o alguna otra restricción del programa. El código advertido realmente se está comportando correctamente. Estos son especialmente malos cuando la advertencia nunca tuvo la intención de disparar en ese patrón de código. En cambio, es una deficiencia en la implementación de la advertencia lo que hace que se dispare allí.
Para las advertencias de Clang, se requiere que el valor esté en términos de corrección , no en términos de estilo, gusto o convenciones de codificación. Esto limita el conjunto de advertencias disponibles, lo que excluye advertencias solicitadas con frecuencia, como advertencias cuando {}
no se utilizan mensajes de correo electrónico alrededor del cuerpo de una if
declaración. Clang también es muy intolerante con los falsos positivos . A diferencia de la mayoría de los otros compiladores, utilizará una increíble variedad de fuentes de información para eliminar los falsos positivos, incluida la ortografía exacta de la construcción, la presencia o ausencia de '()', lanzamientos o incluso macros de preprocesador adicionales.
Ahora tomemos algunas advertencias de ejemplo del mundo real de Clang, y veamos cómo están categorizadas. Primero, una advertencia predeterminada:
% nl x.cc
1 class C { const int x; };
% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
^
1 warning generated.
Aquí no se requería ninguna bandera para obtener esta advertencia. La razón es que este código nunca es realmente correcto, lo que le da un alto valor de advertencia , y la advertencia solo se dispara en el código que Clang puede probar que cae en este segmento, lo que le da una tasa de cero falsos positivos .
% nl x2.cc
1 int f(int x_) {
2 int x = x;
3 return x;
4 }
% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
1 warning generated.
Clang requiere la -Wall
bandera para esta advertencia. La razón es que existe una cantidad de código no trivial que ha utilizado (para bien o para mal) el patrón de código del que estamos advirtiendo que produzca intencionalmente un valor no inicializado. Filosóficamente, no veo ningún punto en esto, pero muchos otros no están de acuerdo y la realidad de esta diferencia de opinión es lo que impulsa la advertencia bajo la
-Wall
bandera. Todavía tiene un valor muy alto y una tasa muy baja de
falsos positivos , pero en algunas bases de código no es un iniciador.
% nl x3.cc
1 void g(int x);
2 void f(int arr[], unsigned int size) {
3 for (int i = 0; i < size; ++i)
4 g(arr[i]);
5 }
% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
for (int i = 0; i < size; ++i)
~ ^ ~~~~
1 warning generated.
Esta advertencia requiere la -Wextra
bandera. La razón es que hay
bases de código muy grandes en las que el signo que no coincide en las comparaciones es extremadamente común. Si bien esta advertencia encuentra algunos errores, la probabilidad de que el código sea un error cuando el usuario escribe es bastante baja en promedio. El resultado es una tasa extremadamente alta de falsos positivos . Sin embargo, cuando hay un error en un programa debido a las extrañas reglas de promoción, a menudo es extremadamente sutil hacer que esta advertencia
cuando señala un error tenga un valor relativamente alto . Como consecuencia, Clang lo proporciona y lo expone bajo una bandera.
Por lo general, las advertencias no viven mucho tiempo fuera de la -Wextra
bandera. Clang se esfuerza mucho por no implementar advertencias que no ven el uso y las pruebas regulares. Las advertencias adicionales activadas por -Weverything
usualmente son advertencias en desarrollo activo o con errores activos. O serán reparados y colocados bajo las banderas apropiadas, o deberían ser eliminados.
Ahora que entendemos cómo funcionan estas cosas con Clang, intentemos volver a la pregunta original: ¿qué advertencias debe activar para su desarrollo? La respuesta es, desafortunadamente, que depende. Considere las siguientes preguntas para ayudar a determinar qué advertencias funcionan mejor para su situación.
- ¿Tiene control sobre todo su código o parte de él es externo?
- ¿Cuáles son tus metas? ¿Capturando errores o escribiendo mejor código?
- ¿Cuál es tu tolerancia falsa positiva? ¿Está dispuesto a escribir código adicional para silenciar las advertencias de forma regular?
En primer lugar, si no controlas el código, no intentes activar advertencias adicionales allí. Prepárate para apagar un poco. Hay muchos códigos incorrectos en el mundo y es posible que no pueda solucionarlos. Es correcto. Trabaja para encontrar una manera de enfocar tus esfuerzos en el código que controlas.
A continuación, descubra lo que quiere de sus advertencias. Esto es diferente para diferentes personas. Clang intentará advertir sin ninguna opción sobre errores atroces o patrones de código para los cuales tenemos un precedente histórico largo que indica que la tasa de errores es extremadamente alta. Al habilitarlo -Wall
, obtendrá un conjunto de advertencias mucho más agresivo dirigido a detectar los errores más comunes que los desarrolladores de Clang han observado en el código C ++. Pero con ambos, la
tasa de falsos positivos debería permanecer bastante baja.
Finalmente, si está perfectamente dispuesto a silenciar * falsos positivos * s a cada paso, vaya -Wextra
. Presente errores si observa advertencias que detectan muchos errores reales, pero que tienen falsos positivos sin sentido o tontos. Trabajamos constantemente para encontrar formas de incorporar cada vez más la lógica de búsqueda de errores -Wextra
en -Wall
donde podamos evitar los falsos positivos.
Muchos descubrirán que ninguna de estas opciones es la adecuada para ellos. En Google, hemos desactivado algunas advertencias -Wall
debido a la gran cantidad de código existente que viola la advertencia. También hemos activado algunas advertencias explícitamente, a pesar de que no están habilitadas -Wall
, porque tienen un valor particularmente alto para nosotros. Su millaje variará, pero probablemente variará de manera similar. A menudo puede ser mucho mejor habilitar algunas advertencias clave en lugar de todas
-Wextra
.
Me gustaría animar a todo el mundo para encender -Wall
para cualquier código no legado. Para el nuevo código, las advertencias aquí son casi siempre valiosas y realmente mejoran la experiencia de desarrollar código. Por el contrario, animaría a todos a
no habilitar las banderas más allá -Wextra
. Si encuentra una advertencia Clang que -Wextra
no incluya pero que resulta en absoluto valioso para usted, sólo tiene que informar de un problema y que probablemente podemos ponerlo bajo -Wextra
. Si habilita explícitamente algún subconjunto de las advertencias -Wextra
dependerá en gran medida de su código, su estilo de codificación y si mantener esa lista es más fácil que arreglar todo lo descubierto por -Wextra
.
De la lista de advertencias del OP (que incluía ambas -Wall
y -Wextra
) solo las siguientes advertencias no están cubiertas por esos dos grupos (o activadas de manera predeterminada). El primer grupo enfatiza por qué la excesiva dependencia de los indicadores de advertencia explícitos puede ser mala: ¡ninguno de estos se implementa en Clang! Se aceptan en la línea de comandos solo por compatibilidad con GCC.
-Wbad-function-cast
-Wdeclaration-after-statement
-Wmissing-format-attribute
-Wmissing-noreturn
-Wnested-externs
-Wnewline-eof
-Wold-style-definition
-Wredundant-decls
-Wsequence-point
-Wstrict-prototypes
-Wswitch-default
El siguiente grupo de advertencias innecesarias en la lista original son las que son redundantes con otras en esa lista:
-Wformat-nonliteral
-- Subconjunto de -Wformat=2
-Wshorten-64-to-32
-- Subconjunto de -Wconversion
-Wsign-conversion
-- Subconjunto de -Wconversion
También hay una selección de advertencias que son más categóricamente diferentes. Estos tratan con variantes de dialecto de idioma en lugar de con código con errores o sin errores. Con la excepción de -Wwrite-strings
, todas estas son advertencias para las extensiones de idioma proporcionadas por Clang. Si Clang advierte sobre su uso depende de la prevalencia de la extensión. Clang apunta a la compatibilidad con GCC, por lo que en muchos casos lo facilita con extensiones de lenguaje implícito que se usan ampliamente. -Wwrite-strings
, como se comentó en el OP, es un indicador de compatibilidad de GCC que realmente cambia la semántica del programa. Lamento profundamente esta bandera, pero tenemos que apoyarla debido al legado que tiene ahora.
-Wfour-char-constants
-Wpointer-arith
-Wwrite-strings
Las opciones restantes que realmente permiten advertencias potencialmente interesantes son estas:
-Wcast-align
-Wconversion
-Wfloat-equal
-Wformat=2
-Wimplicit-atomic-properties
-Wmissing-declarations
-Wmissing-prototypes
-Woverlength-strings
-Wshadow
-Wstrict-selector-match
-Wundeclared-selector
-Wunreachable-code
La razón por la que no están -Wall
o -Wextra
no siempre está clara. Para muchos de ellos, en realidad están basados en los avisos del CCG ( -Wconversion
,
-Wshadow
, etc.) y como tal Clang trata de imitar el comportamiento de GCC. Desglosamos lentamente algunos de estos en advertencias más útiles y de grano fino. Esos tienen una mayor probabilidad de convertirse en uno de los grupos de advertencia de nivel superior. Dicho esto, elegir una advertencia -Wconversion
es tan amplia que probablemente seguirá siendo su propia categoría de "nivel superior" en el futuro previsible. Algunas otras advertencias que tiene el CCG pero que tienen un valor bajo y altas tasas de falsos positivos pueden relegarse a una tierra de nadie similar.
Otras razones por las cuales no están en uno de los grupos más grandes incluyen errores simples, problemas muy positivos falsos positivos y advertencias en desarrollo. Voy a buscar errores en la presentación de los que puedo identificar. Todos deberían eventualmente migrar a una bandera de cubo grande adecuada o ser eliminados de Clang.
Espero que esto aclare la situación de advertencia con Clang y proporcione alguna información para aquellos que intentan elegir un conjunto de advertencias para su uso, o el uso de su compañía.