quick-fix to wrap in unawaited

Fixes: https://github.com/dart-lang/sdk/issues/49262

See also: https://github.com/dart-lang/linter/issues/3429

Change-Id: I0d3bf6c72ae1cf3e08f50b4deda10aba52e25eb4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/248480
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
pq 2022-06-15 18:03:08 +00:00 committed by Commit Bot
parent f52068809d
commit d2e006eefa
5 changed files with 219 additions and 0 deletions

View file

@ -0,0 +1,42 @@
// Copyright (c) 2022, 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:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
class WrapInUnawaited extends CorrectionProducer {
@override
FixKind get fixKind => DartFixKind.WRAP_IN_UNAWAITED;
@override
Future<void> compute(ChangeBuilder builder) async {
AstNode? node = this.node;
if (node is SimpleIdentifier) {
node = node.parent;
}
Expression? expression;
if (node is Expression) {
expression = node;
} else if (node is ExpressionStatement) {
expression = node.expression;
}
if (expression == null) return;
var value = utils.getNodeText(expression);
await builder.addDartFileEdit(file, (builder) {
var libraryPrefix =
builder.importLibraryElement(Uri.parse('dart:async')).prefix;
var prefix = libraryPrefix != null ? '$libraryPrefix.' : '';
builder.addSimpleReplacement(
range.node(expression!),
'${prefix}unawaited($value)',
);
});
}
}

View file

@ -1630,6 +1630,11 @@ class DartFixKind {
DartFixKindPriority.DEFAULT,
"Wrap in a 'Text' widget",
);
static const WRAP_IN_UNAWAITED = FixKind(
'dart.fix.wrap.unawaited',
DartFixKindPriority.DEFAULT,
"Wrap in 'unawaited'",
);
}
class DartFixKindPriority {

View file

@ -194,6 +194,7 @@ import 'package:analysis_server/src/services/correction/dart/use_not_eq_null.dar
import 'package:analysis_server/src/services/correction/dart/use_rethrow.dart';
import 'package:analysis_server/src/services/correction/dart/wrap_in_future.dart';
import 'package:analysis_server/src/services/correction/dart/wrap_in_text.dart';
import 'package:analysis_server/src/services/correction/dart/wrap_in_unawaited.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
@ -449,6 +450,7 @@ class FixProcessor extends BaseProcessor {
],
LintNames.discarded_futures: [
AddAsync.new,
WrapInUnawaited.new,
],
LintNames.empty_catches: [
RemoveEmptyCatch.new,
@ -625,6 +627,7 @@ class FixProcessor extends BaseProcessor {
],
LintNames.unawaited_futures: [
AddAwait.unawaited,
WrapInUnawaited.new,
],
LintNames.unnecessary_brace_in_string_interps: [
RemoveInterpolationBraces.new,

View file

@ -234,6 +234,7 @@ import 'use_not_eq_null_test.dart' as use_not_eq_null;
import 'use_rethrow_test.dart' as use_rethrow;
import 'wrap_in_future_test.dart' as wrap_in_future;
import 'wrap_in_text_test.dart' as wrap_in_text;
import 'wrap_in_unawaited_test.dart' as wrap_in_unawaited;
void main() {
defineReflectiveSuite(() {
@ -438,5 +439,6 @@ void main() {
use_rethrow.main();
wrap_in_future.main();
wrap_in_text.main();
wrap_in_unawaited.main();
}, name: 'fix');
}

View file

@ -0,0 +1,167 @@
// Copyright (c) 2022, 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:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(WrapInUnawaitedTest);
defineReflectiveTests(WrapDiscardedFutureInUnawaitedTest);
});
}
@reflectiveTest
class WrapDiscardedFutureInUnawaitedTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.WRAP_IN_UNAWAITED;
@override
String get lintCode => LintNames.discarded_futures;
Future<void> test_expressionStatement() async {
await resolveTestCode('''
void f() {
g();
}
Future<void> g() async { }
''');
await assertHasFix('''
import 'dart:async';
void f() {
unawaited(g());
}
Future<void> g() async { }
''');
}
}
@reflectiveTest
class WrapInUnawaitedTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.WRAP_IN_UNAWAITED;
@override
String get lintCode => LintNames.unawaited_futures;
Future<void> test_expressionStatement() async {
await resolveTestCode('''
Future<void> f() async {
g();
}
Future<void> g() async { }
''');
await assertHasFix('''
import 'dart:async';
Future<void> f() async {
unawaited(g());
}
Future<void> g() async { }
''');
}
Future<void> test_expressionStatement_prefixed() async {
newFile('$testPackageLibPath/g.dart', '''
Future<void> g() async { }
''');
await resolveTestCode('''
import 'g.dart' as g_lib;
Future<void> f() async {
g_lib.g();
}
''');
await assertHasFix('''
import 'dart:async';
import 'g.dart' as g_lib;
Future<void> f() async {
unawaited(g_lib.g());
}
''');
}
Future<void> test_expressionStatement_prefixedImport() async {
await resolveTestCode('''
import 'dart:async' as dart_async;
dart_async.Future<void> f() async {
g();
}
dart_async.Future<void> g() async { }
''');
await assertHasFix('''
import 'dart:async' as dart_async;
dart_async.Future<void> f() async {
dart_async.unawaited(g());
}
dart_async.Future<void> g() async { }
''');
}
Future<void> test_expressionStatement_prefixedTarget() async {
newFile('$testPackageLibPath/g.dart', '''
class C {
static Future<void> g() async { }
}
''');
await resolveTestCode('''
import 'g.dart' as g_lib;
Future<void> f() async {
g_lib.C.g();
}
''');
await assertHasFix('''
import 'dart:async';
import 'g.dart' as g_lib;
Future<void> f() async {
unawaited(g_lib.C.g());
}
''');
}
Future<void> test_expressionStatement_target() async {
await resolveTestCode('''
class C {
Future<void> g() async { }
}
Future<void> f() async {
var c = C();
c.g();
}
''');
await assertHasFix('''
import 'dart:async';
class C {
Future<void> g() async { }
}
Future<void> f() async {
var c = C();
unawaited(c.g());
}
''');
}
}