Version 2.18.0-179.0.dev
Merge commit '57b192f3a63ac109cd7550071c52cec69e637aeb' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart
index 889c88c..b2b8745 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_await.dart
@@ -4,15 +4,31 @@
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/dart/element/type.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:collection/collection.dart';
class AddAwait extends CorrectionProducer {
- @override
- bool get canBeAppliedInBulk => true;
+ /// The kind of correction to be made.
+ final _CorrectionKind _correctionKind;
@override
- bool get canBeAppliedToFile => true;
+ bool canBeAppliedInBulk;
+
+ @override
+ bool canBeAppliedToFile;
+
+ AddAwait.nonBool()
+ : _correctionKind = _CorrectionKind.nonBool,
+ canBeAppliedInBulk = false,
+ canBeAppliedToFile = false;
+
+ AddAwait.unawaited()
+ : _correctionKind = _CorrectionKind.unawaited,
+ canBeAppliedInBulk = true,
+ canBeAppliedToFile = true;
@override
FixKind get fixKind => DartFixKind.ADD_AWAIT;
@@ -22,8 +38,34 @@
@override
Future<void> compute(ChangeBuilder builder) async {
+ if (_correctionKind == _CorrectionKind.unawaited) {
+ await _addAwait(builder);
+ } else if (_correctionKind == _CorrectionKind.nonBool) {
+ await _computeNonBool(builder);
+ }
+ }
+
+ Future<void> _addAwait(ChangeBuilder builder) async {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleInsertion(node.offset, 'await ');
});
}
+
+ Future<void> _computeNonBool(ChangeBuilder builder) async {
+ var expr = node;
+ if (expr is! Expression) return;
+ var staticType = expr.staticType;
+ if (staticType is! ParameterizedType) return;
+
+ if (staticType.isDartAsyncFuture &&
+ staticType.typeArguments.firstOrNull?.isDartCoreBool == true) {
+ await _addAwait(builder);
+ }
+ }
+}
+
+/// The kinds of corrections supported by [AddAwait].
+enum _CorrectionKind {
+ unawaited,
+ nonBool,
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_type_annotation.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_type_annotation.dart
index 0b1f3c6..853558be 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_type_annotation.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_type_annotation.dart
@@ -49,8 +49,8 @@
Future<void> _removeFromDeclarationList(
ChangeBuilder builder, VariableDeclarationList declarationList) async {
// we need a type
- var typeNode = declarationList.type;
- if (typeNode == null) {
+ var type = declarationList.type;
+ if (type == null) {
return;
}
// ignore if an incomplete variable declaration
@@ -63,19 +63,60 @@
if (selectionOffset > firstVariable.name.end) {
return;
}
+
+ var initializer = firstVariable.initializer;
// The variable must have an initializer, otherwise there is no other
// source for its type.
- if (firstVariable.initializer == null) {
+ if (initializer == null) {
+ return;
+ }
+
+ String? typeArgumentsText;
+ int? typeArgumentsOffset;
+ if (type is NamedType) {
+ var typeArguments = type.typeArguments;
+ if (typeArguments != null) {
+ if (initializer is CascadeExpression) {
+ initializer = initializer.target;
+ }
+ if (initializer is TypedLiteral) {
+ if (initializer.typeArguments == null) {
+ typeArgumentsText = utils.getNodeText(typeArguments);
+ if (initializer is ListLiteral) {
+ typeArgumentsOffset = initializer.leftBracket.offset;
+ } else if (initializer is SetOrMapLiteral) {
+ typeArgumentsOffset = initializer.leftBracket.offset;
+ } else {
+ throw StateError('Unhandled subclass of TypedLiteral');
+ }
+ }
+ } else if (initializer is InstanceCreationExpression) {
+ if (initializer.constructorName.type.typeArguments == null) {
+ typeArgumentsText = utils.getNodeText(typeArguments);
+ typeArgumentsOffset = initializer.constructorName.type.end;
+ }
+ }
+ }
+ }
+ if (initializer is SetOrMapLiteral &&
+ initializer.typeArguments == null &&
+ typeArgumentsText == null) {
+ // This is to prevent the fix from converting a valid map or set literal
+ // into an ambiguous literal. We could apply this in more places
+ // by examining the elements of the collection.
return;
}
var keyword = declarationList.keyword;
await builder.addDartFileEdit(file, (builder) {
- var typeRange = range.startStart(typeNode, firstVariable);
+ var typeRange = range.startStart(type, firstVariable);
if (keyword != null && keyword.lexeme != 'var') {
builder.addSimpleReplacement(typeRange, '');
} else {
builder.addSimpleReplacement(typeRange, 'var ');
}
+ if (typeArgumentsText != null && typeArgumentsOffset != null) {
+ builder.addSimpleInsertion(typeArgumentsOffset, typeArgumentsText);
+ }
});
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_var.dart b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_var.dart
index 49ddf35..3c5a55b 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_var.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_var.dart
@@ -64,6 +64,8 @@
typeArgumentsOffset = initializer.leftBracket.offset;
} else if (initializer is SetOrMapLiteral) {
typeArgumentsOffset = initializer.leftBracket.offset;
+ } else {
+ throw StateError('Unhandled subclass of TypedLiteral');
}
}
} else if (initializer is InstanceCreationExpression) {
@@ -77,9 +79,9 @@
if (initializer is SetOrMapLiteral &&
initializer.typeArguments == null &&
typeArgumentsText == null) {
- // TODO(brianwilkerson) This is to prevent the fix from converting a
- // valid map or set literal into an ambiguous literal. We could apply
- // this in more places by examining the elements of the collection.
+ // This is to prevent the fix from converting a valid map or set literal
+ // into an ambiguous literal. We could apply this in more places
+ // by examining the elements of the collection.
return;
}
await builder.addDartFileEdit(file, (builder) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index dfcb63a..02cf698 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -621,7 +621,7 @@
RemoveTypeAnnotation.new,
],
LintNames.unawaited_futures: [
- AddAwait.new,
+ AddAwait.unawaited,
],
LintNames.unnecessary_brace_in_string_interps: [
RemoveInterpolationBraces.new,
@@ -1010,6 +1010,7 @@
],
CompileTimeErrorCode.NON_BOOL_CONDITION: [
AddNeNull.new,
+ AddAwait.nonBool,
],
CompileTimeErrorCode.NON_CONST_GENERATIVE_ENUM_CONSTRUCTOR: [
AddConst.new,
diff --git a/pkg/analysis_server/test/src/services/correction/assist/remove_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/assist/remove_type_annotation_test.dart
index 99f4ab7..d5fdf25 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/remove_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/remove_type_annotation_test.dart
@@ -54,6 +54,45 @@
await assertNoAssistAt('v');
}
+ Future<void> test_generic_instanceCreation_withoutArguments() async {
+ await resolveTestCode('''
+C<int> c = C();
+class C<T> {}
+''');
+ await assertHasAssistAt('c = ', '''
+var c = C<int>();
+class C<T> {}
+''');
+ }
+
+ Future<void> test_generic_listLiteral() async {
+ await resolveTestCode('''
+List<int> l = [];
+''');
+ await assertHasAssistAt('l = ', '''
+var l = <int>[];
+''');
+ }
+
+ Future<void> test_generic_setLiteral_ambiguous() async {
+ await resolveTestCode('''
+Set f() {
+ /*caret*/Set s = {};
+ return s;
+}
+''');
+ await assertNoAssist();
+ }
+
+ Future<void> test_generic_setLiteral_cascade() async {
+ await resolveTestCode('''
+Set<String> s = {}..addAll([]);
+''');
+ await assertHasAssistAt('s = ', '''
+var s = <String>{}..addAll([]);
+''');
+ }
+
Future<void> test_instanceCreation_freeStanding() async {
await resolveTestCode('''
class A {}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
index d6c2893..cd15fc2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
@@ -67,4 +67,35 @@
}
''');
}
+
+ Future<void> test_nonBoolCondition_futureBool() async {
+ await resolveTestCode('''
+Future<bool> doSomething() async => true;
+
+Future<void> f() async {
+ if (doSomething()) {
+ }
+}
+''');
+ await assertHasFix('''
+Future<bool> doSomething() async => true;
+
+Future<void> f() async {
+ if (await doSomething()) {
+ }
+}
+''');
+ }
+
+ Future<void> test_nonBoolCondition_futureInt() async {
+ await resolveTestCode('''
+Future<int> doSomething() async => 0;
+
+Future<void> f() async {
+ if (doSomething()) {
+ }
+}
+''');
+ await assertNoFix();
+ }
}
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 11e023e..6d5ea0d 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/dart/element/type_system.dart';
+import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart' as file_system;
@@ -636,25 +637,31 @@
void reportLint(AstNode? node,
{List<Object> arguments = const [],
+ List<DiagnosticMessage>? contextMessages,
ErrorCode? errorCode,
bool ignoreSyntheticNodes = true}) {
if (node != null && (!node.isSynthetic || !ignoreSyntheticNodes)) {
- reporter.reportErrorForNode(errorCode ?? lintCode, node, arguments);
+ reporter.reportErrorForNode(
+ errorCode ?? lintCode, node, arguments, contextMessages);
}
}
void reportLintForOffset(int offset, int length,
- {List<Object> arguments = const [], ErrorCode? errorCode}) {
+ {List<Object> arguments = const [],
+ List<DiagnosticMessage>? contextMessages,
+ ErrorCode? errorCode}) {
reporter.reportErrorForOffset(
- errorCode ?? lintCode, offset, length, arguments);
+ errorCode ?? lintCode, offset, length, arguments, contextMessages);
}
void reportLintForToken(Token? token,
{List<Object> arguments = const [],
+ List<DiagnosticMessage>? contextMessages,
ErrorCode? errorCode,
bool ignoreSyntheticTokens = true}) {
if (token != null && (!token.isSynthetic || !ignoreSyntheticTokens)) {
- reporter.reportErrorForToken(errorCode ?? lintCode, token, arguments);
+ reporter.reportErrorForToken(
+ errorCode ?? lintCode, token, arguments, contextMessages);
}
}
diff --git a/tools/VERSION b/tools/VERSION
index abce37d..1ac7c56 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 178
+PRERELEASE 179
PRERELEASE_PATCH 0
\ No newline at end of file