How the fix loop worksComment marche la boucle de correction
Why one --fix can apply fixes that no check showed, and why it never loops forever.Pourquoi un seul --fix peut appliquer des corrections qu'aucune vérification n'a montrées, et pourquoi il ne boucle jamais sans fin.
In one sentence: --fix checks, fixes, then checks again, because a fix can reveal a new issue, until nothing is left to fix.
Definition: Checker::fix runs at most FIX_PASSES (32) passes; each pass re-runs every rule, keeps the allowed fixes whose line ranges do not overlap, applies them, and stops at the first pass with no fix.
En une phrase : --fix vérifie, corrige, puis vérifie encore, car une correction peut révéler un nouveau problème, jusqu'à ce qu'il ne reste rien à corriger.
Définition : Checker::fix fait au plus FIX_PASSES (32) passes ; chaque passe relance toutes les règles, garde les corrections permises dont les plages de lignes ne se chevauchent pas, les applique, et s'arrête à la première passe sans correction.
1. The ideaL'idée
Like tidying a room: you put the books on the shelf, and then you see the shelf needs a label. You tidy, look again, tidy again, until the room is clean.
A fix changes the file, so the issues computed before it are stale. Instead of predicting the effect of a fix, xstyle recomputes: the rules are the only source of truth, and a pass only applies fixes on disjoint line ranges so that two edits never fight over the same lines. The others come back on the next pass.
Comme ranger une chambre : tu mets les livres sur l'étagère, puis tu vois qu'il faut une étiquette sur l'étagère. Tu ranges, tu regardes encore, tu ranges encore, jusqu'à ce que tout soit propre.
Une correction modifie le fichier, donc les problèmes calculés avant elle sont périmés. Au lieu de prédire l'effet d'une correction, xstyle recalcule : les règles sont la seule source de vérité, et une passe n'applique que des corrections sur des plages de lignes disjointes, pour que deux modifications ne se battent jamais sur les mêmes lignes. Les autres reviennent à la passe suivante.
2. How it worksComment ça marche
- Check, pass 1. The rules run on the file: one fixable issue,
LU-ATTRIBUTEon line 4 ([[nodiscard]]). - Keep. Its level is
auto, allowed by--fix, and it overlaps no other fix of this pass: it is kept. - Apply. Line 4 becomes
_nodiscard double angle(double x);. - Check, pass 2.
_nodiscardbelongs to theAttributesection, not defined beforeutils.hpp:LU-SECTIONappears. - Apply.
#define _Attributeis added before the include. - Check, pass 3. No fix left: the loop stops and the file is written (with
-n: only shown).
- Vérification, passe 1. Les règles tournent sur le fichier : un problème corrigeable,
LU-ATTRIBUTEligne 4 ([[nodiscard]]). - Tri. Son niveau est
auto, permis par--fix, et il ne chevauche aucune autre correction de la passe : il est gardé. - Application. La ligne 4 devient
_nodiscard double angle(double x);. - Vérification, passe 2.
_nodiscardfait partie de la sectionAttribute, non définie avantutils.hpp:LU-SECTIONapparaît. - Application.
#define _Attributeest ajouté avant l’include. - Vérification, passe 3. Plus aucune correction : la boucle s’arrête et le fichier est écrit (avec
-n: seulement affiché).
3. The worked exampleL'exemple
The file above, fixed with only the libutils rules:
xstyle --fix -n --libutils on -c LU b.cppWould fix:
b.cpp:4 LU-ATTRIBUTE
- [[nodiscard]] double angle(double x);
+ _nodiscard double angle(double x);
b.cpp:2 LU-SECTION
+ #define _AttributeLU-SECTION was not in the report before the fix: the second pass found it.
Le fichier ci-dessus, corrigé avec seulement les règles libutils :
xstyle --fix -n --libutils on -c LU b.cppWould fix:
b.cpp:4 LU-ATTRIBUTE
- [[nodiscard]] double angle(double x);
+ _nodiscard double angle(double x);
b.cpp:2 LU-SECTION
+ #define _AttributeLU-SECTION n'était pas dans le rapport avant la correction : la deuxième passe l'a trouvé.
4. Why it stopsPourquoi elle s'arrête
It stops as soon as a round fixes nothing, and in any case after 32 rounds.
Three guards: a pass with no fix ends the loop; a fix whose new lines equal the old ones is dropped (a no-op would loop forever); FIX_PASSES (32, include/xstyle/Checker.hpp) bounds the rest.
| Guard | Where |
|---|---|
| no fix in a pass → stop | Checker::fix |
| fix equal to the current lines → skipped | Checker::fix |
| at most 32 passes | FIX_PASSES |
Checker::fix is in src/xstyle/Checker.cpp, FIX_PASSES in include/xstyle/Checker.hpp.
Elle s'arrête dès qu'un tour ne corrige rien, et dans tous les cas après 32 tours.
Trois garde-fous : une passe sans correction termine la boucle ; une correction dont les nouvelles lignes sont égales aux anciennes est écartée (un no-op bouclerait sans fin) ; FIX_PASSES (32, include/xstyle/Checker.hpp) borne le reste.
| Garde-fou | Où |
|---|---|
| aucune correction dans une passe → arrêt | Checker::fix |
| correction égale aux lignes actuelles → sautée | Checker::fix |
| au plus 32 passes | FIX_PASSES |
Checker::fix est dans src/xstyle/Checker.cpp, FIX_PASSES dans include/xstyle/Checker.hpp.
5. PitfallsPièges
-c/-mlimit every pass: a fix of another rule revealed by the first one is not applied (here,-c LU-ATTRIBUTEalone would leave theLU-SECTIONissue).- The counters after a
--fix -nare the issues left after the fixes, not before. --diff/--stagedfilter the fixes too: a fix on an unchanged line is not applied.
-c/-mlimitent chaque passe : la correction d'une autre règle révélée par la première n'est pas appliquée (ici,-c LU-ATTRIBUTEseul laisserait le problèmeLU-SECTION).- Les compteurs après un
--fix -nsont les problèmes restants après les corrections, pas ceux d'avant. --diff/--stagedfiltrent aussi les corrections : une correction sur une ligne non modifiée n'est pas appliquée.
6. Check yourselfVérifie-toi
Two fixes touch line 10 in the same pass: what happens?
The first is applied, the second is left for the next pass, computed again on the new line.
Why can --fix report a rule the check did not show?
A fix revealed it: it only exists once the first fix is written.
Deux corrections touchent la ligne 10 dans la même passe : que se passe-t-il ?
La première est appliquée, la seconde attend la passe suivante, recalculée sur la nouvelle ligne.
Pourquoi --fix peut-il signaler une règle que la vérification n'a pas montrée ?
Une correction l'a révélée : elle n'existe qu'une fois la première correction écrite.
7. GlossaryGlossaire
| Term | Meaning |
|---|---|
| Pass | one run of every rule followed by the fixes it allows |
| Overlap | two fixes on the same lines: only one per pass |
| Dry run | -n: everything computed, nothing written |
| Terme | Sens |
|---|---|
| Passe | un passage de toutes les règles suivi des corrections qu'il permet |
| Chevauchement | deux corrections sur les mêmes lignes : une seule par passe |
| Dry run | -n : tout est calculé, rien n'est écrit |