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

Unified Diff: pkg/compiler/lib/src/native/resolver.dart

Issue 2782503003: Extract NativeClassResolver from NativeResolutionEnqueuer (Closed)
Patch Set: Remove unused getter. 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/native/enqueue.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/native/resolver.dart
diff --git a/pkg/compiler/lib/src/native/resolver.dart b/pkg/compiler/lib/src/native/resolver.dart
index 557e9698c9920a6297f09a41a6aab771c43e52f6..5d055ccd356883267dd2f0a6a60d668862a1cda7 100644
--- a/pkg/compiler/lib/src/native/resolver.dart
+++ b/pkg/compiler/lib/src/native/resolver.dart
@@ -2,10 +2,13 @@
// 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 'package:front_end/src/fasta/scanner.dart' show StringToken, Token;
+import 'package:front_end/src/fasta/scanner.dart'
+ show BeginGroupToken, StringToken, Token;
+import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
import '../common.dart';
import '../common/backend_api.dart';
+import '../common/resolution.dart';
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../elements/elements.dart'
@@ -17,8 +20,10 @@ import '../elements/elements.dart'
MemberElement,
MetadataAnnotation,
MethodElement;
+import '../elements/entities.dart';
import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX;
import '../elements/resolution_types.dart' show ResolutionDartType;
+import '../js_backend/backend_helpers.dart';
import '../js_backend/js_backend.dart';
import '../js_backend/native_data.dart';
import '../patch_parser.dart';
@@ -378,3 +383,188 @@ class JsInteropAnnotationHandler implements EagerAnnotationHandler<bool> {
bool get defaultResult => false;
}
+
+/// Interface for computing all native classes in a set of libraries.
+abstract class NativeClassResolver {
+ Iterable<ClassEntity> computeNativeClasses(Iterable<LibraryEntity> libraries);
+}
+
+class NativeClassResolverImpl implements NativeClassResolver {
+ final DiagnosticReporter _reporter;
+ final Resolution _resolution;
+ final BackendHelpers _helpers;
+ final NativeBasicData _nativeBasicData;
+
+ Map<String, ClassElement> _tagOwner = new Map<String, ClassElement>();
+
+ NativeClassResolverImpl(
+ this._resolution, this._reporter, this._helpers, this._nativeBasicData);
+
+ Iterable<ClassElement> computeNativeClasses(
+ Iterable<LibraryElement> libraries) {
+ Set<ClassElement> nativeClasses = new Set<ClassElement>();
+ libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses));
+ if (_helpers.isolateHelperLibrary != null) {
+ _processNativeClassesInLibrary(
+ _helpers.isolateHelperLibrary, nativeClasses);
+ }
+ _processSubclassesOfNativeClasses(libraries, nativeClasses);
+ return nativeClasses;
+ }
+
+ void _processNativeClassesInLibrary(
+ LibraryElement library, Set<ClassElement> nativeClasses) {
+ // Use implementation to ensure the inclusion of injected members.
+ library.implementation.forEachLocalMember((Element element) {
+ if (element.isClass) {
+ ClassElement cls = element;
+ if (_nativeBasicData.isNativeClass(cls)) {
+ _processNativeClass(element, nativeClasses);
+ }
+ }
+ });
+ }
+
+ void _processNativeClass(
+ ClassElement classElement, Set<ClassElement> nativeClasses) {
+ nativeClasses.add(classElement);
+ // Resolve class to ensure the class has valid inheritance info.
+ classElement.ensureResolved(_resolution);
+ // Js Interop interfaces do not have tags.
+ if (_nativeBasicData.isJsInteropClass(classElement)) return;
+ // Since we map from dispatch tags to classes, a dispatch tag must be used
+ // on only one native class.
+ for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) {
+ ClassElement owner = _tagOwner[tag];
+ if (owner != null) {
+ if (owner != classElement) {
+ _reporter.internalError(
+ classElement, "Tag '$tag' already in use by '${owner.name}'");
+ }
+ } else {
+ _tagOwner[tag] = classElement;
+ }
+ }
+ }
+
+ void _processSubclassesOfNativeClasses(
+ Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) {
+ Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
+ // Collect potential subclasses, e.g.
+ //
+ // class B extends foo.A {}
+ //
+ // String "A" has a potential subclass B.
+
+ var potentialExtends = new Map<String, Set<ClassElement>>();
+
+ libraries.forEach((library) {
+ library.implementation.forEachLocalMember((element) {
+ if (element.isClass) {
+ String extendsName = _findExtendsNameOfClass(element);
+ if (extendsName != null) {
+ Set<ClassElement> potentialSubclasses = potentialExtends
+ .putIfAbsent(extendsName, () => new Set<ClassElement>());
+ potentialSubclasses.add(element);
+ }
+ }
+ });
+ });
+
+ // Resolve all the native classes and any classes that might extend them in
+ // [potentialExtends], and then check that the properly resolved class is in
+ // fact a subclass of a native class.
+
+ ClassElement nativeSuperclassOf(ClassElement classElement) {
+ if (_nativeBasicData.isNativeClass(classElement)) return classElement;
+ if (classElement.superclass == null) return null;
+ return nativeSuperclassOf(classElement.superclass);
+ }
+
+ void walkPotentialSubclasses(ClassElement element) {
+ if (nativeClassesAndSubclasses.contains(element)) return;
+ element.ensureResolved(_resolution);
+ ClassElement nativeSuperclass = nativeSuperclassOf(element);
+ if (nativeSuperclass != null) {
+ nativeClassesAndSubclasses.add(element);
+ Set<ClassElement> potentialSubclasses = potentialExtends[element.name];
+ if (potentialSubclasses != null) {
+ potentialSubclasses.forEach(walkPotentialSubclasses);
+ }
+ }
+ }
+
+ nativeClasses.forEach(walkPotentialSubclasses);
+ nativeClasses.addAll(nativeClassesAndSubclasses);
+ }
+
+ /**
+ * Returns the source string of the class named in the extends clause, or
+ * `null` if there is no extends clause.
+ */
+ String _findExtendsNameOfClass(ClassElement classElement) {
+ if (classElement.isResolved) {
+ ClassElement superClass = classElement.superclass;
+ while (superClass != null) {
+ if (!superClass.isUnnamedMixinApplication) {
+ return superClass.name;
+ }
+ superClass = superClass.superclass;
+ }
+ return null;
+ }
+
+ // "class B extends A ... {}" --> "A"
+ // "class B extends foo.A ... {}" --> "A"
+ // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A"
+
+ // We want to avoid calling classElement.parseNode on every class. Doing so
+ // will slightly increase parse time and size and cause compiler errors and
+ // warnings to me emitted in more unused code.
+
+ // An alternative to this code is to extend the API of ClassElement to
+ // expose the name of the extended element.
+
+ // Pattern match the above cases in the token stream.
+ // [abstract] class X extends [id.]* id
+
+ Token skipTypeParameters(Token token) {
+ BeginGroupToken beginGroupToken = token;
+ Token endToken = beginGroupToken.endGroup;
+ return endToken.next;
+ //for (;;) {
+ // token = token.next;
+ // if (token.stringValue == '>') return token.next;
+ // if (token.stringValue == '<') return skipTypeParameters(token);
+ //}
+ }
+
+ String scanForExtendsName(Token token) {
+ if (token.stringValue == 'abstract') token = token.next;
+ if (token.stringValue != 'class') return null;
+ token = token.next;
+ if (!token.isIdentifier()) return null;
+ token = token.next;
+ // class F<X extends B<X>> extends ...
+ if (token.stringValue == '<') {
+ token = skipTypeParameters(token);
+ }
+ if (token.stringValue != 'extends') return null;
+ token = token.next;
+ Token id = token;
+ while (token.kind != Tokens.EOF_TOKEN) {
+ token = token.next;
+ if (token.stringValue != '.') break;
+ token = token.next;
+ if (!token.isIdentifier()) return null;
+ id = token;
+ }
+ // Should be at '{', 'with', 'implements', '<' or 'native'.
+ return id.lexeme;
+ }
+
+ return _reporter.withCurrentElement(classElement, () {
+ return scanForExtendsName(classElement.position);
+ });
+ }
+}
« 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