Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Unified Diff: pkg/compiler/lib/src/js_backend/js_interop_analysis.dart

Issue 2855593002: Revert "Move JsInteropAnalysis.onQueueClosed to AnnotationProcessor.processJsInteropAnnotation" (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/js_backend/backend.dart ('k') | pkg/compiler/lib/src/js_backend/native_data.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
index b4f0c76a502dc05dc87e7f9ec477df2dfdfb4c76..480b75d87ad4ac7a31951aa895749aafdc75a3c9 100644
--- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
@@ -5,8 +5,22 @@
/// Analysis to determine how to generate code for typed JavaScript interop.
library compiler.src.js_backend.js_interop_analysis;
+import '../common.dart';
+import '../constants/values.dart'
+ show ConstantValue, ConstructedConstantValue, StringConstantValue;
import '../elements/resolution_types.dart'
show ResolutionDartType, ResolutionDynamicType, ResolutionFunctionType;
+import '../diagnostics/messages.dart' show MessageKind;
+import '../elements/elements.dart'
+ show
+ ClassElement,
+ Element,
+ FieldElement,
+ LibraryElement,
+ ParameterElement,
+ MemberElement,
+ MethodElement,
+ MetadataAnnotation;
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
import '../universe/selector.dart' show Selector;
@@ -16,10 +30,167 @@ import 'js_backend.dart' show JavaScriptBackend;
class JsInteropAnalysis {
final JavaScriptBackend backend;
+ /// The resolved [FieldElement] for `Js.name`.
+ FieldElement nameField;
+ bool enabledJsInterop = false;
+
+ /// Whether the backend is currently processing the codegen queue.
+ bool _inCodegen = false;
+
JsInteropAnalysis(this.backend);
+ void onQueueClosed() {
+ if (_inCodegen) return;
+
+ if (backend.compiler.commonElements.jsAnnotationClass != null) {
+ ClassElement cls = backend.compiler.commonElements.jsAnnotationClass;
+ nameField = cls.lookupMember('name');
+ backend.compiler.libraryLoader.libraries
+ .forEach(processJsInteropAnnotationsInLibrary);
+ }
+ }
+
+ void onCodegenStart() {
+ _inCodegen = true;
+ }
+
+ /// Resolves the metadata of [element] and returns the name of the `JS(...)`
+ /// annotation for js interop, if found.
+ String processJsInteropAnnotation(Element element) {
+ for (MetadataAnnotation annotation in element.implementation.metadata) {
+ // TODO(johnniwinther): Avoid processing unresolved elements.
+ if (annotation.constant == null) continue;
+ ConstantValue constant =
+ backend.compiler.constants.getConstantValue(annotation.constant);
+ if (constant == null || constant is! ConstructedConstantValue) continue;
+ ConstructedConstantValue constructedConstant = constant;
+ if (constructedConstant.type.element ==
+ backend.compiler.commonElements.jsAnnotationClass) {
+ ConstantValue value = constructedConstant.fields[nameField];
+ String name;
+ if (value.isString) {
+ StringConstantValue stringValue = value;
+ name = stringValue.primitiveValue.slowToString();
+ } else {
+ // TODO(jacobr): report a warning if the value is not a String.
+ name = '';
+ }
+ enabledJsInterop = true;
+ return name;
+ }
+ }
+ return null;
+ }
+
+ bool hasAnonymousAnnotation(Element element) {
+ if (backend.compiler.commonElements.jsAnonymousClass == null) return false;
+ return element.metadata.any((MetadataAnnotation annotation) {
+ ConstantValue constant =
+ backend.compiler.constants.getConstantValue(annotation.constant);
+ if (constant == null || constant is! ConstructedConstantValue)
+ return false;
+ ConstructedConstantValue constructedConstant = constant;
+ return constructedConstant.type.element ==
+ backend.compiler.commonElements.jsAnonymousClass;
+ });
+ }
+
+ void _checkFunctionParameters(MethodElement fn) {
+ if (fn.hasFunctionSignature &&
+ fn.functionSignature.optionalParametersAreNamed) {
+ backend.reporter.reportErrorMessage(
+ fn,
+ MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
+ {'method': fn.name});
+ }
+ }
+
+ void processJsInteropAnnotationsInLibrary(LibraryElement library) {
+ String libraryName = processJsInteropAnnotation(library);
+ if (libraryName != null) {
+ backend.nativeDataBuilder.setJsInteropLibraryName(library, libraryName);
+ }
+ library.implementation.forEachLocalMember((Element element) {
+ if (element is MemberElement) {
+ String memberName = processJsInteropAnnotation(element);
+ if (memberName != null) {
+ backend.nativeDataBuilder.setJsInteropMemberName(element, memberName);
+ }
+
+ if (element is MethodElement) {
+ if (!backend.nativeData.isJsInteropMember(element)) return;
+ _checkFunctionParameters(element);
+ }
+ }
+
+ if (!element.isClass) return;
+
+ ClassElement classElement = element;
+ String className = processJsInteropAnnotation(classElement);
+ if (className != null) {
+ backend.nativeDataBuilder
+ .setJsInteropClassName(classElement, className);
+ }
+ if (!backend.nativeData.isJsInteropClass(classElement)) return;
+
+ // Skip classes that are completely unreachable. This should only happen
+ // when all of jsinterop types are unreachable from main.
+ if (!backend.compiler.resolutionWorldBuilder
+ .isImplemented(classElement)) {
+ return;
+ }
+
+ if (!classElement.implementsInterface(
+ backend.compiler.commonElements.jsJavaScriptObjectClass)) {
+ backend.reporter.reportErrorMessage(classElement,
+ MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, {
+ 'cls': classElement.name,
+ 'superclass': classElement.superclass.name
+ });
+ }
+
+ classElement
+ .forEachMember((ClassElement classElement, MemberElement member) {
+ String memberName = processJsInteropAnnotation(member);
+ if (memberName != null) {
+ backend.nativeDataBuilder.setJsInteropMemberName(member, memberName);
+ }
+
+ if (!member.isSynthesized &&
+ backend.nativeData.isJsInteropClass(classElement) &&
+ member is MethodElement) {
+ MethodElement fn = member;
+ if (!fn.isExternal &&
+ !fn.isAbstract &&
+ !fn.isConstructor &&
+ !fn.isStatic) {
+ backend.reporter.reportErrorMessage(
+ fn,
+ MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
+ {'cls': classElement.name, 'member': member.name});
+ }
+
+ if (fn.isFactoryConstructor && hasAnonymousAnnotation(classElement)) {
+ fn.functionSignature
+ .orderedForEachParameter((ParameterElement parameter) {
+ if (!parameter.isNamed) {
+ backend.reporter.reportErrorMessage(
+ parameter,
+ MessageKind
+ .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
+ {'parameter': parameter.name, 'cls': classElement.name});
+ }
+ });
+ } else {
+ _checkFunctionParameters(fn);
+ }
+ }
+ });
+ });
+ }
+
jsAst.Statement buildJsInteropBootstrap() {
- if (!backend.nativeBasicData.isJsInteropUsed) return null;
+ if (!enabledJsInterop) return null;
List<jsAst.Statement> statements = <jsAst.Statement>[];
backend.compiler.codegenWorldBuilder.forEachInvokedName(
(String name, Map<Selector, SelectorConstraints> selectors) {
« no previous file with comments | « pkg/compiler/lib/src/js_backend/backend.dart ('k') | pkg/compiler/lib/src/js_backend/native_data.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698