[package:js] Add error for params in factories of anon classes
Adds a static error to check that factory constructors in anonymous
classes contain no positional parameters.
Change-Id: Iae7c5c1d9e2dc91390c85c58eb5e96718e808f9a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/156145
Reviewed-by: Nate Bosch <nbosch@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 61e97af..531cf04 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -5410,6 +5410,17 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeJsInteropAnonymousFactoryPositionalParameters =
+ messageJsInteropAnonymousFactoryPositionalParameters;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageJsInteropAnonymousFactoryPositionalParameters =
+ const MessageCode("JsInteropAnonymousFactoryPositionalParameters",
+ message:
+ r"""Factory constructors for @anonymous JS interop classes should not contain any positional parameters.""",
+ tip: r"""Try replacing them with named parameters instead.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropIndexNotSupported =
messageJsInteropIndexNotSupported;
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 7005741..08cbb83 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -8,6 +8,7 @@
show
Message,
LocatedMessage,
+ messageJsInteropAnonymousFactoryPositionalParameters,
messageJsInteropIndexNotSupported,
messageJsInteropNamedParameters,
messageJsInteropNonExternalConstructor;
@@ -32,7 +33,20 @@
procedure.location.file);
}
- if (!isAnonymousClassMember(procedure) || !procedure.isFactory) {
+ var isAnonymousFactory =
+ isAnonymousClassMember(procedure) && procedure.isFactory;
+
+ if (isAnonymousFactory) {
+ if (procedure.function != null &&
+ !procedure.function.positionalParameters.isEmpty) {
+ var firstPositionalParam = procedure.function.positionalParameters[0];
+ _diagnosticsReporter.report(
+ messageJsInteropAnonymousFactoryPositionalParameters,
+ firstPositionalParam.fileOffset,
+ firstPositionalParam.name.length,
+ firstPositionalParam.location.file);
+ }
+ } else {
// Only factory constructors for anonymous classes are allowed to have
// named parameters.
_checkNoNamedParameters(procedure.function);
@@ -57,12 +71,12 @@
/// Reports an error if [functionNode] has named parameters.
void _checkNoNamedParameters(FunctionNode functionNode) {
if (functionNode != null && !functionNode.namedParameters.isEmpty) {
- var firstNameParam = functionNode.namedParameters[0];
+ var firstNamedParam = functionNode.namedParameters[0];
_diagnosticsReporter.report(
messageJsInteropNamedParameters,
- firstNameParam.fileOffset,
- firstNameParam.name.length,
- firstNameParam.location.file);
+ firstNamedParam.fileOffset,
+ firstNamedParam.name.length,
+ firstNamedParam.location.file);
}
}
}
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index db613ff..151df1e 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -197,27 +197,6 @@
"""
]),
- MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS:
- const MessageTemplate(
- MessageKind
- .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
- "Some parameters in anonymous js-interop class '#{cls}' "
- "object literal constructor are positional instead of named."
- ".",
- howToFix: "Make all arguments in external factory object literal "
- "constructors named.",
- examples: const [
- """
-class Super {
- factory Super.foo() => null;
-}
-class Class extends Super {
- Class() : super.foo();
-}
-main() => new Class();
-"""
- ]),
-
MessageKind.JS_INTEROP_NON_EXTERNAL_MEMBER: const MessageTemplate(
MessageKind.JS_INTEROP_NON_EXTERNAL_MEMBER,
"Js-interop members must be 'external'."),
diff --git a/pkg/compiler/lib/src/kernel/native_basic_data.dart b/pkg/compiler/lib/src/kernel/native_basic_data.dart
index f7a7e97..3d43255 100644
--- a/pkg/compiler/lib/src/kernel/native_basic_data.dart
+++ b/pkg/compiler/lib/src/kernel/native_basic_data.dart
@@ -151,16 +151,6 @@
_nativeBasicDataBuilder.markAsJsInteropMember(
constructor, memberName);
}
-
- if (constructor.isFactoryConstructor && isAnonymous) {
- if (constructor.parameterStructure.positionalParameters > 0) {
- reporter.reportErrorMessage(
- constructor,
- MessageKind
- .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
- {'cls': cls.name});
- }
- }
});
} else {
elementEnvironment.forEachLocalClassMember(cls, (MemberEntity member) {
diff --git a/pkg/compiler/test/jsinterop/declaration_test.dart b/pkg/compiler/test/jsinterop/declaration_test.dart
index 878d20b..0c3a2ce 100644
--- a/pkg/compiler/test/jsinterop/declaration_test.dart
+++ b/pkg/compiler/test/jsinterop/declaration_test.dart
@@ -357,38 +357,6 @@
main() => new A(a: 1);
'''),
- const Test('External factory constructor with required parameters.', '''
-@JS()
-library test;
-
-import 'package:js/js.dart';
-
-@JS()
-@anonymous
-class A {
- external factory A(a, b);
-}
-
-main() => new A(1, 2);
-''', errors: const [
- MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS
- ]),
- const Test('External factory constructor with optional parameters.', '''
-@JS()
-library test;
-
-import 'package:js/js.dart';
-
-@JS()
-@anonymous
-class A {
- external factory A([a, b]);
-}
-
-main() => new A(1);
-''', errors: const [
- MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS
- ]),
const Test('Function-typed return type', '''
@JS()
library lib;
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index e8b5454..6459cc1 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -439,6 +439,8 @@
InvalidVoid/part_wrapped_script2: Fail
InvalidVoid/script1: Fail
InvalidVoid/script2: Fail
+JsInteropAnonymousFactoryPositionalParameters/analyzerCode: Fail # Web compiler specific
+JsInteropAnonymousFactoryPositionalParameters/example: Fail # Web compiler specific
JsInteropIndexNotSupported/analyzerCode: Fail # Web compiler specific
JsInteropIndexNotSupported/example: Fail # Web compiler specific
JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index ecf30d2..62ae4a3 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4086,6 +4086,10 @@
NullableMixinError:
template: "Can't mix '#name' in because it's marked with '?'."
+JsInteropAnonymousFactoryPositionalParameters:
+ template: "Factory constructors for @anonymous JS interop classes should not contain any positional parameters."
+ tip: "Try replacing them with named parameters instead."
+
JsInteropIndexNotSupported:
template: "JS interop classes do not support [] and []= operator methods."
tip: "Try replacing with a normal method."
diff --git a/tests/lib/js/constructor_parameters_static_test.dart b/tests/lib/js/constructor_parameters_static_test.dart
index 597ce1e..3efa2a2 100644
--- a/tests/lib/js/constructor_parameters_static_test.dart
+++ b/tests/lib/js/constructor_parameters_static_test.dart
@@ -30,8 +30,22 @@
// ^
// [web] TODO(srujzs): Add error once supported.
+ // Factories of an anonymous class can only contain named parameters.
+ external factory Bar.barFactoryPositional(int? a);
+ // ^
+ // [web] TODO(srujzs): Add error once supported.
+ external factory Bar.barFactoryOptional([int? a]);
+ // ^
+ // [web] TODO(srujzs): Add error once supported.
+ external factory Bar.barFactoryMixedOptional(int? a, [int? b]);
+ // ^
+ // [web] TODO(srujzs): Add error once supported.
+ external factory Bar.barFactoryMixedNamed(int? a, {int? b});
+ // ^
+ // [web] TODO(srujzs): Add error once supported.
+
// Named parameters are okay only for factories of an anonymous class.
- external factory Bar.barFactory({int? a});
+ external factory Bar.barFactoryNamed({int? a});
}
@JS()