[jsinterop] Add static check for JSName of static class members.

Static class members could technically be mapped to a name with dots,
but in the early days of JSInterop we thought this was not necessary
since it could also be modeled as a top-level member or by adding
additional classes and exposing the member as a simple name on a deeper
class.

This invariant was assumed by DDC (which crashed if this was not the
case) and ignored by dart2js.

This change adds a static check to ensure both compilers act
consistenlty.

Fixes https://github.com/dart-lang/sdk/issues/27926

Change-Id: I20e59fbb75f0378a58ca88dc3910e079b4eeb7a3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/247180
Reviewed-by: Riley Porter <rileyporter@google.com>
Commit-Queue: Riley Porter <rileyporter@google.com>
This commit is contained in:
Sigmund Cherem 2022-06-03 17:02:26 +00:00 committed by Commit Bot
parent 0517e97250
commit e808fa1751
6 changed files with 46 additions and 10 deletions

View file

@ -6939,6 +6939,16 @@ const MessageCode messageJsInteropExternalMemberNotJSAnnotated = const MessageCo
correctionMessage:
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> codeJsInteropInvalidStaticClassMemberName =
messageJsInteropInvalidStaticClassMemberName;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropInvalidStaticClassMemberName = const MessageCode(
"JsInteropInvalidStaticClassMemberName",
problemMessage:
r"""JS interop static class members cannot have '.' in their JS name.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(

View file

@ -14,6 +14,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageJsInteropEnclosingClassJSAnnotationContext,
messageJsInteropExternalExtensionMemberOnTypeInvalid,
messageJsInteropExternalMemberNotJSAnnotated,
messageJsInteropInvalidStaticClassMemberName,
messageJsInteropNamedParameters,
messageJsInteropNonExternalConstructor,
messageJsInteropNonExternalMember,
@ -274,6 +275,18 @@ class JsInteropChecks extends RecursiveVisitor {
// named parameters.
_checkNoNamedParameters(procedure.function);
}
// JS static methods cannot use a JS name with dots.
if (procedure.isStatic && procedure.enclosingClass != null) {
String name = getJSName(procedure);
if (name.contains('.')) {
_diagnosticsReporter.report(
messageJsInteropInvalidStaticClassMemberName,
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
}
}
}
if (_classHasStaticInteropAnnotation &&

View file

@ -2645,16 +2645,9 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
js_ast.LiteralString _emitJSInteropStaticMemberName(NamedNode n) {
if (!usesJSInterop(n)) return null;
var name = _annotationName(n, isPublicJSAnnotation);
if (name != null) {
if (name.contains('.')) {
throw UnsupportedError(
'static members do not support "." in their names. '
'See https://github.com/dart-lang/sdk/issues/27926');
}
} else {
name = getTopLevelName(n);
}
var name = _annotationName(n, isPublicJSAnnotation) ?? getTopLevelName(n);
assert(name != null && !name.contains('.'),
'JS interop checker rejects dotted names on static class members');
return js.escapedString(name, "'");
}

View file

@ -562,6 +562,8 @@ JsInteropExternalExtensionMemberOnTypeInvalid/analyzerCode: Fail # Web compiler
JsInteropExternalExtensionMemberOnTypeInvalid/example: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
JsInteropInvalidStaticClassMemberName/analyzerCode: Fail
JsInteropInvalidStaticClassMemberName/example: Fail
JsInteropJSClassExtendsDartClass/analyzerCode: Fail # Web compiler specific
JsInteropJSClassExtendsDartClass/example: Fail # Web compiler specific
JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific

View file

@ -5173,6 +5173,9 @@ JsInteropOperatorsNotSupported:
problemMessage: "JS interop classes do not support operator methods."
correctionMessage: "Try replacing this with a normal method."
JsInteropInvalidStaticClassMemberName:
problemMessage: "JS interop static class members cannot have '.' in their JS name."
JsInteropStaticInteropWithInstanceMembers:
problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
correctionMessage: "Try moving the instance member to a static extension."

View file

@ -0,0 +1,15 @@
// 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.
import 'package:js/js.dart';
@JS('a.Foo')
class Foo {
@JS('c.d.plus')
external static plus1(arg);
// ^
// [web] JS interop static class members cannot have '.' in their JS name.
}
main() {}