Issue 43397. Fix isDefaultConstructor when view from a legacy library.
Bug: https://github.com/dart-lang/sdk/issues/43397
Change-Id: I1cd4ae4bea441732d1c6ef68a917fcccb144ec62
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/162584
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 9e26d98..a469a99 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1919,6 +1919,7 @@
/// A concrete implementation of a [ConstructorElement].
class ConstructorElementImpl extends ExecutableElementImpl
+ with ConstructorElementMixin
implements ConstructorElement {
/// The constructor to which this constructor is redirecting.
ConstructorElement _redirectedConstructor;
@@ -2008,23 +2009,6 @@
}
@override
- bool get isDefaultConstructor {
- // unnamed
- String name = this.name;
- if (name != null && name.isNotEmpty) {
- return false;
- }
- // no required parameters
- for (ParameterElement parameter in parameters) {
- if (parameter.isNotOptional) {
- return false;
- }
- }
- // OK, can be used as default constructor
- return true;
- }
-
- @override
bool get isFactory {
if (linkedNode != null) {
ConstructorDeclaration linkedNode = this.linkedNode;
@@ -2164,6 +2148,26 @@
}
}
+/// Common implementation for methods defined in [ConstructorElement].
+mixin ConstructorElementMixin implements ConstructorElement {
+ @override
+ bool get isDefaultConstructor {
+ // unnamed
+ var name = this.name;
+ if (name != null && name.isNotEmpty) {
+ return false;
+ }
+ // no required parameters
+ for (ParameterElement parameter in parameters) {
+ if (parameter.isNotOptional) {
+ return false;
+ }
+ }
+ // OK, can be used as default constructor
+ return true;
+ }
+}
+
/// A [TopLevelVariableElement] for a top-level 'const' variable that has an
/// initializer.
class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 29c863b..a37c9d4 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -19,7 +19,9 @@
/// A constructor element defined in a parameterized type where the values of
/// the type parameters are known.
-class ConstructorMember extends ExecutableMember implements ConstructorElement {
+class ConstructorMember extends ExecutableMember
+ with ConstructorElementMixin
+ implements ConstructorElement {
/// Initialize a newly created element to represent a constructor, based on
/// the [declaration], and applied [substitution].
ConstructorMember(
@@ -46,9 +48,6 @@
bool get isConstantEvaluated => declaration.isConstantEvaluated;
@override
- bool get isDefaultConstructor => declaration.isDefaultConstructor;
-
- @override
bool get isFactory => declaration.isFactory;
@override
@@ -787,25 +786,15 @@
@override
bool get isInitializingFormal => declaration.isInitializingFormal;
- @override
- bool get isOptionalNamed {
- if (isLegacy) {
- return super.isNamed;
- }
- return super.isOptionalNamed;
- }
-
- @override
- bool get isRequiredNamed {
- if (isLegacy) {
- return false;
- }
- return super.isRequiredNamed;
- }
-
@deprecated
@override
- ParameterKind get parameterKind => declaration.parameterKind;
+ ParameterKind get parameterKind {
+ var kind = declaration.parameterKind;
+ if (isLegacy && kind == ParameterKind.NAMED_REQUIRED) {
+ return ParameterKind.NAMED;
+ }
+ return kind;
+ }
@override
List<ParameterElement> get parameters {
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 75fcfb7..07891bc 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -3503,6 +3503,8 @@
// try to find default generative super constructor
ConstructorElement superUnnamedConstructor =
superElement.unnamedConstructor;
+ superUnnamedConstructor =
+ _currentLibrary.toLegacyElementIfOptOut(superUnnamedConstructor);
if (superUnnamedConstructor != null) {
if (superUnnamedConstructor.isFactory) {
_errorReporter.reportErrorForNode(
@@ -4309,6 +4311,8 @@
}
ConstructorElement superUnnamedConstructor =
superElement.unnamedConstructor;
+ superUnnamedConstructor =
+ _currentLibrary.toLegacyElementIfOptOut(superUnnamedConstructor);
if (superUnnamedConstructor != null) {
if (superUnnamedConstructor.isFactory) {
_errorReporter.reportErrorForNode(
diff --git a/pkg/analyzer/test/src/diagnostics/no_default_super_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/no_default_super_constructor_test.dart
index 4995806..3643e02 100644
--- a/pkg/analyzer/test/src/diagnostics/no_default_super_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/no_default_super_constructor_test.dart
@@ -10,11 +10,15 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(NoDefaultSuperConstructorTest);
+ defineReflectiveTests(NoDefaultSuperConstructorWithNullSafetyTest);
});
}
@reflectiveTest
-class NoDefaultSuperConstructorTest extends PubPackageResolutionTest {
+class NoDefaultSuperConstructorTest extends PubPackageResolutionTest
+ with NoDefaultSuperConstructorTestCases {}
+
+mixin NoDefaultSuperConstructorTestCases on PubPackageResolutionTest {
test_explicitDefaultSuperConstructor() async {
await assertNoErrorsInCode(r'''
class A {
@@ -81,3 +85,38 @@
]);
}
}
+
+@reflectiveTest
+class NoDefaultSuperConstructorWithNullSafetyTest
+ extends PubPackageResolutionTest
+ with NoDefaultSuperConstructorTestCases, WithNullSafetyMixin {
+ test_super_requiredParameter_legacySubclass_explicitConstructor() async {
+ newFile('$testPackageLibPath/a.dart', content: r'''
+class A {
+ A({required String s});
+}
+''');
+ await assertNoErrorsInCode(r'''
+// @dart=2.8
+import 'a.dart';
+
+class B extends A {
+ B();
+}
+''');
+ }
+
+ test_super_requiredParameter_legacySubclass_implicitConstructor() async {
+ newFile('$testPackageLibPath/a.dart', content: r'''
+class A {
+ A({required String s});
+}
+''');
+ await assertNoErrorsInCode(r'''
+// @dart=2.8
+import 'a.dart';
+
+class B extends A {}
+''');
+ }
+}