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

Side by Side Diff: pkg/compiler/lib/src/js_backend/js_interop_analysis.dart

Issue 2731163002: Split js interop registration into library/class/member elements (Closed)
Patch Set: Cleanup. Created 3 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Analysis to determine how to generate code for typed JavaScript interop. 5 /// Analysis to determine how to generate code for typed JavaScript interop.
6 library compiler.src.js_backend.js_interop_analysis; 6 library compiler.src.js_backend.js_interop_analysis;
7 7
8 import '../common.dart'; 8 import '../common.dart';
9 import '../constants/values.dart' 9 import '../constants/values.dart'
10 show ConstantValue, ConstructedConstantValue, StringConstantValue; 10 show ConstantValue, ConstructedConstantValue, StringConstantValue;
11 import '../elements/resolution_types.dart' 11 import '../elements/resolution_types.dart'
12 show ResolutionDartType, ResolutionDynamicType, ResolutionFunctionType; 12 show ResolutionDartType, ResolutionDynamicType, ResolutionFunctionType;
13 import '../diagnostics/messages.dart' show MessageKind; 13 import '../diagnostics/messages.dart' show MessageKind;
14 import '../elements/elements.dart' 14 import '../elements/elements.dart'
15 show 15 show
16 ClassElement, 16 ClassElement,
17 Element, 17 Element,
18 FieldElement, 18 FieldElement,
19 FunctionElement,
20 LibraryElement, 19 LibraryElement,
21 ParameterElement, 20 ParameterElement,
21 MemberElement,
22 MethodElement, 22 MethodElement,
23 MetadataAnnotation; 23 MetadataAnnotation;
24 import '../js/js.dart' as jsAst; 24 import '../js/js.dart' as jsAst;
25 import '../js/js.dart' show js; 25 import '../js/js.dart' show js;
26 import '../universe/selector.dart' show Selector; 26 import '../universe/selector.dart' show Selector;
27 import '../universe/world_builder.dart' show SelectorConstraints; 27 import '../universe/world_builder.dart' show SelectorConstraints;
28 import 'backend_helpers.dart' show BackendHelpers; 28 import 'backend_helpers.dart' show BackendHelpers;
29 import 'js_backend.dart' show JavaScriptBackend; 29 import 'js_backend.dart' show JavaScriptBackend;
30 30
31 class JsInteropAnalysis { 31 class JsInteropAnalysis {
(...skipping 18 matching lines...) Expand all
50 nameField = cls.lookupMember('name'); 50 nameField = cls.lookupMember('name');
51 backend.compiler.libraryLoader.libraries 51 backend.compiler.libraryLoader.libraries
52 .forEach(processJsInteropAnnotationsInLibrary); 52 .forEach(processJsInteropAnnotationsInLibrary);
53 } 53 }
54 } 54 }
55 55
56 void onCodegenStart() { 56 void onCodegenStart() {
57 _inCodegen = true; 57 _inCodegen = true;
58 } 58 }
59 59
60 void processJsInteropAnnotation(Element e) { 60 /// Resolves the metadata of [element] and returns the name of the `JS(...)`
61 for (MetadataAnnotation annotation in e.implementation.metadata) { 61 /// annotation for js interop, if found.
62 String processJsInteropAnnotation(Element element) {
63 for (MetadataAnnotation annotation in element.implementation.metadata) {
62 // TODO(johnniwinther): Avoid processing unresolved elements. 64 // TODO(johnniwinther): Avoid processing unresolved elements.
63 if (annotation.constant == null) continue; 65 if (annotation.constant == null) continue;
64 ConstantValue constant = 66 ConstantValue constant =
65 backend.compiler.constants.getConstantValue(annotation.constant); 67 backend.compiler.constants.getConstantValue(annotation.constant);
66 if (constant == null || constant is! ConstructedConstantValue) continue; 68 if (constant == null || constant is! ConstructedConstantValue) continue;
67 ConstructedConstantValue constructedConstant = constant; 69 ConstructedConstantValue constructedConstant = constant;
68 if (constructedConstant.type.element == helpers.jsAnnotationClass) { 70 if (constructedConstant.type.element == helpers.jsAnnotationClass) {
69 ConstantValue value = constructedConstant.fields[nameField]; 71 ConstantValue value = constructedConstant.fields[nameField];
72 String name;
70 if (value.isString) { 73 if (value.isString) {
71 StringConstantValue stringValue = value; 74 StringConstantValue stringValue = value;
72 backend.nativeDataBuilder 75 name = stringValue.primitiveValue.slowToString();
73 .setJsInteropName(e, stringValue.primitiveValue.slowToString());
74 } else { 76 } else {
75 // TODO(jacobr): report a warning if the value is not a String. 77 // TODO(jacobr): report a warning if the value is not a String.
76 backend.nativeDataBuilder.setJsInteropName(e, ''); 78 name = '';
77 } 79 }
78 enabledJsInterop = true; 80 enabledJsInterop = true;
79 return; 81 return name;
80 } 82 }
81 } 83 }
84 return null;
82 } 85 }
83 86
84 bool hasAnonymousAnnotation(Element element) { 87 bool hasAnonymousAnnotation(Element element) {
85 if (backend.helpers.jsAnonymousClass == null) return false; 88 if (backend.helpers.jsAnonymousClass == null) return false;
86 return element.metadata.any((MetadataAnnotation annotation) { 89 return element.metadata.any((MetadataAnnotation annotation) {
87 ConstantValue constant = 90 ConstantValue constant =
88 backend.compiler.constants.getConstantValue(annotation.constant); 91 backend.compiler.constants.getConstantValue(annotation.constant);
89 if (constant == null || constant is! ConstructedConstantValue) 92 if (constant == null || constant is! ConstructedConstantValue)
90 return false; 93 return false;
91 ConstructedConstantValue constructedConstant = constant; 94 ConstructedConstantValue constructedConstant = constant;
92 return constructedConstant.type.element == 95 return constructedConstant.type.element ==
93 backend.helpers.jsAnonymousClass; 96 backend.helpers.jsAnonymousClass;
94 }); 97 });
95 } 98 }
96 99
97 void _checkFunctionParameters(FunctionElement fn) { 100 void _checkFunctionParameters(MethodElement fn) {
98 if (fn.hasFunctionSignature && 101 if (fn.hasFunctionSignature &&
99 fn.functionSignature.optionalParametersAreNamed) { 102 fn.functionSignature.optionalParametersAreNamed) {
100 backend.reporter.reportErrorMessage( 103 backend.reporter.reportErrorMessage(
101 fn, 104 fn,
102 MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS, 105 MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
103 {'method': fn.name}); 106 {'method': fn.name});
104 } 107 }
105 } 108 }
106 109
107 void processJsInteropAnnotationsInLibrary(LibraryElement library) { 110 void processJsInteropAnnotationsInLibrary(LibraryElement library) {
108 processJsInteropAnnotation(library); 111 String libraryName = processJsInteropAnnotation(library);
112 if (libraryName != null) {
113 backend.nativeDataBuilder.setJsInteropLibraryName(library, libraryName);
114 }
109 library.implementation.forEachLocalMember((Element element) { 115 library.implementation.forEachLocalMember((Element element) {
110 processJsInteropAnnotation(element); 116 if (element is MemberElement) {
111 if (element is MethodElement) { 117 String memberName = processJsInteropAnnotation(element);
112 if (!backend.nativeData.isJsInteropMember(element)) return; 118 if (memberName != null) {
113 _checkFunctionParameters(element); 119 backend.nativeDataBuilder.setJsInteropMemberName(element, memberName);
120 }
121
122 if (element is MethodElement) {
123 if (!backend.nativeData.isJsInteropMember(element)) return;
124 _checkFunctionParameters(element);
125 }
114 } 126 }
115 127
116 if (!element.isClass) return; 128 if (!element.isClass) return;
117 129
118 ClassElement classElement = element; 130 ClassElement classElement = element;
131 String className = processJsInteropAnnotation(classElement);
132 if (className != null) {
133 backend.nativeDataBuilder
134 .setJsInteropClassName(classElement, className);
135 }
119 if (!backend.nativeData.isJsInteropClass(classElement)) return; 136 if (!backend.nativeData.isJsInteropClass(classElement)) return;
120 137
121 // Skip classes that are completely unreachable. This should only happen 138 // Skip classes that are completely unreachable. This should only happen
122 // when all of jsinterop types are unreachable from main. 139 // when all of jsinterop types are unreachable from main.
123 if (!backend.compiler.resolutionWorldBuilder 140 if (!backend.compiler.resolutionWorldBuilder
124 .isImplemented(classElement)) { 141 .isImplemented(classElement)) {
125 return; 142 return;
126 } 143 }
127 144
128 if (!classElement.implementsInterface(helpers.jsJavaScriptObjectClass)) { 145 if (!classElement.implementsInterface(helpers.jsJavaScriptObjectClass)) {
129 backend.reporter.reportErrorMessage(classElement, 146 backend.reporter.reportErrorMessage(classElement,
130 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, { 147 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, {
131 'cls': classElement.name, 148 'cls': classElement.name,
132 'superclass': classElement.superclass.name 149 'superclass': classElement.superclass.name
133 }); 150 });
134 } 151 }
135 152
136 classElement.forEachMember((ClassElement classElement, Element member) { 153 classElement
137 processJsInteropAnnotation(member); 154 .forEachMember((ClassElement classElement, MemberElement member) {
155 String memberName = processJsInteropAnnotation(member);
156 if (memberName != null) {
157 backend.nativeDataBuilder.setJsInteropMemberName(element, memberName);
158 }
138 159
139 if (!member.isSynthesized && 160 if (!member.isSynthesized &&
140 backend.nativeData.isJsInteropClass(classElement) && 161 backend.nativeData.isJsInteropClass(classElement) &&
141 member is FunctionElement) { 162 member is MethodElement) {
142 FunctionElement fn = member; 163 MethodElement fn = member;
143 if (!fn.isExternal && 164 if (!fn.isExternal &&
144 !fn.isAbstract && 165 !fn.isAbstract &&
145 !fn.isConstructor && 166 !fn.isConstructor &&
146 !fn.isStatic) { 167 !fn.isStatic) {
147 backend.reporter.reportErrorMessage( 168 backend.reporter.reportErrorMessage(
148 fn, 169 fn,
149 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER, 170 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
150 {'cls': classElement.name, 'member': member.name}); 171 {'cls': classElement.name, 'member': member.name});
151 } 172 }
152 173
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 ResolutionFunctionType buildJsFunctionType() { 218 ResolutionFunctionType buildJsFunctionType() {
198 // TODO(jacobr): consider using codegenWorldBuilder.isChecks to determine th e 219 // TODO(jacobr): consider using codegenWorldBuilder.isChecks to determine th e
199 // range of positional arguments that need to be supported by JavaScript 220 // range of positional arguments that need to be supported by JavaScript
200 // function types. 221 // function types.
201 return new ResolutionFunctionType.synthesized( 222 return new ResolutionFunctionType.synthesized(
202 const ResolutionDynamicType(), 223 const ResolutionDynamicType(),
203 [], 224 [],
204 new List<ResolutionDartType>.filled(16, const ResolutionDynamicType())); 225 new List<ResolutionDartType>.filled(16, const ResolutionDynamicType()));
205 } 226 }
206 } 227 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698