From 6753ab40b3327c5cc4c9b1cd60c76e69f21ba494 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Thu, 14 Nov 2024 15:06:06 -0800 Subject: [PATCH] Make "// @dart=" version comments affect the applied style. (#1600) The formatter uses an incoming language version to control how the formatted code is parsed. The langauge version is also used to determine whether you get the short or tall style. Prior to this PR, a "// @dart=" version comment in the formatted code would affect the language version the code is parsed at. But it wouldn't use that comment to determine whether you get the short or tall style. This fixes that. Fix #1599. --- lib/src/dart_formatter.dart | 8 +++- test/cli/language_version_test.dart | 57 +++++++++++++++++++++++++++++ test/dart_formatter_test.dart | 56 ++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart index 6ab5238a..215a9825 100644 --- a/lib/src/dart_formatter.dart +++ b/lib/src/dart_formatter.dart @@ -193,9 +193,15 @@ final class DartFormatter { // Format it. var lineInfo = parseResult.lineInfo; + // If the code has an `@dart=` comment, use that to determine the style. + var sourceLanguageVersion = languageVersion; + if (parseResult.unit.languageVersionToken case var token?) { + sourceLanguageVersion = Version(token.major, token.minor, 0); + } + // Use language version to determine what formatting style to apply. SourceCode output; - if (languageVersion > latestShortStyleLanguageVersion) { + if (sourceLanguageVersion > latestShortStyleLanguageVersion) { // Look for a page width comment before the code. int? pageWidthFromComment; for (Token? comment = node.beginToken.precedingComments; diff --git a/test/cli/language_version_test.dart b/test/cli/language_version_test.dart index 3c874dd7..0b179eeb 100644 --- a/test/cli/language_version_test.dart +++ b/test/cli/language_version_test.dart @@ -266,5 +266,62 @@ main() { await d.dir('code', [d.file('a.dart', after)]).validate(); }); + + test('language version comment override opts into short style', () async { + const before = ''' +// @dart=3.6 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.6 +main() { + f( + argument, // comment + another); +} +'''; + + await d.dir('code', [d.file('a.dart', before)]).create(); + + var process = await runFormatterOnDir(['--language-version=3.7']); + await process.shouldExit(0); + + await d.dir('code', [d.file('a.dart', after)]).validate(); + }); + + test('language version comment override opts into tall style', () async { + // Note that in real-world code it doesn't make sense for a language + // version comment to be *higher* than the specified default language + // version before you can't use a comment that's higher than the minimum + // version in the package's SDK constraint. (Otherwise, you could end up + // trying to run a library whose language version isn't supported by the + // SDK you are running it in.) + // + // But we support it in the formatter since it's possible to specify a + // default language version using mechanisms other than the pubspec SDK + // constraint. + const before = ''' +// @dart=3.7 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.7 +main() { + f( + argument, // comment + another, + ); +} +'''; + + await d.dir('code', [d.file('a.dart', before)]).create(); + + var process = await runFormatterOnDir(['--language-version=3.6']); + await process.shouldExit(0); + + await d.dir('code', [d.file('a.dart', after)]).validate(); + }); }); } diff --git a/test/dart_formatter_test.dart b/test/dart_formatter_test.dart index 76a3c1ed..bf9c347b 100644 --- a/test/dart_formatter_test.dart +++ b/test/dart_formatter_test.dart @@ -81,6 +81,62 @@ main() { }); }); + test('language version comment override opts into short style', () async { + // Use a language version with tall style. + var formatter = makeFormatter(languageVersion: Version(3, 7, 0)); + + // But the code has a comment to opt into the short style. + const before = ''' +// @dart=3.6 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.6 +main() { + f( + argument, // comment + another); +} +'''; + + expect(formatter.format(before), after); + }); + + test('language version comment override opts into tall style', () async { + // Use a language version with short style. + var formatter = makeFormatter(languageVersion: Version(3, 6, 0)); + + // But the code has a comment to opt into the tall style. + // + // Note that in real-world code it doesn't make sense for a language + // version comment to be *higher* than the specified default language + // version before you can't use a comment that's higher than the minimum + // version in the package's SDK constraint. (Otherwise, you could end up + // trying to run a library whose language version isn't supported by the + // SDK you are running it in.) + // + // But we support it in the formatter since it's possible to specify a + // default language version using mechanisms other than the pubspec SDK + // constraint. + const before = ''' +// @dart=3.7 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.7 +main() { + f( + argument, // comment + another, + ); +} +'''; + + expect(formatter.format(before), after); + }); + test('throws a FormatterException on failed parse', () { var formatter = makeFormatter(); expect(() => formatter.format('wat?!'), throwsA(isA()));