Index: pkg/compiler/lib/src/elements/common.dart |
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart |
index 13ea3b6ccad5776ccb782444d5f1e8fd8745bf23..8c8c4ffb2085b2f01d3a44f7b7c70e91a9c2a8b5 100644 |
--- a/pkg/compiler/lib/src/elements/common.dart |
+++ b/pkg/compiler/lib/src/elements/common.dart |
@@ -1,472 +1,472 @@ |
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
-// 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. |
- |
-/// Mixins that implement convenience methods on [Element] subclasses. |
- |
-library elements.common; |
- |
-import '../dart2jslib.dart' show Compiler, isPrivateName; |
-import '../dart_types.dart' show DartType, InterfaceType, FunctionType; |
-import '../util/util.dart' show Link; |
- |
-import 'elements.dart'; |
- |
-abstract class ElementCommon implements Element { |
- @override |
- bool get isLibrary => kind == ElementKind.LIBRARY; |
- |
- @override |
- bool get isCompilationUnit => kind == ElementKind.COMPILATION_UNIT; |
- |
- @override |
- bool get isPrefix => kind == ElementKind.PREFIX; |
- |
- @override |
- bool get isClass => kind == ElementKind.CLASS; |
- |
- @override |
- bool get isTypeVariable => kind == ElementKind.TYPE_VARIABLE; |
- |
- @override |
- bool get isTypedef => kind == ElementKind.TYPEDEF; |
- |
- @override |
- bool get isFunction => kind == ElementKind.FUNCTION; |
- |
- @override |
- bool get isAccessor => isGetter || isSetter; |
- |
- @override |
- bool get isGetter => kind == ElementKind.GETTER; |
- |
- @override |
- bool get isSetter => kind == ElementKind.SETTER; |
- |
- @override |
- bool get isConstructor => isGenerativeConstructor || isFactoryConstructor; |
- |
- @override |
- bool get isGenerativeConstructor => |
- kind == ElementKind.GENERATIVE_CONSTRUCTOR; |
- |
- @override |
- bool get isGenerativeConstructorBody => |
- kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY; |
- |
- @override |
- bool get isVariable => kind == ElementKind.VARIABLE; |
- |
- @override |
- bool get isField => kind == ElementKind.FIELD; |
- |
- @override |
- bool get isAbstractField => kind == ElementKind.ABSTRACT_FIELD; |
- |
- @override |
- bool get isParameter => kind == ElementKind.PARAMETER; |
- |
- @override |
- bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL; |
- |
- @override |
- bool get isErroneous => kind == ElementKind.ERROR; |
- |
- @override |
- bool get isAmbiguous => kind == ElementKind.AMBIGUOUS; |
- |
- @override |
- bool get isWarnOnUse => kind == ElementKind.WARN_ON_USE; |
- |
- @override |
- bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; |
- |
- @override |
- Element get declaration => this; |
- |
- @override |
- Element get implementation => this; |
- |
- @override |
- bool get isDeclaration => true; |
- |
- @override |
- bool get isPatched => false; |
- |
- @override |
- bool get isPatch => false; |
- |
- @override |
- bool get isImplementation => true; |
- |
- @override |
- bool get isInjected => !isPatch && implementationLibrary.isPatch; |
- |
- @override |
- Element get patch { |
- throw new UnsupportedError('patch is not supported on $this'); |
- } |
- |
- @override |
- Element get origin { |
- throw new UnsupportedError('origin is not supported on $this'); |
- } |
-} |
- |
-abstract class LibraryElementCommon implements LibraryElement { |
- @override |
- bool get isDartCore => canonicalUri == Compiler.DART_CORE; |
- |
- @override |
- bool get isPlatformLibrary => canonicalUri.scheme == 'dart'; |
- |
- @override |
- bool get isPackageLibrary => canonicalUri.scheme == 'package'; |
- |
- @override |
- bool get isInternalLibrary => |
- isPlatformLibrary && canonicalUri.path.startsWith('_'); |
-} |
- |
-abstract class ClassElementCommon implements ClassElement { |
- |
- @override |
- Link<DartType> get allSupertypes => allSupertypesAndSelf.supertypes; |
- |
- @override |
- int get hierarchyDepth => allSupertypesAndSelf.maxDepth; |
- |
- @override |
- InterfaceType asInstanceOf(ClassElement cls) { |
- if (cls == this) return thisType; |
- return allSupertypesAndSelf.asInstanceOf(cls); |
- } |
- |
- @override |
- ConstructorElement lookupConstructor(String name) { |
- Element result = localLookup(name); |
- return result != null && result.isConstructor ? result : null; |
- } |
- |
- |
- /** |
- * Find the first member in the class chain with the given [memberName]. |
- * |
- * This method is NOT to be used for resolving |
- * unqualified sends because it does not implement the scoping |
- * rules, where library scope comes before superclass scope. |
- * |
- * When called on the implementation element both members declared in the |
- * origin and the patch class are returned. |
- */ |
- Element lookupByName(Name memberName) { |
- return internalLookupByName(memberName, isSuperLookup: false); |
- } |
- |
- Element lookupSuperByName(Name memberName) { |
- return internalLookupByName(memberName, isSuperLookup: true); |
- } |
- |
- Element internalLookupByName(Name memberName, {bool isSuperLookup}) { |
- String name = memberName.text; |
- bool isPrivate = memberName.isPrivate; |
- LibraryElement library = memberName.library; |
- for (ClassElement current = isSuperLookup ? superclass : this; |
- current != null; |
- current = current.superclass) { |
- Element member = current.lookupLocalMember(name); |
- if (member == null && current.isPatched) { |
- // Doing lookups on selectors is done after resolution, so it |
- // is safe to look in the patch class. |
- member = current.patch.lookupLocalMember(name); |
- } |
- if (member == null) continue; |
- // Private members from a different library are not visible. |
- if (isPrivate && !identical(library, member.library)) continue; |
- // Static members are not inherited. |
- if (member.isStatic && !identical(this, current)) continue; |
- // If we find an abstract field we have to make sure that it has |
- // the getter or setter part we're actually looking |
- // for. Otherwise, we continue up the superclass chain. |
- if (member.isAbstractField) { |
- AbstractFieldElement field = member; |
- FunctionElement getter = field.getter; |
- FunctionElement setter = field.setter; |
- if (memberName.isSetter) { |
- // Abstract members can be defined in a super class. |
- if (setter != null && !setter.isAbstract) { |
- return setter; |
- } |
- } else { |
- if (getter != null && !getter.isAbstract) { |
- return getter; |
- } |
- } |
- // Abstract members can be defined in a super class. |
- } else if (!member.isAbstract) { |
- return member; |
- } |
- } |
- return null; |
- } |
- |
- /** |
- * Find the first member in the class chain with the given |
- * [memberName]. This method is NOT to be used for resolving |
- * unqualified sends because it does not implement the scoping |
- * rules, where library scope comes before superclass scope. |
- */ |
- @override |
- Element lookupMember(String memberName) { |
- Element localMember = lookupLocalMember(memberName); |
- return localMember == null ? lookupSuperMember(memberName) : localMember; |
- } |
- |
- @override |
- Link<Element> get constructors { |
- // TODO(ajohnsen): See if we can avoid this method at some point. |
- Link<Element> result = const Link<Element>(); |
- // TODO(johnniwinther): Should we include injected constructors? |
- forEachMember((_, Element member) { |
- if (member.isConstructor) result = result.prepend(member); |
- }); |
- return result; |
- } |
- |
- /** |
- * Lookup super members for the class. This will ignore constructors. |
- */ |
- @override |
- Element lookupSuperMember(String memberName) { |
- return lookupSuperMemberInLibrary(memberName, library); |
- } |
- |
- /** |
- * Lookup super members for the class that is accessible in [library]. |
- * This will ignore constructors. |
- */ |
- @override |
- Element lookupSuperMemberInLibrary(String memberName, |
- LibraryElement library) { |
- bool isPrivate = isPrivateName(memberName); |
- for (ClassElement s = superclass; s != null; s = s.superclass) { |
- // Private members from a different library are not visible. |
- if (isPrivate && !identical(library, s.library)) continue; |
- Element e = s.lookupLocalMember(memberName); |
- if (e == null) continue; |
- // Static members are not inherited. |
- if (e.isStatic) continue; |
- return e; |
- } |
- return null; |
- } |
- |
- /** |
- * Lookup local members in the class. This will ignore constructors. |
- */ |
- @override |
- Element lookupLocalMember(String memberName) { |
- var result = localLookup(memberName); |
- if (result != null && result.isConstructor) return null; |
- return result; |
- } |
- |
- /** |
- * Runs through all members of this class. |
- * |
- * The enclosing class is passed to the callback. This is useful when |
- * [includeSuperAndInjectedMembers] is [:true:]. |
- * |
- * When called on an implementation element both the members in the origin |
- * and patch class are included. |
- */ |
- // TODO(johnniwinther): Clean up lookup to get rid of the include predicates. |
- @override |
- void forEachMember(void f(ClassElement enclosingClass, Element member), |
- {includeBackendMembers: false, |
- includeSuperAndInjectedMembers: false}) { |
- bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch; |
- ClassElement classElement = declaration; |
- do { |
- // Iterate through the members in textual order, which requires |
- // to reverse the data structure [localMembers] we created. |
- // Textual order may be important for certain operations, for |
- // example when emitting the initializers of fields. |
- classElement.forEachLocalMember((e) => f(classElement, e)); |
- if (includeBackendMembers) { |
- classElement.forEachBackendMember((e) => f(classElement, e)); |
- } |
- if (includeInjectedMembers) { |
- if (classElement.patch != null) { |
- classElement.patch.forEachLocalMember((e) { |
- if (!e.isPatch) f(classElement, e); |
- }); |
- } |
- } |
- classElement = includeSuperAndInjectedMembers |
- ? classElement.superclass |
- : null; |
- } while (classElement != null); |
- } |
- |
- /** |
- * Runs through all instance-field members of this class. |
- * |
- * The enclosing class is passed to the callback. This is useful when |
- * [includeSuperAndInjectedMembers] is [:true:]. |
- * |
- * When called on the implementation element both the fields declared in the |
- * origin and in the patch are included. |
- */ |
- @override |
- void forEachInstanceField(void f(ClassElement enclosingClass, |
- FieldElement field), |
- {bool includeSuperAndInjectedMembers: false}) { |
- // Filters so that [f] is only invoked with instance fields. |
- void fieldFilter(ClassElement enclosingClass, Element member) { |
- if (member.isInstanceMember && member.kind == ElementKind.FIELD) { |
- f(enclosingClass, member); |
- } |
- } |
- |
- forEachMember(fieldFilter, |
- includeSuperAndInjectedMembers: includeSuperAndInjectedMembers); |
- } |
- |
- /// Similar to [forEachInstanceField] but visits static fields. |
- @override |
- void forEachStaticField(void f(ClassElement enclosingClass, Element field)) { |
- // Filters so that [f] is only invoked with static fields. |
- void fieldFilter(ClassElement enclosingClass, Element member) { |
- if (!member.isInstanceMember && member.kind == ElementKind.FIELD) { |
- f(enclosingClass, member); |
- } |
- } |
- |
- forEachMember(fieldFilter); |
- } |
- |
- /** |
- * Returns true if the [fieldMember] shadows another field. The given |
- * [fieldMember] must be a member of this class, i.e. if there is a field of |
- * the same name in the superclass chain. |
- * |
- * This method also works if the [fieldMember] is private. |
- */ |
- @override |
- bool hasFieldShadowedBy(Element fieldMember) { |
- assert(fieldMember.isField); |
- String fieldName = fieldMember.name; |
- bool isPrivate = isPrivateName(fieldName); |
- LibraryElement memberLibrary = fieldMember.library; |
- ClassElement lookupClass = this.superclass; |
- while (lookupClass != null) { |
- Element foundMember = lookupClass.lookupLocalMember(fieldName); |
- if (foundMember != null) { |
- if (foundMember.isField) { |
- if (!isPrivate || memberLibrary == foundMember.library) { |
- // Private fields can only be shadowed by a field declared in the |
- // same library. |
- return true; |
- } |
- } |
- } |
- lookupClass = lookupClass.superclass; |
- } |
- return false; |
- } |
- |
- @override |
- bool implementsInterface(ClassElement intrface) { |
- for (DartType implementedInterfaceType in allSupertypes) { |
- ClassElement implementedInterface = implementedInterfaceType.element; |
- if (identical(implementedInterface, intrface)) { |
- return true; |
- } |
- } |
- return false; |
- } |
- |
- /** |
- * Returns true if [this] is a subclass of [cls]. |
- * |
- * This method is not to be used for checking type hierarchy and |
- * assignments, because it does not take parameterized types into |
- * account. |
- */ |
- bool isSubclassOf(ClassElement cls) { |
- // Use [declaration] for both [this] and [cls], because |
- // declaration classes hold the superclass hierarchy. |
- cls = cls.declaration; |
- for (ClassElement s = declaration; s != null; s = s.superclass) { |
- if (identical(s, cls)) return true; |
- } |
- return false; |
- } |
- |
- FunctionType get callType { |
- MemberSignature member = |
- lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME)); |
- return member != null && member.isMethod ? member.type : null; |
- } |
-} |
- |
-abstract class FunctionSignatureCommon implements FunctionSignature { |
- void forEachRequiredParameter(void function(Element parameter)) { |
- requiredParameters.forEach(function); |
- } |
- |
- void forEachOptionalParameter(void function(Element parameter)) { |
- optionalParameters.forEach(function); |
- } |
- |
- Element get firstOptionalParameter => optionalParameters.first; |
- |
- void forEachParameter(void function(Element parameter)) { |
- forEachRequiredParameter(function); |
- forEachOptionalParameter(function); |
- } |
- |
- void orderedForEachParameter(void function(Element parameter)) { |
- forEachRequiredParameter(function); |
- orderedOptionalParameters.forEach(function); |
- } |
- |
- int get parameterCount => requiredParameterCount + optionalParameterCount; |
- |
- /** |
- * Check whether a function with this signature can be used instead of a |
- * function with signature [signature] without causing a `noSuchMethod` |
- * exception/call. |
- */ |
- bool isCompatibleWith(FunctionSignature signature) { |
- if (optionalParametersAreNamed) { |
- if (!signature.optionalParametersAreNamed) { |
- return requiredParameterCount == signature.parameterCount; |
- } |
- // If both signatures have named parameters, then they must have |
- // the same number of required parameters, and the names in |
- // [signature] must all be in [:this:]. |
- if (requiredParameterCount != signature.requiredParameterCount) { |
- return false; |
- } |
- Set<String> names = optionalParameters.map( |
- (Element element) => element.name).toSet(); |
- for (Element namedParameter in signature.optionalParameters) { |
- if (!names.contains(namedParameter.name)) { |
- return false; |
- } |
- } |
- } else { |
- if (signature.optionalParametersAreNamed) return false; |
- // There must be at least as many arguments as in the other signature, but |
- // this signature must not have more required parameters. Having more |
- // optional parameters is not a problem, they simply are never provided |
- // by call sites of a call to a method with the other signature. |
- int otherTotalCount = signature.parameterCount; |
- return requiredParameterCount <= otherTotalCount |
- && parameterCount >= otherTotalCount; |
- } |
- return true; |
- } |
-} |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// 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. |
+ |
+/// Mixins that implement convenience methods on [Element] subclasses. |
+ |
+library elements.common; |
+ |
+import '../dart2jslib.dart' show Compiler, isPrivateName; |
+import '../dart_types.dart' show DartType, InterfaceType, FunctionType; |
+import '../util/util.dart' show Link; |
+ |
+import 'elements.dart'; |
+ |
+abstract class ElementCommon implements Element { |
+ @override |
+ bool get isLibrary => kind == ElementKind.LIBRARY; |
+ |
+ @override |
+ bool get isCompilationUnit => kind == ElementKind.COMPILATION_UNIT; |
+ |
+ @override |
+ bool get isPrefix => kind == ElementKind.PREFIX; |
+ |
+ @override |
+ bool get isClass => kind == ElementKind.CLASS; |
+ |
+ @override |
+ bool get isTypeVariable => kind == ElementKind.TYPE_VARIABLE; |
+ |
+ @override |
+ bool get isTypedef => kind == ElementKind.TYPEDEF; |
+ |
+ @override |
+ bool get isFunction => kind == ElementKind.FUNCTION; |
+ |
+ @override |
+ bool get isAccessor => isGetter || isSetter; |
+ |
+ @override |
+ bool get isGetter => kind == ElementKind.GETTER; |
+ |
+ @override |
+ bool get isSetter => kind == ElementKind.SETTER; |
+ |
+ @override |
+ bool get isConstructor => isGenerativeConstructor || isFactoryConstructor; |
+ |
+ @override |
+ bool get isGenerativeConstructor => |
+ kind == ElementKind.GENERATIVE_CONSTRUCTOR; |
+ |
+ @override |
+ bool get isGenerativeConstructorBody => |
+ kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY; |
+ |
+ @override |
+ bool get isVariable => kind == ElementKind.VARIABLE; |
+ |
+ @override |
+ bool get isField => kind == ElementKind.FIELD; |
+ |
+ @override |
+ bool get isAbstractField => kind == ElementKind.ABSTRACT_FIELD; |
+ |
+ @override |
+ bool get isParameter => kind == ElementKind.PARAMETER; |
+ |
+ @override |
+ bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL; |
+ |
+ @override |
+ bool get isErroneous => kind == ElementKind.ERROR; |
+ |
+ @override |
+ bool get isAmbiguous => kind == ElementKind.AMBIGUOUS; |
+ |
+ @override |
+ bool get isWarnOnUse => kind == ElementKind.WARN_ON_USE; |
+ |
+ @override |
+ bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; |
+ |
+ @override |
+ Element get declaration => this; |
+ |
+ @override |
+ Element get implementation => this; |
+ |
+ @override |
+ bool get isDeclaration => true; |
+ |
+ @override |
+ bool get isPatched => false; |
+ |
+ @override |
+ bool get isPatch => false; |
+ |
+ @override |
+ bool get isImplementation => true; |
+ |
+ @override |
+ bool get isInjected => !isPatch && implementationLibrary.isPatch; |
+ |
+ @override |
+ Element get patch { |
+ throw new UnsupportedError('patch is not supported on $this'); |
+ } |
+ |
+ @override |
+ Element get origin { |
+ throw new UnsupportedError('origin is not supported on $this'); |
+ } |
+} |
+ |
+abstract class LibraryElementCommon implements LibraryElement { |
+ @override |
+ bool get isDartCore => canonicalUri == Compiler.DART_CORE; |
+ |
+ @override |
+ bool get isPlatformLibrary => canonicalUri.scheme == 'dart'; |
+ |
+ @override |
+ bool get isPackageLibrary => canonicalUri.scheme == 'package'; |
+ |
+ @override |
+ bool get isInternalLibrary => |
+ isPlatformLibrary && canonicalUri.path.startsWith('_'); |
+} |
+ |
+abstract class ClassElementCommon implements ClassElement { |
+ |
+ @override |
+ Link<DartType> get allSupertypes => allSupertypesAndSelf.supertypes; |
+ |
+ @override |
+ int get hierarchyDepth => allSupertypesAndSelf.maxDepth; |
+ |
+ @override |
+ InterfaceType asInstanceOf(ClassElement cls) { |
+ if (cls == this) return thisType; |
+ return allSupertypesAndSelf.asInstanceOf(cls); |
+ } |
+ |
+ @override |
+ ConstructorElement lookupConstructor(String name) { |
+ Element result = localLookup(name); |
+ return result != null && result.isConstructor ? result : null; |
+ } |
+ |
+ |
+ /** |
+ * Find the first member in the class chain with the given [memberName]. |
+ * |
+ * This method is NOT to be used for resolving |
+ * unqualified sends because it does not implement the scoping |
+ * rules, where library scope comes before superclass scope. |
+ * |
+ * When called on the implementation element both members declared in the |
+ * origin and the patch class are returned. |
+ */ |
+ Element lookupByName(Name memberName) { |
+ return internalLookupByName(memberName, isSuperLookup: false); |
+ } |
+ |
+ Element lookupSuperByName(Name memberName) { |
+ return internalLookupByName(memberName, isSuperLookup: true); |
+ } |
+ |
+ Element internalLookupByName(Name memberName, {bool isSuperLookup}) { |
+ String name = memberName.text; |
+ bool isPrivate = memberName.isPrivate; |
+ LibraryElement library = memberName.library; |
+ for (ClassElement current = isSuperLookup ? superclass : this; |
+ current != null; |
+ current = current.superclass) { |
+ Element member = current.lookupLocalMember(name); |
+ if (member == null && current.isPatched) { |
+ // Doing lookups on selectors is done after resolution, so it |
+ // is safe to look in the patch class. |
+ member = current.patch.lookupLocalMember(name); |
+ } |
+ if (member == null) continue; |
+ // Private members from a different library are not visible. |
+ if (isPrivate && !identical(library, member.library)) continue; |
+ // Static members are not inherited. |
+ if (member.isStatic && !identical(this, current)) continue; |
+ // If we find an abstract field we have to make sure that it has |
+ // the getter or setter part we're actually looking |
+ // for. Otherwise, we continue up the superclass chain. |
+ if (member.isAbstractField) { |
+ AbstractFieldElement field = member; |
+ FunctionElement getter = field.getter; |
+ FunctionElement setter = field.setter; |
+ if (memberName.isSetter) { |
+ // Abstract members can be defined in a super class. |
+ if (setter != null && !setter.isAbstract) { |
+ return setter; |
+ } |
+ } else { |
+ if (getter != null && !getter.isAbstract) { |
+ return getter; |
+ } |
+ } |
+ // Abstract members can be defined in a super class. |
+ } else if (!member.isAbstract) { |
+ return member; |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * Find the first member in the class chain with the given |
+ * [memberName]. This method is NOT to be used for resolving |
+ * unqualified sends because it does not implement the scoping |
+ * rules, where library scope comes before superclass scope. |
+ */ |
+ @override |
+ Element lookupMember(String memberName) { |
+ Element localMember = lookupLocalMember(memberName); |
+ return localMember == null ? lookupSuperMember(memberName) : localMember; |
+ } |
+ |
+ @override |
+ Link<Element> get constructors { |
+ // TODO(ajohnsen): See if we can avoid this method at some point. |
+ Link<Element> result = const Link<Element>(); |
+ // TODO(johnniwinther): Should we include injected constructors? |
+ forEachMember((_, Element member) { |
+ if (member.isConstructor) result = result.prepend(member); |
+ }); |
+ return result; |
+ } |
+ |
+ /** |
+ * Lookup super members for the class. This will ignore constructors. |
+ */ |
+ @override |
+ Element lookupSuperMember(String memberName) { |
+ return lookupSuperMemberInLibrary(memberName, library); |
+ } |
+ |
+ /** |
+ * Lookup super members for the class that is accessible in [library]. |
+ * This will ignore constructors. |
+ */ |
+ @override |
+ Element lookupSuperMemberInLibrary(String memberName, |
+ LibraryElement library) { |
+ bool isPrivate = isPrivateName(memberName); |
+ for (ClassElement s = superclass; s != null; s = s.superclass) { |
+ // Private members from a different library are not visible. |
+ if (isPrivate && !identical(library, s.library)) continue; |
+ Element e = s.lookupLocalMember(memberName); |
+ if (e == null) continue; |
+ // Static members are not inherited. |
+ if (e.isStatic) continue; |
+ return e; |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * Lookup local members in the class. This will ignore constructors. |
+ */ |
+ @override |
+ Element lookupLocalMember(String memberName) { |
+ var result = localLookup(memberName); |
+ if (result != null && result.isConstructor) return null; |
+ return result; |
+ } |
+ |
+ /** |
+ * Runs through all members of this class. |
+ * |
+ * The enclosing class is passed to the callback. This is useful when |
+ * [includeSuperAndInjectedMembers] is [:true:]. |
+ * |
+ * When called on an implementation element both the members in the origin |
+ * and patch class are included. |
+ */ |
+ // TODO(johnniwinther): Clean up lookup to get rid of the include predicates. |
+ @override |
+ void forEachMember(void f(ClassElement enclosingClass, Element member), |
+ {includeBackendMembers: false, |
+ includeSuperAndInjectedMembers: false}) { |
+ bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch; |
+ ClassElement classElement = declaration; |
+ do { |
+ // Iterate through the members in textual order, which requires |
+ // to reverse the data structure [localMembers] we created. |
+ // Textual order may be important for certain operations, for |
+ // example when emitting the initializers of fields. |
+ classElement.forEachLocalMember((e) => f(classElement, e)); |
+ if (includeBackendMembers) { |
+ classElement.forEachBackendMember((e) => f(classElement, e)); |
+ } |
+ if (includeInjectedMembers) { |
+ if (classElement.patch != null) { |
+ classElement.patch.forEachLocalMember((e) { |
+ if (!e.isPatch) f(classElement, e); |
+ }); |
+ } |
+ } |
+ classElement = includeSuperAndInjectedMembers |
+ ? classElement.superclass |
+ : null; |
+ } while (classElement != null); |
+ } |
+ |
+ /** |
+ * Runs through all instance-field members of this class. |
+ * |
+ * The enclosing class is passed to the callback. This is useful when |
+ * [includeSuperAndInjectedMembers] is [:true:]. |
+ * |
+ * When called on the implementation element both the fields declared in the |
+ * origin and in the patch are included. |
+ */ |
+ @override |
+ void forEachInstanceField(void f(ClassElement enclosingClass, |
+ FieldElement field), |
+ {bool includeSuperAndInjectedMembers: false}) { |
+ // Filters so that [f] is only invoked with instance fields. |
+ void fieldFilter(ClassElement enclosingClass, Element member) { |
+ if (member.isInstanceMember && member.kind == ElementKind.FIELD) { |
+ f(enclosingClass, member); |
+ } |
+ } |
+ |
+ forEachMember(fieldFilter, |
+ includeSuperAndInjectedMembers: includeSuperAndInjectedMembers); |
+ } |
+ |
+ /// Similar to [forEachInstanceField] but visits static fields. |
+ @override |
+ void forEachStaticField(void f(ClassElement enclosingClass, Element field)) { |
+ // Filters so that [f] is only invoked with static fields. |
+ void fieldFilter(ClassElement enclosingClass, Element member) { |
+ if (!member.isInstanceMember && member.kind == ElementKind.FIELD) { |
+ f(enclosingClass, member); |
+ } |
+ } |
+ |
+ forEachMember(fieldFilter); |
+ } |
+ |
+ /** |
+ * Returns true if the [fieldMember] shadows another field. The given |
+ * [fieldMember] must be a member of this class, i.e. if there is a field of |
+ * the same name in the superclass chain. |
+ * |
+ * This method also works if the [fieldMember] is private. |
+ */ |
+ @override |
+ bool hasFieldShadowedBy(Element fieldMember) { |
+ assert(fieldMember.isField); |
+ String fieldName = fieldMember.name; |
+ bool isPrivate = isPrivateName(fieldName); |
+ LibraryElement memberLibrary = fieldMember.library; |
+ ClassElement lookupClass = this.superclass; |
+ while (lookupClass != null) { |
+ Element foundMember = lookupClass.lookupLocalMember(fieldName); |
+ if (foundMember != null) { |
+ if (foundMember.isField) { |
+ if (!isPrivate || memberLibrary == foundMember.library) { |
+ // Private fields can only be shadowed by a field declared in the |
+ // same library. |
+ return true; |
+ } |
+ } |
+ } |
+ lookupClass = lookupClass.superclass; |
+ } |
+ return false; |
+ } |
+ |
+ @override |
+ bool implementsInterface(ClassElement intrface) { |
+ for (DartType implementedInterfaceType in allSupertypes) { |
+ ClassElement implementedInterface = implementedInterfaceType.element; |
+ if (identical(implementedInterface, intrface)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * Returns true if [this] is a subclass of [cls]. |
+ * |
+ * This method is not to be used for checking type hierarchy and |
+ * assignments, because it does not take parameterized types into |
+ * account. |
+ */ |
+ bool isSubclassOf(ClassElement cls) { |
+ // Use [declaration] for both [this] and [cls], because |
+ // declaration classes hold the superclass hierarchy. |
+ cls = cls.declaration; |
+ for (ClassElement s = declaration; s != null; s = s.superclass) { |
+ if (identical(s, cls)) return true; |
+ } |
+ return false; |
+ } |
+ |
+ FunctionType get callType { |
+ MemberSignature member = |
+ lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME)); |
+ return member != null && member.isMethod ? member.type : null; |
+ } |
+} |
+ |
+abstract class FunctionSignatureCommon implements FunctionSignature { |
+ void forEachRequiredParameter(void function(Element parameter)) { |
+ requiredParameters.forEach(function); |
+ } |
+ |
+ void forEachOptionalParameter(void function(Element parameter)) { |
+ optionalParameters.forEach(function); |
+ } |
+ |
+ Element get firstOptionalParameter => optionalParameters.first; |
+ |
+ void forEachParameter(void function(Element parameter)) { |
+ forEachRequiredParameter(function); |
+ forEachOptionalParameter(function); |
+ } |
+ |
+ void orderedForEachParameter(void function(Element parameter)) { |
+ forEachRequiredParameter(function); |
+ orderedOptionalParameters.forEach(function); |
+ } |
+ |
+ int get parameterCount => requiredParameterCount + optionalParameterCount; |
+ |
+ /** |
+ * Check whether a function with this signature can be used instead of a |
+ * function with signature [signature] without causing a `noSuchMethod` |
+ * exception/call. |
+ */ |
+ bool isCompatibleWith(FunctionSignature signature) { |
+ if (optionalParametersAreNamed) { |
+ if (!signature.optionalParametersAreNamed) { |
+ return requiredParameterCount == signature.parameterCount; |
+ } |
+ // If both signatures have named parameters, then they must have |
+ // the same number of required parameters, and the names in |
+ // [signature] must all be in [:this:]. |
+ if (requiredParameterCount != signature.requiredParameterCount) { |
+ return false; |
+ } |
+ Set<String> names = optionalParameters.map( |
+ (Element element) => element.name).toSet(); |
+ for (Element namedParameter in signature.optionalParameters) { |
+ if (!names.contains(namedParameter.name)) { |
+ return false; |
+ } |
+ } |
+ } else { |
+ if (signature.optionalParametersAreNamed) return false; |
+ // There must be at least as many arguments as in the other signature, but |
+ // this signature must not have more required parameters. Having more |
+ // optional parameters is not a problem, they simply are never provided |
+ // by call sites of a call to a method with the other signature. |
+ int otherTotalCount = signature.parameterCount; |
+ return requiredParameterCount <= otherTotalCount |
+ && parameterCount >= otherTotalCount; |
+ } |
+ return true; |
+ } |
+} |