[pkg:js] Disallow all operators in JS classes
Closes https://github.com/dart-lang/sdk/issues/48515
Expands existing checks for index operations to all operators. This
only affects instance members and not extension members.
Change-Id: I8cbb5b12a49539ea502e4396e1b469ffb0e17d5e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/235980
Reviewed-by: Riley Porter <rileyporter@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 a9ec81e..6035330 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -6569,17 +6569,6 @@
r"""Try removing the 'external' keyword or adding a JS interop annotation.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Null> codeJsInteropIndexNotSupported =
- messageJsInteropIndexNotSupported;
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const MessageCode messageJsInteropIndexNotSupported = const MessageCode(
- "JsInteropIndexNotSupported",
- problemMessage:
- r"""JS interop classes do not support [] and []= operator methods.""",
- correctionMessage: r"""Try replacing with a normal method.""");
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String name,
@@ -6685,6 +6674,16 @@
correctionMessage: r"""Try annotating the member with `external`.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeJsInteropOperatorsNotSupported =
+ messageJsInteropOperatorsNotSupported;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageJsInteropOperatorsNotSupported = const MessageCode(
+ "JsInteropOperatorsNotSupported",
+ problemMessage: r"""JS interop classes do not support operator methods.""",
+ correctionMessage: r"""Try replacing this with a normal method.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)>
templateJsInteropStaticInteropWithInstanceMembers =
const Template<Message Function(String name)>(
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 6dab119..26d8396 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -14,10 +14,10 @@
messageJsInteropEnclosingClassJSAnnotationContext,
messageJsInteropExternalExtensionMemberOnTypeInvalid,
messageJsInteropExternalMemberNotJSAnnotated,
- messageJsInteropIndexNotSupported,
messageJsInteropNamedParameters,
messageJsInteropNonExternalConstructor,
messageJsInteropNonExternalMember,
+ messageJsInteropOperatorsNotSupported,
templateJsInteropDartClassExtendsJSClass,
templateJsInteropStaticInteropWithInstanceMembers,
templateJsInteropStaticInteropWithNonStaticSupertype,
@@ -220,10 +220,9 @@
_checkDisallowedExternal(procedure);
} else {
// Check JS interop indexing.
- if (!procedure.isStatic &&
- (procedure.name.text == '[]=' || procedure.name.text == '[]')) {
+ if (!procedure.isStatic && procedure.kind == ProcedureKind.Operator) {
_diagnosticsReporter.report(
- messageJsInteropIndexNotSupported,
+ messageJsInteropOperatorsNotSupported,
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 6563de2..a4710b5 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -546,8 +546,6 @@
JsInteropExternalExtensionMemberOnTypeInvalid/example: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
-JsInteropIndexNotSupported/analyzerCode: Fail # Web compiler specific
-JsInteropIndexNotSupported/example: Fail # Web compiler specific
JsInteropJSClassExtendsDartClass/analyzerCode: Fail # Web compiler specific
JsInteropJSClassExtendsDartClass/example: Fail # Web compiler specific
JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific
@@ -558,6 +556,8 @@
JsInteropNonExternalConstructor/example: Fail # Web compiler specific
JsInteropNonExternalMember/analyzerCode: Fail # Web compiler specific
JsInteropNonExternalMember/example: Fail # Web compiler specific
+JsInteropOperatorsNotSupported/analyzerCode: Fail # Web compiler specific
+JsInteropOperatorsNotSupported/example: Fail # Web compiler specific
JsInteropStaticInteropWithInstanceMembers/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropWithInstanceMembers/example: Fail # Web compiler specific
JsInteropStaticInteropWithNonStaticSupertype/analyzerCode: Fail # Web compiler specific
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index d165d4c..21e529c 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -5096,18 +5096,6 @@
problemMessage: "Only JS interop members may be 'external'."
correctionMessage: "Try removing the 'external' keyword or adding a JS interop annotation."
-JsInteropIndexNotSupported:
- problemMessage: "JS interop classes do not support [] and []= operator methods."
- correctionMessage: "Try replacing with a normal method."
-
-JsInteropStaticInteropWithInstanceMembers:
- problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
- correctionMessage: "Try moving the instance member to a static extension."
-
-JsInteropStaticInteropWithNonStaticSupertype:
- problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which is non-static."
- correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
-
JsInteropJSClassExtendsDartClass:
problemMessage: "JS interop class '#name' cannot extend Dart class '#name2'."
correctionMessage: "Try removing the JS interop annotation or adding it to the parent class."
@@ -5128,6 +5116,18 @@
problemMessage: "This JS interop member must be annotated with `external`. Only factories and static methods can be non-external."
correctionMessage: "Try annotating the member with `external`."
+JsInteropOperatorsNotSupported:
+ problemMessage: "JS interop classes do not support operator methods."
+ correctionMessage: "Try replacing this with a normal method."
+
+JsInteropStaticInteropWithInstanceMembers:
+ problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
+ correctionMessage: "Try moving the instance member to a static extension."
+
+JsInteropStaticInteropWithNonStaticSupertype:
+ problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which is non-static."
+ correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
+
DefaultListConstructorError:
problemMessage: "Can't use the default List constructor."
correctionMessage: "Try using List.filled instead."
diff --git a/tests/lib/js/operator_test.dart b/tests/lib/js/operator_test.dart
new file mode 100644
index 0000000..cd688cc
--- /dev/null
+++ b/tests/lib/js/operator_test.dart
@@ -0,0 +1,170 @@
+// Copyright (c) 2022, 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.
+
+@JS()
+library operator_test;
+
+import 'package:js/js.dart';
+
+@JS()
+class JSClass {
+ // https://dart.dev/guides/language/language-tour#_operators for the list of
+ // operators allowed by the language.
+ external void operator <(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator -(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator +(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator /(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~/(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator *(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator %(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator |(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ^(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator &(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <<(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator [](_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator []=(_, __);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~();
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external bool operator ==(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+ external void operator <(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator -(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator +(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator /(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~/(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator *(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator %(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator |(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ^(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator &(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <<(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator [](_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator []=(_, __);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~();
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external bool operator ==(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+class JSClassExtensions {}
+
+extension _ on JSClassExtensions {
+ // External operators in extensions are allowed for now, but don't work as
+ // intended. Specific operators will need to be allowlisted in the future.
+ // TODO(srujzs): Remove this test once we do that.
+ external void operator <(_);
+ external void operator >(_);
+ external void operator <=(_);
+ external void operator >=(_);
+ external void operator -(_);
+ external void operator +(_);
+ external void operator /(_);
+ external void operator ~/(_);
+ external void operator *(_);
+ external void operator %(_);
+ external void operator |(_);
+ external void operator ^(_);
+ external void operator &(_);
+ external void operator <<(_);
+ external void operator >>(_);
+ external void operator >>>(_);
+ external void operator [](_);
+ external void operator []=(_, __);
+ external void operator ~();
+ // No `==` as it's an `Object` method.
+}
+
+void main() {}
diff --git a/tests/lib_2/js/operator_test.dart b/tests/lib_2/js/operator_test.dart
new file mode 100644
index 0000000..cd688cc
--- /dev/null
+++ b/tests/lib_2/js/operator_test.dart
@@ -0,0 +1,170 @@
+// Copyright (c) 2022, 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.
+
+@JS()
+library operator_test;
+
+import 'package:js/js.dart';
+
+@JS()
+class JSClass {
+ // https://dart.dev/guides/language/language-tour#_operators for the list of
+ // operators allowed by the language.
+ external void operator <(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator -(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator +(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator /(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~/(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator *(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator %(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator |(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ^(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator &(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <<(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator [](_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator []=(_, __);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~();
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external bool operator ==(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+ external void operator <(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >=(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator -(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator +(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator /(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~/(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator *(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator %(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator |(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ^(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator &(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator <<(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator >>>(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator [](_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator []=(_, __);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external void operator ~();
+ // ^
+ // [web] JS interop classes do not support operator methods.
+ external bool operator ==(_);
+ // ^
+ // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+class JSClassExtensions {}
+
+extension _ on JSClassExtensions {
+ // External operators in extensions are allowed for now, but don't work as
+ // intended. Specific operators will need to be allowlisted in the future.
+ // TODO(srujzs): Remove this test once we do that.
+ external void operator <(_);
+ external void operator >(_);
+ external void operator <=(_);
+ external void operator >=(_);
+ external void operator -(_);
+ external void operator +(_);
+ external void operator /(_);
+ external void operator ~/(_);
+ external void operator *(_);
+ external void operator %(_);
+ external void operator |(_);
+ external void operator ^(_);
+ external void operator &(_);
+ external void operator <<(_);
+ external void operator >>(_);
+ external void operator >>>(_);
+ external void operator [](_);
+ external void operator []=(_, __);
+ external void operator ~();
+ // No `==` as it's an `Object` method.
+}
+
+void main() {}