Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions blink/internal/fixer/rules/constructs.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,11 @@ func (f SingleSpaceAroundConstruct) Fix(s *tokens.Stream) bool {
continue
}
next := s.At(i + 1)
// "static" and "class" directly before "(" are a class reference, not a
// construct: "new static(...)", "new class(...)". They take no space.
// "static", "class" and "enum" directly before "(" are a class reference,
// not a construct: "new static(...)", "new class(...)", "new Enum(...)".
// They take no space ("enum" never opens a "(" as a declaration keyword).
kw := strings.ToLower(t.Value)
classRef := kw == "static" || kw == "class"
classRef := kw == "static" || kw == "class" || kw == "enum"
if next.Kind == token.Whitespace {
if classRef && !hasNewline(next.Value) && i+2 < s.Len() &&
s.At(i+2).Kind == token.Punct && s.At(i+2).Value == "(" {
Expand Down Expand Up @@ -226,6 +227,12 @@ func (NoSpacesAfterFunctionName) Fix(s *tokens.Stream) bool {
if s.At(i).Kind != token.Ident {
continue
}
// "from" in "yield from (expr)" is part of the construct, not a call
if strings.EqualFold(s.At(i).Value, "from") {
if p := sigPrev(s, i); p >= 0 && s.At(p).Kind == token.Keyword && strings.EqualFold(s.At(p).Value, "yield") {
continue
}
}
if i+2 < s.Len() &&
s.At(i+1).Kind == token.Whitespace && !hasNewline(s.At(i+1).Value) &&
s.At(i+2).Kind == token.Punct && s.At(i+2).Value == "(" {
Expand Down
13 changes: 13 additions & 0 deletions blink/internal/fixer/rules/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ func TestSingleSpaceAroundConstruct(t *testing.T) {
if _, changed := apply(t, SingleSpaceAroundConstruct{}, "<?php $o = new class($a) {};"); changed {
t.Fatal("new class( should not gain a space")
}
// "new Enum(" is a class reference; "enum" never opens a "(" as a construct,
// even when "enum" is in the followed list (as ECS configures it)
withEnum := SingleSpaceAroundConstruct{}.WithConfig(map[string]any{"constructs_followed_by_a_single_space": []any{"new", "enum"}}).(fixerRule)
if _, changed := apply(t, withEnum, "<?php $r = new Enum($type);"); changed {
t.Fatal("new Enum( should not gain a space")
}
if got, changed := apply(t, withEnum, "<?php $r = new Enum ($type);"); !changed || got != "<?php $r = new Enum($type);" {
t.Fatalf("new Enum (: changed=%v got=%q", changed, got)
}
}

func TestNoSpacesAfterFunctionName(t *testing.T) {
Expand All @@ -182,6 +191,10 @@ func TestNoSpacesAfterFunctionName(t *testing.T) {
if _, changed := apply(t, NoSpacesAfterFunctionName{}, "<?php if ($a) {}"); changed {
t.Fatal("control keyword is not a function name")
}
// "from" in "yield from (expr)" is part of the construct, not a call
if _, changed := apply(t, NoSpacesAfterFunctionName{}, "<?php function g() { yield from (new Foo())->all(); }"); changed {
t.Fatal("yield from ( must keep its space")
}
}

func TestNoSpacesInsideParenthesis(t *testing.T) {
Expand Down
Loading