Formato y análisis
molto fmt y molto lint, los dos archivos JSON que los configuran, y por qué tu repositorio nunca acumula un .clang-format.
Molto es dueño de la configuración; las herramientas hacen el trabajo.
Molto no formatea ni analiza código, y nunca lo hará. De lo que es dueño es del vocabulario: tú
escribes indent_width y brace_style, y Molto lo traduce a la configuración propia del backend
en .bin/style/ justo antes de ejecutarlo. Tu repositorio nunca acumula un .clang-format, y
cambiar de backend más adelante es modificar una línea, no reescribirlo todo.
Conseguir las herramientas
Molto no instala nada. Se lo pregunta a pickup:
$ pickup tools
KIND NAME VERSION SOURCE
formatter clang-format clang-format version 22.1.8 pickup
linter clang-tidy LLVM version 22.1.8 pickup
Toma la ruta que pickup reporta y la ejecuta: no busca en tu PATH. MOLTO_CLANG_FORMAT y
MOLTO_CLANG_TIDY se saltan la resolución por completo y no se cachean. --refresh-tools vuelve a
preguntarle a pickup en vez de reutilizar la respuesta registrada.
No tener linter no es un error. molto lint sigue ejecutando los diagnósticos del propio
compilador, que es la mayor parte del valor y no necesita instalar nada.
molto fmt
molto fmt # reescribe src/ e include/ en el sitio
molto fmt --check # dice qué cambiaría, no escribe nada; sale con 1 si hay algo
molto fmt --diff # imprime el diff unificado, no escribe nada
--check es la forma para CI. --diff es la misma pregunta con la respuesta enseñada como
parche. Pasar los dos es un error de uso: dos respuestas a una sola pregunta. Las cabeceras también
se formatean.
molto lint
molto lint # diagnósticos del compilador, luego el linter
molto lint --format json # legible por máquinas, para CI
molto lint --profile release # analiza con los defines del perfil release
Dos pasadas sobre cada fuente de src/: el compilador declarado en [target], sólo sintaxis y
sin escribir objetos; y después el linter, si lo hay, configurado desde linter.json y con los
mismos flags de compilación que usaría el build.
--profile importa más de lo que parece. El perfil decide qué defines están en vigor, y un
#ifdef decide qué llega siquiera a compilarse. Analizar con el perfil equivocado revisa código
que el build nunca ve.
--format no tiene valor por defecto. Ausente no es lo mismo que un --format text explícito:
ausente significa «lo que le convenga al flujo», que es rich en una terminal —bloques enmarcados,
un cursor bajo el carácter que la herramienta señaló, color— y text a través de una tubería.
Pídelo por su nombre cuando la salida tenga que ser estable vaya donde vaya; la CI quiere text o
json escritos, no deducidos.
[
{
"file": "src/foo.c",
"line": 12,
"column": 5,
"severity": "warning",
"message": "…",
"rule": "…"
}
]
Códigos de salida: 0 cuando no hubo ningún diagnóstico de severidad error, 1 cuando lo hubo, 2
por configuración inválida y 4 por mal uso. Un warning se reporta y aun así tiene éxito.
Los dos comandos son incrementales
Un archivo que no ha cambiado no se vuelve a analizar: los diagnósticos quedan registrados en la base de datos del workspace y se reproducen, y lo que ves es idéntico de una forma u otra: mismos diagnósticos, mismo orden, mismo código de salida.
Un archivo se reanaliza cuando cambia su contenido, cuando cambia una cabecera que incluye, cuando
el comando sería distinto, cuando cambia linter.json o cuando cambia la versión del linter.
--refresh-analysis ignora los resultados registrados y lo ejecuta todo.
molto fmt registra que un archivo está en su forma final bajo el estilo actual, así que formatear
un proyecto deja a fmt --check sin nada que hacer. Ahí las cabeceras no intervienen: un
formateador sólo lee el archivo que se le da.
Ninguno de los dos escribe compile_commands.json, eso lo hace un build. Un clang-tidy externo
que lea esa base de datos está leyendo lo que dejó el último molto build, no esta ejecución.
format.json
Opcional; si no está, valen los valores por defecto de abajo.
{
"backend": "clang-format@22.1.8",
"preset": "molto",
"exclude": ["src/vendor/**"],
"style": {
"indent_width": 4,
"line_width": 100,
"brace_style": "attach",
"pointer_alignment": "right",
"sort_includes": true
}
}
| Clave | Tipo | Por defecto | Significado |
|---|---|---|---|
indent_width |
int | 4 |
Columnas por nivel de indentación |
use_tabs |
bool | false |
Indentar con tabuladores en vez de espacios |
line_width |
int | 100 |
Columna máxima antes de partir |
brace_style |
string | attach |
attach, break, linux, allman |
pointer_alignment |
string | right |
left para int* p, right para int *p |
sort_includes |
bool | true |
Ordenar los bloques de #include |
space_before_paren |
bool | false |
Espacio entre una palabra clave y ( |
column_limit_comments |
bool | true |
Partir los comentarios en line_width |
Al formateador se le dice qué lenguaje lee
No hay clave para el lenguaje: Molto lo toma de [target].cpp_std.
Un .h no lleva el lenguaje en la extensión, así que clang-format por su cuenta asume el C++ más
nuevo. Un struct de C con un campo llamado requires pasa entonces a leerse como una
requires-clause de C++20, y la declaración queda destrozada en tres líneas. Por eso Molto emite
Standard:
[target].cpp_std |
Standard |
|---|---|
| Ausente, un proyecto en C | c++03, el único dialecto donde requires y concept son identificadores normales |
c++11, c++17, c++20, gnu++20 |
Ese estándar |
| Cualquier otra cosa | Latest |
Un proyecto de C++ que nunca declara cpp_std se formatea como C, y sus cabeceras de C++20
sufren la imagen especular del mismo problema. Decláralo.
linter.json
Opcional. Un mapa de severidades al estilo de ESLint: cada clave nombra una regla o una familia, y
cada valor es off, warn o error.
{
"backend": "clang-tidy@22.1.8",
"preset": "molto",
"exclude": ["src/generated/**"],
"rules": {
"bugprone": "error",
"readability_magic_numbers": "warn",
"modernize": "off"
}
}
Los nombres de las reglas son de Molto, no del backend:
| Regla | Cubre |
|---|---|
bugprone |
Patrones que suelen ser un bug |
performance, portability, modernize, readability |
Las familias del mismo nombre |
dataflow, security |
El analizador sensible a caminos, por mitades |
naming_snake_case |
Nomenclatura de identificadores |
readability_magic_numbers, identifier_length |
Comprobaciones sueltas de legibilidad |
swappable_parameters, spurious_wakeup |
Dos checks de bugprone, con nombre propio para poder rechazar uno sin tirar la familia |
unused, shadow, uninitialized, implicit_conversion, sign_compare |
Diagnósticos del compilador, por nombre |
Una regla que Molto no puede expresar para el backend elegido es un error que nombra la regla y el backend, nunca algo que se descarta en silencio.
El analizador sensible a caminos
Queda fuera del preset por defecto a propósito, y se pide en dos mitades:
"dataflow": "warn"recorre caminos en vez de sintaxis, y encuentra lo que eso compra: un desreferenciado nulo, una fuga, el uso de un campo sin inicializar, una escritura muerta."security": "warn"añade la familia de seguridad, menos el check que exige las funciones del Anexo K de C11 que glibc no trae: ese salta en cada llamada a la librería estándar y entierra todo lo demás.
Espera falsos positivos de cualquiera de los dos, y espera que ambos sean lentos. Son la razón de
que --refresh-analysis exista como flag separado de --refresh-tools.
Claves compartidas
preset — molto (por defecto) o none. El preset molto le pide al compilador
-Wall -Wextra -Wpedantic y al linter clang-diagnostic-* y bugprone-*. kernel y gnu
aparecen en la RFC pero no están implementados; declarar uno es un error, no una sustitución
silenciosa.
exclude — patrones glob contrastados con la ruta relativa a la raíz del proyecto. Un asterisco
cruza barras, así que vendor/* casa con vendor/a/b.c; un /** final casa también con el propio
directorio.
backend — fija un nombre y opcionalmente una versión. Molto verifica la fijación contra lo
que reporta pickup; no instala. Una fijación incumplida es un error que nombra ambas versiones,
porque dos releases de un mismo formateador producen salidas distintas para el mismo archivo: justo
el ruido que un formateador existe para eliminar.
La configuración de estilo falla en cerrado
Una clave desconocida, un valor desconocido, una regla sin traducción, una lista que se desborda,
una fijación incumplida: cada una es un error que nombra qué está mal. Nada de format.json ni de
linter.json se ignora.
Es deliberado. Una clave que en silencio no hace nada es peor que una rechazada: mantendrías la
línea en tu configuración durante años creyendo que se aplicaba. Esto no se extiende a
Project.toml, que descarta las claves desconocidas sin avisar.
Resolución de problemas
| Síntoma | Causa | Arreglo |
|---|---|---|
this machine has no formatter |
Pickup no reporta ninguno | pickup install clang-format |
unknown key 'styl' |
Una errata | Compruébala en las tablas de arriba |
rule 'x' is not supported by clang-tidy |
Nombre de regla no canónico | Usa uno de la tabla de reglas |
backend is pinned to '…' but this machine has '…' |
La versión instalada no coincide | Instala la fijada, o cámbiala |
preset is not implemented yet |
kernel o gnu |
Usa molto o none |
| El lint no reporta nada del linter | No hay linter instalado | Mira pickup tools; la pasada del compilador sí corrió |
| El lint reporta lo que el build no | Perfil equivocado | molto lint --profile release |