[package:js] Allow external extension members for Native classes

Change-Id: I5baf81c3c2b6b3a112327e1aea084a93677bd9b5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/208380
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Riley Porter <rileyporter@google.com>
This commit is contained in:
Riley Porter 2021-07-30 18:43:47 +00:00 committed by commit-bot@chromium.org
parent 2a99af9bc9
commit d63c2dfa83
8 changed files with 156 additions and 62 deletions

View file

@ -6237,14 +6237,14 @@ const MessageCode messageJsInteropEnclosingClassJSAnnotationContext =
message: r"""This is the enclosing class.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropExternalExtensionMemberNotOnJSClass =
messageJsInteropExternalExtensionMemberNotOnJSClass;
const Code<Null> codeJsInteropExternalExtensionMemberOnTypeInvalid =
messageJsInteropExternalExtensionMemberOnTypeInvalid;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropExternalExtensionMemberNotOnJSClass =
const MessageCode("JsInteropExternalExtensionMemberNotOnJSClass",
const MessageCode messageJsInteropExternalExtensionMemberOnTypeInvalid =
const MessageCode("JsInteropExternalExtensionMemberOnTypeInvalid",
message:
r"""JS interop class required for 'external' extension members.""",
r"""JS interop or Native class required for 'external' extension members.""",
tip:
r"""Try adding a JS interop annotation to the on type class of the extension.""");

View file

@ -12,7 +12,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageJsInteropAnonymousFactoryPositionalParameters,
messageJsInteropEnclosingClassJSAnnotation,
messageJsInteropEnclosingClassJSAnnotationContext,
messageJsInteropExternalExtensionMemberNotOnJSClass,
messageJsInteropExternalExtensionMemberOnTypeInvalid,
messageJsInteropExternalMemberNotJSAnnotated,
messageJsInteropIndexNotSupported,
messageJsInteropNamedParameters,
@ -282,13 +282,14 @@ class JsInteropChecks extends RecursiveVisitor {
/// [member] is `external` and not an allowed `external` usage.
void _checkDisallowedExternal(Member member) {
if (member.isExternal) {
// TODO(rileyporter): Allow extension members on some Native classes.
if (member.isExtensionMember) {
_diagnosticsReporter.report(
messageJsInteropExternalExtensionMemberNotOnJSClass,
member.fileOffset,
member.name.text.length,
member.fileUri);
if (!_isNativeExtensionMember(member)) {
_diagnosticsReporter.report(
messageJsInteropExternalExtensionMemberOnTypeInvalid,
member.fileOffset,
member.name.text.length,
member.fileUri);
}
} else if (!hasJSInteropAnnotation(member) &&
!_isAllowedExternalUsage(member)) {
// Member could be JS annotated and not considered a JS interop member
@ -338,6 +339,18 @@ class JsInteropChecks extends RecursiveVisitor {
/// Returns whether given extension [member] is in an extension that is on a
/// JS interop class.
bool _isJSExtensionMember(Member member) {
return _checkExtensionMember(member, hasJSInteropAnnotation);
}
/// Returns whether given extension [member] is in an extension on a Native
/// class.
bool _isNativeExtensionMember(Member member) {
return _checkExtensionMember(member, _nativeClasses.containsValue);
}
/// Returns whether given extension [member] is on a class that passses the
/// given [validateExtensionClass].
bool _checkExtensionMember(Member member, Function validateExtensionClass) {
assert(member.isExtensionMember);
if (_libraryExtensionsIndex == null) {
_libraryExtensionsIndex = {};
@ -347,6 +360,6 @@ class JsInteropChecks extends RecursiveVisitor {
}
var onType = _libraryExtensionsIndex![member.reference]!.onType;
return onType is InterfaceType && hasJSInteropAnnotation(onType.classNode);
return onType is InterfaceType && validateExtensionClass(onType.classNode);
}
}

View file

@ -514,8 +514,8 @@ JsInteropDartClassExtendsJSClass/analyzerCode: Fail # Web compiler specific
JsInteropDartClassExtendsJSClass/example: Fail # Web compiler specific
JsInteropEnclosingClassJSAnnotation/analyzerCode: Fail # Web compiler specific
JsInteropEnclosingClassJSAnnotation/example: Fail # Web compiler specific
JsInteropExternalExtensionMemberNotOnJSClass/analyzerCode: Fail # Web compiler specific
JsInteropExternalExtensionMemberNotOnJSClass/example: Fail # Web compiler specific
JsInteropExternalExtensionMemberOnTypeInvalid/analyzerCode: Fail # Web compiler specific
JsInteropExternalExtensionMemberOnTypeInvalid/example: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
JsInteropIndexNotSupported/analyzerCode: Fail # Web compiler specific

View file

@ -4914,8 +4914,8 @@ JsInteropEnclosingClassJSAnnotationContext:
template: "This is the enclosing class."
severity: CONTEXT
JsInteropExternalExtensionMemberNotOnJSClass:
template: "JS interop class required for 'external' extension members."
JsInteropExternalExtensionMemberOnTypeInvalid:
template: "JS interop or Native class required for 'external' extension members."
tip: "Try adding a JS interop annotation to the on type class of the extension."
JsInteropExternalMemberNotJSAnnotated:

View file

@ -7,6 +7,7 @@
library external_nonjs_static_test;
import 'dart:html';
import 'package:js/js.dart';
external var topLevelField;
@ -101,43 +102,43 @@ class AnonymousClass {
extension ExtensionNonJS on NonJSClass {
external var field;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external final finalField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static var staticField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static final staticFinalField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external get getter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external optionalParameterMethod([int? a, int b = 0]);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@ -150,9 +151,29 @@ class NonJSClass {
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
extension ExtensionNative on HtmlElement {
external var field;
external final finalField;
external static var staticField;
external static final staticFinalField;
external get getter;
external set setter(_);
external static get staticGetter;
external static set staticSetter(_);
external method();
external static staticMethod();
external optionalParameterMethod([int? a, int b = 0]);
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
}
main() {}

View file

@ -8,6 +8,7 @@
@JS()
library external_static_test;
import 'dart:html';
import 'package:js/js.dart';
// external top level members ok in @JS() library.
@ -89,52 +90,52 @@ class AnonymousClass {
extension ExtensionNonJS on NonJSClass {
external var field;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external final finalField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static var staticField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static final staticFinalField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external get getter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external optionalParameterMethod([int? a, int b = 0]);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
@JS('fieldAnnotation')
external var annotatedField;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
@JS('memberAnnotation')
external annotatedMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@ -147,7 +148,7 @@ class NonJSClass {
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
@ -229,4 +230,24 @@ extension ExtensionPrivateJS on _privateJSClass {
@JS()
class _privateJSClass {}
extension ExtensionNative on HtmlElement {
external var field;
external final finalField;
external static var staticField;
external static final staticFinalField;
external get getter;
external set setter(_);
external static get staticGetter;
external static set staticSetter(_);
external method();
external static staticMethod();
external optionalParameterMethod([int? a, int b = 0]);
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
}
main() {}

View file

@ -9,6 +9,7 @@
library external_nonjs_static_test;
import 'dart:html';
import 'package:js/js.dart';
external get topLevelGetter;
@ -75,27 +76,30 @@ class AnonymousClass {
extension ExtensionNonJS on NonJSClass {
external get getter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external optionalParameterMethod([int a, int b = 0]);
// ^
// [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@ -108,9 +112,24 @@ class NonJSClass {
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
extension ExtensionNative on HtmlElement {
external get getter;
external set setter(_);
external static get staticGetter;
external static set staticSetter(_);
external method();
external static staticMethod();
external optionalParameterMethod([int a, int b = 0]);
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
}
main() {}

View file

@ -10,6 +10,7 @@
@JS()
library external_static_test;
import 'dart:html';
import 'package:js/js.dart';
// external top level members ok in @JS() library.
@ -69,32 +70,35 @@ class AnonymousClass {
extension ExtensionNonJS on NonJSClass {
external get getter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
external optionalParameterMethod([int a, int b = 0]);
// ^
// [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
@JS('memberAnnotation')
external annotatedMethod();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@ -107,7 +111,7 @@ class NonJSClass {
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
// [web] JS interop class required for 'external' extension members.
// [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
@ -121,6 +125,7 @@ extension ExtensionJS on JSClass {
external method();
external static staticMethod();
external optionalParameterMethod([int a, int b = 0]);
@JS('memberAnnotation')
external annotatedMethod();
@ -176,4 +181,19 @@ extension ExtensionPrivateJS on _privateJSClass {
@JS()
class _privateJSClass {}
extension ExtensionNative on HtmlElement {
external get getter;
external set setter(_);
external static get staticGetter;
external static set staticSetter(_);
external method();
external static staticMethod();
external optionalParameterMethod([int a, int b = 0]);
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
}
main() {}