[analyzer] UNNECESSARY_SET_LITERAL to handle multiple expressions

Bug: https://github.com/dart-lang/sdk/issues/50900
Change-Id: Id09e102c2cc12c9043d3f6c22b3af3babf18920e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284021
Reviewed-by: Nate Biggs <natebiggs@google.com>
Reviewed-by: Oleh Prypin <oprypin@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Oleh Prypin <oprypin@google.com>
This commit is contained in:
Ahmed Ashour 2023-12-11 21:24:59 +00:00 committed by Commit Queue
parent 33ad2086c1
commit d9962e5053
12 changed files with 446 additions and 120 deletions

View file

@ -101,7 +101,7 @@ class AssistProcessor extends BaseProcessor {
ConvertDocumentationIntoLine.new,
ConvertIfStatementToSwitchStatement.new,
ConvertIntoAsyncBody.new,
ConvertIntoBlockBody.new,
ConvertIntoBlockBody.missingBody,
ConvertIntoFinalField.new,
ConvertIntoForIndex.new,
ConvertIntoGetter.new,

View file

@ -2,6 +2,7 @@
// 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:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analyzer/dart/ast/ast.dart';
@ -16,14 +17,47 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
import '../fix.dart';
class ConvertIntoBlockBody extends ResolvedCorrectionProducer {
/// The kind of correction to be made.
final _CorrectionKind _correctionKind;
@override
bool canBeAppliedInBulk;
@override
bool canBeAppliedToFile;
/// Initialize a newly created instance that adds a function body.
ConvertIntoBlockBody.missingBody()
: _correctionKind = _CorrectionKind.missingBody,
canBeAppliedInBulk = false,
canBeAppliedToFile = false;
/// Initialize a newly created instance that converts the set literal to
/// a function body.
ConvertIntoBlockBody.setLiteral()
: _correctionKind = _CorrectionKind.setLiteral,
canBeAppliedInBulk = true,
canBeAppliedToFile = true;
@override
AssistKind get assistKind => DartAssistKind.CONVERT_INTO_BLOCK_BODY;
@override
FixKind get fixKind => DartFixKind.CONVERT_INTO_BLOCK_BODY;
@override
FixKind get multiFixKind => DartFixKind.CONVERT_INTO_BLOCK_BODY_MULTI;
@override
Future<void> compute(ChangeBuilder builder) async {
if (_correctionKind == _CorrectionKind.missingBody) {
await _computeMissingBody(builder);
} else {
await _computeSetLiteral(builder);
}
}
Future<void> _computeMissingBody(ChangeBuilder builder) async {
final body = getEnclosingFunctionBody();
if (body == null || body.isGenerator) return;
@ -58,6 +92,57 @@ class ConvertIntoBlockBody extends ResolvedCorrectionProducer {
});
}
Future<void> _computeSetLiteral(ChangeBuilder builder) async {
var node = this.node;
if (node is! SetOrMapLiteral || !node.isSet) return;
var parent = node.parent;
if (parent is! ExpressionFunctionBody) return;
var functionDefinition = parent.functionDefinition;
var elements = node.elements;
await builder.addDartFileEdit(file, (builder) {
var next = functionDefinition.next!;
builder.addDeletion(
range.startStart(functionDefinition, next.precedingComments ?? next));
for (var element in elements) {
bool isCommaAdded;
if (element is IfElement) {
builder.addSimpleInsertion(element.thenElement.end, ';');
var elseElement = element.elseElement;
if (elseElement != null) {
builder.addSimpleInsertion(elseElement.end, ';');
}
isCommaAdded = true;
} else if (element is ForElement) {
builder.addSimpleInsertion(element.body.end, ';');
isCommaAdded = true;
} else {
isCommaAdded = false;
}
var endToken = element.endToken;
var next = endToken.next;
if (next?.type == TokenType.COMMA) {
builder.addSimpleReplacement(
range.token(next!), isCommaAdded ? '' : ';');
} else if (!isCommaAdded) {
builder.addSimpleInsertion(endToken.end, ';');
}
}
var semiColon = parent.semicolon;
if (semiColon != null) {
var precedingComments = semiColon.precedingComments;
var next = precedingComments?.next;
while (next is CommentToken) {
precedingComments = next;
next = next.next;
}
builder.addDeletion(
range.endEnd(precedingComments ?? semiColon.previous!, semiColon));
}
});
}
List<String>? _getCodeForEmptyBody(EmptyFunctionBody body) {
var functionElement = _getFunctionElement(body.parent);
if (functionElement == null) return null;
@ -106,3 +191,9 @@ class ConvertIntoBlockBody extends ResolvedCorrectionProducer {
return null;
}
}
/// The kinds of corrections supported by [ConvertIntoBlockBody].
enum _CorrectionKind {
missingBody,
setLiteral,
}

View file

@ -1,65 +0,0 @@
// Copyright (c) 2023, 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/dart/ast/token.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 RemoveSetLiteral extends ResolvedCorrectionProducer {
@override
bool get canBeAppliedInBulk => true;
@override
bool get canBeAppliedToFile => true;
@override
FixKind get fixKind => DartFixKind.REMOVE_SET_LITERAL;
@override
FixKind get multiFixKind => DartFixKind.REMOVE_SET_LITERAL_MULTI;
@override
Future<void> compute(ChangeBuilder builder) async {
var node = this.node;
if (node is! SetOrMapLiteral) return;
var leftToken = node.leftBracket;
var rightBracket = node.rightBracket;
var rightStart = rightBracket.offset;
var rightEnd = rightBracket.next!.offset;
var elements = node.elements;
if (elements.isEmpty) return;
var first = elements.first;
var parent = node.parent?.parent?.parent;
if (parent is FunctionDeclaration) {
var nextToElement = first.endToken.next!;
if (nextToElement.type == TokenType.COMMA) {
rightStart = first.end;
}
} else {
var nextToElement = first.endToken.next!;
var nextToBracket = rightBracket.next!;
if (nextToElement.type == TokenType.COMMA) {
rightStart = nextToElement.end;
rightEnd = nextToBracket.offset;
if (nextToBracket.type == TokenType.COMMA) {
rightEnd = nextToBracket.next!.offset;
}
} else if (nextToBracket.type == TokenType.COMMA) {
rightStart = first.end;
rightEnd = nextToBracket.offset;
}
}
await builder.addDartFileEdit(file, (builder) {
builder.addDeletion(range.startStart(leftToken, leftToken.next!));
builder.addDeletion(range.startOffsetEndOffset(rightStart, rightEnd));
});
}
}

View file

@ -402,6 +402,11 @@ class DartFixKind {
DartFixKindPriority.DEFAULT,
'Convert to block body',
);
static const CONVERT_INTO_BLOCK_BODY_MULTI = FixKind(
'dart.fix.convert.bodyToBlock.multi',
DartFixKindPriority.IN_FILE,
'Convert to block body everywhere in file',
);
static const CONVERT_FOR_EACH_TO_FOR_LOOP = FixKind(
'dart.fix.convert.toForLoop',
DartFixKindPriority.DEFAULT,
@ -1278,16 +1283,6 @@ class DartFixKind {
DartFixKindPriority.IN_FILE,
'Remove invalid returned values in file',
);
static const REMOVE_SET_LITERAL = FixKind(
'dart.fix.remove.setLiteral',
DartFixKindPriority.DEFAULT,
'Remove set literal',
);
static const REMOVE_SET_LITERAL_MULTI = FixKind(
'dart.fix.remove.setLiteral.multi',
DartFixKindPriority.IN_FILE,
'Remove set literal everywhere in file',
);
static const REMOVE_THIS_EXPRESSION = FixKind(
'dart.fix.remove.thisExpression',
DartFixKindPriority.DEFAULT,

View file

@ -157,7 +157,6 @@ import 'package:analysis_server/src/services/correction/dart/remove_print.dart';
import 'package:analysis_server/src/services/correction/dart/remove_question_mark.dart';
import 'package:analysis_server/src/services/correction/dart/remove_required.dart';
import 'package:analysis_server/src/services/correction/dart/remove_returned_value.dart';
import 'package:analysis_server/src/services/correction/dart/remove_set_literal.dart';
import 'package:analysis_server/src/services/correction/dart/remove_this_expression.dart';
import 'package:analysis_server/src/services/correction/dart/remove_to_list.dart';
import 'package:analysis_server/src/services/correction/dart/remove_type_annotation.dart';
@ -1048,7 +1047,7 @@ class FixProcessor extends BaseProcessor {
CreateMixin.new,
],
CompileTimeErrorCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER: [
ConvertIntoBlockBody.new,
ConvertIntoBlockBody.missingBody,
CreateNoSuchMethod.new,
MakeClassAbstract.new,
],
@ -1078,7 +1077,7 @@ class FixProcessor extends BaseProcessor {
ReplaceEmptyMapPattern.empty,
],
CompileTimeErrorCode.ENUM_WITH_ABSTRACT_MEMBER: [
ConvertIntoBlockBody.new,
ConvertIntoBlockBody.missingBody,
],
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS: [
RemoveNameFromDeclarationClause.new,
@ -1494,7 +1493,7 @@ class FixProcessor extends BaseProcessor {
AddTypeAnnotation.new,
],
ParserErrorCode.MISSING_FUNCTION_BODY: [
ConvertIntoBlockBody.new,
ConvertIntoBlockBody.missingBody,
],
ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR: [
RemoveConstructor.new,
@ -1695,7 +1694,7 @@ class FixProcessor extends BaseProcessor {
RemoveQuestionMark.new,
],
WarningCode.UNNECESSARY_SET_LITERAL: [
RemoveSetLiteral.new,
ConvertIntoBlockBody.setLiteral,
],
WarningCode.UNNECESSARY_TYPE_CHECK_FALSE: [
RemoveComparison.typeCheck,

View file

@ -295,7 +295,8 @@ void f(List<int> list) {
list.forEach((x) => {print(''), print('')});
}
''');
await assertNoFix();
await assertNoFix(
errorFilter: (error) => error.errorCode.type == ErrorType.LINT);
}
Future<void> test_setLiteral_statement() async {
@ -304,7 +305,8 @@ void f(List<int> list, bool b) {
list.forEach((x) => {if (b) print('')});
}
''');
await assertNoFix();
await assertNoFix(
errorFilter: (error) => error.errorCode.type == ErrorType.LINT);
}
Future<void> test_setLiteral_typeArguments() async {

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -10,12 +11,15 @@ import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ConvertIntoBlockBodyTest);
defineReflectiveTests(ConvertIntoBlockBodyMissingBodyTest);
defineReflectiveTests(ConvertIntoBlockBodySetLiteralBulkTest);
defineReflectiveTests(ConvertIntoBlockBodySetLiteralTest);
defineReflectiveTests(ConvertIntoBlockBodySetLiteralMultiTest);
});
}
@reflectiveTest
class ConvertIntoBlockBodyTest extends FixProcessorTest {
class ConvertIntoBlockBodyMissingBodyTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.CONVERT_INTO_BLOCK_BODY;
@ -129,3 +133,218 @@ class A {
''');
}
}
@reflectiveTest
class ConvertIntoBlockBodySetLiteralBulkTest extends BulkFixProcessorTest {
Future<void> test_file() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => {
g(() => {
1
})
});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() {
g(() {
1;
});
});
}
''');
}
}
@reflectiveTest
class ConvertIntoBlockBodySetLiteralMultiTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.CONVERT_INTO_BLOCK_BODY_MULTI;
Future<void> test_multi() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => {
g(() => {
1
})
});
}
''');
await assertHasFixAllFix(WarningCode.UNNECESSARY_SET_LITERAL, '''
void g(void Function() fun) {}
void f() {
g(() {
g(() {
1;
});
});
}
''');
}
}
@reflectiveTest
class ConvertIntoBlockBodySetLiteralTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.CONVERT_INTO_BLOCK_BODY;
Future<void> test_expressionFunctionBody() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => {1});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() {1;});
}
''');
}
Future<void> test_expressionFunctionBody_comma_both() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => {1,},);
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() {1;},);
}
''');
}
Future<void> test_expressionFunctionBody_comma_both_spaces() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => { 1 , } , );
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() { 1 ; } , );
}
''');
}
Future<void> test_expressionFunctionBody_comma_inside() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => {1,});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() {1;});
}
''');
}
Future<void> test_expressionFunctionBody_comma_outside() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => {1},);
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() {1;},);
}
''');
}
Future<void> test_expressionFunctionBody_comment() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => /* hi */ {1});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() /* hi */ {1;});
}
''');
}
Future<void> test_expressionFunctionBody_multiple() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f(bool b) {
g(() => {1, if (b) 2, if (b) 3 else 4, for(;;) 5});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f(bool b) {
g(() {1; if (b) 2; if (b) 3; else 4; for(;;) 5;});
}
''');
}
Future<void> test_functionDeclaration() async {
await resolveTestCode('''
void f() => {1};
''');
await assertHasFix('''
void f() {1;}
''');
}
Future<void> test_functionDeclaration_comma() async {
await resolveTestCode('''
void f() => {1,};
''');
await assertHasFix('''
void f() {1;}
''');
}
Future<void> test_functionDeclaration_comma_spaces() async {
await resolveTestCode('''
void f() => { 1 , } ;
''');
await assertHasFix('''
void f() { 1 ; }
''');
}
Future<void> test_functionDeclaration_comments() async {
await resolveTestCode('''
void f() => /* first */ {1} /* second */ /* third */ ;
''');
await assertHasFix('''
void f() /* first */ {1;} /* second */ /* third */
''');
}
Future<void> test_functionDeclaration_multiple() async {
await resolveTestCode('''
void f(bool b) => {for (;b;) 1, if (b) 2 else 3, if (b) 4,};
''');
await assertHasFix('''
void f(bool b) {for (;b;) 1; if (b) 2; else 3; if (b) 4;}
''');
}
}

View file

@ -11,14 +11,14 @@ import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(RemoveSetLiteralBulkTest);
defineReflectiveTests(RemoveSetLiteralMultiTest);
defineReflectiveTests(RemoveSetLiteralTest);
defineReflectiveTests(ConvertToBlockFunctionBodyBulkTest);
defineReflectiveTests(ConvertToBlockFunctionBodyMultiTest);
defineReflectiveTests(ConvertToBlockFunctionBodyTest);
});
}
@reflectiveTest
class RemoveSetLiteralBulkTest extends BulkFixProcessorTest {
class ConvertToBlockFunctionBodyBulkTest extends BulkFixProcessorTest {
Future<void> test_file() async {
await resolveTestCode('''
void g(void Function() fun) {}
@ -31,16 +31,16 @@ void f() {
void g(void Function() fun) {}
void f() {
g(() => g(() => 1));
g(() {g(() {1;});});
}
''');
}
}
@reflectiveTest
class RemoveSetLiteralMultiTest extends FixProcessorTest {
class ConvertToBlockFunctionBodyMultiTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.REMOVE_SET_LITERAL_MULTI;
FixKind get kind => DartFixKind.CONVERT_INTO_BLOCK_BODY_MULTI;
Future<void> test_multi() async {
await resolveTestCode('''
@ -54,16 +54,16 @@ void f() {
void g(void Function() fun) {}
void f() {
g(() => g(() => 1));
g(() {g(() {1;});});
}
''');
}
}
@reflectiveTest
class RemoveSetLiteralTest extends FixProcessorTest {
class ConvertToBlockFunctionBodyTest extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.REMOVE_SET_LITERAL;
FixKind get kind => DartFixKind.CONVERT_INTO_BLOCK_BODY;
Future<void> test_expressionFunctionBody() async {
await resolveTestCode('''
@ -75,7 +75,7 @@ void f() {
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() => 1);
g(() {1;});
}
''');
}
@ -90,7 +90,7 @@ void f() {
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() => 1,);
g(() {1;},);
}
''');
}
@ -105,7 +105,7 @@ void f() {
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() => 1 ,);
g(() { 1 ; } , );
}
''');
}
@ -120,7 +120,7 @@ void f() {
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() => 1,);
g(() {1;});
}
''');
}
@ -135,7 +135,37 @@ void f() {
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() => 1,);
g(() {1;},);
}
''');
}
Future<void> test_expressionFunctionBody_comment() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f() {
g(() => /* hi */ {1});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f() {
g(() /* hi */ {1;});
}
''');
}
Future<void> test_expressionFunctionBody_multiple() async {
await resolveTestCode('''
void g(void Function() fun) {}
void f(bool b) {
g(() => {1, if (b) 2, if (b) 3 else 4, for(;;) 5});
}
''');
await assertHasFix('''
void g(void Function() fun) {}
void f(bool b) {
g(() {1; if (b) 2; if (b) 3; else 4; for(;;) 5;});
}
''');
}
@ -145,7 +175,7 @@ void f() {
void f() => {1};
''');
await assertHasFix('''
void f() => 1;
void f() {1;}
''');
}
@ -154,7 +184,7 @@ void f() => 1;
void f() => {1,};
''');
await assertHasFix('''
void f() => 1;
void f() {1;}
''');
}
@ -163,7 +193,25 @@ void f() => 1;
void f() => { 1 , } ;
''');
await assertHasFix('''
void f() => 1;
void f() { 1 ; }
''');
}
Future<void> test_functionDeclaration_comments() async {
await resolveTestCode('''
void f() => /* first */ {1} /* second */ /* third */ ;
''');
await assertHasFix('''
void f() /* first */ {1;} /* second */ /* third */
''');
}
Future<void> test_functionDeclaration_multiple() async {
await resolveTestCode('''
void f(bool b) => {for (;b;) 1, if (b) 2 else 3, if (b) 4,};
''');
await assertHasFix('''
void f(bool b) {for (;b;) 1; if (b) 2; else 3; if (b) 4;}
''');
}
}

View file

@ -66,6 +66,8 @@ import 'convert_into_block_body_test.dart' as convert_into_block_body;
import 'convert_into_expression_body_test.dart' as convert_into_expression_body;
import 'convert_into_is_not_test.dart' as convert_into_is_not;
import 'convert_quotes_test.dart' as convert_quotes;
import 'convert_to_block_function_body_test.dart'
as convert_to_block_function_body;
import 'convert_to_boolean_expression_test.dart'
as convert_to_boolean_expression;
import 'convert_to_cascade_test.dart' as convert_to_cascade;
@ -193,7 +195,6 @@ import 'remove_print_test.dart' as remove_print;
import 'remove_question_mark_test.dart' as remove_question_mark;
import 'remove_required_test.dart' as remove_required;
import 'remove_returned_value_test.dart' as remove_returned_value;
import 'remove_set_literal_test.dart' as remove_set_literal;
import 'remove_this_expression_test.dart' as remove_this_expression;
import 'remove_type_annotation_test.dart' as remove_type_annotation;
import 'remove_type_arguments_test.dart' as remove_type_arguments;
@ -336,6 +337,7 @@ void main() {
convert_into_expression_body.main();
convert_into_is_not.main();
convert_quotes.main();
convert_to_block_function_body.main();
convert_to_boolean_expression.main();
convert_to_cascade.main();
convert_to_constant_pattern.main();
@ -446,7 +448,6 @@ void main() {
remove_question_mark.main();
remove_required.main();
remove_returned_value.main();
remove_set_literal.main();
remove_this_expression.main();
remove_type_annotation.main();
remove_type_arguments.main();

View file

@ -1383,11 +1383,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
if (isReturnVoid) {
var expression = body.expression;
if (expression is SetOrMapLiteralImpl && expression.isSet) {
var elements = expression.elements;
if (elements.length == 1 && elements.first is Expression) {
_errorReporter.reportErrorForNode(
WarningCode.UNNECESSARY_SET_LITERAL, expression);
}
_errorReporter.reportErrorForNode(
WarningCode.UNNECESSARY_SET_LITERAL, expression);
}
}
}

View file

@ -116,13 +116,27 @@ void f() {
}
test_expressionFunctionBody_multipleElements() async {
await assertNoErrorsInCode(r'''
await assertErrorsInCode(r'''
void g(void Function() fun) {}
void f() {
g(() => {1, 2});
}
''');
''', [
error(WarningCode.UNNECESSARY_SET_LITERAL, 53, 6),
]);
}
test_expressionFunctionBody_multipleElements_statements() async {
await assertErrorsInCode(r'''
void g(void Function() fun) {}
void f(bool b) {
g(() => {1, if (b) 2 else 3, 4, for (;;) 5},);
}
''', [
error(WarningCode.UNNECESSARY_SET_LITERAL, 59, 35),
]);
}
test_expressionFunctionBody_object() async {
@ -136,13 +150,15 @@ void f() {
}
test_expressionFunctionBody_statement() async {
await assertNoErrorsInCode(r'''
await assertErrorsInCode(r'''
void g(void Function(bool) fun) {}
void f() {
g((value) => {if (value) print('')});
}
''');
''', [
error(WarningCode.UNNECESSARY_SET_LITERAL, 62, 22),
]);
}
test_expressionFunctionBody_void() async {
@ -157,6 +173,16 @@ void f() {
]);
}
test_expressionFunctionBody_void_empty() async {
await assertNoErrorsInCode(r'''
void g(void Function() fun) {}
void f() {
g(() => {});
}
''');
}
test_functionDeclaration_dynamic() async {
await assertNoErrorsInCode(r'''
f() => {1};
@ -216,9 +242,19 @@ void f() => {1: 2};
}
test_functionDeclaration_multipleElements() async {
await assertNoErrorsInCode(r'''
await assertErrorsInCode(r'''
void f() => {1, 2};
''');
''', [
error(WarningCode.UNNECESSARY_SET_LITERAL, 12, 6),
]);
}
test_functionDeclaration_multipleElements_statements() async {
await assertErrorsInCode(r'''
void f(bool b) => {1, if (b) 2 else 3, 4, for (;;) 5};
''', [
error(WarningCode.UNNECESSARY_SET_LITERAL, 18, 35),
]);
}
test_functionDeclaration_object() async {
@ -228,9 +264,11 @@ Object f() => {1};
}
test_functionDeclaration_statement() async {
await assertNoErrorsInCode(r'''
await assertErrorsInCode(r'''
void f(bool value) => {if (value) print('')};
''');
''', [
error(WarningCode.UNNECESSARY_SET_LITERAL, 22, 22),
]);
}
test_functionDeclaration_void() async {

View file

@ -143,8 +143,9 @@ class MetricsVisitor extends RecursiveVisitor {
var parentMethods = classInfo[parentName]!.methods.map((m) => m.name);
var classMethods = classInfo[className]!.methods.map((m) => m.name);
parentMethods.forEach((method) =>
{if (!classMethods.contains(method)) notOverridden.add(method)});
parentMethods.forEach((method) {
if (!classMethods.contains(method)) notOverridden.add(method);
});
// Update Method Info.
classInfo[className]!.notOverriddenMethods = notOverridden;