Version 2.16.0-130.0.dev
Merge commit '2fb63da09ff48bcd912a680a0b4c4416a0f3e207' into 'dev'
diff --git a/DEPS b/DEPS
index 727fe76..b98102b 100644
--- a/DEPS
+++ b/DEPS
@@ -107,7 +107,7 @@
# For more details, see https://github.com/dart-lang/sdk/issues/30164
"dart_style_rev": "08b0294d0a500d5c02168ef57dcb8868d0c3cb48",
- "dartdoc_rev" : "ff0d94bdb87f11c04a7e0ddab811bf94211b08a4",
+ "dartdoc_rev" : "11c4b3c9723bfa7155efcf0fef02329233a6381d",
"devtools_rev" : "85932bb66aa782c4b2c528be7718960bf256ffb7",
"jsshell_tag": "version:88.0",
"ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_return_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_return_null.dart
new file mode 100644
index 0000000..8b37810
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_return_null.dart
@@ -0,0 +1,76 @@
+// 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: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';
+
+class AddReturnNull extends CorrectionProducer {
+ @override
+ bool get canBeAppliedInBulk => true;
+
+ @override
+ bool get canBeAppliedToFile => true;
+
+ @override
+ FixKind get fixKind => DartFixKind.ADD_RETURN_NULL;
+
+ @override
+ FixKind? get multiFixKind => DartFixKind.ADD_RETURN_NULL_MULTI;
+
+ @override
+ Future<void> compute(ChangeBuilder builder) async {
+ Block block;
+
+ var coveringNode = coveredNode;
+ if (coveringNode is Block) {
+ block = coveringNode;
+ } else if (coveringNode is SimpleIdentifier) {
+ var declaration = coveringNode.parent;
+ if (declaration is FunctionDeclaration) {
+ var body = declaration.functionExpression.body;
+ if (body is BlockFunctionBody) {
+ block = body.block;
+ } else {
+ return;
+ }
+ } else if (declaration is MethodDeclaration) {
+ var body = declaration.body;
+ if (body is BlockFunctionBody) {
+ block = body.block;
+ } else {
+ return;
+ }
+ } else {
+ return;
+ }
+ } else {
+ return;
+ }
+ int position;
+ String returnStatement;
+ if (block.statements.isEmpty) {
+ position = block.offset + 1;
+ var prefix = utils.getLinePrefix(block.offset);
+ returnStatement =
+ '$eol$prefix${utils.getIndent(1)}return null;$eol$prefix';
+ } else {
+ var lastStatement = block.statements.last;
+ position = lastStatement.offset + lastStatement.length;
+ var prefix = utils.getNodePrefix(lastStatement);
+ returnStatement = '$eol${prefix}return null;';
+ }
+
+ await builder.addDartFileEdit(file, (builder) {
+ builder.addInsertion(position, (builder) {
+ builder.write(returnStatement);
+ });
+ });
+ }
+
+ /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+ static AddReturnNull newInstance() => AddReturnNull();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index e802922..59471b3 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -213,6 +213,16 @@
DartFixKindPriority.IN_FILE,
"Add 'required' keywords everywhere in file",
);
+ static const ADD_RETURN_NULL = FixKind(
+ 'dart.fix.add.returnNull',
+ DartFixKindPriority.DEFAULT,
+ "Add 'return null'",
+ );
+ static const ADD_RETURN_NULL_MULTI = FixKind(
+ 'dart.fix.add.returnNull.multi',
+ DartFixKindPriority.IN_FILE,
+ "Add 'return null' everywhere in file",
+ );
static const ADD_RETURN_TYPE = FixKind(
'dart.fix.add.returnType',
DartFixKindPriority.DEFAULT,
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 6b3f145..128e4eb 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -25,6 +25,7 @@
import 'package:analysis_server/src/services/correction/dart/add_override.dart';
import 'package:analysis_server/src/services/correction/dart/add_required.dart';
import 'package:analysis_server/src/services/correction/dart/add_required_keyword.dart';
+import 'package:analysis_server/src/services/correction/dart/add_return_null.dart';
import 'package:analysis_server/src/services/correction/dart/add_return_type.dart';
import 'package:analysis_server/src/services/correction/dart/add_static.dart';
import 'package:analysis_server/src/services/correction/dart/add_super_constructor_invocation.dart';
@@ -1077,6 +1078,9 @@
MakeReturnTypeNullable.newInstance,
],
+ HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE: [
+ AddReturnNull.newInstance,
+ ],
HintCode.CAN_BE_NULL_AFTER_NULL_AWARE: [
ReplaceWithNullAware.inChain,
],
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_return_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_return_null_test.dart
new file mode 100644
index 0000000..f12fd37
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_return_null_test.dart
@@ -0,0 +1,125 @@
+// 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:analysis_server/src/services/correction/fix.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(AddReturnNullBulkTest);
+ defineReflectiveTests(AddReturnNullTest);
+ });
+}
+
+@reflectiveTest
+class AddReturnNullBulkTest extends BulkFixProcessorTest {
+ Future<void> test_singleFile() async {
+ await resolveTestCode('''
+int? f() {
+ // ignore: unused_element
+ int? g() {
+ if (1 == 2) return 5;
+ }
+ if (1 == 2) return 7;
+}
+''');
+ await assertHasFix('''
+int? f() {
+ // ignore: unused_element
+ int? g() {
+ if (1 == 2) return 5;
+ return null;
+ }
+ if (1 == 2) return 7;
+ return null;
+}
+''');
+ }
+}
+
+@reflectiveTest
+class AddReturnNullTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.ADD_RETURN_NULL;
+
+ Future<void> test_functionExpression() async {
+ await resolveTestCode('''
+int? Function() f = () {
+ if (1 == 2) return 7;
+};
+''');
+ await assertHasFix('''
+int? Function() f = () {
+ if (1 == 2) return 7;
+ return null;
+};
+''');
+ }
+
+ Future<void> test_functionExpression_empty() async {
+ await resolveTestCode('''
+int? Function() f = () {};
+''');
+ await assertHasFix('''
+int? Function() f = () {
+ return null;
+};
+''');
+ }
+
+ Future<void> test_localFunction() async {
+ await resolveTestCode('''
+void m() {
+ // ignore: unused_element
+ int? f() {
+ if (1 == 2) return 7;
+ }
+}
+''');
+ await assertHasFix('''
+void m() {
+ // ignore: unused_element
+ int? f() {
+ if (1 == 2) return 7;
+ return null;
+ }
+}
+''');
+ }
+
+ Future<void> test_method() async {
+ await resolveTestCode('''
+class A {
+ int? m() {
+ if (1 == 2) return 7;
+ }
+}
+''');
+ await assertHasFix('''
+class A {
+ int? m() {
+ if (1 == 2) return 7;
+ return null;
+ }
+}
+''');
+ }
+
+ Future<void> test_topLevelFunction_block() async {
+ await resolveTestCode('''
+int? f() {
+ if (1 == 2) return 7;
+}
+''');
+ await assertHasFix('''
+int? f() {
+ if (1 == 2) return 7;
+ return null;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 3753bfb..46e09ff 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -30,6 +30,7 @@
import 'add_null_check_test.dart' as add_null_check;
import 'add_override_test.dart' as add_override;
import 'add_required_test.dart' as add_required;
+import 'add_return_null_test.dart' as add_return_null;
import 'add_return_type_test.dart' as add_return_type;
import 'add_static_test.dart' as add_static;
import 'add_super_constructor_invocation_test.dart'
@@ -234,6 +235,7 @@
add_null_check.main();
add_override.main();
add_required.main();
+ add_return_null.main();
add_return_type.main();
add_static.main();
add_super_constructor_invocation.main();
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 105ec72..a6f4d42 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,5 +1,6 @@
## 3.1.0-dev
* New internal API for `package:dart_style`.
+* Removed deprecated non-API `MockSdk` class.
## 3.0.0
* Removed deprecated `DartType.aliasElement/aliasArguments`.
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 8a34bc8..25895fe 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -523,6 +523,7 @@
FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH,
HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE_TO_ERROR_HANDLER,
HintCode.ASSIGNMENT_OF_DO_NOT_STORE,
+ HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE,
HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
HintCode.DEAD_CODE,
HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index c24474a..8c78fc5 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -91,6 +91,19 @@
);
/**
+ * Parameters:
+ * 0: the name of the declared return type
+ */
+ static const HintCode BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE = HintCode(
+ 'BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE',
+ "This function has a nullable return type of '{0}', but ends without "
+ "returning a value.",
+ correctionMessage:
+ "Try adding a return statement, or if no value is ever returned, try "
+ "changing the return type to 'void'.",
+ );
+
+ /**
* When the target expression uses '?.' operator, it can be `null`, so all the
* subsequent invocations should also use '?.' operator.
*/
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
index be1eec6..2558708 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_resolver.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
import 'package:analyzer/src/generated/migration.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -64,9 +63,7 @@
_resolve2(node);
if (_resolver.flowAnalysis.flow != null && !isFunctionDeclaration) {
- var bodyContext = BodyInferenceContext.of(node.body);
_resolver.checkForBodyMayCompleteNormally(
- returnType: bodyContext?.contextType,
body: body,
errorNode: body,
);
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index b6c24eb..42f8ae1 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -1115,13 +1115,15 @@
// }
// ```
//
- // If the method intentionally returns `null` at the end, then change the
+ // If the method intentionally returns `null` at the end, then add an
+ // explicit return of `null` at the end of the method and change the
// return type so that it's valid to return `null`:
//
// ```dart
// class C<T> {
// T? m(T t) {
// print(t);
+ // return null;
// }
// }
// ```
@@ -1129,7 +1131,7 @@
CompileTimeErrorCode(
'BODY_MIGHT_COMPLETE_NORMALLY',
"The body might complete normally, causing 'null' to be returned, but the "
- "return type is a potentially non-nullable type.",
+ "return type, '{0}', is a potentially non-nullable type.",
correctionMessage:
"Try adding either a return or a throw statement at the end.",
hasPublishedDocs: true,
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 95f6e32..ddcbc07 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -472,7 +472,6 @@
}
void checkForBodyMayCompleteNormally({
- required DartType? returnType,
required FunctionBody body,
required AstNode errorNode,
}) {
@@ -481,6 +480,12 @@
return;
}
+ // TODO(scheglov) encapsulate
+ var bodyContext = BodyInferenceContext.of(body);
+ if (bodyContext == null) {
+ return null;
+ }
+ var returnType = bodyContext.contextType;
if (returnType == null) {
return;
}
@@ -490,24 +495,59 @@
return;
}
- if (typeSystem.isPotentiallyNonNullable(returnType)) {
- if (errorNode is ConstructorDeclaration) {
- errorReporter.reportErrorForName(
- CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY,
- errorNode,
- );
- } else if (errorNode is BlockFunctionBody) {
- errorReporter.reportErrorForToken(
- CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY,
- errorNode.block.leftBracket,
- );
- } else {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY,
- errorNode,
- );
+ if (body.isAsynchronous) {
+ // Check whether the return type is legal. If not, return rather than
+ // reporting a second error.
+
+ // This is the same check as [ReturnTypeVerifier._isLegalReturnType].
+ // TODO(srawlins): When this check is moved into the resolution stage,
+ // use the result of that check to determine whether this check should
+ // be done.
+ var lowerBound = typeProvider.futureElement.instantiate(
+ typeArguments: [NeverTypeImpl.instance],
+ nullabilitySuffix: NullabilitySuffix.star,
+ );
+ var imposedType = bodyContext.imposedType;
+ if (imposedType != null &&
+ !typeSystem.isSubtypeOf(lowerBound, imposedType)) {
+ // [imposedType] is an illegal return type for an asynchronous
+ // non-generator function; do not report an additional error here.
+ return;
}
}
+
+ ErrorCode errorCode;
+ if (typeSystem.isPotentiallyNonNullable(returnType)) {
+ errorCode = CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY;
+ } else {
+ var returnTypeBase = typeSystem.futureOrBase(returnType);
+ if (returnTypeBase.isVoid ||
+ returnTypeBase.isDynamic ||
+ returnTypeBase.isDartCoreNull) {
+ return;
+ } else {
+ errorCode = HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE;
+ }
+ }
+ if (errorNode is ConstructorDeclaration) {
+ errorReporter.reportErrorForName(
+ errorCode,
+ errorNode,
+ arguments: [returnType],
+ );
+ } else if (errorNode is BlockFunctionBody) {
+ errorReporter.reportErrorForToken(
+ errorCode,
+ errorNode.block.leftBracket,
+ [returnType],
+ );
+ } else {
+ errorReporter.reportErrorForNode(
+ errorCode,
+ errorNode,
+ [returnType],
+ );
+ }
}
}
@@ -1342,9 +1382,7 @@
}
if (node.factoryKeyword != null) {
- var bodyContext = BodyInferenceContext.of(node.body);
checkForBodyMayCompleteNormally(
- returnType: bodyContext?.contextType,
body: node.body,
errorNode: node,
);
@@ -1573,12 +1611,7 @@
}
if (!node.isSetter) {
- // TODO(scheglov) encapsulate
- var bodyContext = BodyInferenceContext.of(
- node.functionExpression.body,
- );
checkForBodyMayCompleteNormally(
- returnType: bodyContext?.contextType,
body: node.functionExpression.body,
errorNode: node.name,
);
@@ -1804,10 +1837,7 @@
}
if (!node.isSetter) {
- // TODO(scheglov) encapsulate
- var bodyContext = BodyInferenceContext.of(node.body);
checkForBodyMayCompleteNormally(
- returnType: bodyContext?.contextType,
body: node.body,
errorNode: node.name,
);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 44de859..4b84ce8 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -352,9 +352,6 @@
_enclosingContext.addParameter(null, element);
}
element.hasImplicitType = node.type == null && node.parameters == null;
- // TODO(scheglov) Do we need these two below?
- element.isExplicitlyCovariant = node.covariantKeyword != null;
- element.isFinal = node.isFinal;
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
@@ -823,9 +820,6 @@
_enclosingContext.addParameter(null, element);
}
element.hasImplicitType = node.type == null && node.parameters == null;
- // TODO(scheglov) Do we need these two below?
- // element.isExplicitlyCovariant = node.covariantKeyword != null;
- // element.isFinal = node.isFinal;
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 6589d31..4208e83 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -383,8 +383,6 @@
scope = TypeParameterScope(scope, element.typeParameters);
- // TODO(scheglov) More tests when the parse issue fixed.
- // https://github.com/dart-lang/sdk/issues/47951
node.type?.accept(this);
node.typeParameters?.accept(this);
node.parameters?.accept(this);
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index fc19a52..53b27e3 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -313,8 +313,6 @@
}
void _superFormalParameter(SuperFormalParameter node) {
- // TODO(scheglov) More tests when the parse issue fixed.
- // https://github.com/dart-lang/sdk/issues/47951
var element = node.declaredElement as SuperFormalParameterElementImpl;
var parameterList = node.parameters;
if (parameterList != null) {
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index d13df5d..44a6369 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -7,13 +7,9 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:meta/meta.dart';
-@Deprecated('Use createMockSdk() instead')
-const String sdkRoot = '/sdk';
-
final MockSdkLibrary _LIB_ASYNC = MockSdkLibrary('async', [
MockSdkLibraryUnit(
'async/async.dart',
@@ -1303,51 +1299,6 @@
);
}
-@Deprecated('Use createMockSdk() and FolderBasedDartSdk instead.')
-class MockSdk extends FolderBasedDartSdk {
- /// Optional [additionalLibraries] should have unique URIs, and paths in
- /// their units are relative (will be put into `sdkRoot/lib`).
- factory MockSdk({
- required MemoryResourceProvider resourceProvider,
- List<MockSdkLibrary> additionalLibraries = const [],
- }) {
- var sdkDirectory = resourceProvider.getFolder(
- resourceProvider.convertPath(sdkRoot),
- );
- createMockSdk(
- resourceProvider: resourceProvider,
- root: sdkDirectory,
- additionalLibraries: additionalLibraries,
- );
- return MockSdk._(resourceProvider, sdkDirectory);
- }
-
- /// Initialize a newly created SDK to represent the Dart SDK installed in the
- /// [sdkDirectory].
- MockSdk._(ResourceProvider resourceProvider, Folder sdkDirectory)
- : super(resourceProvider, sdkDirectory);
-
- @override
- MemoryResourceProvider get resourceProvider {
- return super.resourceProvider as MemoryResourceProvider;
- }
-
- @override
- List<SdkLibraryImpl> get sdkLibraries {
- return super.sdkLibraries.map((library) {
- var pathContext = resourceProvider.pathContext;
- var path = library.path;
- if (pathContext.isAbsolute(path)) {
- return library;
- }
- return SdkLibraryImpl(library.shortName)
- ..path = pathContext.join(directory.path, 'lib', path)
- ..category = library.category
- ..documented = library.isDocumented;
- }).toList();
- }
-}
-
class MockSdkLibrary implements SdkLibrary {
final String name;
final String categories;
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 675733f..b079038 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -1082,7 +1082,7 @@
immediately enclosing _a_ is not declared asynchronous. (Where _a_ is the
await expression.)
BODY_MIGHT_COMPLETE_NORMALLY:
- problemMessage: "The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type."
+ problemMessage: "The body might complete normally, causing 'null' to be returned, but the return type, '{0}', is a potentially non-nullable type."
correctionMessage: Try adding either a return or a throw statement at the end.
hasPublishedDocs: true
comment: No parameters.
@@ -1146,13 +1146,15 @@
}
```
- If the method intentionally returns `null` at the end, then change the
+ If the method intentionally returns `null` at the end, then add an
+ explicit return of `null` at the end of the method and change the
return type so that it's valid to return `null`:
```dart
class C<T> {
T? m(T t) {
print(t);
+ return null;
}
}
```
@@ -14069,6 +14071,13 @@
problemMessage: "'{0}' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable."
correctionMessage: Try removing the assignment.
comment: Users should not assign values marked `@doNotStore`.
+ BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE:
+ problemMessage: "This function has a nullable return type of '{0}', but ends without returning a value."
+ correctionMessage: "Try adding a return statement, or if no value is ever returned, try changing the return type to 'void'."
+ hasPublishedDocs: false
+ comment: |-
+ Parameters:
+ 0: the name of the declared return type
CAN_BE_NULL_AFTER_NULL_AWARE:
problemMessage: "The receiver uses '?.', so its value can be null."
correctionMessage: "Replace the '.' with a '?.' in the invocation."
diff --git a/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_nullable_test.dart b/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_nullable_test.dart
new file mode 100644
index 0000000..3925f45
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_nullable_test.dart
@@ -0,0 +1,74 @@
+// 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/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(BodyMightCompleteNormallyNullableTest);
+ });
+}
+
+@reflectiveTest
+class BodyMightCompleteNormallyNullableTest extends PubPackageResolutionTest {
+ test_function_async_block_futureOrIntQuestion() async {
+ await assertErrorsInCode('''
+import 'dart:async';
+FutureOr<int?> f(Future f) async {}
+''', [
+ error(HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE, 36, 1),
+ ]);
+ }
+
+ test_function_async_block_futureOrVoid() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+FutureOr<void> f(Future f) async {}
+''');
+ }
+
+ test_function_async_block_void() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+void f(Future f) async {}
+''');
+ }
+
+ test_function_sync_block_dynamic() async {
+ await assertNoErrorsInCode('''
+dynamic f() {}
+''');
+ }
+
+ test_function_sync_block_intQuestion() async {
+ await assertErrorsInCode('''
+int? f() {}
+''', [
+ error(HintCode.BODY_MIGHT_COMPLETE_NORMALLY_NULLABLE, 5, 1),
+ ]);
+ }
+
+ test_function_sync_block_intQuestion_definiteReturn() async {
+ await assertNoErrorsInCode('''
+int? f() {
+ return null;
+}
+''');
+ }
+
+ test_function_sync_block_Null() async {
+ await assertNoErrorsInCode('''
+Null f() {}
+''');
+ }
+
+ test_function_sync_block_void() async {
+ await assertNoErrorsInCode('''
+void f() {}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_test.dart b/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_test.dart
index e223720..973910e 100644
--- a/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/body_might_complete_normally_test.dart
@@ -222,16 +222,6 @@
''');
}
- test_functionExpression_nullable_blockBody() async {
- await assertNoErrorsInCode(r'''
-main() {
- int? Function() foo = () {
- };
- foo;
-}
-''');
- }
-
test_generativeConstructor_blockBody() async {
await assertNoErrorsInCode(r'''
class A {
@@ -350,14 +340,6 @@
''');
}
- test_method_nullable_blockBody() async {
- await assertNoErrorsInCode(r'''
-class A {
- int? foo() {}
-}
-''');
- }
-
test_method_nullable_blockBody_return() async {
await assertNoErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart b/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart
index 01e30f0..1d56d74 100644
--- a/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/illegal_async_return_type_test.dart
@@ -17,7 +17,9 @@
class IllegalAsyncReturnTypeTest extends PubPackageResolutionTest {
test_function_nonFuture() async {
await assertErrorsInCode('''
-int f() async {}
+int f() async {
+ return 1;
+}
''', [
error(CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, 0, 3),
]);
@@ -53,7 +55,9 @@
test_method_nonFuture() async {
await assertErrorsInCode('''
class C {
- int m() async {}
+ int m() async {
+ return 1;
+ }
}
''', [
error(CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, 12, 3),
diff --git a/pkg/analyzer/test/src/diagnostics/missing_return_test.dart b/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
index 7fbed0b..9f75275 100644
--- a/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/missing_return_test.dart
@@ -140,7 +140,7 @@
}
test_functionExpression_sync_dynamic() async {
- await assertNoErrorsInCode(r'''
+ await assertNoErrorsInCode('''
Function() f = () {};
''');
}
@@ -153,7 +153,7 @@
test_localFunction_sync_dynamic() async {
await assertNoErrorsInCode(r'''
-main() {
+void foo() {
f() {}
f;
}
@@ -217,7 +217,26 @@
@reflectiveTest
class MissingReturnWithNullSafetyTest extends PubPackageResolutionTest {
- test_returnNever() async {
+ test_function_async_block_futureOrVoid() async {
+ await assertNoErrorsInCode('''
+import 'dart:async';
+FutureOr<void> f() async {}
+''');
+ }
+
+ test_function_async_block_void() async {
+ await assertNoErrorsInCode('''
+void f() async {}
+''');
+ }
+
+ test_function_sync_block_dynamic() async {
+ await assertNoErrorsInCode('''
+dynamic f() {}
+''');
+ }
+
+ test_function_sync_block_Never() async {
newFile('$testPackageLibPath/a.dart', content: r'''
Never foo() {
throw 0;
@@ -232,4 +251,16 @@
}
''');
}
+
+ test_function_sync_block_Null() async {
+ await assertNoErrorsInCode('''
+Null f() {}
+''');
+ }
+
+ test_function_sync_block_void() async {
+ await assertNoErrorsInCode('''
+void f() {}
+''');
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 4456cef..485fb55 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -41,6 +41,8 @@
as await_in_late_local_variable_initializer;
import 'await_in_wrong_context_test.dart' as await_in_wrong_context;
import 'binary_operator_written_out_test.dart' as binary_operator_written_out;
+import 'body_might_complete_normally_nullable_test.dart'
+ as body_might_complete_normally_nullable;
import 'body_might_complete_normally_test.dart' as body_might_complete_normally;
import 'built_in_identifier_as_extension_name_test.dart'
as built_in_as_extension_name;
@@ -751,6 +753,7 @@
await_in_late_local_variable_initializer.main();
await_in_wrong_context.main();
binary_operator_written_out.main();
+ body_might_complete_normally_nullable.main();
body_might_complete_normally.main();
built_in_as_extension_name.main();
built_in_as_prefix_name.main();
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 197ed0d..6040d05 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -632,7 +632,7 @@
} else if (e.isOptionalPositional) {
buffer.write('optionalPositional ');
} else if (e.isRequiredNamed) {
- buffer.write('requiredName ');
+ buffer.write('requiredNamed ');
} else if (e.isOptionalNamed) {
buffer.write('optionalNamed ');
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 0176996..9b74e08 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1453,6 +1453,78 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/47951')
+ test_class_constructor_parameters_super_explicitType_function() async {
+ var library = await checkLibrary('''
+class A {
+ A(Object? a);
+}
+
+class B extends A {
+ B(int super.a<T extends num>(T d)?);
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredPositional a @22
+ type: Object?
+ class B @35
+ supertype: A
+ constructors
+ @51
+ parameters
+ requiredPositional final super.a @63
+ type: int Function<T extends num>(T)?
+ typeParameters
+ covariant T @65
+ bound: num
+ parameters
+ requiredPositional d @82
+ type: T
+ superConstructorParameter: a@22
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/47951')
+ test_class_constructor_parameters_super_explicitType_interface() async {
+ var library = await checkLibrary('''
+class A {
+ A(num a);
+}
+
+class B extends A {
+ B(int super.a);
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredPositional a @18
+ type: num
+ class B @31
+ supertype: A
+ constructors
+ @47
+ parameters
+ requiredPositional final super.a @49
+ type: int
+ superConstructorParameter: a@18
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
test_class_constructor_parameters_super_optionalNamed() async {
var library = await checkLibrary('''
class A {
@@ -1471,9 +1543,9 @@
constructors
@12
parameters
- requiredName a @28
+ requiredNamed a @28
type: int
- requiredName b @47
+ requiredNamed b @47
type: double
class B @61
supertype: A
@@ -1512,7 +1584,7 @@
constructors
@12
parameters
- requiredName a @28
+ requiredNamed a @28
type: int
class B @42
supertype: A
@@ -1590,23 +1662,23 @@
constructors
@12
parameters
- requiredName a @28
+ requiredNamed a @28
type: int
- requiredName b @47
+ requiredNamed b @47
type: double
class B @61
supertype: A
constructors
@77
parameters
- requiredName o1 @101
+ requiredNamed o1 @101
type: String
- requiredName final super.a @124
+ requiredNamed final super.a @124
type: int
superConstructorParameter: self::@class::A::@constructor::•::@parameter::a
- requiredName o2 @147
+ requiredNamed o2 @147
type: String
- requiredName final super.b @170
+ requiredNamed final super.b @170
type: double
superConstructorParameter: self::@class::A::@constructor::•::@parameter::b
superConstructor: self::@class::A::@constructor::•
@@ -27621,7 +27693,7 @@
functions
f @5
parameters
- requiredName f @22
+ requiredNamed f @22
type: void Function<U>(int)
typeParameters
covariant U @24
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 97d64c9..8f8c3aa 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -1323,7 +1323,7 @@
### body_might_complete_normally
_The body might complete normally, causing 'null' to be returned, but the return
-type is a potentially non-nullable type._
+type, '{0}', is a potentially non-nullable type._
#### Description
@@ -1384,13 +1384,15 @@
}
{% endprettify %}
-If the method intentionally returns `null` at the end, then change the
+If the method intentionally returns `null` at the end, then add an
+explicit return of `null` at the end of the method and change the
return type so that it's valid to return `null`:
{% prettify dart tag=pre+code %}
class C<T> {
T? m(T t) {
print(t);
+ return null;
}
}
{% endprettify %}
diff --git a/tools/VERSION b/tools/VERSION
index 8f2a41d..880412c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 129
+PRERELEASE 130
PRERELEASE_PATCH 0
\ No newline at end of file