2f2bdc3c22
Change-Id: I182e28a3c4b44dd899e5ea30ac5c5c3ba60fd6cc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425333 Reviewed-by: Srujan Gaddam <srujzs@google.com> Commit-Queue: Bob Nystrom <rnystrom@google.com> Auto-Submit: Bob Nystrom <rnystrom@google.com>
249 lines
7.4 KiB
Dart
249 lines
7.4 KiB
Dart
// 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.
|
|
|
|
// Tests uses of `@JSExport` and `createDartExport` or `createJSInteropWrapper`.
|
|
|
|
import 'dart:js_interop';
|
|
|
|
import 'package:js/js_util.dart';
|
|
|
|
// You can either have a @JSExport annotation on the entire class or select
|
|
// members only, and they may contain members that are ignored.
|
|
@JSExport()
|
|
class ExportAll {
|
|
int field = throw '';
|
|
final int finalField = throw '';
|
|
int get getSet => throw '';
|
|
set getSet(int val) => throw '';
|
|
int method() => throw '';
|
|
}
|
|
|
|
class ExportSome {
|
|
ExportSome();
|
|
factory ExportSome.factory() => ExportSome();
|
|
|
|
@JSExport()
|
|
int field = throw '';
|
|
final int finalField = throw '';
|
|
@JSExport()
|
|
int get getSet => throw '';
|
|
set getSet(int val) => throw '';
|
|
@JSExport()
|
|
int method() => throw '';
|
|
|
|
static int staticField = throw '';
|
|
static void staticMethod() => throw '';
|
|
}
|
|
|
|
extension on ExportSome {
|
|
int extensionMethod() => throw '';
|
|
|
|
static int extensionStaticField = throw '';
|
|
static void extensionStaticMethod() => throw '';
|
|
}
|
|
|
|
// We should leave Dart classes with no exports alone unless used in
|
|
// `createDartExport`.
|
|
class NoAnnotations {
|
|
int field = throw '';
|
|
final int finalField = throw '';
|
|
int get getSet => throw '';
|
|
set getSet(int val) => throw '';
|
|
int method() => throw '';
|
|
}
|
|
|
|
// If there is a `@JSExport` annotation, but no exportable members, it's
|
|
// considered an error.
|
|
@JSExport()
|
|
abstract class ExportNoneQualify {
|
|
// ^
|
|
// [web] Class 'ExportNoneQualify' has no exportable members in the class or the inheritance chain.
|
|
factory ExportNoneQualify() => throw '';
|
|
|
|
abstract int abstractField;
|
|
void abstractMethod();
|
|
|
|
static int staticField = throw '';
|
|
static void staticMethod() => throw '';
|
|
}
|
|
|
|
extension on ExportNoneQualify {
|
|
int method() => throw '';
|
|
|
|
static int staticField = throw '';
|
|
static void staticMethod() => throw '';
|
|
}
|
|
|
|
@JSExport()
|
|
class ExportEmpty {}
|
|
// ^
|
|
// [web] Class 'ExportEmpty' has no exportable members in the class or the inheritance chain.
|
|
|
|
// These are errors, as there are no exportable members that have the annotation
|
|
// on them or on their class.
|
|
@JSExport()
|
|
class ExportWithNoExportSuperclass extends NoAnnotations {}
|
|
// ^
|
|
// [web] Class 'ExportWithNoExportSuperclass' has no exportable members in the class or the inheritance chain.
|
|
|
|
@JSExport()
|
|
class ExportWithEmptyExportSuperclass extends ExportEmpty {}
|
|
// ^
|
|
// [web] Class 'ExportWithEmptyExportSuperclass' has no exportable members in the class or the inheritance chain.
|
|
|
|
// This isn't an error to write, but it will be when you use it as part of
|
|
// `createDartExport`.
|
|
class NoExportWithExportSuperclass extends ExportAll {}
|
|
|
|
void testNumberOfExports() {
|
|
createDartExport(ExportAll());
|
|
createDartExport(ExportSome());
|
|
createDartExport(NoAnnotations());
|
|
// [error column 3]
|
|
// [web] Class 'NoAnnotations' does not have a `@JSExport` on it or any of its members.
|
|
createDartExport(ExportNoneQualify());
|
|
createDartExport(ExportEmpty());
|
|
createDartExport(ExportWithNoExportSuperclass());
|
|
createDartExport(ExportWithEmptyExportSuperclass());
|
|
createDartExport(NoExportWithExportSuperclass());
|
|
// [error column 3]
|
|
// [web] Class 'NoExportWithExportSuperclass' does not have a `@JSExport` on it or any of its members.
|
|
|
|
// Same method with different name and type.
|
|
createJSInteropWrapper(ExportAll());
|
|
createJSInteropWrapper(ExportSome());
|
|
createJSInteropWrapper(NoAnnotations());
|
|
// [error column 3]
|
|
// [web] Class 'NoAnnotations' does not have a `@JSExport` on it or any of its members.
|
|
createJSInteropWrapper(ExportNoneQualify());
|
|
createJSInteropWrapper(ExportEmpty());
|
|
createJSInteropWrapper(ExportWithNoExportSuperclass());
|
|
createJSInteropWrapper(ExportWithEmptyExportSuperclass());
|
|
createJSInteropWrapper(NoExportWithExportSuperclass());
|
|
// [error column 3]
|
|
// [web] Class 'NoExportWithExportSuperclass' does not have a `@JSExport` on it or any of its members.
|
|
}
|
|
|
|
@JS()
|
|
@staticInterop
|
|
class StaticInterop {
|
|
external factory StaticInterop();
|
|
}
|
|
|
|
typedef InvalidType = void Function();
|
|
|
|
void testUseDartInterface() {
|
|
// Needs to be an interface type.
|
|
createDartExport<InvalidType>(() {});
|
|
// [error column 3]
|
|
// [web] Type argument 'void Function()' needs to be an interface type.
|
|
|
|
// Can't use an interop class.
|
|
createDartExport(StaticInterop());
|
|
// [error column 3]
|
|
// [web] Type argument 'StaticInterop' needs to be a non-JS interop type.
|
|
|
|
createJSInteropWrapper<InvalidType>(() {});
|
|
// [error column 3]
|
|
// [web] Type argument 'void Function()' needs to be an interface type.
|
|
|
|
// Can't use an interop class.
|
|
createJSInteropWrapper(StaticInterop());
|
|
// [error column 3]
|
|
// [web] Type argument 'StaticInterop' needs to be a non-JS interop type.
|
|
}
|
|
|
|
// Incompatible members can't have the same export name using renaming.
|
|
@JSExport()
|
|
class RenameCollision {
|
|
// ^
|
|
// [web] The following class members collide with the same export 'exportName': RenameCollision.exportName, RenameCollision.finalField, RenameCollision.getSet, RenameCollision.getSet, RenameCollision.method.
|
|
int exportName = throw '';
|
|
@JSExport('exportName')
|
|
final int finalField = throw '';
|
|
@JSExport('exportName')
|
|
int get getSet => throw '';
|
|
@JSExport('exportName')
|
|
set getSet(int val) => throw '';
|
|
@JSExport('exportName')
|
|
void method() => throw '';
|
|
}
|
|
|
|
// Allowed collisions are only between getters and setters.
|
|
@JSExport()
|
|
class GetSetNoCollision {
|
|
int get getSet => throw '';
|
|
set getSet(int val) => throw '';
|
|
|
|
@JSExport('renamedGetSet')
|
|
int get renamedGetter => throw '';
|
|
@JSExport('renamedGetSet')
|
|
set renamedSetter(int val) => throw '';
|
|
}
|
|
|
|
void testCollisions() {
|
|
createDartExport(RenameCollision());
|
|
createDartExport(GetSetNoCollision());
|
|
|
|
createJSInteropWrapper(RenameCollision());
|
|
createJSInteropWrapper(GetSetNoCollision());
|
|
}
|
|
|
|
// Class annotation values are warnings, not values, so they don't show up in
|
|
// static error tests.
|
|
@JSExport('Invalid')
|
|
class ClassWithValue {
|
|
int get getSet => throw '';
|
|
}
|
|
|
|
@JSExport('Invalid')
|
|
mixin MixinWithValue {
|
|
int get getSet => throw '';
|
|
}
|
|
|
|
void testClassExportWithValue() {
|
|
createDartExport(ClassWithValue());
|
|
|
|
createJSInteropWrapper(ClassWithValue());
|
|
}
|
|
|
|
// `JSExport` classes can't export methods that define type parameters as those
|
|
// type parameters will never be instantiated through interop. Class type
|
|
// parameters are okay, however.
|
|
@JSExport()
|
|
class GenericAll {
|
|
// ^
|
|
// [web] Class 'GenericAll' has no exportable members in the class or the inheritance chain.
|
|
void defineTypeParam<T extends int>() {}
|
|
T useTypeParam<T extends Object>(T t) => t;
|
|
}
|
|
|
|
class GenericSome<U> {
|
|
@JSExport()
|
|
void defineTypeParam<T extends int>() {}
|
|
// ^
|
|
// [web] Member 'defineTypeParam' is not a concrete instance member or declares type parameters, and therefore can't be exported.
|
|
T useTypeParam<T extends Object>(T t) => t;
|
|
@JSExport()
|
|
U useClassParam(U u) => u;
|
|
}
|
|
|
|
void testClassWithGenerics() {
|
|
createDartExport(GenericAll());
|
|
createDartExport(GenericSome());
|
|
createDartExport(GenericSome<int>());
|
|
|
|
createJSInteropWrapper(GenericAll());
|
|
createJSInteropWrapper(GenericSome());
|
|
createJSInteropWrapper(GenericSome<int>());
|
|
}
|
|
|
|
void main() {
|
|
testNumberOfExports();
|
|
testUseDartInterface();
|
|
testCollisions();
|
|
testClassExportWithValue();
|
|
testClassWithGenerics();
|
|
}
|