From a69aa14b50672b8d9bef3ae723cbf7f289dc4fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Sat, 25 Mar 2023 17:08:00 +0100 Subject: [PATCH] Formatter: Add feature flag for `method_signature_yield` (#13215) --- spec/compiler/formatter/formatter_spec.cr | 212 ++++++++++++++++++---- src/compiler/crystal/tools/formatter.cr | 20 +- 2 files changed, 193 insertions(+), 39 deletions(-) diff --git a/spec/compiler/formatter/formatter_spec.cr b/spec/compiler/formatter/formatter_spec.cr index bba24f11a90e..7c9cc990e116 100644 --- a/spec/compiler/formatter/formatter_spec.cr +++ b/spec/compiler/formatter/formatter_spec.cr @@ -1,10 +1,10 @@ require "spec" require "../../../src/compiler/crystal/formatter" -private def assert_format(input, output = input, strict = false, file = __FILE__, line = __LINE__) +private def assert_format(input, output = input, strict = false, flags = nil, file = __FILE__, line = __LINE__) it "formats #{input.inspect}", file, line do output = "#{output}\n" unless strict - result = Crystal.format(input) + result = Crystal.format(input, flags: flags) unless result == output message = <<-ERROR Expected @@ -553,133 +553,122 @@ describe Crystal::Formatter do assert_format "with foo yield bar" context "adds `&` to yielding methods that don't have a block parameter (#8764)" do - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo yield end CRYSTAL - <<-CRYSTAL def foo(&) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo() yield end CRYSTAL - <<-CRYSTAL def foo(&) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo( ) yield end CRYSTAL - <<-CRYSTAL def foo(&) yield end CRYSTAL # #13091 - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo # bar yield end CRYSTAL - <<-CRYSTAL def foo(&) # bar yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo(x) yield end CRYSTAL - <<-CRYSTAL def foo(x, &) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo(x ,) yield end CRYSTAL - <<-CRYSTAL def foo(x, &) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo(x, y) yield end CRYSTAL - <<-CRYSTAL def foo(x, y, &) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo(x, y,) yield end CRYSTAL - <<-CRYSTAL def foo(x, y, &) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo(x ) yield end CRYSTAL - <<-CRYSTAL def foo(x, &) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo(x, ) yield end CRYSTAL - <<-CRYSTAL def foo(x, &) yield end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo( x) yield end CRYSTAL - <<-CRYSTAL def foo( x, & ) @@ -687,13 +676,12 @@ describe Crystal::Formatter do end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo( x, y) yield end CRYSTAL - <<-CRYSTAL def foo( x, y, & ) @@ -701,14 +689,13 @@ describe Crystal::Formatter do end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo( x, y) yield end CRYSTAL - <<-CRYSTAL def foo( x, y, & @@ -717,14 +704,13 @@ describe Crystal::Formatter do end CRYSTAL - assert_format <<-CRYSTAL, + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] def foo( x, ) yield end CRYSTAL - <<-CRYSTAL def foo( x, & @@ -733,7 +719,171 @@ describe Crystal::Formatter do end CRYSTAL - assert_format "macro f\n yield\n {{ yield }}\nend" + assert_format <<-CRYSTAL, <<-CRYSTAL, flags: %w[method_signature_yield] + def foo(a, **b) + yield + end + CRYSTAL + def foo(a, **b, &) + yield + end + CRYSTAL + + assert_format "macro f\n yield\n {{ yield }}\nend", flags: %w[method_signature_yield] + end + + context "does not add `&` without flag `method_signature_yield`" do + assert_format <<-CRYSTAL + def foo + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo() + yield + end + CRYSTAL + def foo + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo( + ) + yield + end + CRYSTAL + def foo + yield + end + CRYSTAL + + # #13091 + assert_format <<-CRYSTAL + def foo # bar + yield + end + CRYSTAL + + assert_format <<-CRYSTAL + def foo(x) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo(x ,) + yield + end + CRYSTAL + def foo(x) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL + def foo(x, + y) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo(x, + y,) + yield + end + CRYSTAL + def foo(x, + y) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo(x + ) + yield + end + CRYSTAL + def foo(x) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo(x, + ) + yield + end + CRYSTAL + def foo(x) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo( + x) + yield + end + CRYSTAL + def foo( + x + ) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo( + x, y) + yield + end + CRYSTAL + def foo( + x, y + ) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo( + x, + y) + yield + end + CRYSTAL + def foo( + x, + y + ) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL, <<-CRYSTAL + def foo( + x, + ) + yield + end + CRYSTAL + def foo( + x + ) + yield + end + CRYSTAL + + assert_format <<-CRYSTAL + def foo(a, **b) + yield + end + CRYSTAL end assert_format "1 + 2", "1 + 2" diff --git a/src/compiler/crystal/tools/formatter.cr b/src/compiler/crystal/tools/formatter.cr index e69b98161d20..25915b29ab75 100644 --- a/src/compiler/crystal/tools/formatter.cr +++ b/src/compiler/crystal/tools/formatter.cr @@ -1,12 +1,12 @@ require "../syntax" module Crystal - def self.format(source, filename = nil, report_warnings : IO? = nil) - Crystal::Formatter.format(source, filename: filename, report_warnings: report_warnings) + def self.format(source, filename = nil, report_warnings : IO? = nil, flags : Array(String)? = nil) + Crystal::Formatter.format(source, filename: filename, report_warnings: report_warnings, flags: flags) end class Formatter < Visitor - def self.format(source, filename = nil, report_warnings : IO? = nil) + def self.format(source, filename = nil, report_warnings : IO? = nil, flags : Array(String)? = nil) parser = Parser.new(source) parser.filename = filename nodes = parser.parse @@ -17,7 +17,7 @@ module Crystal parser.warnings.report(report_warnings) end - formatter = new(source) + formatter = new(source, flags: flags) formatter.skip_space_or_newline nodes.accept formatter formatter.finish @@ -102,7 +102,7 @@ module Crystal property indent property subformat_nesting = 0 - def initialize(source) + def initialize(source, @flags : Array(String)? = nil) @lexer = Lexer.new(source) @lexer.comments_enabled = true @lexer.count_whitespace = true @@ -158,6 +158,10 @@ module Crystal @vars = [Set(String).new] end + def flag?(flag) + !!@flags.try(&.includes?(flag)) + end + def end_visit_any(node) case node when StringInterpolation @@ -1470,7 +1474,7 @@ module Crystal # this formats `def foo # ...` to `def foo(&) # ...` for yielding # methods before consuming the comment line if node.block_arity && node.args.empty? && !node.block_arg && !node.double_splat - write "(&)" + write "(&)" if flag?("method_signature_yield") end skip_space consume_newline: false @@ -1517,7 +1521,7 @@ module Crystal end def format_def_args(node : Def | Macro) - yields = node.is_a?(Def) && !node.block_arity.nil? + yields = node.is_a?(Def) && !node.block_arity.nil? && flag?("method_signature_yield") format_def_args node.args, node.block_arg, node.splat_index, false, node.double_splat, yields end @@ -1675,7 +1679,7 @@ module Crystal elsif @token.type.op_rparen? && has_more && !just_wrote_newline # if we found a `)` and there are still more parameters to write, it # must have been a missing `&` for a def that yields - write " " + write " " if flag?("method_signature_yield") end just_wrote_newline