[pkg/_js_interop_checks] use package:lints/recommended.yaml

Change-Id: Ia8024f6f5a2185c1ac6d6dc666c9e246f5131c52
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282391
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Commit-Queue: Devon Carew <devoncarew@google.com>
This commit is contained in:
Devon Carew 2023-02-14 19:17:26 +00:00 committed by Commit Queue
parent 13521eebab
commit f39365c8e5
8 changed files with 247 additions and 238 deletions

View file

@ -1 +1,7 @@
include: package:lints/core.yaml
include: package:lints/recommended.yaml
linter:
rules:
depend_on_referenced_packages: true
directives_ordering: true
sort_pub_dependencies: true

View file

@ -2,11 +2,8 @@
// 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.
// Used for importing CFE utility functions for constructor tear-offs.
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/target/targets.dart';
// ignore_for_file: implementation_imports
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show
Message,
@ -35,6 +32,11 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
templateJsInteropStaticInteropTrustTypesUsageNotAllowed,
templateJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop;
import 'package:_js_interop_checks/src/transformations/export_checker.dart';
// Used for importing CFE utility functions for constructor tear-offs.
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/target/targets.dart';
import 'src/js_interop.dart';
@ -89,7 +91,7 @@ class JsInteropChecks extends RecursiveVisitor {
/// Native tests to exclude from checks on external.
// TODO(rileyporter): Use ExternalName from CFE to exclude native tests.
List<Pattern> _allowedNativeTestPatterns = [
final List<Pattern> _allowedNativeTestPatterns = [
RegExp(r'(?<!generated_)tests/web/native'),
RegExp(r'(?<!generated_)tests/web/internal'),
'generated_tests/web/native/native_test',
@ -98,7 +100,7 @@ class JsInteropChecks extends RecursiveVisitor {
'generated_tests/web_2/native/native_test',
];
List<Pattern> _allowedTrustTypesTestPatterns = [
final List<Pattern> _allowedTrustTypesTestPatterns = [
RegExp(r'(?<!generated_)tests/lib/js'),
RegExp(r'(?<!generated_)tests/lib_2/js'),
];
@ -130,124 +132,124 @@ class JsInteropChecks extends RecursiveVisitor {
}
@override
void defaultMember(Member member) {
_checkInstanceMemberJSAnnotation(member);
if (!_isJSInteropMember(member)) _checkDisallowedExternal(member);
void defaultMember(Member node) {
_checkInstanceMemberJSAnnotation(node);
if (!_isJSInteropMember(node)) _checkDisallowedExternal(node);
// TODO(43530): Disallow having JS interop annotations on non-external
// members (class members or otherwise). Currently, they're being ignored.
exportChecker.visitMember(member);
super.defaultMember(member);
exportChecker.visitMember(node);
super.defaultMember(node);
}
@override
void visitClass(Class cls) {
_classHasJSAnnotation = hasJSInteropAnnotation(cls);
_classHasAnonymousAnnotation = hasAnonymousAnnotation(cls);
_classHasStaticInteropAnnotation = hasStaticInteropAnnotation(cls);
bool classHasTrustTypesAnnotation = hasTrustTypesAnnotation(cls);
void visitClass(Class node) {
_classHasJSAnnotation = hasJSInteropAnnotation(node);
_classHasAnonymousAnnotation = hasAnonymousAnnotation(node);
_classHasStaticInteropAnnotation = hasStaticInteropAnnotation(node);
bool classHasTrustTypesAnnotation = hasTrustTypesAnnotation(node);
if (classHasTrustTypesAnnotation) {
if (!_isAllowedTrustTypesUsage(cls)) {
if (!_isAllowedTrustTypesUsage(node)) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropTrustTypesUsageNotAllowed
.withArguments(cls.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
.withArguments(node.name),
node.fileOffset,
node.name.length,
node.fileUri);
}
if (!_classHasStaticInteropAnnotation) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop
.withArguments(cls.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
.withArguments(node.name),
node.fileOffset,
node.name.length,
node.fileUri);
}
}
var superclass = cls.superclass;
var superclass = node.superclass;
if (superclass != null && superclass != _coreTypes.objectClass) {
var superHasJSAnnotation = hasJSInteropAnnotation(superclass);
if (_classHasJSAnnotation && !superHasJSAnnotation) {
_diagnosticsReporter.report(
templateJsInteropJSClassExtendsDartClass.withArguments(
cls.name, superclass.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
node.name, superclass.name),
node.fileOffset,
node.name.length,
node.fileUri);
} else if (!_classHasJSAnnotation && superHasJSAnnotation) {
_diagnosticsReporter.report(
templateJsInteropDartClassExtendsJSClass.withArguments(
cls.name, superclass.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
node.name, superclass.name),
node.fileOffset,
node.name.length,
node.fileUri);
} else if (_classHasStaticInteropAnnotation &&
!hasStaticInteropAnnotation(superclass)) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropWithNonStaticSupertype.withArguments(
cls.name, superclass.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
node.name, superclass.name),
node.fileOffset,
node.name.length,
node.fileUri);
} else if (!_classHasStaticInteropAnnotation &&
hasStaticInteropAnnotation(superclass)) {
_diagnosticsReporter.report(
templateJsInteropNonStaticWithStaticInteropSupertype.withArguments(
cls.name, superclass.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
node.name, superclass.name),
node.fileOffset,
node.name.length,
node.fileUri);
}
}
if (_classHasStaticInteropAnnotation) {
if (!_classHasJSAnnotation) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropNoJSAnnotation
.withArguments(cls.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
.withArguments(node.name),
node.fileOffset,
node.name.length,
node.fileUri);
}
// Validate that superinterfaces are all annotated as static as well. Note
// that mixins are already disallowed and therefore are not checked here.
for (var supertype in cls.implementedTypes) {
for (var supertype in node.implementedTypes) {
if (!hasStaticInteropAnnotation(supertype.classNode)) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropWithNonStaticSupertype
.withArguments(cls.name, supertype.classNode.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
.withArguments(node.name, supertype.classNode.name),
node.fileOffset,
node.name.length,
node.fileUri);
}
}
}
// The converse of the above. If the class is not marked as static, it
// should not implement a class that is.
if (!_classHasStaticInteropAnnotation) {
for (var supertype in cls.implementedTypes) {
for (var supertype in node.implementedTypes) {
if (hasStaticInteropAnnotation(supertype.classNode)) {
_diagnosticsReporter.report(
templateJsInteropNonStaticWithStaticInteropSupertype
.withArguments(cls.name, supertype.classNode.name),
cls.fileOffset,
cls.name.length,
cls.fileUri);
.withArguments(node.name, supertype.classNode.name),
node.fileOffset,
node.name.length,
node.fileUri);
}
}
}
// Since this is a breaking check, it is language-versioned.
if (cls.enclosingLibrary.languageVersion >= Version(2, 13) &&
if (node.enclosingLibrary.languageVersion >= Version(2, 13) &&
_classHasJSAnnotation &&
!_classHasStaticInteropAnnotation &&
!_classHasAnonymousAnnotation &&
_libraryIsGlobalNamespace) {
var jsClass = getJSName(cls);
var jsClass = getJSName(node);
if (jsClass.isEmpty) {
// No rename, take the name of the class directly.
jsClass = cls.name;
jsClass = node.name;
} else {
// Remove any global prefixes. Regex here is greedy and will only return
// a value for `className` that doesn't start with 'self.' or 'window.'.
var classRegexp = new RegExp(r'^((self|window)\.)*(?<className>.*)$');
var classRegexp = RegExp(r'^((self|window)\.)*(?<className>.*)$');
var matches = classRegexp.allMatches(jsClass);
jsClass = matches.first.namedGroup('className')!;
}
@ -255,29 +257,29 @@ class JsInteropChecks extends RecursiveVisitor {
if (nativeClass != null) {
_diagnosticsReporter.report(
templateJsInteropNativeClassInAnnotation.withArguments(
cls.name,
node.name,
nativeClass.name,
nativeClass.enclosingLibrary.importUri.toString()),
cls.fileOffset,
cls.name.length,
cls.fileUri);
node.fileOffset,
node.name.length,
node.fileUri);
}
}
super.visitClass(cls);
super.visitClass(node);
// Validate `@JSExport` usage after so we know if the members have the
// annotation.
exportChecker.visitClass(cls);
exportChecker.visitClass(node);
_classHasAnonymousAnnotation = false;
_classHasJSAnnotation = false;
}
@override
void visitLibrary(Library lib) {
_libraryHasJSAnnotation = hasJSInteropAnnotation(lib);
void visitLibrary(Library node) {
_libraryHasJSAnnotation = hasJSInteropAnnotation(node);
_libraryIsGlobalNamespace = false;
if (_libraryHasJSAnnotation) {
var libraryAnnotation = getJSName(lib);
var globalRegexp = new RegExp(r'^(self|window)(\.(self|window))*$');
var libraryAnnotation = getJSName(node);
var globalRegexp = RegExp(r'^(self|window)(\.(self|window))*$');
if (libraryAnnotation.isEmpty ||
globalRegexp.hasMatch(libraryAnnotation)) {
_libraryIsGlobalNamespace = true;
@ -285,52 +287,43 @@ class JsInteropChecks extends RecursiveVisitor {
} else {
_libraryIsGlobalNamespace = true;
}
super.visitLibrary(lib);
exportChecker.visitLibrary(lib);
super.visitLibrary(node);
exportChecker.visitLibrary(node);
_libraryIsGlobalNamespace = false;
_libraryHasJSAnnotation = false;
_libraryExtensionsIndex = null;
}
@override
void visitProcedure(Procedure procedure) {
void visitProcedure(Procedure node) {
// TODO(joshualitt): Add a check that only supported operators are allowed
// in external extension members / inline classes.
_checkInstanceMemberJSAnnotation(procedure);
if (_classHasJSAnnotation && !procedure.isExternal) {
_checkInstanceMemberJSAnnotation(node);
if (_classHasJSAnnotation && !node.isExternal) {
// If not one of few exceptions, member is not allowed to exclude
// `external` inside of a JS interop class.
if (!(procedure.isAbstract ||
procedure.isFactory ||
procedure.isStatic)) {
_diagnosticsReporter.report(
messageJsInteropNonExternalMember,
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
if (!(node.isAbstract || node.isFactory || node.isStatic)) {
_diagnosticsReporter.report(messageJsInteropNonExternalMember,
node.fileOffset, node.name.text.length, node.fileUri);
}
}
if (!_isJSInteropMember(procedure)) {
_checkDisallowedExternal(procedure);
if (!_isJSInteropMember(node)) {
_checkDisallowedExternal(node);
} else {
// Check JS interop indexing.
if (!procedure.isStatic && procedure.kind == ProcedureKind.Operator) {
_diagnosticsReporter.report(
messageJsInteropOperatorsNotSupported,
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
if (!node.isStatic && node.kind == ProcedureKind.Operator) {
_diagnosticsReporter.report(messageJsInteropOperatorsNotSupported,
node.fileOffset, node.name.text.length, node.fileUri);
}
// Check JS Interop positional and named parameters.
var isAnonymousFactory =
_classHasAnonymousAnnotation && procedure.isFactory;
var isAnonymousFactory = _classHasAnonymousAnnotation && node.isFactory;
if (isAnonymousFactory) {
// ignore: unnecessary_null_comparison
if (procedure.function != null &&
procedure.function.positionalParameters.isNotEmpty) {
var firstPositionalParam = procedure.function.positionalParameters[0];
if (node.function != null &&
node.function.positionalParameters.isNotEmpty) {
var firstPositionalParam = node.function.positionalParameters[0];
_diagnosticsReporter.report(
messageJsInteropAnonymousFactoryPositionalParameters,
firstPositionalParam.fileOffset,
@ -340,97 +333,94 @@ class JsInteropChecks extends RecursiveVisitor {
} else {
// Only factory constructors for anonymous classes are allowed to have
// named parameters.
_checkNoNamedParameters(procedure.function);
_checkNoNamedParameters(node.function);
}
// JS static methods cannot use a JS name with dots.
if (procedure.isStatic && procedure.enclosingClass != null) {
String name = getJSName(procedure);
if (node.isStatic && node.enclosingClass != null) {
String name = getJSName(node);
if (name.contains('.')) {
_diagnosticsReporter.report(
messageJsInteropInvalidStaticClassMemberName,
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
node.fileOffset,
node.name.text.length,
node.fileUri);
}
}
}
if (_classHasStaticInteropAnnotation &&
procedure.isInstanceMember &&
!procedure.isFactory &&
!procedure.isSynthetic) {
node.isInstanceMember &&
!node.isFactory &&
!node.isSynthetic) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropWithInstanceMembers
.withArguments(procedure.enclosingClass!.name),
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
.withArguments(node.enclosingClass!.name),
node.fileOffset,
node.name.text.length,
node.fileUri);
}
if (procedure.isExternal &&
procedure.isExtensionMember &&
_isStaticInteropExtensionMember(procedure) &&
!_isAllowedCustomStaticInteropImplementation(procedure)) {
if (node.isExternal &&
node.isExtensionMember &&
_isStaticInteropExtensionMember(node) &&
!_isAllowedCustomStaticInteropImplementation(node)) {
// If the extension has type parameters of its own, it copies those type
// parameters to the procedure's type parameters (in the front) as well.
// Ignore these for the analysis.
var extensionTypeParams =
_libraryExtensionsIndex![procedure.reference]!.typeParameters;
var procedureTypeParams = List.from(procedure.function.typeParameters);
_libraryExtensionsIndex![node.reference]!.typeParameters;
var procedureTypeParams = List.from(node.function.typeParameters);
procedureTypeParams.removeRange(0, extensionTypeParams.length);
if (procedureTypeParams.isNotEmpty ||
_typeParameterVisitor.usesTypeParameters(procedure)) {
_typeParameterVisitor.usesTypeParameters(node)) {
_diagnosticsReporter.report(
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters,
procedure.fileOffset,
procedure.name.text.length,
procedure.fileUri);
node.fileOffset,
node.name.text.length,
node.fileUri);
}
}
_inTearoff = isTearOffLowering(procedure);
super.visitProcedure(procedure);
_inTearoff = isTearOffLowering(node);
super.visitProcedure(node);
_inTearoff = false;
}
@override
void visitField(Field field) {
if (_classHasStaticInteropAnnotation && field.isInstanceMember) {
void visitField(Field node) {
if (_classHasStaticInteropAnnotation && node.isInstanceMember) {
_diagnosticsReporter.report(
templateJsInteropStaticInteropWithInstanceMembers
.withArguments(field.enclosingClass!.name),
field.fileOffset,
field.name.text.length,
field.fileUri);
.withArguments(node.enclosingClass!.name),
node.fileOffset,
node.name.text.length,
node.fileUri);
}
super.visitField(field);
super.visitField(node);
}
@override
void visitConstructor(Constructor constructor) {
_checkInstanceMemberJSAnnotation(constructor);
if (!constructor.isSynthetic) {
if (_classHasJSAnnotation && !constructor.isExternal) {
void visitConstructor(Constructor node) {
_checkInstanceMemberJSAnnotation(node);
if (!node.isSynthetic) {
if (_classHasJSAnnotation && !node.isExternal) {
// Non-synthetic constructors must be annotated with `external`.
_diagnosticsReporter.report(
messageJsInteropNonExternalConstructor,
constructor.fileOffset,
constructor.name.text.length,
constructor.fileUri);
_diagnosticsReporter.report(messageJsInteropNonExternalConstructor,
node.fileOffset, node.name.text.length, node.fileUri);
}
if (_classHasStaticInteropAnnotation) {
_diagnosticsReporter.report(
messageJsInteropStaticInteropGenerativeConstructor,
constructor.fileOffset,
constructor.name.text.length,
constructor.fileUri);
node.fileOffset,
node.name.text.length,
node.fileUri);
}
}
if (!_isJSInteropMember(constructor)) {
_checkDisallowedExternal(constructor);
if (!_isJSInteropMember(node)) {
_checkDisallowedExternal(node);
} else {
_checkNoNamedParameters(constructor.function);
_checkNoNamedParameters(node.function);
}
}
@ -619,9 +609,11 @@ class JsInteropChecks extends RecursiveVisitor {
assert(member.isExtensionMember);
if (_libraryExtensionsIndex == null) {
_libraryExtensionsIndex = {};
member.enclosingLibrary.extensions.forEach((extension) =>
extension.members.forEach((memberDescriptor) =>
_libraryExtensionsIndex![memberDescriptor.member] = extension));
for (var extension in member.enclosingLibrary.extensions) {
for (var memberDescriptor in extension.members) {
_libraryExtensionsIndex![memberDescriptor.member] = extension;
}
}
}
var onType = _libraryExtensionsIndex![member.reference]!.onType;

View file

@ -185,14 +185,14 @@ List<String> stringAnnotationValues(Expression node) {
var value = constant.fieldValues.values.elementAt(0);
if (value is StringConstant) values.addAll(value.value.split(','));
} else if (argLength > 1) {
throw new ArgumentError('Method expects annotation with at most one '
throw ArgumentError('Method expects annotation with at most one '
'positional argument: $node.');
}
}
} else if (node is ConstructorInvocation) {
var argLength = node.arguments.positional.length;
if (argLength > 1 || node.arguments.named.isNotEmpty) {
throw new ArgumentError('Method expects annotation with at most one '
throw ArgumentError('Method expects annotation with at most one '
'positional argument: $node.');
} else if (argLength == 1) {
var value = node.arguments.positional[0];
@ -233,7 +233,7 @@ List<Library>? calculateTransitiveImportsOfJsInteropIfUsed(
if (jsInteropLibrary == null) return null;
kernel_graph.LibraryGraph graph =
new kernel_graph.LibraryGraph(component.libraries);
kernel_graph.LibraryGraph(component.libraries);
Set<Library> result =
kernel_graph.calculateTransitiveDependenciesOf(graph, {jsInteropLibrary});
return result.toList();

View file

@ -2,8 +2,8 @@
// 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:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
// ignore_for_file: implementation_imports
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show
Message,
@ -13,18 +13,20 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
templateJsInteropExportMemberCollision,
templateJsInteropExportNoExportableMembers;
import 'package:_js_interop_checks/src/js_interop.dart' as js_interop;
import 'package:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
enum ExportStatus {
EXPORT_ERROR,
EXPORTABLE,
NON_EXPORTABLE,
exportError,
exportable,
nonExportable,
}
class _GetSet {
class GetSet {
Member? getter;
Member? setter;
_GetSet(this.getter, this.setter);
GetSet(this.getter, this.setter);
}
class ExportChecker {
@ -44,7 +46,7 @@ class ExportChecker {
///
/// [exports] should be a set of members from the [exportClassToMemberMap]. If
/// missing a getter and/or setter, the corresponding field will be `null`.
_GetSet getGetterSetter(Set<Member> exports) {
GetSet getGetterSetter(Set<Member> exports) {
assert(exports.isNotEmpty && exports.length <= 2);
Member? getter;
Member? setter;
@ -70,7 +72,7 @@ class ExportChecker {
}
}
return _GetSet(getter, setter);
return GetSet(getter, setter);
}
/// Calculates the overrides, including inheritance, for [cls].
@ -95,10 +97,10 @@ class ExportChecker {
]) {
var memberName = member.name.text;
if (member is Procedure && member.isSetter) {
memberMap[memberName + '='] = member;
memberMap['$memberName='] = member;
} else {
if (member is Field && !member.isFinal) {
memberMap[memberName + '='] = member;
memberMap['$memberName='] = member;
}
memberMap[memberName] = member;
}
@ -122,8 +124,8 @@ class ExportChecker {
// when we visited the members and checked their annotations, there's
// nothing to do for this class.
if (!classHasJSExport &&
exportStatus[cls.reference] != ExportStatus.EXPORTABLE) {
exportStatus[cls.reference] = ExportStatus.NON_EXPORTABLE;
exportStatus[cls.reference] != ExportStatus.exportable) {
exportStatus[cls.reference] = ExportStatus.nonExportable;
return;
}
@ -134,7 +136,7 @@ class ExportChecker {
cls.fileOffset,
cls.name.length,
cls.location?.file);
exportStatus[cls.reference] = ExportStatus.EXPORT_ERROR;
exportStatus[cls.reference] = ExportStatus.exportError;
}
_collectOverrides(cls);
@ -195,7 +197,7 @@ class ExportChecker {
cls.fileOffset,
cls.name.length,
cls.location?.file);
exportStatus[cls.reference] = ExportStatus.EXPORT_ERROR;
exportStatus[cls.reference] = ExportStatus.exportError;
}
if (exports.isEmpty) {
@ -204,11 +206,11 @@ class ExportChecker {
cls.fileOffset,
cls.name.length,
cls.location?.file);
exportStatus[cls.reference] = ExportStatus.EXPORT_ERROR;
exportStatus[cls.reference] = ExportStatus.exportError;
}
exportClassToMemberMap[cls.reference] = exports;
exportStatus[cls.reference] ??= ExportStatus.EXPORTABLE;
exportStatus[cls.reference] ??= ExportStatus.exportable;
}
/// Check that the [member] can be exportable if it has an annotation, and if
@ -225,12 +227,12 @@ class ExportChecker {
member.name.text.length,
member.location?.file);
if (cls != null) {
exportStatus[cls.reference] = ExportStatus.EXPORT_ERROR;
exportStatus[cls.reference] = ExportStatus.exportError;
}
} else {
// Mark as exportable so we know that the class has an exportable member
// when we process the class later.
if (cls != null) exportStatus[cls.reference] = ExportStatus.EXPORTABLE;
if (cls != null) exportStatus[cls.reference] = ExportStatus.exportable;
}
}
}
@ -249,34 +251,34 @@ class ExportChecker {
}
extension ExtensionMemberDescriptorExtension on ExtensionMemberDescriptor {
bool get isGetter => this.kind == ExtensionMemberKind.Getter;
bool get isSetter => this.kind == ExtensionMemberKind.Setter;
bool get isMethod => this.kind == ExtensionMemberKind.Method;
bool get isGetter => kind == ExtensionMemberKind.Getter;
bool get isSetter => kind == ExtensionMemberKind.Setter;
bool get isMethod => kind == ExtensionMemberKind.Method;
bool get isExternal => (this.member.asProcedure).isExternal;
bool get isExternal => (member.asProcedure).isExternal;
}
extension ProcedureExtension on Procedure {
// We only care about concrete instance procedures.
bool get exportable =>
!this.isAbstract &&
!this.isStatic &&
!this.isExtensionMember &&
!this.isFactory &&
!this.isExternal &&
this.kind != ProcedureKind.Operator;
!isAbstract &&
!isStatic &&
!isExtensionMember &&
!isFactory &&
!isExternal &&
kind != ProcedureKind.Operator;
}
extension FieldExtension on Field {
// We only care about concrete instance fields.
bool get exportable => !this.isAbstract && !this.isStatic && !this.isExternal;
bool get exportable => !isAbstract && !isStatic && !isExternal;
}
extension MemberExtension on Member {
// Get the property name that this member will be exported as.
String get exportPropertyName {
var rename = js_interop.getJSExportName(this);
return rename.isEmpty ? this.name.text : rename;
return rename.isEmpty ? name.text : rename;
}
bool get exportable =>
@ -297,8 +299,7 @@ extension MemberExtension on Member {
this is Field || (this is Procedure && (this as Procedure).isGetter);
bool get isSetter =>
this.isNonFinalField ||
(this is Procedure && (this as Procedure).isSetter);
isNonFinalField || (this is Procedure && (this as Procedure).isSetter);
bool get isMethod =>
this is Procedure && (this as Procedure).kind == ProcedureKind.Method;

View file

@ -2,6 +2,14 @@
// 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.
// ignore_for_file: implementation_imports
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show
Message,
LocatedMessage,
templateJsInteropExportClassNotMarkedExportable;
import 'package:_js_interop_checks/src/js_interop.dart' as js_interop;
import 'package:front_end/src/fasta/fasta_codes.dart'
show
templateJsInteropExportInvalidInteropTypeArgument,
@ -9,12 +17,6 @@ import 'package:front_end/src/fasta/fasta_codes.dart'
import 'package:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
import 'package:kernel/type_environment.dart';
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show
Message,
LocatedMessage,
templateJsInteropExportClassNotMarkedExportable;
import 'package:_js_interop_checks/src/js_interop.dart' as js_interop;
import 'export_checker.dart';
import 'static_interop_mock_validator.dart';
@ -126,13 +128,16 @@ class ExportCreator extends Transformer {
// This occurs when we deserialize previously compiled modules. Those
// modules may contain export classes, so we need to revisit the classes
// in those previously compiled modules if they are used.
dartClass.procedures
.forEach((member) => _exportChecker.visitMember(member));
dartClass.fields.forEach((member) => _exportChecker.visitMember(member));
for (var member in dartClass.procedures) {
_exportChecker.visitMember(member);
}
for (var member in dartClass.fields) {
_exportChecker.visitMember(member);
}
_exportChecker.visitClass(dartClass);
}
var exportStatus = _exportChecker.exportStatus[dartClass.reference];
if (exportStatus == ExportStatus.NON_EXPORTABLE) {
if (exportStatus == ExportStatus.nonExportable) {
_diagnosticReporter.report(
templateJsInteropExportClassNotMarkedExportable
.withArguments(dartClass.name),
@ -141,7 +146,7 @@ class ExportCreator extends Transformer {
node.location?.file);
return false;
}
return exportStatus == ExportStatus.EXPORTABLE;
return exportStatus == ExportStatus.exportable;
}
/// Create the object literal using the export map that was computed from the

View file

@ -97,15 +97,15 @@ class JsUtilOptimizer extends Transformer {
_listEmptyFactory =
_coreTypes.index.getProcedure('dart:core', 'List', 'empty'),
_staticTypeContext = StatefulStaticTypeContext.stacked(
TypeEnvironment(_coreTypes, hierarchy)) {}
TypeEnvironment(_coreTypes, hierarchy));
@override
visitLibrary(Library lib) {
_inlineExtensionIndex = InlineExtensionIndex(lib);
_staticTypeContext.enterLibrary(lib);
lib.transformChildren(this);
_staticTypeContext.leaveLibrary(lib);
return lib;
visitLibrary(Library node) {
_inlineExtensionIndex = InlineExtensionIndex(node);
_staticTypeContext.enterLibrary(node);
node.transformChildren(this);
_staticTypeContext.leaveLibrary(node);
return node;
}
@override
@ -660,26 +660,27 @@ class InlineExtensionIndex {
if (_extensionMemberIndex != null) return;
_extensionMemberIndex = {};
_shouldTrustType = {};
_library.extensions
.forEach((extension) => extension.members.forEach((descriptor) {
var reference = descriptor.member;
var onType = extension.onType;
Annotatable? cls;
if (onType is InterfaceType) {
cls = onType.classNode;
// For now, `@trustTypes` can only be used on non-inline
// classes.
if (hasTrustTypesAnnotation(cls)) {
_shouldTrustType.add(reference);
}
} else if (onType is InlineType) {
cls = onType.inlineClass;
}
if (cls == null) return;
if (hasJSInteropAnnotation(cls) || hasNativeAnnotation(cls)) {
_extensionMemberIndex![reference] = descriptor;
}
}));
for (var extension in _library.extensions) {
for (var descriptor in extension.members) {
var reference = descriptor.member;
var onType = extension.onType;
Annotatable? cls;
if (onType is InterfaceType) {
cls = onType.classNode;
// For now, `@trustTypes` can only be used on non-inline
// classes.
if (hasTrustTypesAnnotation(cls)) {
_shouldTrustType.add(reference);
}
} else if (onType is InlineType) {
cls = onType.inlineClass;
}
if (cls == null) continue;
if (hasJSInteropAnnotation(cls) || hasNativeAnnotation(cls)) {
_extensionMemberIndex![reference] = descriptor;
}
}
}
}
ExtensionMemberDescriptor? getExtensionDescriptor(Reference reference) {
@ -700,15 +701,15 @@ class InlineExtensionIndex {
if (_inlineMemberIndex != null) return;
_inlineMemberIndex = {};
_inlineClassIndex = {};
_library.inlineClasses.forEach((inlineClass) {
for (var inlineClass in _library.inlineClasses) {
if (hasJSInteropAnnotation(inlineClass)) {
inlineClass.members.forEach((descriptor) {
for (var descriptor in inlineClass.members) {
var reference = descriptor.member;
_inlineMemberIndex![reference] = descriptor;
_inlineClassIndex[reference] = inlineClass;
});
}
}
});
}
}
InlineClassMemberDescriptor? getInlineDescriptor(Reference reference) {

View file

@ -2,6 +2,9 @@
// 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.
// ignore_for_file: implementation_imports
import 'package:_js_interop_checks/src/js_interop.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/clone.dart';
import 'package:kernel/core_types.dart';
@ -9,7 +12,6 @@ import 'package:kernel/kernel.dart';
import 'package:kernel/reference_from_index.dart';
import 'package:kernel/src/constant_replacer.dart';
import 'package:kernel/src/replacement_visitor.dart';
import 'package:_js_interop_checks/src/js_interop.dart';
class _TypeSubstitutor extends ReplacementVisitor {
final Class _javaScriptObject;
@ -36,7 +38,7 @@ class StaticInteropClassEraser extends Transformer {
// Visiting core libraries that don't contain `@staticInterop` adds overhead.
// To avoid this, we use an allowlist that contains libraries that we know use
// `@staticInterop`.
late Set<String> _erasableCoreLibraries = {'ui', '_engine'};
late final Set<String> _erasableCoreLibraries = {'ui', '_engine'};
StaticInteropClassEraser(CoreTypes coreTypes, this.referenceFromIndex,
{String libraryForJavaScriptObject = 'dart:_interceptors',
@ -218,9 +220,9 @@ class StaticInteropClassEraser extends Transformer {
}
@override
DartType visitDartType(DartType type) {
var substitutedType = _getSubstitutedType(type);
return substitutedType != null ? substitutedType : type;
DartType visitDartType(DartType node) {
var substitutedType = _getSubstitutedType(node);
return substitutedType ?? node;
}
@override

View file

@ -2,11 +2,8 @@
// 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:front_end/src/fasta/fasta_codes.dart'
show templateJsInteropStaticInteropMockNotStaticInteropType;
import 'package:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
import 'package:kernel/type_environment.dart';
// ignore_for_file: implementation_imports
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show
Message,
@ -14,6 +11,11 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
templateJsInteropStaticInteropMockMissingGetterOrSetter,
templateJsInteropStaticInteropMockMissingImplements;
import 'package:_js_interop_checks/src/js_interop.dart' as js_interop;
import 'package:front_end/src/fasta/fasta_codes.dart'
show templateJsInteropStaticInteropMockNotStaticInteropType;
import 'package:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
import 'package:kernel/type_environment.dart';
import 'export_checker.dart';
@ -289,9 +291,9 @@ class StaticInteropMockValidator {
}
}
}
cls.supers.forEach((Supertype supertype) {
for (var supertype in cls.supers) {
getAllDescriptors(supertype.classNode);
});
}
}
}