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; |
+ } |
} |