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

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

Issue 2852603003: Move JsInteropAnalysis.onQueueClosed to AnnotationProcessor.processJsInteropAnnotation (Closed)
Patch Set: Register anonymous classes correctly + add test Created 3 years, 7 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';
9 import '../constants/values.dart'
10 show ConstantValue, ConstructedConstantValue, StringConstantValue;
11 import '../elements/resolution_types.dart' 8 import '../elements/resolution_types.dart'
12 show ResolutionDartType, ResolutionDynamicType, ResolutionFunctionType; 9 show ResolutionDartType, ResolutionDynamicType, ResolutionFunctionType;
13 import '../diagnostics/messages.dart' show MessageKind;
14 import '../elements/elements.dart'
15 show
16 ClassElement,
17 Element,
18 FieldElement,
19 LibraryElement,
20 ParameterElement,
21 MemberElement,
22 MethodElement,
23 MetadataAnnotation;
24 import '../js/js.dart' as jsAst; 10 import '../js/js.dart' as jsAst;
25 import '../js/js.dart' show js; 11 import '../js/js.dart' show js;
26 import '../universe/selector.dart' show Selector; 12 import '../universe/selector.dart' show Selector;
27 import '../universe/world_builder.dart' show SelectorConstraints; 13 import '../universe/world_builder.dart' show SelectorConstraints;
28 import 'js_backend.dart' show JavaScriptBackend; 14 import 'js_backend.dart' show JavaScriptBackend;
29 15
30 class JsInteropAnalysis { 16 class JsInteropAnalysis {
31 final JavaScriptBackend backend; 17 final JavaScriptBackend backend;
32 18
33 /// The resolved [FieldElement] for `Js.name`.
34 FieldElement nameField;
35 bool enabledJsInterop = false;
36
37 /// Whether the backend is currently processing the codegen queue.
38 bool _inCodegen = false;
39
40 JsInteropAnalysis(this.backend); 19 JsInteropAnalysis(this.backend);
41 20
42 void onQueueClosed() {
43 if (_inCodegen) return;
44
45 if (backend.compiler.commonElements.jsAnnotationClass != null) {
46 ClassElement cls = backend.compiler.commonElements.jsAnnotationClass;
47 nameField = cls.lookupMember('name');
48 backend.compiler.libraryLoader.libraries
49 .forEach(processJsInteropAnnotationsInLibrary);
50 }
51 }
52
53 void onCodegenStart() {
54 _inCodegen = true;
55 }
56
57 /// Resolves the metadata of [element] and returns the name of the `JS(...)`
58 /// annotation for js interop, if found.
59 String processJsInteropAnnotation(Element element) {
60 for (MetadataAnnotation annotation in element.implementation.metadata) {
61 // TODO(johnniwinther): Avoid processing unresolved elements.
62 if (annotation.constant == null) continue;
63 ConstantValue constant =
64 backend.compiler.constants.getConstantValue(annotation.constant);
65 if (constant == null || constant is! ConstructedConstantValue) continue;
66 ConstructedConstantValue constructedConstant = constant;
67 if (constructedConstant.type.element ==
68 backend.compiler.commonElements.jsAnnotationClass) {
69 ConstantValue value = constructedConstant.fields[nameField];
70 String name;
71 if (value.isString) {
72 StringConstantValue stringValue = value;
73 name = stringValue.primitiveValue.slowToString();
74 } else {
75 // TODO(jacobr): report a warning if the value is not a String.
76 name = '';
77 }
78 enabledJsInterop = true;
79 return name;
80 }
81 }
82 return null;
83 }
84
85 bool hasAnonymousAnnotation(Element element) {
86 if (backend.compiler.commonElements.jsAnonymousClass == null) return false;
87 return element.metadata.any((MetadataAnnotation annotation) {
88 ConstantValue constant =
89 backend.compiler.constants.getConstantValue(annotation.constant);
90 if (constant == null || constant is! ConstructedConstantValue)
91 return false;
92 ConstructedConstantValue constructedConstant = constant;
93 return constructedConstant.type.element ==
94 backend.compiler.commonElements.jsAnonymousClass;
95 });
96 }
97
98 void _checkFunctionParameters(MethodElement fn) {
99 if (fn.hasFunctionSignature &&
100 fn.functionSignature.optionalParametersAreNamed) {
101 backend.reporter.reportErrorMessage(
102 fn,
103 MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
104 {'method': fn.name});
105 }
106 }
107
108 void processJsInteropAnnotationsInLibrary(LibraryElement library) {
109 String libraryName = processJsInteropAnnotation(library);
110 if (libraryName != null) {
111 backend.nativeDataBuilder.setJsInteropLibraryName(library, libraryName);
112 }
113 library.implementation.forEachLocalMember((Element element) {
114 if (element is MemberElement) {
115 String memberName = processJsInteropAnnotation(element);
116 if (memberName != null) {
117 backend.nativeDataBuilder.setJsInteropMemberName(element, memberName);
118 }
119
120 if (element is MethodElement) {
121 if (!backend.nativeData.isJsInteropMember(element)) return;
122 _checkFunctionParameters(element);
123 }
124 }
125
126 if (!element.isClass) return;
127
128 ClassElement classElement = element;
129 String className = processJsInteropAnnotation(classElement);
130 if (className != null) {
131 backend.nativeDataBuilder
132 .setJsInteropClassName(classElement, className);
133 }
134 if (!backend.nativeData.isJsInteropClass(classElement)) return;
135
136 // Skip classes that are completely unreachable. This should only happen
137 // when all of jsinterop types are unreachable from main.
138 if (!backend.compiler.resolutionWorldBuilder
139 .isImplemented(classElement)) {
140 return;
141 }
142
143 if (!classElement.implementsInterface(
144 backend.compiler.commonElements.jsJavaScriptObjectClass)) {
145 backend.reporter.reportErrorMessage(classElement,
146 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, {
147 'cls': classElement.name,
148 'superclass': classElement.superclass.name
149 });
150 }
151
152 classElement
153 .forEachMember((ClassElement classElement, MemberElement member) {
154 String memberName = processJsInteropAnnotation(member);
155 if (memberName != null) {
156 backend.nativeDataBuilder.setJsInteropMemberName(member, memberName);
157 }
158
159 if (!member.isSynthesized &&
160 backend.nativeData.isJsInteropClass(classElement) &&
161 member is MethodElement) {
162 MethodElement fn = member;
163 if (!fn.isExternal &&
164 !fn.isAbstract &&
165 !fn.isConstructor &&
166 !fn.isStatic) {
167 backend.reporter.reportErrorMessage(
168 fn,
169 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
170 {'cls': classElement.name, 'member': member.name});
171 }
172
173 if (fn.isFactoryConstructor && hasAnonymousAnnotation(classElement)) {
174 fn.functionSignature
175 .orderedForEachParameter((ParameterElement parameter) {
176 if (!parameter.isNamed) {
177 backend.reporter.reportErrorMessage(
178 parameter,
179 MessageKind
180 .JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS ,
181 {'parameter': parameter.name, 'cls': classElement.name});
182 }
183 });
184 } else {
185 _checkFunctionParameters(fn);
186 }
187 }
188 });
189 });
190 }
191
192 jsAst.Statement buildJsInteropBootstrap() { 21 jsAst.Statement buildJsInteropBootstrap() {
193 if (!enabledJsInterop) return null; 22 if (!backend.nativeBasicData.isJsInteropUsed) return null;
194 List<jsAst.Statement> statements = <jsAst.Statement>[]; 23 List<jsAst.Statement> statements = <jsAst.Statement>[];
195 backend.compiler.codegenWorldBuilder.forEachInvokedName( 24 backend.compiler.codegenWorldBuilder.forEachInvokedName(
196 (String name, Map<Selector, SelectorConstraints> selectors) { 25 (String name, Map<Selector, SelectorConstraints> selectors) {
197 selectors.forEach((Selector selector, SelectorConstraints constraints) { 26 selectors.forEach((Selector selector, SelectorConstraints constraints) {
198 if (selector.isClosureCall) { 27 if (selector.isClosureCall) {
199 // TODO(jacobr): support named arguments. 28 // TODO(jacobr): support named arguments.
200 if (selector.namedArgumentCount > 0) return; 29 if (selector.namedArgumentCount > 0) return;
201 int argumentCount = selector.argumentCount; 30 int argumentCount = selector.argumentCount;
202 var candidateParameterNames = 31 var candidateParameterNames =
203 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 32 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
(...skipping 13 matching lines...) Expand all
217 ResolutionFunctionType buildJsFunctionType() { 46 ResolutionFunctionType buildJsFunctionType() {
218 // TODO(jacobr): consider using codegenWorldBuilder.isChecks to determine th e 47 // TODO(jacobr): consider using codegenWorldBuilder.isChecks to determine th e
219 // range of positional arguments that need to be supported by JavaScript 48 // range of positional arguments that need to be supported by JavaScript
220 // function types. 49 // function types.
221 return new ResolutionFunctionType.synthesized( 50 return new ResolutionFunctionType.synthesized(
222 const ResolutionDynamicType(), 51 const ResolutionDynamicType(),
223 [], 52 [],
224 new List<ResolutionDartType>.filled(16, const ResolutionDynamicType())); 53 new List<ResolutionDartType>.filled(16, const ResolutionDynamicType()));
225 } 54 }
226 } 55 }
OLDNEW
« 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