diff --git a/blink/internal/fixer/rules/add_missing_param_name_test.go b/blink/internal/fixer/rules/add_missing_param_name_test.go index 10e204735a..ad1808298d 100644 --- a/blink/internal/fixer/rules/add_missing_param_name_test.go +++ b/blink/internal/fixer/rules/add_missing_param_name_test.go @@ -4,6 +4,7 @@ import "testing" // TestAddMissingParamName adds the positional variable name to a type-only @param. func TestAddMissingParamName(t *testing.T) { + t.Parallel() src := "}>,\n * timeless: list}>\n * } $messages\n */\n function f(array $messages) {}\n}\n" if got, changed := apply(t, AddMissingParamName{}, src); changed || got != src { t.Fatalf("multi-line array-shape param with name must be left alone: changed=%v got=%q", changed, got) diff --git a/blink/internal/fixer/rules/array_indentation_test.go b/blink/internal/fixer/rules/array_indentation_test.go index fbac89beb8..cc98621a7b 100644 --- a/blink/internal/fixer/rules/array_indentation_test.go +++ b/blink/internal/fixer/rules/array_indentation_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestArrayIndentation(t *testing.T) { + t.Parallel() f := ArrayIndentation{} // nested array under-indented: each level indented exactly once diff --git a/blink/internal/fixer/rules/array_list_item_newline_test.go b/blink/internal/fixer/rules/array_list_item_newline_test.go index f4fdc9b465..042abf0672 100644 --- a/blink/internal/fixer/rules/array_list_item_newline_test.go +++ b/blink/internal/fixer/rules/array_list_item_newline_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestArrayListItemNewline(t *testing.T) { + t.Parallel() f := ArrayListItemNewline{} // associative single-line array -> one item per line, trailing comma, [] on own lines diff --git a/blink/internal/fixer/rules/array_notation_config_test.go b/blink/internal/fixer/rules/array_notation_config_test.go index 03eec4cc3b..49af193814 100644 --- a/blink/internal/fixer/rules/array_notation_config_test.go +++ b/blink/internal/fixer/rules/array_notation_config_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestArrayNotationConfigCases(t *testing.T) { + t.Parallel() cases := []struct { name string rule fixerRule diff --git a/blink/internal/fixer/rules/array_opener_and_closer_newline_test.go b/blink/internal/fixer/rules/array_opener_and_closer_newline_test.go index 294d694159..38ed700db2 100644 --- a/blink/internal/fixer/rules/array_opener_and_closer_newline_test.go +++ b/blink/internal/fixer/rules/array_opener_and_closer_newline_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestArrayOpenerAndCloserNewline(t *testing.T) { + t.Parallel() f := ArrayOpenerAndCloserNewline{} // associative array: "[" and "]" go on their own lines, items untouched diff --git a/blink/internal/fixer/rules/batch10_test.go b/blink/internal/fixer/rules/batch10_test.go index 33df97e624..8d01dc6752 100644 --- a/blink/internal/fixer/rules/batch10_test.go +++ b/blink/internal/fixer/rules/batch10_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestTrailingCommaInMultiline(t *testing.T) { + t.Parallel() got, changed := apply(t, TrailingCommaInMultiline{}, " b -> c();") if want := "b->c();"; !changed || got != want { t.Fatalf("changed=%v got=%q want=%q", changed, got, want) @@ -50,6 +54,7 @@ func TestObjectOperatorWithoutWhitespace(t *testing.T) { } func TestNativeFunctionCasing(t *testing.T) { + t.Parallel() got, changed := apply(t, NativeFunctionCasing{}, "foo()\n->bar()\n ->baz();\n") if want := "foo()\n ->bar()\n ->baz();\n"; !changed || got != want { t.Fatalf("changed=%v got=%q want=%q", changed, got, want) diff --git a/blink/internal/fixer/rules/batchD_test.go b/blink/internal/fixer/rules/batchD_test.go index 3a658d5ca5..f8f084a5bb 100644 --- a/blink/internal/fixer/rules/batchD_test.go +++ b/blink/internal/fixer/rules/batchD_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestSimplifiedNullReturn(t *testing.T) { + t.Parallel() // no return type -> simplified got, changed := apply(t, SimplifiedNullReturn{}, "{$prop}" is dynamic access, not a control block: no space inserted if _, changed := apply(t, BracesPosition{}, "{$prop} != $v) {\n}"); changed { t.Fatal("dynamic property access brace must not get a space") @@ -52,6 +56,7 @@ func TestBracesPositionDynamicAccessLeftAlone(t *testing.T) { } func TestClassifyBrace(t *testing.T) { + t.Parallel() cases := []struct { src string want braceKind @@ -80,6 +85,7 @@ func TestClassifyBrace(t *testing.T) { // a trait adaptation block "use T { ... }" is not a class/function body func TestClassifyTraitBlockIsOther(t *testing.T) { + t.Parallel() s := lexStream(" $b) {}") if want := " aligned under the first "*" got, changed := apply(t, AlignMultilineComment{}, " 1;") @@ -39,6 +41,7 @@ func TestFunctionDeclarationClosureFnSpacing(t *testing.T) { } func TestFunctionDeclarationTrailingCommaSingleLine(t *testing.T) { + t.Parallel() // trailing_comma_single_line=false: drop the trailing comma in a single-line signature cfg := FunctionDeclaration{}.WithConfig(map[string]any{"trailing_comma_single_line": false}) got, changed := apply(t, cfg, " // comment @@ -62,6 +63,7 @@ func TestGen4ASingleLineCommentStyle(t *testing.T) { } func TestGen4ANoNullPropertyInitialization(t *testing.T) { + t.Parallel() f := NoNullPropertyInitialization{} // untyped property loses its null default @@ -126,6 +128,7 @@ func TestGen4ANoNullPropertyInitialization(t *testing.T) { // TestGen4ASourceURL verifies each SourceURL matches SourceURLFor(Name()). func TestGen4ASourceURL(t *testing.T) { + t.Parallel() for _, f := range []fixer.Fixer{SingleLineCommentStyle{}, NoNullPropertyInitialization{}} { if got, want := f.SourceURL(), fixer.SourceURLFor(f.Name()); got != want { t.Errorf("%s: SourceURL %q != SourceURLFor %q", f.Name(), got, want) diff --git a/blink/internal/fixer/rules/gen4_b_test.go b/blink/internal/fixer/rules/gen4_b_test.go index cb23b72cd5..b2fece820b 100644 --- a/blink/internal/fixer/rules/gen4_b_test.go +++ b/blink/internal/fixer/rules/gen4_b_test.go @@ -7,6 +7,7 @@ import ( ) func TestGen4BExplicitIndirectVariable(t *testing.T) { + t.Parallel() cases := []struct { src, want string changed bool @@ -52,6 +53,7 @@ func TestGen4BExplicitIndirectVariable(t *testing.T) { } func TestGen4BSourceURLs(t *testing.T) { + t.Parallel() fixers := []fixer.Fixer{ ExplicitIndirectVariable{}, } diff --git a/blink/internal/fixer/rules/gen4_phpdoc_config_test.go b/blink/internal/fixer/rules/gen4_phpdoc_config_test.go index d443adbf2f..8eaecbfeb6 100644 --- a/blink/internal/fixer/rules/gen4_phpdoc_config_test.go +++ b/blink/internal/fixer/rules/gen4_phpdoc_config_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestPhpdocLineSpanConfig(t *testing.T) { + t.Parallel() single := " $this @@ -67,6 +68,7 @@ func TestGen5PhpdocMiscReturnSelfReference(t *testing.T) { } func TestGen5PhpdocMiscReturnSelfReferenceSourceURL(t *testing.T) { + t.Parallel() var f fixer.Fixer = PhpdocReturnSelfReference{} if got, want := f.SourceURL(), fixer.SourceURLFor(f.Name()); got != want { t.Fatalf("SourceURL %q, want %q", got, want) diff --git a/blink/internal/fixer/rules/gen5_phpdoc_order_test.go b/blink/internal/fixer/rules/gen5_phpdoc_order_test.go index 4dc4de06cd..f8b0abeaba 100644 --- a/blink/internal/fixer/rules/gen5_phpdoc_order_test.go +++ b/blink/internal/fixer/rules/gen5_phpdoc_order_test.go @@ -7,6 +7,7 @@ import ( ) func TestGen5PhpdocOrderTypesOrder(t *testing.T) { + t.Parallel() f := PhpdocTypesOrder{} // null moves to the end, other members keep order: string|null|int -> string|int|null @@ -56,6 +57,7 @@ func TestGen5PhpdocOrderTypesOrder(t *testing.T) { } func TestGen5PhpdocOrderVarAnnotation(t *testing.T) { + t.Parallel() f := PhpdocVarAnnotationCorrectOrder{} // swapped single-line @var @@ -90,6 +92,7 @@ func TestGen5PhpdocOrderVarAnnotation(t *testing.T) { } func TestGen5PhpdocOrderSourceURLs(t *testing.T) { + t.Parallel() for _, f := range []fixer.Fixer{PhpdocTypesOrder{}, PhpdocVarAnnotationCorrectOrder{}} { if got, want := f.SourceURL(), fixer.SourceURLFor(f.Name()); got != want { t.Fatalf("%s SourceURL %q, want %q", f.Name(), got, want) diff --git a/blink/internal/fixer/rules/gen6_phpdoc_test.go b/blink/internal/fixer/rules/gen6_phpdoc_test.go index 9e422daa38..e8ebf3efdc 100644 --- a/blink/internal/fixer/rules/gen6_phpdoc_test.go +++ b/blink/internal/fixer/rules/gen6_phpdoc_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoAliasLanguageConstructCall(t *testing.T) { + t.Parallel() got, changed := apply(t, NoAliasLanguageConstructCall{}, "\n 1,\n];") if want := " 1,\n];"; !changed || got != want { t.Fatalf("after: changed=%v got=%q want=%q", changed, got, want) @@ -88,6 +91,7 @@ func TestGenArraysNoMultilineWhitespaceAroundDoubleArrow(t *testing.T) { // TestGenArraysSourceURLs verifies every SourceURL matches SourceURLFor(Name()). func TestGenArraysSourceURLs(t *testing.T) { + t.Parallel() fixers := []fixerpkg.Fixer{ NoWhitespaceInEmptyArray{}, NormalizeIndexBrace{}, @@ -102,6 +106,7 @@ func TestGenArraysSourceURLs(t *testing.T) { // TestGenArraysIdempotent guarantees a second pass is a no-op. func TestGenArraysIdempotent(t *testing.T) { + t.Parallel() fixers := []fixerRule{ NoWhitespaceInEmptyArray{}, NormalizeIndexBrace{}, diff --git a/blink/internal/fixer/rules/gen_control_test.go b/blink/internal/fixer/rules/gen_control_test.go index 1f64e81fd3..14a5c0c99b 100644 --- a/blink/internal/fixer/rules/gen_control_test.go +++ b/blink/internal/fixer/rules/gen_control_test.go @@ -7,6 +7,7 @@ import ( ) func TestGenControlSwitchContinueToBreak(t *testing.T) { + t.Parallel() cases := []struct { src string want string @@ -106,6 +107,7 @@ func TestGenControlSwitchContinueToBreak(t *testing.T) { // TestGenControlSourceURLs verifies each SourceURL matches SourceURLFor(Name()). func TestGenControlSourceURLs(t *testing.T) { + t.Parallel() for _, f := range []fixer.Fixer{SwitchContinueToBreak{}} { if got, want := f.SourceURL(), fixer.SourceURLFor(f.Name()); got != want { t.Errorf("%s: SourceURL %q != SourceURLFor %q", f.Name(), got, want) diff --git a/blink/internal/fixer/rules/gen_imports_test.go b/blink/internal/fixer/rules/gen_imports_test.go index d522770a32..262d9fe671 100644 --- a/blink/internal/fixer/rules/gen_imports_test.go +++ b/blink/internal/fixer/rules/gen_imports_test.go @@ -7,6 +7,7 @@ import ( ) func TestGenImportsNoUnneededImportAlias(t *testing.T) { + t.Parallel() got, changed := apply(t, NoUnneededImportAlias{}, "\nHi\n\n" if _, changed := apply(t, NoAlternativeSyntax{}, src); !changed { t.Fatal("default should fix inline HTML code") diff --git a/blink/internal/fixer/rules/no_alternative_syntax_test.go b/blink/internal/fixer/rules/no_alternative_syntax_test.go index 4e3e5ca5aa..e18cf2135d 100644 --- a/blink/internal/fixer/rules/no_alternative_syntax_test.go +++ b/blink/internal/fixer/rules/no_alternative_syntax_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoAlternativeSyntax(t *testing.T) { + t.Parallel() cases := []struct { src string want string diff --git a/blink/internal/fixer/rules/no_blank_line_between_imports_test.go b/blink/internal/fixer/rules/no_blank_line_between_imports_test.go index fec7108bbc..95a7e9f412 100644 --- a/blink/internal/fixer/rules/no_blank_line_between_imports_test.go +++ b/blink/internal/fixer/rules/no_blank_line_between_imports_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoBlankLineBetweenImports(t *testing.T) { + t.Parallel() f := NoBlankLineBetweenImports{} // blank lines between consecutive imports collapse; the namespace gap stays diff --git a/blink/internal/fixer/rules/no_break_comment_config_test.go b/blink/internal/fixer/rules/no_break_comment_config_test.go index 63e88e7fae..312c5c26c4 100644 --- a/blink/internal/fixer/rules/no_break_comment_config_test.go +++ b/blink/internal/fixer/rules/no_break_comment_config_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoBreakCommentConfig(t *testing.T) { + t.Parallel() src := " elseif becomes if diff --git a/blink/internal/fixer/rules/no_superfluous_phpdoc_tags_config_test.go b/blink/internal/fixer/rules/no_superfluous_phpdoc_tags_config_test.go index 59bfc82531..c170a835f2 100644 --- a/blink/internal/fixer/rules/no_superfluous_phpdoc_tags_config_test.go +++ b/blink/internal/fixer/rules/no_superfluous_phpdoc_tags_config_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoSuperfluousPhpdocTagsConfig(t *testing.T) { + t.Parallel() // default keeps "@param mixed" on an untyped parameter (allow_mixed behavior) mixed := " removed @@ -96,6 +97,7 @@ func TestNoSuperfluousPhpdocTags(t *testing.T) { } func TestNoSuperfluousPhpdocTagsSourceURL(t *testing.T) { + t.Parallel() f := NoSuperfluousPhpdocTags{} if got, want := f.SourceURL(), fixer.SourceURLFor(f.Name()); got != want { t.Fatalf("SourceURL %q, want %q", got, want) diff --git a/blink/internal/fixer/rules/no_unneeded_braces_config_test.go b/blink/internal/fixer/rules/no_unneeded_braces_config_test.go index 7302ab51cc..f59f1fb2a3 100644 --- a/blink/internal/fixer/rules/no_unneeded_braces_config_test.go +++ b/blink/internal/fixer/rules/no_unneeded_braces_config_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoUnneededBracesConfig(t *testing.T) { + t.Parallel() src := "parentMethod(); }\n}\n") diff --git a/blink/internal/fixer/rules/offset_config_test.go b/blink/internal/fixer/rules/offset_config_test.go index 3c3dbf873e..6daf89ca4a 100644 --- a/blink/internal/fixer/rules/offset_config_test.go +++ b/blink/internal/fixer/rules/offset_config_test.go @@ -3,6 +3,7 @@ package rules import "testing" func TestNoSpacesAroundOffsetConfig(t *testing.T) { + t.Parallel() src := " $x;") if want := " $x;"; !changed || got != want { t.Fatalf("changed=%v got=%q want=%q", changed, got, want) @@ -13,6 +14,7 @@ func TestArrowFnSpacing(t *testing.T) { } func TestPhpdocTypesGenericsAndConst(t *testing.T) { + t.Parallel() // a pseudo-type keyword inside generics is lowercased got, changed := apply(t, PhpdocTypes{}, "\n */\nclass A {}") if want := "\n */\nclass A {}"; !changed || got != want { @@ -25,6 +27,7 @@ func TestPhpdocTypesGenericsAndConst(t *testing.T) { } func TestNoBlankLinesAfterPhpdocKeepsFileDocblock(t *testing.T) { + t.Parallel() // a file-level docblock before "declare" keeps its blank line src := " @var got, changed := apply(t, PhpdocNoAliasTag{}, " fixer + canonicalPos map[string]int // Name -> index in sortedFixers +) + +func buildRegistry() { all := []fixer.Fixer{FullOpeningTag{}} all = append(all, CommonFixers()...) all = append(all, PhpdocFixers()...) @@ -274,7 +283,21 @@ func All() []fixer.Fixer { } return fixerSortName(all[a]) < fixerSortName(all[b]) }) - return all + + sortedFixers = all + fixerByName = make(map[string]fixer.Fixer, len(all)) + canonicalPos = make(map[string]int, len(all)) + for i, f := range all { + fixerByName[f.Name()] = f + canonicalPos[f.Name()] = i + } +} + +// All returns every fixer in PHP-CS-Fixer execution order. The registry is built +// once; the returned slice is a fresh copy the caller may append to or reorder. +func All() []fixer.Fixer { + registryOnce.Do(buildRegistry) + return slices.Clone(sortedFixers) } // fixerSortName returns the name PHP-CS-Fixer sorts a fixer by: a core fixer's @@ -295,13 +318,10 @@ func fixerSortName(f fixer.Fixer) string { // applies rules in the same order as the standalone path. Fixers unknown to // All() are placed last. func CanonicalOrder(fixers []fixer.Fixer) { - idx := map[string]int{} - for i, f := range All() { - idx[f.Name()] = i - } + registryOnce.Do(buildRegistry) const last = 1 << 30 pos := func(f fixer.Fixer) int { - if i, ok := idx[f.Name()]; ok { + if i, ok := canonicalPos[f.Name()]; ok { return i } return last @@ -329,13 +349,10 @@ var deprecatedAliases = map[string]string{ // ByName returns the fixer whose Name matches, if any. func ByName(name string) (fixer.Fixer, bool) { + registryOnce.Do(buildRegistry) if canonical, ok := deprecatedAliases[name]; ok { name = canonical } - for _, f := range All() { - if f.Name() == name { - return f, true - } - } - return nil, false + f, ok := fixerByName[name] + return f, ok } diff --git a/blink/internal/fixer/rules/regression_test.go b/blink/internal/fixer/rules/regression_test.go index 3aded384d6..d99a196687 100644 --- a/blink/internal/fixer/rules/regression_test.go +++ b/blink/internal/fixer/rules/regression_test.go @@ -4,6 +4,7 @@ import "testing" // keyword-spelled class-constant names must not be lowercased (sweep finding) func TestLowercaseKeywordsKeepsConstantName(t *testing.T) { + t.Parallel() src := "%command.name% command is send a channel broadcast to pending contacts.\n\nphp %command.full_name% --channel=email --id=3\nTXT\n)]\nclass A {}\n" got, changed := apply(t, RemoveUselessDefaultComment{}, src) if changed || got != src { @@ -11,6 +12,7 @@ func TestRemoveUselessDefaultCommentKeepsHeredocBlankLine(t *testing.T) { } func TestRemoveUselessDefaultCommentStillRemovesTodo(t *testing.T) { + t.Parallel() src := "1, 'y' => 2];") if want := " 1, 'y' => 2];"; !changed || got != want { t.Fatalf("changed=%v got=%q want=%q", changed, got, want) @@ -91,6 +97,7 @@ func TestBinaryOperatorSpaces(t *testing.T) { } func TestConcatSpace(t *testing.T) { + t.Parallel() got, changed := apply(t, ConcatSpace{}, "bar ();") if want := "bar();"; !changed || got != want { t.Fatalf("changed=%v got=%q want=%q", changed, got, want) @@ -202,6 +216,7 @@ func TestNoSpacesAfterFunctionName(t *testing.T) { } func TestNoSpacesInsideParenthesis(t *testing.T) { + t.Parallel() got, changed := apply(t, NoSpacesInsideParenthesis{}, "\n") if want := "{$key}") in a multiline ternary must not be read // as a block/statement end; the ":" line stays aligned with the "?" line src := "condition\n ? $this->target->{$key}\n : $this->target;\n }\n}\n" @@ -30,6 +32,7 @@ func TestStatementIndentationTernaryDynamicMember(t *testing.T) { } func TestStatementIndentationNamedArgumentKeyword(t *testing.T) { + t.Parallel() // a reserved word used as a named-argument label ("default:", "case:") is not // a switch case; it must not indent the statements that follow the call src := "