Chromium Code Reviews| Index: pkg/dev_compiler/lib/src/compiler/extension_types.dart |
| diff --git a/pkg/dev_compiler/lib/src/compiler/extension_types.dart b/pkg/dev_compiler/lib/src/compiler/extension_types.dart |
| index 1e26fb46598c49dc8d9497d8dcc3cfd41001c060..383f7da46a76747c1b739cb2f2935c0c6a0bc9e0 100644 |
| --- a/pkg/dev_compiler/lib/src/compiler/extension_types.dart |
| +++ b/pkg/dev_compiler/lib/src/compiler/extension_types.dart |
| @@ -2,11 +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. |
| +import 'dart:async'; |
| import 'dart:collection'; |
| + |
| import 'package:analyzer/dart/element/element.dart' |
| show ClassElement, CompilationUnitElement, Element; |
| +import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart' show DartType, InterfaceType; |
| -import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| +import 'package:analyzer/src/dart/analysis/driver.dart'; |
| /// Contains information about native JS types (those types provided by the |
| /// implementation) that are also provided by the Dart SDK. |
| @@ -26,66 +29,32 @@ import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| /// This will provide the [Iterable.first] property, without needing to add |
| /// `first` to the `Array.prototype`. |
| class ExtensionTypeSet { |
| - final AnalysisContext _context; |
| + final AnalysisDriver _driver; |
| - // Abstract types that may be implemented by both native and non-native |
| - // classes. |
| + /// Abstract types that may be implemented by both native and non-native |
| + /// classes. |
| final _extensibleTypes = new HashSet<ClassElement>(); |
| - // Concrete native types. |
| + /// Concrete native types. |
| final _nativeTypes = new HashSet<ClassElement>(); |
| - final _pendingLibraries = new HashSet<String>(); |
| - ExtensionTypeSet(this._context) { |
| - // TODO(vsm): Eventually, we want to make this extensible - i.e., find |
| - // annotations in user code as well. It would need to be summarized in |
| - // the element model - not searched this way on every compile. To make this |
| - // a little more efficient now, we do this in two phases. |
| + ExtensionTypeSet._(this._driver); |
| - // First, core types: |
| - // TODO(vsm): If we're analyzing against the main SDK, those |
| - // types are not explicitly annotated. |
| - var types = _context.typeProvider; |
| - _addExtensionType(types.intType, true); |
| - _addExtensionType(types.doubleType, true); |
| - _addExtensionType(types.boolType, true); |
| - _addExtensionType(types.stringType, true); |
| - _addExtensionTypes('dart:_interceptors'); |
| - _addExtensionTypes('dart:_native_typed_data'); |
| - |
| - // These are used natively by dart:html but also not annotated. |
| - _addExtensionTypesForLibrary('dart:core', ['Comparable', 'Map']); |
| - _addExtensionTypesForLibrary('dart:collection', ['ListMixin']); |
| - _addExtensionTypesForLibrary('dart:math', ['Rectangle']); |
| - |
| - // Second, html types - these are only searched if we use dart:html, etc.: |
| - _addPendingExtensionTypes('dart:html'); |
| - _addPendingExtensionTypes('dart:indexed_db'); |
| - _addPendingExtensionTypes('dart:svg'); |
| - _addPendingExtensionTypes('dart:web_audio'); |
| - _addPendingExtensionTypes('dart:web_gl'); |
| - _addPendingExtensionTypes('dart:web_sql'); |
| + /// Collects all supertypes that may themselves contain native subtypes, |
| + /// excluding [Object], for example `List` is implemented by several native |
| + /// types. |
| + LinkedHashSet<ClassElement> collectNativeInterfaces(ClassElement element) { |
| + var types = new LinkedHashSet<ClassElement>(); |
| + _collectNativeInterfaces(element.type, types); |
| + return types; |
| } |
| - void _visitCompilationUnit(CompilationUnitElement unit) { |
| - unit.types.forEach(_visitClass); |
| - } |
| + bool hasNativeSubtype(DartType type) => |
| + isNativeInterface(type.element) || isNativeClass(type.element); |
| - void _visitClass(ClassElement element) { |
| - if (_isNative(element)) { |
| - _addExtensionType(element.type, true); |
| - } |
| - } |
| + bool isNativeClass(Element element) => _nativeTypes.contains(element); |
| - bool _isNative(ClassElement element) { |
| - for (var metadata in element.metadata) { |
| - var e = metadata.element?.enclosingElement; |
| - if (e.name == 'Native' || e.name == 'JsPeerInterface') { |
| - if (e.source.isInSystemLibrary) return true; |
| - } |
| - } |
| - return false; |
| - } |
| + bool isNativeInterface(Element element) => _extensibleTypes.contains(element); |
| void _addExtensionType(InterfaceType t, [bool mustBeNative = false]) { |
| if (t.isObject) return; |
| @@ -104,59 +73,19 @@ class ExtensionTypeSet { |
| _addExtensionType(element.supertype); |
| } |
| - void _addExtensionTypesForLibrary(String libraryUri, List<String> typeNames) { |
| - var sourceFactory = _context.sourceFactory.forUri(libraryUri); |
| - var library = _context.computeLibraryElement(sourceFactory); |
| - for (var typeName in typeNames) { |
| - _addExtensionType(library.getType(typeName).type); |
| - } |
| - } |
| - |
| - void _addExtensionTypes(String libraryUri) { |
| - var sourceFactory = _context.sourceFactory.forUri(libraryUri); |
| - var library = _context.computeLibraryElement(sourceFactory); |
| + Future<Null> _addExtensionTypes(String libraryUri) async { |
| + LibraryElement library = await _computeLibraryByUri(libraryUri); |
| _visitCompilationUnit(library.definingCompilationUnit); |
| library.parts.forEach(_visitCompilationUnit); |
| } |
| - void _addPendingExtensionTypes(String libraryUri) { |
| - _pendingLibraries.add(libraryUri); |
| - } |
| - |
| - bool _processPending(Element element) { |
| - if (_pendingLibraries.isEmpty) return false; |
| - if (element is ClassElement) { |
| - var uri = element.library.source.uri.toString(); |
| - if (_pendingLibraries.contains(uri)) { |
| - // Load all pending libraries |
| - _pendingLibraries.forEach(_addExtensionTypes); |
| - _pendingLibraries.clear(); |
| - return true; |
| - } |
| + Future<Null> _addExtensionTypesForLibrary( |
| + String libraryUri, List<String> typeNames, |
| + [bool mustBeNative = false]) async { |
| + LibraryElement library = await _computeLibraryByUri(libraryUri); |
| + for (var typeName in typeNames) { |
| + _addExtensionType(library.getType(typeName).type, mustBeNative); |
| } |
| - return false; |
| - } |
| - |
| - bool _setContains(HashSet<ClassElement> set, Element element) { |
| - return set.contains(element) || |
| - _processPending(element) && set.contains(element); |
| - } |
| - |
| - bool isNativeClass(Element element) => _setContains(_nativeTypes, element); |
| - |
| - bool isNativeInterface(Element element) => |
| - _setContains(_extensibleTypes, element); |
| - |
| - bool hasNativeSubtype(DartType type) => |
| - isNativeInterface(type.element) || isNativeClass(type.element); |
| - |
| - /// Collects all supertypes that may themselves contain native subtypes, |
| - /// excluding [Object], for example `List` is implemented by several native |
| - /// types. |
| - LinkedHashSet<ClassElement> collectNativeInterfaces(ClassElement element) { |
| - var types = new LinkedHashSet<ClassElement>(); |
| - _collectNativeInterfaces(element.type, types); |
| - return types; |
| } |
| void _collectNativeInterfaces(InterfaceType type, Set<ClassElement> types) { |
| @@ -171,4 +100,62 @@ class ExtensionTypeSet { |
| } |
| _collectNativeInterfaces(element.supertype, types); |
| } |
| + |
| + Future<LibraryElement> _computeLibraryByUri(String libraryUri) async { |
| + return await _driver.resynthesizeLibrary(libraryUri); |
| + } |
| + |
| + Future<Null> _initialize() async { |
|
Jennifer Messerly
2017/03/17 18:33:38
similar comment here; I would prefer to factor thi
scheglov
2017/04/25 17:07:35
Done.
|
| + // TODO(vsm): Eventually, we want to make this extensible - i.e., find |
| + // annotations in user code as well. It would need to be summarized in |
| + // the element model - not searched this way on every compile. To make this |
| + // a little more efficient now, we do this in two phases. |
| + |
| + // First, core types: |
| + // TODO(vsm): If we're analyzing against the main SDK, those |
| + // types are not explicitly annotated. |
| + await _addExtensionTypesForLibrary( |
| + 'dart:core', ['int', 'double', 'bool', 'String'], true); |
| + await _addExtensionTypes('dart:_interceptors'); |
| + await _addExtensionTypes('dart:_native_typed_data'); |
| + |
| + // These are used natively by dart:html but also not annotated. |
| + await _addExtensionTypesForLibrary('dart:core', ['Comparable', 'Map']); |
| + await _addExtensionTypesForLibrary('dart:collection', ['ListMixin']); |
| + await _addExtensionTypesForLibrary('dart:math', ['Rectangle']); |
| + |
| + // Second, html types - these are only searched if we use dart:html, etc.: |
| + await _addExtensionTypes('dart:html'); |
| + await _addExtensionTypes('dart:indexed_db'); |
| + await _addExtensionTypes('dart:svg'); |
| + await _addExtensionTypes('dart:web_audio'); |
| + await _addExtensionTypes('dart:web_gl'); |
| + await _addExtensionTypes('dart:web_sql'); |
| + } |
| + |
| + bool _isNative(ClassElement element) { |
| + for (var metadata in element.metadata) { |
| + var e = metadata.element?.enclosingElement; |
| + if (e.name == 'Native' || e.name == 'JsPeerInterface') { |
| + if (e.source.isInSystemLibrary) return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + void _visitClass(ClassElement element) { |
| + if (_isNative(element)) { |
| + _addExtensionType(element.type, true); |
| + } |
| + } |
| + |
| + void _visitCompilationUnit(CompilationUnitElement unit) { |
| + unit.types.forEach(_visitClass); |
| + } |
| + |
| + static Future<ExtensionTypeSet> create(AnalysisDriver driver) async { |
| + var typeSet = new ExtensionTypeSet._(driver); |
| + await typeSet._initialize(); |
| + return typeSet; |
| + } |
| } |