DeCo. Issue 63214. Add new tests for primary constructors and warnings.

Bug: https://github.com/dart-lang/sdk/issues/63214
Change-Id: I2054315eaddc87e0370f82ca8d2a1ebf140d4d18
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/497140
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Konstantin Shcheglov
2026-04-22 10:35:24 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent e1d540f0d2
commit 9d75d4db0d
5 changed files with 1369 additions and 419 deletions
@@ -584,17 +584,26 @@ class AnnotationVerifier {
reportInvalidAnnotation(fieldName);
}
}
} else if (parent.declaredFragment?.element case var declaredElement?) {
if (element.isVisibleForOverriding &&
(!declaredElement.isInstanceMember ||
declaredElement.enclosingElement is ExtensionTypeElement)) {
// This is reported by `_checkKinds`.
return;
} else {
Element? declaredElement;
if (parent is PrimaryConstructorBody) {
declaredElement = parent.declaration?.declaredFragment?.element;
} else {
declaredElement = parent.declaredFragment?.element;
}
var name = declaredElement.name;
if (name != null && Identifier.isPrivateName(name)) {
reportInvalidAnnotation(name);
if (declaredElement != null) {
if (element.isVisibleForOverriding &&
(!declaredElement.isInstanceMember ||
declaredElement.enclosingElement is ExtensionTypeElement)) {
// This is reported by `_checkKinds`.
return;
}
var name = declaredElement.name;
if (name != null && Identifier.isPrivateName(name)) {
reportInvalidAnnotation(name);
}
}
}
}
@@ -62,6 +62,29 @@ class C {
''');
}
test_primaryConstructor_private() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class C._() {
@visibleForTesting
this;
}
''',
[error(diag.invalidVisibilityAnnotation, 50, 17)],
);
}
test_primaryConstructor_public() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class C.named() {
@visibleForTesting
this;
}
''');
}
test_privateClass() async {
await assertErrorsInCode(
r'''
@@ -75,18 +98,6 @@ import 'package:meta/meta.dart';
);
}
test_privateConstructor() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class C {
@visibleForTesting C._() {}
}
''',
[error(diag.invalidVisibilityAnnotation, 46, 17)],
);
}
test_privateEnum() async {
await assertErrorsInCode(
r'''
@@ -193,6 +204,29 @@ import 'package:meta/meta.dart';
);
}
test_secondaryConstructor_private() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class C {
@visibleForTesting
C._() {}
}
''',
[error(diag.invalidVisibilityAnnotation, 46, 17)],
);
}
test_secondaryConstructor_public() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class C {
@visibleForTesting
C.named() {}
}
''');
}
test_topLevelVariable_multipleMixed() async {
await assertErrorsInCode(
r'''
@@ -21,78 +21,46 @@ class NonConstCallToLiteralConstructorTest extends PubPackageResolutionTest {
writeTestPackageConfigWithMeta();
}
test_constConstructor() async {
test_class_primaryConstructor_constContext() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
class const A() {
@literal
const A();
}
''');
}
test_constContextCreation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
this;
}
const a = A();
''');
}
test_constCreation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
}
const a = const A();
''');
}
test_constCreation_extensionType() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
extension type const E(int i) {
@literal
const E.zero(): this(0);
}
E e = const E.zero();
''');
}
test_dotShorthand_namedConstructor() async {
test_class_primaryConstructor_dotShorthand_unnamed() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class A {
class const A() {
@literal
const A.named();
}
A a = .named();
''',
[error(diag.nonConstCallToLiteralConstructor, 81, 8)],
);
}
test_dotShorthand_unnamedConstructor() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
this;
}
A a = .new();
''',
[error(diag.nonConstCallToLiteralConstructor, 75, 6)],
[error(diag.nonConstCallToLiteralConstructor, 78, 6)],
);
}
test_namedConstructor() async {
test_class_primaryConstructor_nonConstContext() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class const A() {
@literal
this;
}
var a = A();
''',
[error(diag.nonConstCallToLiteralConstructor, 80, 3)],
);
}
test_class_secondaryConstructor() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
@@ -106,7 +74,67 @@ var a = A.named();
);
}
test_nonConstContext() async {
test_class_secondaryConstructor_const() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
}
''');
}
test_class_secondaryConstructor_constContextCreation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
}
const a = A();
''');
}
test_class_secondaryConstructor_constCreation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
}
const a = const A();
''');
}
test_class_secondaryConstructor_dotShorthand() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class A {
@literal
const A.named();
}
A a = .named();
''',
[error(diag.nonConstCallToLiteralConstructor, 81, 8)],
);
}
test_class_secondaryConstructor_dotShorthand_unnamed() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
class A {
@literal
const A();
}
A a = .new();
''',
[error(diag.nonConstCallToLiteralConstructor, 75, 6)],
);
}
test_class_secondaryConstructor_nonConstContext() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
@@ -120,7 +148,7 @@ var a = A();
);
}
test_unconstableCreation() async {
test_class_secondaryConstructor_unconstableCreation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
class A {
@@ -131,7 +159,7 @@ var a = A(new List.filled(1, ''));
''');
}
test_usingNew() async {
test_class_secondaryConstructor_usingNew() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
@@ -145,17 +173,28 @@ var a = new A();
);
}
test_usingNew_extensionType() async {
test_extensionType_constCreation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
extension type const E(int i) {
@literal
const E.zero(): this(0);
}
E e = const E.zero();
''');
}
test_extensionType_usingNew() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
extension type const E(int i) {
extension type const E(int i) {
@literal
const E.zero(): this(0);
}
E e = E.zero();
''',
[error(diag.nonConstCallToLiteralConstructor, 112, 8)],
[error(diag.nonConstCallToLiteralConstructor, 111, 8)],
);
}
}
@@ -21,42 +21,7 @@ class TearoffWithMustBeConstParameterTest extends PubPackageResolutionTest {
writeTestPackageConfigWithMeta();
}
test_constructor_invocation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
var g = C.new(1);
class C {
// ignore: experimental_member_use
C(@mustBeConst int x);
}
''');
}
test_constructor_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = C.new;
class C {
// ignore: experimental_member_use
C(@mustBeConst int x);
}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 5)],
);
}
test_function_commentReference() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
/// Reference to [f].
var a = 1;
// ignore: experimental_member_use
void f(@mustBeConst int x) {}
''');
}
test_function_commentReference_threeNames() async {
test_class_method_commentReference_threeNames() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
import '' as self;
@@ -69,7 +34,7 @@ class C {
''');
}
test_function_commentReference_twoNames() async {
test_class_method_commentReference_twoNames() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
/// Reference to [C.f].
@@ -81,40 +46,7 @@ class C {
''');
}
test_function_invocation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
var g = f(1);
// ignore: experimental_member_use
void f(@mustBeConst int x) {}
''');
}
test_function_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = f;
// ignore: experimental_member_use
void f(@mustBeConst int x) {}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 1)],
);
}
test_genericFunction_instantiated_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = f<int>;
// ignore: experimental_member_use
void f<T>(@mustBeConst T x) {}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 1)],
);
}
test_method_implicitThis_tearoff() async {
test_class_method_implicitThis_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
@@ -128,7 +60,7 @@ class C {
);
}
test_method_invocation() async {
test_class_method_invocation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
var g = C().m(1);
@@ -139,7 +71,7 @@ class C {
''');
}
test_method_tearoff() async {
test_class_method_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
@@ -152,4 +84,119 @@ class C {
[error(diag.tearoffWithMustBeConstParameter, 45, 1)],
);
}
test_class_primaryConstructor_named_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = C.named;
// ignore: experimental_member_use
class C.named(@mustBeConst int x);
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 7)],
);
}
test_class_primaryConstructor_unnamed_invocation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
var g = C(1);
// ignore: experimental_member_use
class C(@mustBeConst int x);
''');
}
test_class_primaryConstructor_unnamed_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = C.new;
// ignore: experimental_member_use
class C(@mustBeConst int x);
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 5)],
);
}
test_class_secondaryConstructor_named_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = C.named;
class C {
// ignore: experimental_member_use
C.named(@mustBeConst int x);
}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 7)],
);
}
test_class_secondaryConstructor_unnamed_invocation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
var g = C.new(1);
class C {
// ignore: experimental_member_use
C(@mustBeConst int x);
}
''');
}
test_class_secondaryConstructor_unnamed_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = C.new;
class C {
// ignore: experimental_member_use
C(@mustBeConst int x);
}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 5)],
);
}
test_topLevelFunction_commentReference() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
/// Reference to [f].
var a = 1;
// ignore: experimental_member_use
void f(@mustBeConst int x) {}
''');
}
test_topLevelFunction_instantiated_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = f<int>;
// ignore: experimental_member_use
void f<T>(@mustBeConst T x) {}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 1)],
);
}
test_topLevelFunction_invocation() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
var g = f(1);
// ignore: experimental_member_use
void f(@mustBeConst int x) {}
''');
}
test_topLevelFunction_tearoff() async {
await assertErrorsInCode(
r'''
import 'package:meta/meta.dart';
var g = f;
// ignore: experimental_member_use
void f(@mustBeConst int x) {}
''',
[error(diag.tearoffWithMustBeConstParameter, 41, 1)],
);
}
}
File diff suppressed because it is too large Load Diff