Skip to content

Commit 6c98570

Browse files
Merge pull request #982 from Workiva/analyzer-7
FED-3977 Allow analyzer 7
2 parents 893e53c + 6711c56 commit 6c98570

File tree

10 files changed

+201
-40
lines changed

10 files changed

+201
-40
lines changed

.github/workflows/dart_ci.yml

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,18 @@ jobs:
5050
- name: Print Dart SDK version
5151
run: dart --version
5252

53-
- name: Delete Dart-2-only files when running on Dart 3
53+
- id: install
54+
name: Install dependencies
55+
run: dart pub get
56+
57+
- name: Delete Dart-2-only files and update tests when running on Dart 3
5458
run: |
5559
DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}"
5660
if [[ "$DART_VERSION" =~ ^3 ]]; then
5761
./tool/delete_dart_2_only_files.sh
62+
./tool/update_tests_for_dart_3.sh
5863
fi
5964
60-
- id: install
61-
name: Install dependencies
62-
run: dart pub get
63-
6465
- name: Validate dependencies
6566
run: dart run dependency_validator
6667
if: always() && steps.install.outcome == 'success'
@@ -133,10 +134,13 @@ jobs:
133134
analyzer:
134135
- ^5.13.0 # This should match the lower bound
135136
- ^6.0.0
137+
- ^7.0.0
136138
exclude:
137-
# Analyzer 6 only resolves in Dart 3
139+
# Analyzer 6+ only resolves in Dart 3
138140
- sdk: 2.19.6
139141
analyzer: ^6.0.0
142+
- sdk: 2.19.6
143+
analyzer: ^7.0.0
140144

141145
steps:
142146
- uses: actions/checkout@v4
@@ -148,13 +152,6 @@ jobs:
148152
- name: Print Dart SDK version
149153
run: dart --version
150154

151-
- name: Delete Dart-2-only files when running on Dart 3
152-
run: |
153-
DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}"
154-
if [[ "$DART_VERSION" =~ ^3 ]]; then
155-
./tool/delete_dart_2_only_files.sh
156-
fi
157-
158155
- name: Update analyzer constraint to ${{ matrix.analyzer }} and validate `dart pub get` can resolve
159156
id: resolve
160157
run: |
@@ -163,6 +160,14 @@ jobs:
163160
git diff pubspec.yaml
164161
dart pub get
165162
163+
- name: Delete Dart-2-only files and update tests when running on Dart 3
164+
run: |
165+
DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}"
166+
if [[ "$DART_VERSION" =~ ^3 ]]; then
167+
./tool/delete_dart_2_only_files.sh
168+
./tool/update_tests_for_dart_3.sh
169+
fi
170+
166171
- name: Analyze package source
167172
run: dart analyze .
168173

@@ -197,13 +202,6 @@ jobs:
197202
- name: Print Dart SDK version
198203
run: dart --version
199204

200-
- name: Delete Dart-2-only files when running on Dart 3
201-
run: |
202-
DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}"
203-
if [[ "$DART_VERSION" =~ ^3 ]]; then
204-
(cd ../.. && ./tool/delete_dart_2_only_files.sh)
205-
fi
206-
207205
- id: link
208206
name: Override over_react dependency with local path
209207
run: cd ../.. && dart pub get && dart tool/travis_link_plugin_deps.dart
@@ -213,6 +211,13 @@ jobs:
213211
run: dart pub get
214212
if: always() && steps.link.outcome == 'success'
215213

214+
- name: Delete Dart-2-only files and update tests when running on Dart 3
215+
run: |
216+
DART_VERSION="${{ steps.setup-dart.outputs.dart-version }}"
217+
if [[ "$DART_VERSION" =~ ^3 ]]; then
218+
(cd ../.. && ./tool/delete_dart_2_only_files.sh && ./tool/update_tests_for_dart_3.sh)
219+
fi
220+
216221
- name: Validate dependencies
217222
run: dart run dependency_validator
218223
if: always() && steps.install.outcome == 'success'

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# OverReact Changelog
22

3+
## 5.4.5
4+
- Update analyzer dependency to `>=5.13.0 <8.0.0` (allow v8)
5+
- Update dart_style dependency to `>=2.0.0 <4.0.0` (allow v3)
6+
- Pub package tarball: exclude documentation image files, optimizing download size from ~5.9MB to ~1.3MB
7+
38
## 5.4.4
49
- [#972] Generate parts even when there are analysis warnings/errors in the source file's unresolved AST
510
- For example, the new `doc_directive_unknown` warning on doc comments in Dart 3

lib/src/builder/builder.dart

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,18 @@ import 'dart:isolate';
1818

1919
import 'package:analyzer/dart/analysis/utilities.dart';
2020
import 'package:analyzer/dart/ast/ast.dart';
21+
import 'package:analyzer/dart/ast/token.dart' show LanguageVersionToken;
2122
import 'package:build/build.dart';
2223
import 'package:dart_style/dart_style.dart';
2324
import 'package:path/path.dart' as p;
2425
import 'package:package_config/package_config.dart' as pc;
26+
import 'package:pub_semver/pub_semver.dart' as semver;
2527
import 'package:source_span/source_span.dart';
2628

2729
import './util.dart';
2830
import 'codegen.dart';
2931
import 'codegen/language_version_util.dart';
32+
import 'dart_style_compat.dart';
3033
import 'parsing.dart';
3134

3235
Builder overReactBuilder(BuilderOptions? options) => OverReactBuilder();
@@ -62,6 +65,7 @@ class OverReactBuilder extends Builder {
6265
return;
6366
}
6467

68+
pc.LanguageVersion? packageConfigLanguageVersion;
6569
String nullSafetyReason;
6670
bool nullSafety;
6771
{
@@ -84,7 +88,6 @@ class OverReactBuilder extends Builder {
8488
// Catch any errors coming from our implementation of `$packageConfig`.
8589
// We can remove this once we switch to build 2.4.0's `packageConfig`
8690
// (see `$packageConfig` doc comment for more info).
87-
pc.LanguageVersion? packageConfigLanguageVersion;
8891
try {
8992
packageConfigLanguageVersion = (await buildStep.$packageConfig)
9093
.packages
@@ -222,11 +225,30 @@ class OverReactBuilder extends Builder {
222225
final nullSafetyCommentText = 'Using nullSafety: $nullSafety.${nullSafety ? ' ' : ''} $nullSafetyReason';
223226

224227
// Generated part files must have matching language version comments, so copy them over if they exist.
225-
// TODO use CompilationUnit.languageVersionToken instead of parsing this manually once we're sure we can get on analyzer version 0.39.5 or greater
226-
final languageVersionCommentMatch = RegExp(r'//\s*@dart\s*=\s*.+').firstMatch(source);
228+
final languageVersionComment = libraryUnit.languageVersionToken?.value();
229+
230+
DartFormatter? formatter;
231+
try {
232+
formatter = constructFormatter(
233+
// Try to use the actual version of the library if possible:
234+
// 1. to avoid any potential parse errors
235+
// 2. to preserve existing formatting in checked-in generated files in this repo when running on Dart 2
236+
languageVersion: libraryUnit.languageVersionToken?.asSemver() ??
237+
packageConfigLanguageVersion?.asSemver() ??
238+
// TODO use DartFormatter.latestLanguageVersion here once this package supports only Dart 3 and dart_style >=2.3.7
239+
semver.Version.parse(Platform.version
240+
.split(RegExp(r'\s'))
241+
.first),
242+
);
243+
} catch (e, st) {
244+
// Formatting is not critical, so if it we can't construct a formatter, just skip it.
245+
log.warning('Error constructing Dart formatter, skipping formatting step', e, st);
246+
}
247+
227248
await _writePart(buildStep, outputId, outputs,
249+
formatter: formatter,
228250
nullSafetyCommentText: nullSafetyCommentText,
229-
languageVersionComment: languageVersionCommentMatch?.group(0));
251+
languageVersionComment: languageVersionComment);
230252
} else {
231253
if (hasOutputPartDirective()) {
232254
log.warning('An over_react part directive was found in ${buildStep.inputId.path}, '
@@ -238,8 +260,6 @@ class OverReactBuilder extends Builder {
238260

239261
static final _headerLine = '// '.padRight(77, '*');
240262

241-
static final _formatter = DartFormatter();
242-
243263
static CompilationUnit? _tryParseCompilationUnit(String source, AssetId id) {
244264
final result = parseString(content: source, path: id.path, throwIfDiagnostics: false);
245265

@@ -264,8 +284,14 @@ class OverReactBuilder extends Builder {
264284
'invalid_use_of_visible_for_overriding_member',
265285
};
266286

267-
static FutureOr<void> _writePart(BuildStep buildStep, AssetId outputId, Iterable<String> outputs,
268-
{required String nullSafetyCommentText, String? languageVersionComment}) async {
287+
static FutureOr<void> _writePart(
288+
BuildStep buildStep,
289+
AssetId outputId,
290+
Iterable<String> outputs, {
291+
required DartFormatter? formatter,
292+
required String nullSafetyCommentText,
293+
String? languageVersionComment,
294+
}) async {
269295
final partOf = "'${p.basename(buildStep.inputId.uri.toString())}'";
270296

271297
final buffer = StringBuffer();
@@ -298,15 +324,25 @@ class OverReactBuilder extends Builder {
298324

299325
var output = buffer.toString();
300326
// Output the file even if formatting fails, so that it can be used to debug the issue.
301-
try {
302-
output = _formatter.format(buffer.toString());
303-
} catch (e, st) {
304-
log.severe('Error formatting generated code', e, st);
327+
if (formatter != null) {
328+
try {
329+
output = formatter.format(buffer.toString());
330+
} catch (e, st) {
331+
log.severe('Error formatting generated code', e, st);
332+
}
305333
}
306334
await buildStep.writeAsString(outputId, output);
307335
}
308336
}
309337

338+
extension on pc.LanguageVersion {
339+
semver.Version asSemver() => semver.Version(major, minor, 0); // There's no patch available on this version.
340+
}
341+
342+
extension on LanguageVersionToken {
343+
semver.Version asSemver() => semver.Version(major, minor, 0); // There's no patch available on this version.
344+
}
345+
310346
extension on BuildStep {
311347
// Cache the result so we don't read and parse the package config for every file.
312348
//
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import 'dart:mirrors';
2+
3+
import 'package:dart_style/dart_style.dart' show DartFormatter;
4+
import 'package:pub_semver/pub_semver.dart' show Version;
5+
6+
/// Uses `dart:mirrors` to construct a [DartFormatter] instance, since we can't
7+
/// statically author code that works in both Dart 2 and dart_style 3.0.0.
8+
///
9+
/// Returns null if, for some reason, we can't construct a formatter.
10+
///
11+
// TODO remove this code once this package supports only Dart 3 and dart_style >=2.3.7
12+
DartFormatter? constructFormatter({required Version languageVersion}) {
13+
// In dart_style 3.0.0, the languageVersion parameter is required.
14+
// However, that parameter wasn't added until dart_style 2.3.7,
15+
// which doesn't support Dart 2.
16+
17+
try {
18+
// Works with dart_style >=2.3.7 <4.0.0 (Dart 3 only)
19+
return _dartFormatterMirror.newInstance(
20+
Symbol.empty,
21+
[],
22+
{#languageVersion: languageVersion},
23+
).reflectee as DartFormatter;
24+
} catch (_) {}
25+
26+
// Works with dart_style >=2.0.0 <3.0.0 (Dart 2, Dart 3)
27+
return _dartFormatterMirror.newInstance(
28+
Symbol.empty,
29+
[],
30+
).reflectee as DartFormatter;
31+
}
32+
33+
late final _dartFormatterMirror = reflectClass(DartFormatter);

pubspec.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ environment:
77

88
dependencies:
99
collection: ^1.15.0
10-
analyzer: '>=5.13.0 <7.0.0'
10+
analyzer: '>=5.13.0 <8.0.0'
1111
build: ^2.0.0
12-
dart_style: ^2.0.0
12+
dart_style: '>=2.0.0 <4.0.0'
1313
js: ^0.6.1+1
1414
logging: ^1.0.0
1515
meta: ^1.16.0
1616
package_config: ^2.1.0
17+
pub_semver: ^2.0.0
1718
path: ^1.5.1
1819
react: ^7.3.0
1920
redux: ^5.0.0
@@ -29,7 +30,7 @@ dev_dependencies:
2930
benchmark_harness: ^2.2.1
3031
build_resolvers: ^2.0.0
3132
build_runner: ^2.0.0
32-
build_test: ^2.0.0
33+
build_test: '>=2.0.0 <4.0.0'
3334
build_web_compilers: '>=3.2.6 <5.0.0'
3435
dart_dev: ^4.0.1
3536
dependency_validator: ^3.0.0

test/vm_tests/builder/conditionally_null_safe_builder_test.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ main() {
2929
'dart', ['pub', 'run', 'build_runner', 'build'],
3030
workingDirectory: nonNullSafePackagePath);
3131

32-
expect(build.exitCode, 0);
32+
expect(build.exitCode, 0,
33+
reason: 'build should have succeeded.'
34+
'\nstdout: ${build.stdout}'
35+
'\nstderr: ${build.stderr}');
3336
});
3437

3538
test('', () {
@@ -92,7 +95,10 @@ main() {
9295
'dart', ['pub', 'run', 'build_runner', 'build'],
9396
workingDirectory: nonNullSafePackagePath);
9497

95-
expect(build.exitCode, 0);
98+
expect(build.exitCode, 0,
99+
reason: 'build should have succeeded.'
100+
'\nstdout: ${build.stdout}'
101+
'\nstderr: ${build.stderr}');
96102
});
97103

98104
test('', () {

test/vm_tests/builder/over_react_builder_test.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,28 @@ main() {
3030
final builder = overReactBuilder(null);
3131
final logger = Logger('overReactBuilderTestLogger');
3232

33+
// [1] Note: for this test code to analyze/run in Dart 3 with build_test 3.x,
34+
// it needs to be temporarily modified to use new APIs.
35+
//
36+
// We do this in CI, and it can also be done during local development;
37+
// see tool/update_tests_for_dart_3.sh.
38+
//
39+
// This is a workaround to us not being able to be compatible with build
40+
// test 2.x and 3.x at the same time, and Dart 2 not being compatible with
41+
// build_test 3.x.
42+
3343
late AssetReader reader;
34-
late InMemoryAssetWriter writer;
44+
late InMemoryAssetWriter writer; // [1]
3545
late AssetWriterSpy writerSpy;
3646
late List<LogRecord> logs;
3747

3848
setUp(() async {
49+
// [1]
3950
reader = await PackageAssetReader.currentIsolate(
4051
rootPackage: 'over_react',
4152
);
4253

43-
writer = InMemoryAssetWriter();
54+
writer = InMemoryAssetWriter(); // [1]
4455
writerSpy = AssetWriterSpy(writer);
4556

4657
logs = [];

tool/delete_dart_2_only_files.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#
77

88
set -e
9+
set -x
910

1011
rm -rf test/over_react/component_declaration/non_null_safe_builder_integration_tests
1112
rm test/over_react/component_declaration/flux_component_test/component2/unsound_flux_component_test.dart
@@ -23,4 +24,4 @@ rm dart_test.yaml.old
2324

2425
rm -rf tools/analyzer_plugin/test/unit/util/non_null_safe
2526
rm -rf tools/analyzer_plugin/test/integration/assists/non_null_safe
26-
rm -rf tools/analyzer_plugin/test/integration/diagnostics/non_null_safe
27+
rm -rf tools/analyzer_plugin/test/integration/diagnostics/non_null_safe

tool/update_tests_for_dart_3.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
#
4+
# This script makes updates to tests to make them compatible with Dart 3.
5+
# This is a last-resort workaround for cases that can't analyze cleanly in both versions.
6+
#
7+
8+
set -e
9+
set -x
10+
11+
# Update over_react_builder_test.dart by applying a patch in build_test 3 (Dart 3 only);
12+
# see comment in test file for more details on the changes.
13+
build_test_version=$(yq '.packages.build_test.version' pubspec.lock)
14+
if [[ "$build_test_version" == "3."* ]]; then
15+
# This patch is derived from fixing tests in build_test 3 and getting the diff with:
16+
# git diff test/vm_tests/builder/over_react_builder_test.dart > tool/update_tests_for_dart_3/build_test_3_updates.patch
17+
git apply tool/update_tests_for_dart_3/build_test_3_updates.patch
18+
fi

0 commit comments

Comments
 (0)