Version 2.15.0-174.0.dev
Merge commit '7fb8c7afea0e4d9efc89bfcfe7006c9753e08ef2' into 'dev'
diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart
index 28c658d..a92b60e 100644
--- a/pkg/analysis_server/benchmark/benchmarks.dart
+++ b/pkg/analysis_server/benchmark/benchmarks.dart
@@ -15,6 +15,7 @@
import 'perf/benchmarks_impl.dart';
import 'perf/flutter_analyze_benchmark.dart';
+import 'perf/flutter_completion_benchmark.dart';
Future main(List<String> args) async {
var benchmarks = <Benchmark>[
@@ -23,6 +24,8 @@
AnalysisBenchmark(ServerBenchmark.das),
AnalysisBenchmark(ServerBenchmark.lsp),
FlutterAnalyzeBenchmark(),
+ FlutterCompletionBenchmark.das,
+ FlutterCompletionBenchmark.lsp,
];
var runner = CommandRunner(
diff --git a/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart b/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart
new file mode 100644
index 0000000..1784e96
--- /dev/null
+++ b/pkg/analysis_server/benchmark/perf/flutter_completion_benchmark.dart
@@ -0,0 +1,317 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+
+import '../benchmarks.dart';
+import 'memory_tests.dart';
+
+Future<int> _runProcess(
+ String command,
+ List<String> args, {
+ String? cwd,
+ bool failOnError = true,
+}) async {
+ print('\n$command ${args.join(' ')}');
+
+ var process = await Process.start(command, args, workingDirectory: cwd);
+
+ process.stdout
+ .transform(utf8.decoder)
+ .transform(LineSplitter())
+ .listen((line) {
+ print(' $line');
+ });
+ process.stderr
+ .transform(utf8.decoder)
+ .transform(LineSplitter())
+ .listen((line) => print(' $line'));
+
+ var exitCode = await process.exitCode;
+ if (exitCode != 0 && failOnError) {
+ throw '$command exited with $exitCode';
+ }
+
+ return exitCode;
+}
+
+/// benchmarks:
+/// - analysis-server-warm-analysis
+/// - analysis-server-warm-memory
+/// - analysis-server-edit
+/// - analysis-server-completion
+class FlutterCompletionBenchmark extends Benchmark {
+ static final das = FlutterCompletionBenchmark(
+ 'das',
+ () => AnalysisServerBenchmarkTest(),
+ );
+
+ static final lsp = FlutterCompletionBenchmark(
+ 'lsp',
+ () => LspAnalysisServerBenchmarkTest(),
+ );
+
+ final AbstractBenchmarkTest Function() testConstructor;
+
+ late String flutterPath;
+
+ FlutterCompletionBenchmark(String protocolName, this.testConstructor)
+ : super(
+ '$protocolName-flutter-completion',
+ 'Completion benchmarks with Flutter.',
+ kind: 'group',
+ );
+
+ @override
+ bool get needsSetup => true;
+
+ @override
+ Future oneTimeSetup() async {
+ flutterPath = Directory.systemTemp.createTempSync('flutter').path;
+
+ // git clone https://github.com/flutter/flutter $flutterDir
+ await _runProcess('git', [
+ 'clone',
+ 'https://github.com/flutter/flutter',
+ path.canonicalize(flutterPath)
+ ]);
+
+ var flutterTool = path.join(flutterPath, 'bin', 'flutter');
+
+ // flutter --version
+ await _runProcess(flutterTool, ['--version'], cwd: flutterPath);
+
+ // flutter update-packages
+ await _runProcess(
+ flutterTool,
+ ['pub', 'get'],
+ cwd: path.join(flutterPath, 'packages', 'flutter'),
+ );
+ }
+
+ @override
+ Future<BenchMarkResult> run({
+ bool quick = false,
+ bool verbose = false,
+ }) async {
+ if (!quick) {
+ deleteServerCache();
+ }
+
+ var test = testConstructor();
+ if (verbose) {
+ test.debugStdio();
+ }
+
+ final flutterPkgPath = path.join(flutterPath, 'packages', 'flutter');
+
+ // Open a small directory, but with the package config that allows us
+ // to analyze any file in `package:flutter`, including tests.
+ var startTimer = Stopwatch()..start();
+ await test.setUp([
+ '$flutterPkgPath/lib/src/physics',
+ ]);
+
+ await test.analysisFinished;
+ startTimer.stop();
+
+ var result = CompoundBenchMarkResult(id);
+ result.add(
+ 'start',
+ BenchMarkResult(
+ 'micros',
+ startTimer.elapsedMicroseconds,
+ ),
+ );
+
+ // This is a scenario of an easy case - the file is small, less than
+ // 3KB, and we insert a prefix with a good selectivity. So, everything
+ // should be fast. We should just make sure to don't spend too much
+ // time analyzing, and do apply the filter.
+ // Total number of suggestions: 2322.
+ // Filtered to: 82.
+ result.add(
+ 'smallFile-body',
+ BenchMarkResult(
+ 'micros',
+ await _completionTiming(
+ test,
+ filePath: '$flutterPkgPath/lib/src/material/flutter_logo.dart',
+ uniquePrefix: 'Widget build(BuildContext context) {',
+ insertStringGenerator: () => 'M',
+ name: 'smallFile-body',
+ ),
+ ),
+ );
+
+ if (!quick) {
+ // This scenario is relatively easy - the file is small, less then 3KB.
+ // But we don't have any prefix to filter, so if we don't restrict the
+ // number of suggestions, we might spend too much time serializing into
+ // JSON in the server, and deserializing on the client.
+ // Total number of suggestions: 2322.
+ // Filtered to: 2322.
+ result.add(
+ 'smallFile-body-withoutPrefix',
+ BenchMarkResult(
+ 'micros',
+ await _completionTiming(
+ test,
+ filePath: '$flutterPkgPath/lib/src/material/flutter_logo.dart',
+ uniquePrefix: 'Widget build(BuildContext context) {',
+ insertStringGenerator: null,
+ name: 'smallFile-body-withoutPrefix',
+ ),
+ ),
+ );
+
+ // The key part of this scenario is that we work in a relatively large
+ // file, about 340KB. So, it is expensive to parse and resolve. And
+ // we simulate changing it by typing a prefix, as users often do.
+ // The target method body is small, so something could be optimized.
+ // Total number of suggestions: 4654.
+ // Filtered to: 182.
+ result.add(
+ 'smallLibraryCycle-largeFile-smallBody',
+ BenchMarkResult(
+ 'micros',
+ await _completionTiming(
+ test,
+ filePath: '$flutterPkgPath/test/material/text_field_test.dart',
+ uniquePrefix: 'getOpacity(WidgetTester tester, Finder finder) {',
+ insertStringGenerator: () => 'M',
+ name: 'smallLibraryCycle-largeFile-smallBody',
+ ),
+ ),
+ );
+
+ // In this scenario we change a file that is in a library cycle
+ // with 69 libraries. So, the implementation might discard information
+ // about all these libraries. We change a method body, so the API
+ // signature is the same, and we are able to reload these libraries
+ // from bytes. But this still costs something.
+ // There is also a spill-over from the previous test - we send a lot
+ // (about 5MB) of available declarations after each change. This makes
+ // completion response times very large.
+ // TODO(scheglov) Remove the previous sentence when improved.
+ // Total number of suggestions: 3429.
+ // Filtered to: 133.
+ result.add(
+ 'mediumLibraryCycle-mediumFile-smallBody',
+ BenchMarkResult(
+ 'micros',
+ await _completionTiming(
+ test,
+ filePath: '$flutterPkgPath/lib/src/material/app_bar.dart',
+ uniquePrefix: 'computeDryLayout(BoxConstraints constraints) {',
+ insertStringGenerator: () => 'M',
+ name: 'mediumLibraryCycle-mediumFile-smallBody',
+ ),
+ ),
+ );
+
+ // In this scenario is that we change a file that is in a library cycle
+ // with 69 libraries. Moreover, we change the API - the type of a
+ // formal parameter. So, potentially we need to relink the whole library
+ // cycle. This is expensive.
+ // Total number of suggestions: 1510.
+ // Filtered to: 0.
+ result.add(
+ 'mediumLibraryCycle-mediumFile-api-parameterType',
+ BenchMarkResult(
+ 'micros',
+ await _completionTiming(
+ test,
+ filePath: '$flutterPkgPath/lib/src/material/app_bar.dart',
+ uniquePrefix: 'computeDryLayout(BoxConstraints',
+ insertStringGenerator: _IncrementingStringGenerator(),
+ name: 'mediumLibraryCycle-mediumFile-api-parameterType',
+ ),
+ ),
+ );
+ }
+
+ await test.shutdown();
+
+ return result;
+ }
+
+ /// Perform completion in [filePath] at the end of the [uniquePrefix].
+ ///
+ /// If [insertStringGenerator] is not `null`, insert it, and complete after
+ /// it. So, we can simulate user typing to start completion.
+ Future<int> _completionTiming(
+ AbstractBenchmarkTest test, {
+ required String filePath,
+ required String uniquePrefix,
+ required String Function()? insertStringGenerator,
+ String? name,
+ }) async {
+ final fileContent = File(filePath).readAsStringSync();
+
+ final prefixOffset = fileContent.indexOf(uniquePrefix);
+ if (prefixOffset == -1) {
+ throw StateError('Cannot find: $uniquePrefix');
+ }
+ if (fileContent.contains(uniquePrefix, prefixOffset + 1)) {
+ throw StateError('Not unique: $uniquePrefix');
+ }
+
+ final prefixEnd = prefixOffset + uniquePrefix.length;
+
+ await test.openFile(filePath, fileContent);
+
+ Future<void> perform() async {
+ var completionOffset = prefixEnd;
+
+ if (insertStringGenerator != null) {
+ final insertString = insertStringGenerator();
+ completionOffset += insertString.length;
+ var newCode = fileContent.substring(0, prefixEnd) +
+ insertString +
+ fileContent.substring(prefixEnd);
+ await test.updateFile(
+ filePath,
+ newCode,
+ );
+ }
+
+ await test.complete(filePath, completionOffset);
+
+ if (insertStringGenerator != null) {
+ await test.updateFile(filePath, fileContent);
+ }
+ }
+
+ // Perform warm-up.
+ // The cold start does not matter.
+ // The sustained performance is much more important.
+ const kWarmUpCount = 50;
+ for (var i = 0; i < kWarmUpCount; i++) {
+ await perform();
+ }
+
+ const kRepeatCount = 10;
+ final timer = Stopwatch()..start();
+ for (var i = 0; i < kRepeatCount; i++) {
+ await perform();
+ }
+
+ await test.closeFile(filePath);
+
+ return timer.elapsedMicroseconds ~/ kRepeatCount;
+ }
+}
+
+class _IncrementingStringGenerator {
+ int _value = 0;
+
+ String call() {
+ return '${_value++}';
+ }
+}
diff --git a/pkg/analysis_server/benchmark/perf/memory_tests.dart b/pkg/analysis_server/benchmark/perf/memory_tests.dart
index b67b63c..528f672 100644
--- a/pkg/analysis_server/benchmark/perf/memory_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/memory_tests.dart
@@ -79,6 +79,7 @@
Future<void> setUp(List<String> roots) async {
await _test.setUp();
await _test.subscribeToStatusNotifications();
+ await _test.subscribeToAvailableSuggestions();
await _test.sendAnalysisSetAnalysisRoots(roots, []);
}
@@ -127,6 +128,16 @@
/// After every test, the server is stopped.
Future shutdown() async => await shutdownIfNeeded();
+ /// Enable using available suggestions during completion.
+ Future<void> subscribeToAvailableSuggestions() async {
+ await server.send(
+ 'completion.setSubscriptions',
+ CompletionSetSubscriptionsParams(
+ [CompletionService.AVAILABLE_SUGGESTION_SETS],
+ ).toJson(),
+ );
+ }
+
/// Enable [ServerService.STATUS] notifications so that [analysisFinished]
/// can be used.
Future subscribeToStatusNotifications() async {
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index d2a5859..04235d9 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -100,11 +100,6 @@
/// Compute analysis results for all units of the library.
Map<FileState, UnitAnalysisResult> analyze() {
- return analyzeSync();
- }
-
- /// Compute analysis results for all units of the library.
- Map<FileState, UnitAnalysisResult> analyzeSync() {
timerLibraryAnalyzer.start();
Map<FileState, CompilationUnitImpl> units = {};
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 2b2efd4..1fa7152 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -100,7 +100,7 @@
TypeSystemImpl get _typeSystem => _libraryElement.typeSystem;
/// Compute analysis results for all units of the library.
- Map<FileState, UnitAnalysisResult> analyzeSync({
+ Map<FileState, UnitAnalysisResult> analyze({
required String? completionPath,
required int? completionOffset,
required OperationPerformanceImpl performance,
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index d52742b..daf5dbd 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -526,7 +526,7 @@
try {
results = performance!.run('analyze', (performance) {
- return libraryAnalyzer.analyzeSync(
+ return libraryAnalyzer.analyze(
completionPath: completionOffset != null ? completionPath : null,
completionOffset: completionOffset,
performance: performance,
diff --git a/pkg/scrape/example/superclass_parameters.dart b/pkg/scrape/example/superclass_parameters.dart
new file mode 100644
index 0000000..de5923e
--- /dev/null
+++ b/pkg/scrape/example/superclass_parameters.dart
@@ -0,0 +1,317 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:scrape/scrape.dart';
+
+enum ArgumentMatch {
+ noArguments,
+ none,
+ all,
+ some,
+ prefix,
+ suffix,
+ middle,
+ noncontiguous
+}
+
+extension on ArgumentMatch {
+ String get description {
+ switch (this) {
+ case ArgumentMatch.noArguments:
+ return 'No arguments to match';
+ case ArgumentMatch.none:
+ return 'Matched none';
+ case ArgumentMatch.all:
+ return 'Matched all';
+ case ArgumentMatch.some:
+ return 'Matched some';
+ case ArgumentMatch.prefix:
+ return 'Matched prefix';
+ case ArgumentMatch.suffix:
+ return 'Matched suffix';
+ case ArgumentMatch.middle:
+ return 'Matched middle';
+ case ArgumentMatch.noncontiguous:
+ return 'Matched noncontiguous';
+ }
+ }
+}
+
+void main(List<String> arguments) {
+ Scrape()
+ ..addHistogram('Potential use')
+ ..addHistogram('Individual arguments')
+ ..addHistogram('Named arguments')
+ ..addHistogram('Positional arguments')
+ ..addHistogram('Argument pattern')
+ ..addHistogram('Append super args')
+ ..addHistogram('Prepend super args')
+ ..addHistogram('Insert super args')
+ ..addHistogram('Do not merge super args')
+ ..addHistogram('No explicit super(), call unnamed')
+ ..addHistogram('No explicit super(), call same name')
+ ..addVisitor(() => SuperclassParameterVisitor())
+ ..runCommandLine(arguments);
+}
+
+class SuperclassParameterVisitor extends ScrapeVisitor {
+ @override
+ void visitConstructorDeclaration(ConstructorDeclaration node) {
+ // Whether the constructor might benefit from the feature at all.
+ var initializer = _findSuper(node);
+ if (initializer == null) {
+ record('Potential use', 'No: No initializer');
+ return;
+ }
+
+ if (initializer.argumentList.arguments.isEmpty) {
+ record('Potential use', 'No: Empty super() argument list');
+ return;
+ }
+
+ record('Potential use', 'Yes');
+
+ // If we get here, we have a superclass constructor call with arguments.
+ // See if any of them could use the feature.
+ var positionalParamNames = node.parameters.parameters
+ .where((param) => param.isPositional)
+ .map((param) => param.identifier!.name)
+ .toList();
+
+ var namedParamNames = node.parameters.parameters
+ .where((param) => param.isNamed)
+ .map((param) => param.identifier!.name)
+ .toSet();
+
+ var matchedNamedArguments = 0;
+ var unmatchedNamedArguments = 0;
+
+ var lastPositionalParam = -1;
+ var matchedIndexes = <int>[];
+ var unmatchedPositionalArguments = 0;
+ var positionalArgCount = 0;
+ for (var i = 0; i < initializer.argumentList.arguments.length; i++) {
+ var argument = initializer.argumentList.arguments[i];
+
+ if (argument is NamedExpression) {
+ var expression = argument.expression;
+ if (expression is! SimpleIdentifier) {
+ record('Individual arguments',
+ 'Named argument expression is not identifier');
+ unmatchedNamedArguments++;
+ } else if (argument.name.label.name != expression.name) {
+ record('Individual arguments',
+ 'Named argument name does not match expression name');
+ unmatchedNamedArguments++;
+ } else if (!namedParamNames.contains(expression.name)) {
+ record('Individual arguments',
+ 'Named argument does not match a parameter');
+ unmatchedNamedArguments++;
+ } else {
+ record('Individual arguments', 'Argument matches a parameter');
+ matchedNamedArguments++;
+ }
+ } else {
+ positionalArgCount++;
+ if (argument is! SimpleIdentifier) {
+ record('Individual arguments',
+ 'Positional argument expression is not identifier');
+ unmatchedPositionalArguments++;
+ } else {
+ // Start searching after the last matched positional parameter because
+ // we don't allow reordering them. If two arguments are out of order,
+ // that doesn't mean we can't use "super." at all, just that we can
+ // only use it for *one* of those arguments.
+ var index =
+ positionalParamNames.indexOf(argument.name, lastPositionalParam);
+ if (index == -1) {
+ record('Individual arguments',
+ 'Positional argument does not match a parameter');
+ } else {
+ record('Individual arguments', 'Argument matches a parameter');
+ lastPositionalParam = index;
+ matchedIndexes.add(i);
+ }
+ }
+ }
+ }
+
+ // Characterize the positional argument list.
+ ArgumentMatch positionalMatch;
+ if (unmatchedPositionalArguments == 0) {
+ if (matchedIndexes.isEmpty) {
+ positionalMatch = ArgumentMatch.noArguments;
+ } else {
+ positionalMatch = ArgumentMatch.all;
+ }
+ } else if (matchedIndexes.isEmpty) {
+ positionalMatch = ArgumentMatch.none;
+ } else {
+ // If there is any unmatched argument before a matched one, then the
+ // matched arguments are not all at the beginning.
+ var matchedArePrefix = true;
+ for (var i = 1; i < positionalArgCount; i++) {
+ if (!matchedIndexes.contains(i - 1) && matchedIndexes.contains(i)) {
+ matchedArePrefix = false;
+ break;
+ }
+ }
+
+ // If there is any unmatched argument after a matched one, then the
+ // matched arguments are not all at the end.
+ var matchedAreSuffix = true;
+ for (var i = 0; i < positionalArgCount - 1; i++) {
+ if (!matchedIndexes.contains(i + 1) && matchedIndexes.contains(i)) {
+ matchedAreSuffix = false;
+ break;
+ }
+ }
+
+ // If any index between the first and last matched arg is not matched,
+ // then the arguments are not contiguous.
+ var matchedAreContiguous = true;
+ if (matchedIndexes.isNotEmpty) {
+ for (var i = matchedIndexes.first; i <= matchedIndexes.last; i++) {
+ if (!matchedIndexes.contains(i)) {
+ matchedAreContiguous = false;
+ break;
+ }
+ }
+ }
+
+ if (!matchedAreContiguous) {
+ positionalMatch = ArgumentMatch.noncontiguous;
+ } else if (matchedArePrefix) {
+ positionalMatch = ArgumentMatch.prefix;
+ } else if (matchedAreSuffix) {
+ positionalMatch = ArgumentMatch.suffix;
+ } else {
+ positionalMatch = ArgumentMatch.middle;
+ }
+ }
+
+ record('Positional arguments', positionalMatch.description);
+
+ // Characterize the named argument list.
+ ArgumentMatch namedMatch;
+ if (matchedNamedArguments == 0) {
+ if (unmatchedNamedArguments == 0) {
+ namedMatch = ArgumentMatch.noArguments;
+ } else {
+ namedMatch = ArgumentMatch.none;
+ }
+ } else {
+ if (unmatchedNamedArguments == 0) {
+ namedMatch = ArgumentMatch.all;
+ } else {
+ namedMatch = ArgumentMatch.some;
+ }
+ }
+
+ record('Named arguments', namedMatch.description);
+
+ var pattern = [
+ for (var i = 0; i < positionalArgCount; i++)
+ matchedIndexes.contains(i) ? 's' : '_',
+ for (var i = 0; i < matchedNamedArguments; i++) ':s',
+ for (var i = 0; i < unmatchedNamedArguments; i++) ':_',
+ ].join(',');
+ record('Argument pattern', '($pattern)');
+
+ // If none of the arguments could be 'super.', then none of the proposals
+ // apply.
+ if (matchedIndexes.isEmpty && matchedNamedArguments == 0) return;
+
+ var append = true;
+ var prepend = true;
+ var insert = true;
+ var noMerge = true;
+ var allParams = true;
+
+ switch (positionalMatch) {
+ case ArgumentMatch.noArguments:
+ case ArgumentMatch.all:
+ // OK.
+ break;
+
+ case ArgumentMatch.none:
+ allParams = false;
+ break;
+
+ case ArgumentMatch.some:
+ throw Exception('Should not get some for positional args.');
+
+ case ArgumentMatch.prefix:
+ append = false;
+ noMerge = false;
+ allParams = false;
+ break;
+
+ case ArgumentMatch.suffix:
+ prepend = false;
+ noMerge = false;
+ allParams = false;
+ break;
+
+ case ArgumentMatch.middle:
+ append = false;
+ prepend = false;
+ noMerge = false;
+ allParams = false;
+ break;
+
+ case ArgumentMatch.noncontiguous:
+ append = false;
+ prepend = false;
+ insert = false;
+ noMerge = false;
+ allParams = false;
+ break;
+ }
+
+ switch (namedMatch) {
+ case ArgumentMatch.noArguments:
+ case ArgumentMatch.all:
+ // OK.
+ break;
+
+ case ArgumentMatch.none:
+ case ArgumentMatch.some:
+ allParams = false;
+ break;
+
+ default:
+ throw Exception('Unexpected match.');
+ }
+
+ record('Append super args', append ? 'Yes' : 'No');
+ record('Prepend super args', prepend ? 'Yes' : 'No');
+ record('Insert super args', insert ? 'Yes' : 'No');
+ record('Do not merge super args', noMerge ? 'Yes' : 'No');
+
+ var subName = _constructorName(node.name);
+ var superName = _constructorName(initializer.constructorName);
+
+ record('No explicit super(), call same name',
+ (allParams && superName == subName) ? 'Yes' : 'No');
+
+ record('No explicit super(), call unnamed',
+ (allParams && superName == '(unnamed)') ? 'Yes' : 'No');
+ }
+
+ String _constructorName(SimpleIdentifier? name) {
+ if (name == null) return '(unnamed)';
+ return name.name;
+ }
+
+ SuperConstructorInvocation? _findSuper(ConstructorDeclaration node) {
+ for (var initializer in node.initializers) {
+ if (initializer is SuperConstructorInvocation) {
+ return initializer;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/compile_protos.sh b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/compile_protos.sh
index 8031891..d4f6355 100755
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/compile_protos.sh
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/compile_protos.sh
@@ -16,4 +16,4 @@
protoc --dart_out=$GENERATED_DIR -I$DIR/protos $DIR/protos/*.proto
rm $GENERATED_DIR/*.pbenum.dart $GENERATED_DIR/*.pbjson.dart $GENERATED_DIR/*.pbserver.dart
-dartfmt -w $DIR/lib/generated
+dart format $DIR/lib/generated
diff --git a/pkg/vm_service/tool/generate.dart b/pkg/vm_service/tool/generate.dart
index b9ef51f..79d74eb 100644
--- a/pkg/vm_service/tool/generate.dart
+++ b/pkg/vm_service/tool/generate.dart
@@ -46,9 +46,9 @@
dart.api.parse(nodes);
dart.api.generate(generator);
outputFile.writeAsStringSync(generator.toString());
- ProcessResult result = Process.runSync('dartfmt', ['-w', outDirPath]);
+ ProcessResult result = Process.runSync('dart', ['format', outDirPath]);
if (result.exitCode != 0) {
- print('dartfmt: ${result.stdout}\n${result.stderr}');
+ print('dart format: ${result.stdout}\n${result.stderr}');
throw result.exitCode;
}
@@ -103,9 +103,9 @@
dart.api.parse(nodes);
dart.api.generateAsserts(generator);
outputFile.writeAsStringSync(generator.toString());
- ProcessResult result = Process.runSync('dartfmt', ['-w', outDirPath]);
+ ProcessResult result = Process.runSync('dart', ['format', outDirPath]);
if (result.exitCode != 0) {
- print('dartfmt: ${result.stdout}\n${result.stderr}');
+ print('dart format: ${result.stdout}\n${result.stderr}');
throw result.exitCode;
}
diff --git a/runtime/observatory/tool/ensure_dartfmt.sh b/runtime/observatory/tool/ensure_dartfmt.sh
index 6aa50e9..0579deb 100755
--- a/runtime/observatory/tool/ensure_dartfmt.sh
+++ b/runtime/observatory/tool/ensure_dartfmt.sh
@@ -3,13 +3,13 @@
dart_files=$(find lib web -name "*.dart")
[ -z "$dart_files" ] && exit 0
-unformatted=$(dartfmt -n $dart_files)
+unformatted=$(dart format -o none $dart_files)
[ -z "$unformatted" ] && exit 0
-# Some files are not dartfmt'd. Print message and fail.
-echo >&2 "dart files must be formatted with dartfmt. Please run:"
+# Some files are not dart formatted. Print message and fail.
+echo >&2 "dart files must be formatted with dart format. Please run:"
for fn in $unformatted; do
- echo >&2 " dartfmt -w $PWD/$fn"
+ echo >&2 " dart format $PWD/$fn"
done
exit 1
diff --git a/runtime/observatory_2/tool/ensure_dartfmt.sh b/runtime/observatory_2/tool/ensure_dartfmt.sh
index 6aa50e9..0579deb 100755
--- a/runtime/observatory_2/tool/ensure_dartfmt.sh
+++ b/runtime/observatory_2/tool/ensure_dartfmt.sh
@@ -3,13 +3,13 @@
dart_files=$(find lib web -name "*.dart")
[ -z "$dart_files" ] && exit 0
-unformatted=$(dartfmt -n $dart_files)
+unformatted=$(dart format -o none $dart_files)
[ -z "$unformatted" ] && exit 0
-# Some files are not dartfmt'd. Print message and fail.
-echo >&2 "dart files must be formatted with dartfmt. Please run:"
+# Some files are not dart formatted. Print message and fail.
+echo >&2 "dart files must be formatted with dart format. Please run:"
for fn in $unformatted; do
- echo >&2 " dartfmt -w $PWD/$fn"
+ echo >&2 " dart format $PWD/$fn"
done
exit 1
diff --git a/runtime/tests/concurrency/generate_stress_test.dart b/runtime/tests/concurrency/generate_stress_test.dart
index 3870ef2..a22bc34 100644
--- a/runtime/tests/concurrency/generate_stress_test.dart
+++ b/runtime/tests/concurrency/generate_stress_test.dart
@@ -17,7 +17,7 @@
final Map testMap = json.decode(File(stressTestListJson).readAsStringSync());
final testFiles = testMap['non-nnbd'].cast<String>();
final testFilesNnbd = testMap['nnbd'].cast<String>();
-final dartfmt = 'tools/sdks/dart-sdk/bin/dartfmt';
+final dart = 'tools/sdks/dart-sdk/bin/dart';
main(List<String> args) async {
File(generatedNnbdTest)
@@ -188,7 +188,7 @@
Future<String> format(String generatedSource) async {
try {
- final result = await Process.start(dartfmt, []);
+ final result = await Process.start(dart, ['format']);
result.stdin.writeln(generatedSource);
final results = await Future.wait([
@@ -200,13 +200,14 @@
final exitCode = results[3] as int;
if (exitCode != 0) {
- print('Note: Failed to format source code. Dartfmt exited non-0.');
+ print('Note: Failed to format source code. Dart format exited non-0.');
return generatedSource;
}
final stdout = results[1] as String;
final stderr = results[2] as String;
if (stderr.trim().length != 0) {
- print('Note: Failed to format source code. Dartfmt had stderr: $stderr');
+ print('Note: Failed to format source code. Dart format had stderr: '
+ '$stderr');
return generatedSource;
}
return stdout;
diff --git a/runtime/tools/dartfuzz/gen_type_table.dart b/runtime/tools/dartfuzz/gen_type_table.dart
index 0f2599a..6bd642e 100644
--- a/runtime/tools/dartfuzz/gen_type_table.dart
+++ b/runtime/tools/dartfuzz/gen_type_table.dart
@@ -8,7 +8,7 @@
// dart gen_type_table.dart > dartfuzz_type_table.dart
//
// Reformat:
-// tools/sdks/dart-sdk/bin/dartfmt -w \
+// tools/sdks/dart-sdk/bin/dart format \
// runtime/tools/dartfuzz/dartfuzz_type_table.dart
//
// Then send out modified dartfuzz_type_table.dart for review together
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 274a04f..9355b01 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -1621,8 +1621,15 @@
blocked_registers[loc.reg()] = true;
} else if (loc.IsFpuRegister()) {
// Check that a register is not specified twice in the summary.
- ASSERT(!blocked_fpu_registers[loc.fpu_reg()]);
- blocked_fpu_registers[loc.fpu_reg()] = true;
+ const FpuRegister fpu_reg = loc.fpu_reg();
+ if ((fpu_reg < 0) || (fpu_reg >= kNumberOfFpuRegisters)) {
+ // Debug prints for https://github.com/dart-lang/sdk/issues/47314.
+ OS::PrintErr("input(%" Pd ") fpu_reg = %d\n", i, fpu_reg);
+ OS::PrintErr("instr = %s\n", instr->ToCString());
+ UNREACHABLE();
+ }
+ ASSERT(!blocked_fpu_registers[fpu_reg]);
+ blocked_fpu_registers[fpu_reg] = true;
}
}
@@ -1634,8 +1641,15 @@
blocked_registers[loc.reg()] = true;
} else if (loc.IsFpuRegister()) {
// Check that a register is not specified twice in the summary.
- ASSERT(!blocked_fpu_registers[loc.fpu_reg()]);
- blocked_fpu_registers[loc.fpu_reg()] = true;
+ const FpuRegister fpu_reg = loc.fpu_reg();
+ if ((fpu_reg < 0) || (fpu_reg >= kNumberOfFpuRegisters)) {
+ // Debug prints for https://github.com/dart-lang/sdk/issues/47314.
+ OS::PrintErr("temp(%" Pd ") fpu_reg = %d\n", i, fpu_reg);
+ OS::PrintErr("instr = %s\n", instr->ToCString());
+ UNREACHABLE();
+ }
+ ASSERT(!blocked_fpu_registers[fpu_reg]);
+ blocked_fpu_registers[fpu_reg] = true;
}
}
diff --git a/tools/VERSION b/tools/VERSION
index bd4c19d..39d9d47 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 173
+PRERELEASE 174
PRERELEASE_PATCH 0
\ No newline at end of file