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

Side by Side Diff: pkg/compiler/lib/src/native/resolver.dart

Issue 2782503003: Extract NativeClassResolver from NativeResolutionEnqueuer (Closed)
Patch Set: Remove unused getter. 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 unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/native/enqueue.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token; 5 import 'package:front_end/src/fasta/scanner.dart'
6 show BeginGroupToken, StringToken, Token;
7 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
6 8
7 import '../common.dart'; 9 import '../common.dart';
8 import '../common/backend_api.dart'; 10 import '../common/backend_api.dart';
11 import '../common/resolution.dart';
9 import '../compiler.dart' show Compiler; 12 import '../compiler.dart' show Compiler;
10 import '../constants/values.dart'; 13 import '../constants/values.dart';
11 import '../elements/elements.dart' 14 import '../elements/elements.dart'
12 show 15 show
13 ClassElement, 16 ClassElement,
14 Element, 17 Element,
15 FieldElement, 18 FieldElement,
16 LibraryElement, 19 LibraryElement,
17 MemberElement, 20 MemberElement,
18 MetadataAnnotation, 21 MetadataAnnotation,
19 MethodElement; 22 MethodElement;
23 import '../elements/entities.dart';
20 import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX; 24 import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX;
21 import '../elements/resolution_types.dart' show ResolutionDartType; 25 import '../elements/resolution_types.dart' show ResolutionDartType;
26 import '../js_backend/backend_helpers.dart';
22 import '../js_backend/js_backend.dart'; 27 import '../js_backend/js_backend.dart';
23 import '../js_backend/native_data.dart'; 28 import '../js_backend/native_data.dart';
24 import '../patch_parser.dart'; 29 import '../patch_parser.dart';
25 import '../tree/tree.dart'; 30 import '../tree/tree.dart';
26 import 'behavior.dart'; 31 import 'behavior.dart';
27 32
28 /// Interface for computing native members and [NativeBehavior]s in member code 33 /// Interface for computing native members and [NativeBehavior]s in member code
29 /// based on the AST. 34 /// based on the AST.
30 abstract class NativeDataResolver { 35 abstract class NativeDataResolver {
31 /// Returns `true` if [element] is a JsInterop member. 36 /// Returns `true` if [element] is a JsInterop member.
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 JavaScriptBackend backend = compiler.backend; 376 JavaScriptBackend backend = compiler.backend;
372 ResolutionDartType type = constant.getType(compiler.commonElements); 377 ResolutionDartType type = constant.getType(compiler.commonElements);
373 if (type.element != backend.helpers.jsAnnotationClass) { 378 if (type.element != backend.helpers.jsAnnotationClass) {
374 compiler.reporter 379 compiler.reporter
375 .internalError(annotation, 'Invalid @JS(...) annotation.'); 380 .internalError(annotation, 'Invalid @JS(...) annotation.');
376 } 381 }
377 } 382 }
378 383
379 bool get defaultResult => false; 384 bool get defaultResult => false;
380 } 385 }
386
387 /// Interface for computing all native classes in a set of libraries.
388 abstract class NativeClassResolver {
389 Iterable<ClassEntity> computeNativeClasses(Iterable<LibraryEntity> libraries);
390 }
391
392 class NativeClassResolverImpl implements NativeClassResolver {
393 final DiagnosticReporter _reporter;
394 final Resolution _resolution;
395 final BackendHelpers _helpers;
396 final NativeBasicData _nativeBasicData;
397
398 Map<String, ClassElement> _tagOwner = new Map<String, ClassElement>();
399
400 NativeClassResolverImpl(
401 this._resolution, this._reporter, this._helpers, this._nativeBasicData);
402
403 Iterable<ClassElement> computeNativeClasses(
404 Iterable<LibraryElement> libraries) {
405 Set<ClassElement> nativeClasses = new Set<ClassElement>();
406 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses));
407 if (_helpers.isolateHelperLibrary != null) {
408 _processNativeClassesInLibrary(
409 _helpers.isolateHelperLibrary, nativeClasses);
410 }
411 _processSubclassesOfNativeClasses(libraries, nativeClasses);
412 return nativeClasses;
413 }
414
415 void _processNativeClassesInLibrary(
416 LibraryElement library, Set<ClassElement> nativeClasses) {
417 // Use implementation to ensure the inclusion of injected members.
418 library.implementation.forEachLocalMember((Element element) {
419 if (element.isClass) {
420 ClassElement cls = element;
421 if (_nativeBasicData.isNativeClass(cls)) {
422 _processNativeClass(element, nativeClasses);
423 }
424 }
425 });
426 }
427
428 void _processNativeClass(
429 ClassElement classElement, Set<ClassElement> nativeClasses) {
430 nativeClasses.add(classElement);
431 // Resolve class to ensure the class has valid inheritance info.
432 classElement.ensureResolved(_resolution);
433 // Js Interop interfaces do not have tags.
434 if (_nativeBasicData.isJsInteropClass(classElement)) return;
435 // Since we map from dispatch tags to classes, a dispatch tag must be used
436 // on only one native class.
437 for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) {
438 ClassElement owner = _tagOwner[tag];
439 if (owner != null) {
440 if (owner != classElement) {
441 _reporter.internalError(
442 classElement, "Tag '$tag' already in use by '${owner.name}'");
443 }
444 } else {
445 _tagOwner[tag] = classElement;
446 }
447 }
448 }
449
450 void _processSubclassesOfNativeClasses(
451 Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) {
452 Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
453 // Collect potential subclasses, e.g.
454 //
455 // class B extends foo.A {}
456 //
457 // String "A" has a potential subclass B.
458
459 var potentialExtends = new Map<String, Set<ClassElement>>();
460
461 libraries.forEach((library) {
462 library.implementation.forEachLocalMember((element) {
463 if (element.isClass) {
464 String extendsName = _findExtendsNameOfClass(element);
465 if (extendsName != null) {
466 Set<ClassElement> potentialSubclasses = potentialExtends
467 .putIfAbsent(extendsName, () => new Set<ClassElement>());
468 potentialSubclasses.add(element);
469 }
470 }
471 });
472 });
473
474 // Resolve all the native classes and any classes that might extend them in
475 // [potentialExtends], and then check that the properly resolved class is in
476 // fact a subclass of a native class.
477
478 ClassElement nativeSuperclassOf(ClassElement classElement) {
479 if (_nativeBasicData.isNativeClass(classElement)) return classElement;
480 if (classElement.superclass == null) return null;
481 return nativeSuperclassOf(classElement.superclass);
482 }
483
484 void walkPotentialSubclasses(ClassElement element) {
485 if (nativeClassesAndSubclasses.contains(element)) return;
486 element.ensureResolved(_resolution);
487 ClassElement nativeSuperclass = nativeSuperclassOf(element);
488 if (nativeSuperclass != null) {
489 nativeClassesAndSubclasses.add(element);
490 Set<ClassElement> potentialSubclasses = potentialExtends[element.name];
491 if (potentialSubclasses != null) {
492 potentialSubclasses.forEach(walkPotentialSubclasses);
493 }
494 }
495 }
496
497 nativeClasses.forEach(walkPotentialSubclasses);
498 nativeClasses.addAll(nativeClassesAndSubclasses);
499 }
500
501 /**
502 * Returns the source string of the class named in the extends clause, or
503 * `null` if there is no extends clause.
504 */
505 String _findExtendsNameOfClass(ClassElement classElement) {
506 if (classElement.isResolved) {
507 ClassElement superClass = classElement.superclass;
508 while (superClass != null) {
509 if (!superClass.isUnnamedMixinApplication) {
510 return superClass.name;
511 }
512 superClass = superClass.superclass;
513 }
514 return null;
515 }
516
517 // "class B extends A ... {}" --> "A"
518 // "class B extends foo.A ... {}" --> "A"
519 // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A"
520
521 // We want to avoid calling classElement.parseNode on every class. Doing so
522 // will slightly increase parse time and size and cause compiler errors and
523 // warnings to me emitted in more unused code.
524
525 // An alternative to this code is to extend the API of ClassElement to
526 // expose the name of the extended element.
527
528 // Pattern match the above cases in the token stream.
529 // [abstract] class X extends [id.]* id
530
531 Token skipTypeParameters(Token token) {
532 BeginGroupToken beginGroupToken = token;
533 Token endToken = beginGroupToken.endGroup;
534 return endToken.next;
535 //for (;;) {
536 // token = token.next;
537 // if (token.stringValue == '>') return token.next;
538 // if (token.stringValue == '<') return skipTypeParameters(token);
539 //}
540 }
541
542 String scanForExtendsName(Token token) {
543 if (token.stringValue == 'abstract') token = token.next;
544 if (token.stringValue != 'class') return null;
545 token = token.next;
546 if (!token.isIdentifier()) return null;
547 token = token.next;
548 // class F<X extends B<X>> extends ...
549 if (token.stringValue == '<') {
550 token = skipTypeParameters(token);
551 }
552 if (token.stringValue != 'extends') return null;
553 token = token.next;
554 Token id = token;
555 while (token.kind != Tokens.EOF_TOKEN) {
556 token = token.next;
557 if (token.stringValue != '.') break;
558 token = token.next;
559 if (!token.isIdentifier()) return null;
560 id = token;
561 }
562 // Should be at '{', 'with', 'implements', '<' or 'native'.
563 return id.lexeme;
564 }
565
566 return _reporter.withCurrentElement(classElement, () {
567 return scanForExtendsName(classElement.position);
568 });
569 }
570 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/native/enqueue.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698