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

Unified Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 1903663003: Move InheritanceManager to its own file. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/generated/incremental_resolver.dart ('k') | pkg/analyzer/lib/src/summary/link.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index cde13629fd19820eff574000f2d4a4bb307e780e..6800981365de56b8d284367d92cb12ab0394c894 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -16,9 +16,9 @@ import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/utilities.dart';
+import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
@@ -34,6 +34,7 @@ import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/task/strong/info.dart'
show InferredType, StaticInfo;
+export 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
export 'package:analyzer/src/dart/resolver/scope.dart';
export 'package:analyzer/src/generated/type_system.dart';
@@ -4836,1041 +4837,6 @@ class InferenceContext {
}
/**
- * Instances of the class `InheritanceManager` manage the knowledge of where class members
- * (methods, getters & setters) are inherited from.
- */
-class InheritanceManager {
- /**
- * The [LibraryElement] that is managed by this manager.
- */
- LibraryElement _library;
-
- /**
- * This is a mapping between each [ClassElement] and a map between the [String] member
- * names and the associated [ExecutableElement] in the mixin and superclass chain.
- */
- HashMap<ClassElement, MemberMap> _classLookup;
-
- /**
- * This is a mapping between each [ClassElement] and a map between the [String] member
- * names and the associated [ExecutableElement] in the interface set.
- */
- HashMap<ClassElement, MemberMap> _interfaceLookup;
-
- /**
- * A map between each visited [ClassElement] and the set of [AnalysisError]s found on
- * the class element.
- */
- HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement =
- new HashMap<ClassElement, HashSet<AnalysisError>>();
-
- /**
- * Initialize a newly created inheritance manager.
- *
- * @param library the library element context that the inheritance mappings are being generated
- */
- InheritanceManager(LibraryElement library) {
- this._library = library;
- _classLookup = new HashMap<ClassElement, MemberMap>();
- _interfaceLookup = new HashMap<ClassElement, MemberMap>();
- }
-
- /**
- * Set the new library element context.
- *
- * @param library the new library element
- */
- void set libraryElement(LibraryElement library) {
- this._library = library;
- }
-
- /**
- * Return the set of [AnalysisError]s found on the passed [ClassElement], or
- * `null` if there are none.
- *
- * @param classElt the class element to query
- * @return the set of [AnalysisError]s found on the passed [ClassElement], or
- * `null` if there are none
- */
- HashSet<AnalysisError> getErrors(ClassElement classElt) =>
- _errorsInClassElement[classElt];
-
- /**
- * Get and return a mapping between the set of all string names of the members inherited from the
- * passed [ClassElement] superclass hierarchy, and the associated [ExecutableElement].
- *
- * @param classElt the class element to query
- * @return a mapping between the set of all members inherited from the passed [ClassElement]
- * superclass hierarchy, and the associated [ExecutableElement]
- */
- MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) =>
- _computeClassChainLookupMap(classElt, new HashSet<ClassElement>());
-
- /**
- * Get and return a mapping between the set of all string names of the members inherited from the
- * passed [ClassElement] interface hierarchy, and the associated [ExecutableElement].
- *
- * @param classElt the class element to query
- * @return a mapping between the set of all string names of the members inherited from the passed
- * [ClassElement] interface hierarchy, and the associated [ExecutableElement].
- */
- MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) =>
- _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>());
-
- /**
- * Given some [ClassElement] and some member name, this returns the
- * [ExecutableElement] that the class inherits from the mixins,
- * superclasses or interfaces, that has the member name, if no member is inherited `null` is
- * returned.
- *
- * @param classElt the class element to query
- * @param memberName the name of the executable element to find and return
- * @return the inherited executable element with the member name, or `null` if no such
- * member exists
- */
- ExecutableElement lookupInheritance(
- ClassElement classElt, String memberName) {
- if (memberName == null || memberName.isEmpty) {
- return null;
- }
- ExecutableElement executable =
- _computeClassChainLookupMap(classElt, new HashSet<ClassElement>())
- .get(memberName);
- if (executable == null) {
- return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>())
- .get(memberName);
- }
- return executable;
- }
-
- /**
- * Given some [ClassElement] and some member name, this returns the
- * [ExecutableElement] that the class either declares itself, or
- * inherits, that has the member name, if no member is inherited `null` is returned.
- *
- * @param classElt the class element to query
- * @param memberName the name of the executable element to find and return
- * @return the inherited executable element with the member name, or `null` if no such
- * member exists
- */
- ExecutableElement lookupMember(ClassElement classElt, String memberName) {
- ExecutableElement element = _lookupMemberInClass(classElt, memberName);
- if (element != null) {
- return element;
- }
- return lookupInheritance(classElt, memberName);
- }
-
- /**
- * Determine the set of methods which is overridden by the given class member. If no member is
- * inherited, an empty list is returned. If one of the inherited members is a
- * [MultiplyInheritedExecutableElement], then it is expanded into its constituent inherited
- * elements.
- *
- * @param classElt the class to query
- * @param memberName the name of the class member to query
- * @return a list of overridden methods
- */
- List<ExecutableElement> lookupOverrides(
- ClassElement classElt, String memberName) {
- List<ExecutableElement> result = new List<ExecutableElement>();
- if (memberName == null || memberName.isEmpty) {
- return result;
- }
- List<MemberMap> interfaceMaps =
- _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>());
- if (interfaceMaps != null) {
- for (MemberMap interfaceMap in interfaceMaps) {
- ExecutableElement overriddenElement = interfaceMap.get(memberName);
- if (overriddenElement != null) {
- if (overriddenElement is MultiplyInheritedExecutableElement) {
- MultiplyInheritedExecutableElement multiplyInheritedElement =
- overriddenElement;
- for (ExecutableElement element
- in multiplyInheritedElement.inheritedElements) {
- result.add(element);
- }
- } else {
- result.add(overriddenElement);
- }
- }
- }
- }
- return result;
- }
-
- /**
- * This method takes some inherited [FunctionType], and resolves all the parameterized types
- * in the function type, dependent on the class in which it is being overridden.
- *
- * @param baseFunctionType the function type that is being overridden
- * @param memberName the name of the member, this is used to lookup the inheritance path of the
- * override
- * @param definingType the type that is overriding the member
- * @return the passed function type with any parameterized types substituted
- */
- // TODO(jmesserly): investigate why this is needed in ErrorVerifier's override
- // checking. There seems to be some rare cases where we get partially
- // substituted type arguments, and the function types don't compare equally.
- FunctionType substituteTypeArgumentsInMemberFromInheritance(
- FunctionType baseFunctionType,
- String memberName,
- InterfaceType definingType) {
- // if the baseFunctionType is null, or does not have any parameters,
- // return it.
- if (baseFunctionType == null ||
- baseFunctionType.typeArguments.length == 0) {
- return baseFunctionType;
- }
- // First, generate the path from the defining type to the overridden member
- Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
- _computeInheritancePath(inheritancePath, definingType, memberName);
- if (inheritancePath == null || inheritancePath.isEmpty) {
- // TODO(jwren) log analysis engine error
- return baseFunctionType;
- }
- FunctionType functionTypeToReturn = baseFunctionType;
- // loop backward through the list substituting as we go:
- while (!inheritancePath.isEmpty) {
- InterfaceType lastType = inheritancePath.removeLast();
- List<DartType> parameterTypes = lastType.element.type.typeArguments;
- List<DartType> argumentTypes = lastType.typeArguments;
- functionTypeToReturn =
- functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
- }
- return functionTypeToReturn;
- }
-
- /**
- * Compute and return a mapping between the set of all string names of the members inherited from
- * the passed [ClassElement] superclass hierarchy, and the associated
- * [ExecutableElement].
- *
- * @param classElt the class element to query
- * @param visitedClasses a set of visited classes passed back into this method when it calls
- * itself recursively
- * @return a mapping between the set of all string names of the members inherited from the passed
- * [ClassElement] superclass hierarchy, and the associated [ExecutableElement]
- */
- MemberMap _computeClassChainLookupMap(
- ClassElement classElt, HashSet<ClassElement> visitedClasses) {
- MemberMap resultMap = _classLookup[classElt];
- if (resultMap != null) {
- return resultMap;
- } else {
- resultMap = new MemberMap();
- }
- ClassElement superclassElt = null;
- InterfaceType supertype = classElt.supertype;
- if (supertype != null) {
- superclassElt = supertype.element;
- } else {
- // classElt is Object
- _classLookup[classElt] = resultMap;
- return resultMap;
- }
- if (superclassElt != null) {
- if (!visitedClasses.contains(superclassElt)) {
- visitedClasses.add(superclassElt);
- try {
- resultMap = new MemberMap.from(
- _computeClassChainLookupMap(superclassElt, visitedClasses));
- //
- // Substitute the super types down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(supertype, resultMap);
- //
- // Include the members from the superclass in the resultMap.
- //
- _recordMapWithClassMembers(resultMap, supertype, false);
- } finally {
- visitedClasses.remove(superclassElt);
- }
- } else {
- // This case happens only when the superclass was previously visited and
- // not in the lookup, meaning this is meant to shorten the compute for
- // recursive cases.
- _classLookup[superclassElt] = resultMap;
- return resultMap;
- }
- }
- //
- // Include the members from the mixins in the resultMap. If there are
- // multiple mixins, visit them in the order listed so that methods in later
- // mixins will overwrite identically-named methods in earlier mixins.
- //
- List<InterfaceType> mixins = classElt.mixins;
- for (InterfaceType mixin in mixins) {
- ClassElement mixinElement = mixin.element;
- if (mixinElement != null) {
- if (!visitedClasses.contains(mixinElement)) {
- visitedClasses.add(mixinElement);
- try {
- MemberMap map = new MemberMap.from(
- _computeClassChainLookupMap(mixinElement, visitedClasses));
- //
- // Substitute the super types down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(mixin, map);
- //
- // Include the members from the superclass in the resultMap.
- //
- _recordMapWithClassMembers(map, mixin, false);
- //
- // Add the members from map into result map.
- //
- for (int j = 0; j < map.size; j++) {
- String key = map.getKey(j);
- ExecutableElement value = map.getValue(j);
- if (key != null) {
- ClassElement definingClass = value
- .getAncestor((Element element) => element is ClassElement);
- if (!definingClass.type.isObject) {
- ExecutableElement existingValue = resultMap.get(key);
- if (existingValue == null ||
- (existingValue != null && !_isAbstract(value))) {
- resultMap.put(key, value);
- }
- }
- }
- }
- } finally {
- visitedClasses.remove(mixinElement);
- }
- } else {
- // This case happens only when the superclass was previously visited
- // and not in the lookup, meaning this is meant to shorten the compute
- // for recursive cases.
- _classLookup[mixinElement] = resultMap;
- return resultMap;
- }
- }
- }
- _classLookup[classElt] = resultMap;
- return resultMap;
- }
-
- /**
- * Compute and return the inheritance path given the context of a type and a member that is
- * overridden in the inheritance path (for which the type is in the path).
- *
- * @param chain the inheritance path that is built up as this method calls itself recursively,
- * when this method is called an empty [LinkedList] should be provided
- * @param currentType the current type in the inheritance path
- * @param memberName the name of the member that is being looked up the inheritance path
- */
- void _computeInheritancePath(Queue<InterfaceType> chain,
- InterfaceType currentType, String memberName) {
- // TODO (jwren) create a public version of this method which doesn't require
- // the initial chain to be provided, then provided tests for this
- // functionality in InheritanceManagerTest
- chain.add(currentType);
- ClassElement classElt = currentType.element;
- InterfaceType supertype = classElt.supertype;
- // Base case- reached Object
- if (supertype == null) {
- // Looked up the chain all the way to Object, return null.
- // This should never happen.
- return;
- }
- // If we are done, return the chain
- // We are not done if this is the first recursive call on this method.
- if (chain.length != 1) {
- // We are done however if the member is in this classElt
- if (_lookupMemberInClass(classElt, memberName) != null) {
- return;
- }
- }
- // Mixins- note that mixins call lookupMemberInClass, not lookupMember
- List<InterfaceType> mixins = classElt.mixins;
- for (int i = mixins.length - 1; i >= 0; i--) {
- ClassElement mixinElement = mixins[i].element;
- if (mixinElement != null) {
- ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
- if (elt != null) {
- // this is equivalent (but faster than) calling this method
- // recursively
- // (return computeInheritancePath(chain, mixins[i], memberName);)
- chain.add(mixins[i]);
- return;
- }
- }
- }
- // Superclass
- ClassElement superclassElt = supertype.element;
- if (lookupMember(superclassElt, memberName) != null) {
- _computeInheritancePath(chain, supertype, memberName);
- return;
- }
- // Interfaces
- List<InterfaceType> interfaces = classElt.interfaces;
- for (InterfaceType interfaceType in interfaces) {
- ClassElement interfaceElement = interfaceType.element;
- if (interfaceElement != null &&
- lookupMember(interfaceElement, memberName) != null) {
- _computeInheritancePath(chain, interfaceType, memberName);
- return;
- }
- }
- }
-
- /**
- * Compute and return a mapping between the set of all string names of the members inherited from
- * the passed [ClassElement] interface hierarchy, and the associated
- * [ExecutableElement].
- *
- * @param classElt the class element to query
- * @param visitedInterfaces a set of visited classes passed back into this method when it calls
- * itself recursively
- * @return a mapping between the set of all string names of the members inherited from the passed
- * [ClassElement] interface hierarchy, and the associated [ExecutableElement]
- */
- MemberMap _computeInterfaceLookupMap(
- ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
- MemberMap resultMap = _interfaceLookup[classElt];
- if (resultMap != null) {
- return resultMap;
- }
- List<MemberMap> lookupMaps =
- _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
- if (lookupMaps == null) {
- resultMap = new MemberMap();
- } else {
- HashMap<String, List<ExecutableElement>> unionMap =
- _unionInterfaceLookupMaps(lookupMaps);
- resultMap = _resolveInheritanceLookup(classElt, unionMap);
- }
- _interfaceLookup[classElt] = resultMap;
- return resultMap;
- }
-
- /**
- * Collect a list of interface lookup maps whose elements correspond to all of the classes
- * directly above [classElt] in the class hierarchy (the direct superclass if any, all
- * mixins, and all direct superinterfaces). Each item in the list is the interface lookup map
- * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
- * parameters appropriately substituted.
- *
- * @param classElt the class element to query
- * @param visitedInterfaces a set of visited classes passed back into this method when it calls
- * itself recursively
- * @return `null` if there was a problem (such as a loop in the class hierarchy) or if there
- * are no classes above this one in the class hierarchy. Otherwise, a list of interface
- * lookup maps.
- */
- List<MemberMap> _gatherInterfaceLookupMaps(
- ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
- InterfaceType supertype = classElt.supertype;
- ClassElement superclassElement =
- supertype != null ? supertype.element : null;
- List<InterfaceType> mixins = classElt.mixins;
- List<InterfaceType> interfaces = classElt.interfaces;
- // Recursively collect the list of mappings from all of the interface types
- List<MemberMap> lookupMaps = new List<MemberMap>();
- //
- // Superclass element
- //
- if (superclassElement != null) {
- if (!visitedInterfaces.contains(superclassElement)) {
- try {
- visitedInterfaces.add(superclassElement);
- //
- // Recursively compute the map for the super type.
- //
- MemberMap map =
- _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
- map = new MemberMap.from(map);
- //
- // Substitute the super type down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(supertype, map);
- //
- // Add any members from the super type into the map as well.
- //
- _recordMapWithClassMembers(map, supertype, true);
- lookupMaps.add(map);
- } finally {
- visitedInterfaces.remove(superclassElement);
- }
- } else {
- return null;
- }
- }
- //
- // Mixin elements
- //
- for (int i = mixins.length - 1; i >= 0; i--) {
- InterfaceType mixinType = mixins[i];
- ClassElement mixinElement = mixinType.element;
- if (mixinElement != null) {
- if (!visitedInterfaces.contains(mixinElement)) {
- try {
- visitedInterfaces.add(mixinElement);
- //
- // Recursively compute the map for the mixin.
- //
- MemberMap map =
- _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
- map = new MemberMap.from(map);
- //
- // Substitute the mixin type down the hierarchy.
- //
- _substituteTypeParametersDownHierarchy(mixinType, map);
- //
- // Add any members from the mixin type into the map as well.
- //
- _recordMapWithClassMembers(map, mixinType, true);
- lookupMaps.add(map);
- } finally {
- visitedInterfaces.remove(mixinElement);
- }
- } else {
- return null;
- }
- }
- }
- //
- // Interface elements
- //
- for (InterfaceType interfaceType in interfaces) {
- ClassElement interfaceElement = interfaceType.element;
- if (interfaceElement != null) {
- if (!visitedInterfaces.contains(interfaceElement)) {
- try {
- visitedInterfaces.add(interfaceElement);
- //
- // Recursively compute the map for the interfaces.
- //
- MemberMap map =
- _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
- map = new MemberMap.from(map);
- //
- // Substitute the supertypes down the hierarchy
- //
- _substituteTypeParametersDownHierarchy(interfaceType, map);
- //
- // And add any members from the interface into the map as well.
- //
- _recordMapWithClassMembers(map, interfaceType, true);
- lookupMaps.add(map);
- } finally {
- visitedInterfaces.remove(interfaceElement);
- }
- } else {
- return null;
- }
- }
- }
- if (lookupMaps.length == 0) {
- return null;
- }
- return lookupMaps;
- }
-
- /**
- * Given some [ClassElement], this method finds and returns the [ExecutableElement] of
- * the passed name in the class element. Static members, members in super types and members not
- * accessible from the current library are not considered.
- *
- * @param classElt the class element to query
- * @param memberName the name of the member to lookup in the class
- * @return the found [ExecutableElement], or `null` if no such member was found
- */
- ExecutableElement _lookupMemberInClass(
- ClassElement classElt, String memberName) {
- List<MethodElement> methods = classElt.methods;
- for (MethodElement method in methods) {
- if (memberName == method.name &&
- method.isAccessibleIn(_library) &&
- !method.isStatic) {
- return method;
- }
- }
- List<PropertyAccessorElement> accessors = classElt.accessors;
- for (PropertyAccessorElement accessor in accessors) {
- if (memberName == accessor.name &&
- accessor.isAccessibleIn(_library) &&
- !accessor.isStatic) {
- return accessor;
- }
- }
- return null;
- }
-
- /**
- * Record the passed map with the set of all members (methods, getters and setters) in the type
- * into the passed map.
- *
- * @param map some non-`null` map to put the methods and accessors from the passed
- * [ClassElement] into
- * @param type the type that will be recorded into the passed map
- * @param doIncludeAbstract `true` if abstract members will be put into the map
- */
- void _recordMapWithClassMembers(
- MemberMap map, InterfaceType type, bool doIncludeAbstract) {
- List<MethodElement> methods = type.methods;
- for (MethodElement method in methods) {
- if (method.isAccessibleIn(_library) &&
- !method.isStatic &&
- (doIncludeAbstract || !method.isAbstract)) {
- map.put(method.name, method);
- }
- }
- List<PropertyAccessorElement> accessors = type.accessors;
- for (PropertyAccessorElement accessor in accessors) {
- if (accessor.isAccessibleIn(_library) &&
- !accessor.isStatic &&
- (doIncludeAbstract || !accessor.isAbstract)) {
- map.put(accessor.name, accessor);
- }
- }
- }
-
- /**
- * This method is used to report errors on when they are found computing inheritance information.
- * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where these generated
- * error codes are reported back into the analysis engine.
- *
- * @param classElt the location of the source for which the exception occurred
- * @param offset the offset of the location of the error
- * @param length the length of the location of the error
- * @param errorCode the error code to be associated with this error
- * @param arguments the arguments used to build the error message
- */
- void _reportError(ClassElement classElt, int offset, int length,
- ErrorCode errorCode, List<Object> arguments) {
- HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
- if (errorSet == null) {
- errorSet = new HashSet<AnalysisError>();
- _errorsInClassElement[classElt] = errorSet;
- }
- errorSet.add(new AnalysisError(
- classElt.source, offset, length, errorCode, arguments));
- }
-
- /**
- * Given the set of methods defined by classes above [classElt] in the class hierarchy,
- * apply the appropriate inheritance rules to determine those methods inherited by or overridden
- * by [classElt]. Also report static warnings
- * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
- * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if appropriate.
- *
- * @param classElt the class element to query.
- * @param unionMap a mapping from method name to the set of unique (in terms of signature) methods
- * defined in superclasses of [classElt].
- * @return the inheritance lookup map for [classElt].
- */
- MemberMap _resolveInheritanceLookup(ClassElement classElt,
- HashMap<String, List<ExecutableElement>> unionMap) {
- MemberMap resultMap = new MemberMap();
- unionMap.forEach((String key, List<ExecutableElement> list) {
- int numOfEltsWithMatchingNames = list.length;
- if (numOfEltsWithMatchingNames == 1) {
- //
- // Example: class A inherits only 1 method named 'm'.
- // Since it is the only such method, it is inherited.
- // Another example: class A inherits 2 methods named 'm' from 2
- // different interfaces, but they both have the same signature, so it is
- // the method inherited.
- //
- resultMap.put(key, list[0]);
- } else {
- //
- // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
- //
- bool allMethods = true;
- bool allSetters = true;
- bool allGetters = true;
- for (ExecutableElement executableElement in list) {
- if (executableElement is PropertyAccessorElement) {
- allMethods = false;
- if (executableElement.isSetter) {
- allGetters = false;
- } else {
- allSetters = false;
- }
- } else {
- allGetters = false;
- allSetters = false;
- }
- }
- //
- // If there isn't a mixture of methods with getters, then continue,
- // otherwise create a warning.
- //
- if (allMethods || allGetters || allSetters) {
- //
- // Compute the element whose type is the subtype of all of the other
- // types.
- //
- List<ExecutableElement> elements = new List.from(list);
- List<FunctionType> executableElementTypes =
- new List<FunctionType>(numOfEltsWithMatchingNames);
- for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
- executableElementTypes[i] = elements[i].type;
- }
- List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
- for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
- FunctionType subtype = executableElementTypes[i];
- if (subtype == null) {
- continue;
- }
- bool subtypeOfAllTypes = true;
- TypeSystem typeSystem = _library.context.typeSystem;
- for (int j = 0;
- j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
- j++) {
- if (i != j) {
- if (!typeSystem.isSubtypeOf(
- subtype, executableElementTypes[j])) {
- subtypeOfAllTypes = false;
- break;
- }
- }
- }
- if (subtypeOfAllTypes) {
- subtypesOfAllOtherTypesIndexes.add(i);
- }
- }
- //
- // The following is split into three cases determined by the number of
- // elements in subtypesOfAllOtherTypes
- //
- if (subtypesOfAllOtherTypesIndexes.length == 1) {
- //
- // Example: class A inherited only 2 method named 'm'.
- // One has the function type '() -> dynamic' and one has the
- // function type '([int]) -> dynamic'. Since the second method is a
- // subtype of all the others, it is the inherited method.
- // Tests: InheritanceManagerTest.
- // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
- //
- resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
- } else {
- if (subtypesOfAllOtherTypesIndexes.isEmpty) {
- //
- // Determine if the current class has a method or accessor with
- // the member name, if it does then then this class does not
- // "inherit" from any of the supertypes. See issue 16134.
- //
- bool classHasMember = false;
- if (allMethods) {
- classHasMember = classElt.getMethod(key) != null;
- } else {
- List<PropertyAccessorElement> accessors = classElt.accessors;
- for (int i = 0; i < accessors.length; i++) {
- if (accessors[i].name == key) {
- classHasMember = true;
- }
- }
- }
- //
- // Example: class A inherited only 2 method named 'm'.
- // One has the function type '() -> int' and one has the function
- // type '() -> String'. Since neither is a subtype of the other,
- // we create a warning, and have this class inherit nothing.
- //
- if (!classHasMember) {
- String firstTwoFuntionTypesStr =
- "${executableElementTypes[0]}, ${executableElementTypes[1]}";
- _reportError(
- classElt,
- classElt.nameOffset,
- classElt.nameLength,
- StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
- [key, firstTwoFuntionTypesStr]);
- }
- } else {
- //
- // Example: class A inherits 2 methods named 'm'.
- // One has the function type '(int) -> dynamic' and one has the
- // function type '(num) -> dynamic'. Since they are both a subtype
- // of the other, a synthetic function '(dynamic) -> dynamic' is
- // inherited.
- // Tests: test_getMapOfMembersInheritedFromInterfaces_
- // union_multipleSubtypes_*
- //
- List<ExecutableElement> elementArrayToMerge =
- new List<ExecutableElement>(
- subtypesOfAllOtherTypesIndexes.length);
- for (int i = 0; i < elementArrayToMerge.length; i++) {
- elementArrayToMerge[i] =
- elements[subtypesOfAllOtherTypesIndexes[i]];
- }
- ExecutableElement mergedExecutableElement =
- _computeMergedExecutableElement(elementArrayToMerge);
- resultMap.put(key, mergedExecutableElement);
- }
- }
- } else {
- _reportError(
- classElt,
- classElt.nameOffset,
- classElt.nameLength,
- StaticWarningCode
- .INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD,
- [key]);
- }
- }
- });
- return resultMap;
- }
-
- /**
- * Loop through all of the members in some [MemberMap], performing type parameter
- * substitutions using a passed supertype.
- *
- * @param superType the supertype to substitute into the members of the [MemberMap]
- * @param map the MemberMap to perform the substitutions on
- */
- void _substituteTypeParametersDownHierarchy(
- InterfaceType superType, MemberMap map) {
- for (int i = 0; i < map.size; i++) {
- ExecutableElement executableElement = map.getValue(i);
- if (executableElement is MethodMember) {
- executableElement =
- MethodMember.from(executableElement as MethodMember, superType);
- map.setValue(i, executableElement);
- } else if (executableElement is PropertyAccessorMember) {
- executableElement = PropertyAccessorMember.from(
- executableElement as PropertyAccessorMember, superType);
- map.setValue(i, executableElement);
- }
- }
- }
-
- /**
- * Union all of the [lookupMaps] together into a single map, grouping the ExecutableElements
- * into a list where none of the elements are equal where equality is determined by having equal
- * function types. (We also take note too of the kind of the element: ()->int and () -> int may
- * not be equal if one is a getter and the other is a method.)
- *
- * @param lookupMaps the maps to be unioned together.
- * @return the resulting union map.
- */
- HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
- List<MemberMap> lookupMaps) {
- HashMap<String, List<ExecutableElement>> unionMap =
- new HashMap<String, List<ExecutableElement>>();
- for (MemberMap lookupMap in lookupMaps) {
- int lookupMapSize = lookupMap.size;
- for (int i = 0; i < lookupMapSize; i++) {
- // Get the string key, if null, break.
- String key = lookupMap.getKey(i);
- if (key == null) {
- break;
- }
- // Get the list value out of the unionMap
- List<ExecutableElement> list = unionMap[key];
- // If we haven't created such a map for this key yet, do create it and
- // put the list entry into the unionMap.
- if (list == null) {
- list = new List<ExecutableElement>();
- unionMap[key] = list;
- }
- // Fetch the entry out of this lookupMap
- ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
- if (list.isEmpty) {
- // If the list is empty, just the new value
- list.add(newExecutableElementEntry);
- } else {
- // Otherwise, only add the newExecutableElementEntry if it isn't
- // already in the list, this covers situation where a class inherits
- // two methods (or two getters) that are identical.
- bool alreadyInList = false;
- bool isMethod1 = newExecutableElementEntry is MethodElement;
- for (ExecutableElement executableElementInList in list) {
- bool isMethod2 = executableElementInList is MethodElement;
- if (isMethod1 == isMethod2 &&
- executableElementInList.type ==
- newExecutableElementEntry.type) {
- alreadyInList = true;
- break;
- }
- }
- if (!alreadyInList) {
- list.add(newExecutableElementEntry);
- }
- }
- }
- }
- return unionMap;
- }
-
- /**
- * Given some array of [ExecutableElement]s, this method creates a synthetic element as
- * described in 8.1.1:
- *
- * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional parameters of a
- * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote the number of
- * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denote the set of all
- * named parameters of the <i>m<sub>1</sub>, &hellip;, m<sub>k</sub></i>. Then let
- * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
- * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
- * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameters of type
- * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, named parameters
- * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
- *
- */
- static ExecutableElement _computeMergedExecutableElement(
- List<ExecutableElement> elementArrayToMerge) {
- int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
- int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
- Set<String> namedParametersList = new HashSet<String>();
- for (int i = 1; i < elementArrayToMerge.length; i++) {
- ExecutableElement element = elementArrayToMerge[i];
- int numOfPositionalParams = _getNumOfPositionalParameters(element);
- if (h < numOfPositionalParams) {
- h = numOfPositionalParams;
- }
- int numOfRequiredParams = _getNumOfRequiredParameters(element);
- if (r > numOfRequiredParams) {
- r = numOfRequiredParams;
- }
- namedParametersList.addAll(_getNamedParameterNames(element));
- }
- return _createSyntheticExecutableElement(
- elementArrayToMerge,
- elementArrayToMerge[0].displayName,
- r,
- h - r,
- new List.from(namedParametersList));
- }
-
- /**
- * Used by [computeMergedExecutableElement] to actually create the
- * synthetic element.
- *
- * @param elementArrayToMerge the array used to create the synthetic element
- * @param name the name of the method, getter or setter
- * @param numOfRequiredParameters the number of required parameters
- * @param numOfPositionalParameters the number of positional parameters
- * @param namedParameters the list of [String]s that are the named parameters
- * @return the created synthetic element
- */
- static ExecutableElement _createSyntheticExecutableElement(
- List<ExecutableElement> elementArrayToMerge,
- String name,
- int numOfRequiredParameters,
- int numOfPositionalParameters,
- List<String> namedParameters) {
- DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
- SimpleIdentifier nameIdentifier =
- new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0));
- ExecutableElementImpl executable;
- if (elementArrayToMerge[0] is MethodElement) {
- MultiplyInheritedMethodElementImpl unionedMethod =
- new MultiplyInheritedMethodElementImpl(nameIdentifier);
- unionedMethod.inheritedElements = elementArrayToMerge;
- executable = unionedMethod;
- } else {
- MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
- new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
- unionedPropertyAccessor.getter =
- (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
- unionedPropertyAccessor.setter =
- (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
- unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
- executable = unionedPropertyAccessor;
- }
- int numOfParameters = numOfRequiredParameters +
- numOfPositionalParameters +
- namedParameters.length;
- List<ParameterElement> parameters =
- new List<ParameterElement>(numOfParameters);
- int i = 0;
- for (int j = 0; j < numOfRequiredParameters; j++, i++) {
- ParameterElementImpl parameter = new ParameterElementImpl("", 0);
- parameter.type = dynamicType;
- parameter.parameterKind = ParameterKind.REQUIRED;
- parameters[i] = parameter;
- }
- for (int k = 0; k < numOfPositionalParameters; k++, i++) {
- ParameterElementImpl parameter = new ParameterElementImpl("", 0);
- parameter.type = dynamicType;
- parameter.parameterKind = ParameterKind.POSITIONAL;
- parameters[i] = parameter;
- }
- for (int m = 0; m < namedParameters.length; m++, i++) {
- ParameterElementImpl parameter =
- new ParameterElementImpl(namedParameters[m], 0);
- parameter.type = dynamicType;
- parameter.parameterKind = ParameterKind.NAMED;
- parameters[i] = parameter;
- }
- executable.returnType = dynamicType;
- executable.parameters = parameters;
- FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
- executable.type = methodType;
- return executable;
- }
-
- /**
- * Given some [ExecutableElement], return the list of named parameters.
- */
- static List<String> _getNamedParameterNames(
- ExecutableElement executableElement) {
- List<String> namedParameterNames = new List<String>();
- List<ParameterElement> parameters = executableElement.parameters;
- for (int i = 0; i < parameters.length; i++) {
- ParameterElement parameterElement = parameters[i];
- if (parameterElement.parameterKind == ParameterKind.NAMED) {
- namedParameterNames.add(parameterElement.name);
- }
- }
- return namedParameterNames;
- }
-
- /**
- * Given some [ExecutableElement] return the number of parameters of the specified kind.
- */
- static int _getNumOfParameters(
- ExecutableElement executableElement, ParameterKind parameterKind) {
- int parameterCount = 0;
- List<ParameterElement> parameters = executableElement.parameters;
- for (int i = 0; i < parameters.length; i++) {
- ParameterElement parameterElement = parameters[i];
- if (parameterElement.parameterKind == parameterKind) {
- parameterCount++;
- }
- }
- return parameterCount;
- }
-
- /**
- * Given some [ExecutableElement] return the number of positional parameters.
- *
- * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSITIONAL].
- */
- static int _getNumOfPositionalParameters(
- ExecutableElement executableElement) =>
- _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
- _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
-
- /**
- * Given some [ExecutableElement] return the number of required parameters.
- */
- static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
- _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
-
- /**
- * Given some [ExecutableElement] returns `true` if it is an abstract member of a
- * class.
- *
- * @param executableElement some [ExecutableElement] to evaluate
- * @return `true` if the given element is an abstract member of a class
- */
- static bool _isAbstract(ExecutableElement executableElement) {
- if (executableElement is MethodElement) {
- return executableElement.isAbstract;
- } else if (executableElement is PropertyAccessorElement) {
- return executableElement.isAbstract;
- }
- return false;
- }
-}
-
-/**
* This enum holds one of four states of a field initialization state through a constructor
* signature, not initialized, initialized in the field declaration, initialized in the field
* formal, and finally, initialized in the initializers list.
@@ -5898,166 +4864,6 @@ class INIT_STATE extends Enum<INIT_STATE> {
}
/**
- * This class is used to replace uses of `HashMap<String, ExecutableElement>`
- * which are not as performant as this class.
- */
-class MemberMap {
- /**
- * The current size of this map.
- */
- int _size = 0;
-
- /**
- * The array of keys.
- */
- List<String> _keys;
-
- /**
- * The array of ExecutableElement values.
- */
- List<ExecutableElement> _values;
-
- /**
- * Initialize a newly created member map to have the given [initialCapacity].
- * The map will grow if needed.
- */
- MemberMap([int initialCapacity = 10]) {
- _initArrays(initialCapacity);
- }
-
- /**
- * Initialize a newly created member map to contain the same members as the
- * given [memberMap].
- */
- MemberMap.from(MemberMap memberMap) {
- _initArrays(memberMap._size + 5);
- for (int i = 0; i < memberMap._size; i++) {
- _keys[i] = memberMap._keys[i];
- _values[i] = memberMap._values[i];
- }
- _size = memberMap._size;
- }
-
- /**
- * The size of the map.
- *
- * @return the size of the map.
- */
- int get size => _size;
-
- /**
- * Given some key, return the ExecutableElement value from the map, if the key does not exist in
- * the map, `null` is returned.
- *
- * @param key some key to look up in the map
- * @return the associated ExecutableElement value from the map, if the key does not exist in the
- * map, `null` is returned
- */
- ExecutableElement get(String key) {
- for (int i = 0; i < _size; i++) {
- if (_keys[i] != null && _keys[i] == key) {
- return _values[i];
- }
- }
- return null;
- }
-
- /**
- * Get and return the key at the specified location. If the key/value pair has been removed from
- * the set, then `null` is returned.
- *
- * @param i some non-zero value less than size
- * @return the key at the passed index
- * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than
- * zero or greater than or equal to the capacity of the arrays
- */
- String getKey(int i) => _keys[i];
-
- /**
- * Get and return the ExecutableElement at the specified location. If the key/value pair has been
- * removed from the set, then then `null` is returned.
- *
- * @param i some non-zero value less than size
- * @return the key at the passed index
- * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than
- * zero or greater than or equal to the capacity of the arrays
- */
- ExecutableElement getValue(int i) => _values[i];
-
- /**
- * Given some key/value pair, store the pair in the map. If the key exists already, then the new
- * value overrides the old value.
- *
- * @param key the key to store in the map
- * @param value the ExecutableElement value to store in the map
- */
- void put(String key, ExecutableElement value) {
- // If we already have a value with this key, override the value
- for (int i = 0; i < _size; i++) {
- if (_keys[i] != null && _keys[i] == key) {
- _values[i] = value;
- return;
- }
- }
- // If needed, double the size of our arrays and copy values over in both
- // arrays
- if (_size == _keys.length) {
- int newArrayLength = _size * 2;
- List<String> keys_new_array = new List<String>(newArrayLength);
- List<ExecutableElement> values_new_array =
- new List<ExecutableElement>(newArrayLength);
- for (int i = 0; i < _size; i++) {
- keys_new_array[i] = _keys[i];
- }
- for (int i = 0; i < _size; i++) {
- values_new_array[i] = _values[i];
- }
- _keys = keys_new_array;
- _values = values_new_array;
- }
- // Put new value at end of array
- _keys[_size] = key;
- _values[_size] = value;
- _size++;
- }
-
- /**
- * Given some [String] key, this method replaces the associated key and value pair with
- * `null`. The size is not decremented with this call, instead it is expected that the users
- * check for `null`.
- *
- * @param key the key of the key/value pair to remove from the map
- */
- void remove(String key) {
- for (int i = 0; i < _size; i++) {
- if (_keys[i] == key) {
- _keys[i] = null;
- _values[i] = null;
- return;
- }
- }
- }
-
- /**
- * Sets the ExecutableElement at the specified location.
- *
- * @param i some non-zero value less than size
- * @param value the ExecutableElement value to store in the map
- */
- void setValue(int i, ExecutableElement value) {
- _values[i] = value;
- }
-
- /**
- * Initializes [keys] and [values].
- */
- void _initArrays(int initialCapacity) {
- _keys = new List<String>(initialCapacity);
- _values = new List<ExecutableElement>(initialCapacity);
- }
-}
-
-/**
* Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
* unit to verify that if they have an override annotation it is being used correctly.
*/
« no previous file with comments | « pkg/analyzer/lib/src/generated/incremental_resolver.dart ('k') | pkg/analyzer/lib/src/summary/link.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698