¿Puede clang-format romper mi código?
(6)
Dado que clang-format
es una herramienta para reformatear solo el código, ¿es posible que dicho formato rompa el código de trabajo o al menos cambie la forma en que funciona? ¿Hay algún tipo de contrato que no pueda cambiar la forma en que funciona el código?
Tenemos un montón de código que queremos formatear con el formato clang-format
. Esto significa que muchas líneas de código cambiarán. No tener que revisar cada una de las líneas de código que solo cambiaron debido a un clang-format
sería una gran simplificación de este proceso.
Yo diría que clang-format
no cambiará cómo funciona el código. Por otro lado, no estoy 100% seguro, si esto se puede garantizar.
Respuesta corta: SI.
La herramienta de clang-format
tiene una opción -sort-includes
. Cambiar el orden de las directivas #include
definitivamente puede cambiar el comportamiento del código existente y puede romper el código existente.
Debido a que la opción SortIncludes
correspondiente está establecida en true
por varios de los estilos incorporados, puede que no sea obvio que clang-format
va a reordenar sus inclusiones.
MyStruct.h:
struct MyStruct {
uint8_t value;
};
original.c:
#include <stdint.h>
#include <stddef.h>
#include "MyStruct.h"
int main (int argc, char **argv) {
struct MyStruct s = { 0 };
return s.value;
}
Ahora digamos que ejecutamos clang-format -style=llvm original.c > restyled.c
.
restyled.c:
#include "MyStruct.h"
#include <stddef.h>
#include <stdint.h>
int main(int argc, char **argv) {
struct MyStruct s = {0};
return s.value;
}
Debido a la reordenación de los archivos de encabezado, recibo el siguiente error al compilar restyled.c
:
In file included from restyled.c:1:
./MyStruct.h:2:5: error: unknown type name ''uint8_t''
uint8_t value;
^
1 error generated.
Sin embargo, este problema debe ser fácil de solucionar. Es improbable que tenga pedidos dependientes del orden como este, pero si lo hace, puede solucionar el problema colocando una línea en blanco entre los grupos de encabezados que requieren un orden específico, ya que aparentemente clang-format
solo clasifica los grupos de directivas #include
con No hay líneas que no sean #include
en medio.
fijo-original.c:
#include <stdint.h>
#include <stddef.h>
#include "MyStruct.h"
int main (int argc, char **argv) {
struct MyStruct s = { 0 };
return s.value;
}
fijado-restyled.c:
#include <stddef.h>
#include <stdint.h>
#include "MyStruct.h"
int main(int argc, char **argv) {
struct MyStruct s = {0};
return s.value;
}
Tenga en cuenta que stdint.h
y stddef.h
todavía se reordenaron debido a que sus stddef.h
aún están "agrupadas", pero que la nueva línea en blanco impidió que MyStruct.h
se moviera antes de que se incluyera la biblioteca estándar.
Sin embargo...
Si reordenar sus directivas #include
rompe su código, probablemente debería hacer una de las siguientes acciones de todos modos:
Incluya explícitamente las dependencias para cada encabezado en el archivo de encabezado. En mi ejemplo, necesitaría incluir
stdint.h
enMyStruct.h
.Agregue una línea de comentarios entre los grupos de inclusión que indique explícitamente la dependencia de pedido. Recuerde que cualquier línea que no sea
#include
debe dividir un grupo, así que las líneas de comentarios también funcionan. La línea de comentarios en el siguiente código también evita queclang-format
incluyaMyStruct.h
antes de los encabezados de la biblioteca estándar.
alternate-original.c:
#include <stdint.h>
#include <stddef.h>
// must come after stdint.h
#include "MyStruct.h"
int main (int argc, char **argv) {
struct MyStruct s = { 0 };
return s.value;
}
Dado que clang-format
Clang solo afecta a los caracteres de espacio en blanco, puede verificar que los archivos antes y después clang-format
Clang sean idénticos hasta los espacios en blanco. En Linux / BSD / OS X puede usar diff
y tr
para eso:
$ diff --ignore-all-space <(tr ''/n'' '' '' < 2.c ) <(tr ''/n'' '' '' < 1.c)
1.c:
#include <stdio.h>
int main() {printf("Hello, world!/n"); return 0;}
2.c:
#include <stdio.h>
int main() {
printf("Hello, world!/n");
return 0;
}
La salida del comando diff
está vacía, lo que significa que los archivos 1.c
y 2.c
son idénticos a los espacios en blanco.
Como mencionó Karoly en su comentario, tenga en cuenta que en condiciones ideales todavía tiene que verificar los espacios que importan, por ejemplo, literales de cadena. Pero en el mundo real, creo que esta prueba es más que suficiente.
Me imagino que no, dado que se basa en el análisis estático de Clang y, por lo tanto, tiene conocimiento de la estructura del código en sí, en lugar de ser un simple formateador de código fuente que opera solo con el texto (una de las ventajas de poder utilizar una biblioteca de compilación). Dado que el formateador usa el mismo analizador y lexer que el compilador en sí mismo, me sentiría lo suficientemente seguro como para no tener ningún problema en escupir el código que se comporta de la misma manera que lo alimenta.
Puede ver el código fuente del formateador C ++ aquí: http://clang.llvm.org/doxygen/Format_8cpp_source.html
Seguro que puede cambiar cómo funciona tu código. Y la razón es que el programa C puede ver algunas propiedades de su código fuente. Lo que estoy pensando es en la macro __LINE__
, pero no estoy seguro de que no haya otras formas.
Considere 1.c
:
#include <stdio.h>
int main(){printf("%d/n", __LINE__);}
Entonces:
> clang 1.c -o 1.exe & 1.exe
2
Ahora haz un poco clang-format
:
> clang-format -style=Chromium 1.c >2.c
Y 2.c
es:
#include <stdio.h>
int main() {
printf("%d/n", __LINE__);
}
Y, por supuesto, la salida ha cambiado:
> clang 2.c -o 2.exe & 2.exe
3
formato ASG reformateado del código ASM en un proyecto porque efectivamente hicimos esto:
#define ASM _asm
ASM {
...
}
sí
no romperá el flujo de trabajo
el sistema tiene el interruptor de configuración: "C_Cpp.clang_format_sortIncludes": falso , pero no funciona, no sé qué está mal ...
Mi versión es: ms-vscode.cpptools-0.13.1
esta es mi solucion
Para el flujo de trabajo estable, use la gramática:
// formato clang desactivado
...Aquí está tu código
// formato clang en