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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.generated.resolver; 5 library analyzer.src.generated.resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
11 import 'package:analyzer/dart/ast/visitor.dart'; 11 import 'package:analyzer/dart/ast/visitor.dart';
12 import 'package:analyzer/dart/element/element.dart'; 12 import 'package:analyzer/dart/element/element.dart';
13 import 'package:analyzer/dart/element/type.dart'; 13 import 'package:analyzer/dart/element/type.dart';
14 import 'package:analyzer/dart/element/visitor.dart'; 14 import 'package:analyzer/dart/element/visitor.dart';
15 import 'package:analyzer/src/dart/ast/ast.dart'; 15 import 'package:analyzer/src/dart/ast/ast.dart';
16 import 'package:analyzer/src/dart/ast/token.dart'; 16 import 'package:analyzer/src/dart/ast/token.dart';
17 import 'package:analyzer/src/dart/ast/utilities.dart'; 17 import 'package:analyzer/src/dart/ast/utilities.dart';
18 import 'package:analyzer/src/dart/element/element.dart'; 18 import 'package:analyzer/src/dart/element/element.dart';
19 import 'package:analyzer/src/dart/element/member.dart';
20 import 'package:analyzer/src/dart/element/type.dart'; 19 import 'package:analyzer/src/dart/element/type.dart';
21 import 'package:analyzer/src/dart/element/utilities.dart'; 20 import 'package:analyzer/src/dart/element/utilities.dart';
21 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
22 import 'package:analyzer/src/dart/resolver/scope.dart'; 22 import 'package:analyzer/src/dart/resolver/scope.dart';
23 import 'package:analyzer/src/generated/constant.dart'; 23 import 'package:analyzer/src/generated/constant.dart';
24 import 'package:analyzer/src/generated/element_resolver.dart'; 24 import 'package:analyzer/src/generated/element_resolver.dart';
25 import 'package:analyzer/src/generated/engine.dart'; 25 import 'package:analyzer/src/generated/engine.dart';
26 import 'package:analyzer/src/generated/error.dart'; 26 import 'package:analyzer/src/generated/error.dart';
27 import 'package:analyzer/src/generated/error_verifier.dart'; 27 import 'package:analyzer/src/generated/error_verifier.dart';
28 import 'package:analyzer/src/generated/java_core.dart'; 28 import 'package:analyzer/src/generated/java_core.dart';
29 import 'package:analyzer/src/generated/java_engine.dart'; 29 import 'package:analyzer/src/generated/java_engine.dart';
30 import 'package:analyzer/src/generated/source.dart'; 30 import 'package:analyzer/src/generated/source.dart';
31 import 'package:analyzer/src/generated/static_type_analyzer.dart'; 31 import 'package:analyzer/src/generated/static_type_analyzer.dart';
32 import 'package:analyzer/src/generated/type_system.dart'; 32 import 'package:analyzer/src/generated/type_system.dart';
33 import 'package:analyzer/src/generated/utilities_dart.dart'; 33 import 'package:analyzer/src/generated/utilities_dart.dart';
34 import 'package:analyzer/src/task/strong/info.dart' 34 import 'package:analyzer/src/task/strong/info.dart'
35 show InferredType, StaticInfo; 35 show InferredType, StaticInfo;
36 36
37 export 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
37 export 'package:analyzer/src/dart/resolver/scope.dart'; 38 export 'package:analyzer/src/dart/resolver/scope.dart';
38 export 'package:analyzer/src/generated/type_system.dart'; 39 export 'package:analyzer/src/generated/type_system.dart';
39 40
40 /** 41 /**
41 * Instances of the class `BestPracticesVerifier` traverse an AST structure look ing for 42 * Instances of the class `BestPracticesVerifier` traverse an AST structure look ing for
42 * violations of Dart best practices. 43 * violations of Dart best practices.
43 */ 44 */
44 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { 45 class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
45 // static String _HASHCODE_GETTER_NAME = "hashCode"; 46 // static String _HASHCODE_GETTER_NAME = "hashCode";
46 47
(...skipping 4782 matching lines...) Expand 10 before | Expand all | Expand 10 after
4829 /** 4830 /**
4830 * Attach contextual type information [type] to [node] for use during 4831 * Attach contextual type information [type] to [node] for use during
4831 * inference. 4832 * inference.
4832 */ 4833 */
4833 static void setTypeFromNode(AstNode innerNode, AstNode outerNode) { 4834 static void setTypeFromNode(AstNode innerNode, AstNode outerNode) {
4834 setType(innerNode, getType(outerNode)); 4835 setType(innerNode, getType(outerNode));
4835 } 4836 }
4836 } 4837 }
4837 4838
4838 /** 4839 /**
4839 * Instances of the class `InheritanceManager` manage the knowledge of where cla ss members
4840 * (methods, getters & setters) are inherited from.
4841 */
4842 class InheritanceManager {
4843 /**
4844 * The [LibraryElement] that is managed by this manager.
4845 */
4846 LibraryElement _library;
4847
4848 /**
4849 * This is a mapping between each [ClassElement] and a map between the [String ] member
4850 * names and the associated [ExecutableElement] in the mixin and superclass ch ain.
4851 */
4852 HashMap<ClassElement, MemberMap> _classLookup;
4853
4854 /**
4855 * This is a mapping between each [ClassElement] and a map between the [String ] member
4856 * names and the associated [ExecutableElement] in the interface set.
4857 */
4858 HashMap<ClassElement, MemberMap> _interfaceLookup;
4859
4860 /**
4861 * A map between each visited [ClassElement] and the set of [AnalysisError]s f ound on
4862 * the class element.
4863 */
4864 HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement =
4865 new HashMap<ClassElement, HashSet<AnalysisError>>();
4866
4867 /**
4868 * Initialize a newly created inheritance manager.
4869 *
4870 * @param library the library element context that the inheritance mappings ar e being generated
4871 */
4872 InheritanceManager(LibraryElement library) {
4873 this._library = library;
4874 _classLookup = new HashMap<ClassElement, MemberMap>();
4875 _interfaceLookup = new HashMap<ClassElement, MemberMap>();
4876 }
4877
4878 /**
4879 * Set the new library element context.
4880 *
4881 * @param library the new library element
4882 */
4883 void set libraryElement(LibraryElement library) {
4884 this._library = library;
4885 }
4886
4887 /**
4888 * Return the set of [AnalysisError]s found on the passed [ClassElement], or
4889 * `null` if there are none.
4890 *
4891 * @param classElt the class element to query
4892 * @return the set of [AnalysisError]s found on the passed [ClassElement], or
4893 * `null` if there are none
4894 */
4895 HashSet<AnalysisError> getErrors(ClassElement classElt) =>
4896 _errorsInClassElement[classElt];
4897
4898 /**
4899 * Get and return a mapping between the set of all string names of the members inherited from the
4900 * passed [ClassElement] superclass hierarchy, and the associated [ExecutableE lement].
4901 *
4902 * @param classElt the class element to query
4903 * @return a mapping between the set of all members inherited from the passed [ClassElement]
4904 * superclass hierarchy, and the associated [ExecutableElement]
4905 */
4906 MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) =>
4907 _computeClassChainLookupMap(classElt, new HashSet<ClassElement>());
4908
4909 /**
4910 * Get and return a mapping between the set of all string names of the members inherited from the
4911 * passed [ClassElement] interface hierarchy, and the associated [ExecutableEl ement].
4912 *
4913 * @param classElt the class element to query
4914 * @return a mapping between the set of all string names of the members inheri ted from the passed
4915 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement].
4916 */
4917 MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) =>
4918 _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>());
4919
4920 /**
4921 * Given some [ClassElement] and some member name, this returns the
4922 * [ExecutableElement] that the class inherits from the mixins,
4923 * superclasses or interfaces, that has the member name, if no member is inher ited `null` is
4924 * returned.
4925 *
4926 * @param classElt the class element to query
4927 * @param memberName the name of the executable element to find and return
4928 * @return the inherited executable element with the member name, or `null` if no such
4929 * member exists
4930 */
4931 ExecutableElement lookupInheritance(
4932 ClassElement classElt, String memberName) {
4933 if (memberName == null || memberName.isEmpty) {
4934 return null;
4935 }
4936 ExecutableElement executable =
4937 _computeClassChainLookupMap(classElt, new HashSet<ClassElement>())
4938 .get(memberName);
4939 if (executable == null) {
4940 return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>())
4941 .get(memberName);
4942 }
4943 return executable;
4944 }
4945
4946 /**
4947 * Given some [ClassElement] and some member name, this returns the
4948 * [ExecutableElement] that the class either declares itself, or
4949 * inherits, that has the member name, if no member is inherited `null` is ret urned.
4950 *
4951 * @param classElt the class element to query
4952 * @param memberName the name of the executable element to find and return
4953 * @return the inherited executable element with the member name, or `null` if no such
4954 * member exists
4955 */
4956 ExecutableElement lookupMember(ClassElement classElt, String memberName) {
4957 ExecutableElement element = _lookupMemberInClass(classElt, memberName);
4958 if (element != null) {
4959 return element;
4960 }
4961 return lookupInheritance(classElt, memberName);
4962 }
4963
4964 /**
4965 * Determine the set of methods which is overridden by the given class member. If no member is
4966 * inherited, an empty list is returned. If one of the inherited members is a
4967 * [MultiplyInheritedExecutableElement], then it is expanded into its constitu ent inherited
4968 * elements.
4969 *
4970 * @param classElt the class to query
4971 * @param memberName the name of the class member to query
4972 * @return a list of overridden methods
4973 */
4974 List<ExecutableElement> lookupOverrides(
4975 ClassElement classElt, String memberName) {
4976 List<ExecutableElement> result = new List<ExecutableElement>();
4977 if (memberName == null || memberName.isEmpty) {
4978 return result;
4979 }
4980 List<MemberMap> interfaceMaps =
4981 _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>());
4982 if (interfaceMaps != null) {
4983 for (MemberMap interfaceMap in interfaceMaps) {
4984 ExecutableElement overriddenElement = interfaceMap.get(memberName);
4985 if (overriddenElement != null) {
4986 if (overriddenElement is MultiplyInheritedExecutableElement) {
4987 MultiplyInheritedExecutableElement multiplyInheritedElement =
4988 overriddenElement;
4989 for (ExecutableElement element
4990 in multiplyInheritedElement.inheritedElements) {
4991 result.add(element);
4992 }
4993 } else {
4994 result.add(overriddenElement);
4995 }
4996 }
4997 }
4998 }
4999 return result;
5000 }
5001
5002 /**
5003 * This method takes some inherited [FunctionType], and resolves all the param eterized types
5004 * in the function type, dependent on the class in which it is being overridde n.
5005 *
5006 * @param baseFunctionType the function type that is being overridden
5007 * @param memberName the name of the member, this is used to lookup the inheri tance path of the
5008 * override
5009 * @param definingType the type that is overriding the member
5010 * @return the passed function type with any parameterized types substituted
5011 */
5012 // TODO(jmesserly): investigate why this is needed in ErrorVerifier's override
5013 // checking. There seems to be some rare cases where we get partially
5014 // substituted type arguments, and the function types don't compare equally.
5015 FunctionType substituteTypeArgumentsInMemberFromInheritance(
5016 FunctionType baseFunctionType,
5017 String memberName,
5018 InterfaceType definingType) {
5019 // if the baseFunctionType is null, or does not have any parameters,
5020 // return it.
5021 if (baseFunctionType == null ||
5022 baseFunctionType.typeArguments.length == 0) {
5023 return baseFunctionType;
5024 }
5025 // First, generate the path from the defining type to the overridden member
5026 Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
5027 _computeInheritancePath(inheritancePath, definingType, memberName);
5028 if (inheritancePath == null || inheritancePath.isEmpty) {
5029 // TODO(jwren) log analysis engine error
5030 return baseFunctionType;
5031 }
5032 FunctionType functionTypeToReturn = baseFunctionType;
5033 // loop backward through the list substituting as we go:
5034 while (!inheritancePath.isEmpty) {
5035 InterfaceType lastType = inheritancePath.removeLast();
5036 List<DartType> parameterTypes = lastType.element.type.typeArguments;
5037 List<DartType> argumentTypes = lastType.typeArguments;
5038 functionTypeToReturn =
5039 functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
5040 }
5041 return functionTypeToReturn;
5042 }
5043
5044 /**
5045 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5046 * the passed [ClassElement] superclass hierarchy, and the associated
5047 * [ExecutableElement].
5048 *
5049 * @param classElt the class element to query
5050 * @param visitedClasses a set of visited classes passed back into this method when it calls
5051 * itself recursively
5052 * @return a mapping between the set of all string names of the members inheri ted from the passed
5053 * [ClassElement] superclass hierarchy, and the associated [Executable Element]
5054 */
5055 MemberMap _computeClassChainLookupMap(
5056 ClassElement classElt, HashSet<ClassElement> visitedClasses) {
5057 MemberMap resultMap = _classLookup[classElt];
5058 if (resultMap != null) {
5059 return resultMap;
5060 } else {
5061 resultMap = new MemberMap();
5062 }
5063 ClassElement superclassElt = null;
5064 InterfaceType supertype = classElt.supertype;
5065 if (supertype != null) {
5066 superclassElt = supertype.element;
5067 } else {
5068 // classElt is Object
5069 _classLookup[classElt] = resultMap;
5070 return resultMap;
5071 }
5072 if (superclassElt != null) {
5073 if (!visitedClasses.contains(superclassElt)) {
5074 visitedClasses.add(superclassElt);
5075 try {
5076 resultMap = new MemberMap.from(
5077 _computeClassChainLookupMap(superclassElt, visitedClasses));
5078 //
5079 // Substitute the super types down the hierarchy.
5080 //
5081 _substituteTypeParametersDownHierarchy(supertype, resultMap);
5082 //
5083 // Include the members from the superclass in the resultMap.
5084 //
5085 _recordMapWithClassMembers(resultMap, supertype, false);
5086 } finally {
5087 visitedClasses.remove(superclassElt);
5088 }
5089 } else {
5090 // This case happens only when the superclass was previously visited and
5091 // not in the lookup, meaning this is meant to shorten the compute for
5092 // recursive cases.
5093 _classLookup[superclassElt] = resultMap;
5094 return resultMap;
5095 }
5096 }
5097 //
5098 // Include the members from the mixins in the resultMap. If there are
5099 // multiple mixins, visit them in the order listed so that methods in later
5100 // mixins will overwrite identically-named methods in earlier mixins.
5101 //
5102 List<InterfaceType> mixins = classElt.mixins;
5103 for (InterfaceType mixin in mixins) {
5104 ClassElement mixinElement = mixin.element;
5105 if (mixinElement != null) {
5106 if (!visitedClasses.contains(mixinElement)) {
5107 visitedClasses.add(mixinElement);
5108 try {
5109 MemberMap map = new MemberMap.from(
5110 _computeClassChainLookupMap(mixinElement, visitedClasses));
5111 //
5112 // Substitute the super types down the hierarchy.
5113 //
5114 _substituteTypeParametersDownHierarchy(mixin, map);
5115 //
5116 // Include the members from the superclass in the resultMap.
5117 //
5118 _recordMapWithClassMembers(map, mixin, false);
5119 //
5120 // Add the members from map into result map.
5121 //
5122 for (int j = 0; j < map.size; j++) {
5123 String key = map.getKey(j);
5124 ExecutableElement value = map.getValue(j);
5125 if (key != null) {
5126 ClassElement definingClass = value
5127 .getAncestor((Element element) => element is ClassElement);
5128 if (!definingClass.type.isObject) {
5129 ExecutableElement existingValue = resultMap.get(key);
5130 if (existingValue == null ||
5131 (existingValue != null && !_isAbstract(value))) {
5132 resultMap.put(key, value);
5133 }
5134 }
5135 }
5136 }
5137 } finally {
5138 visitedClasses.remove(mixinElement);
5139 }
5140 } else {
5141 // This case happens only when the superclass was previously visited
5142 // and not in the lookup, meaning this is meant to shorten the compute
5143 // for recursive cases.
5144 _classLookup[mixinElement] = resultMap;
5145 return resultMap;
5146 }
5147 }
5148 }
5149 _classLookup[classElt] = resultMap;
5150 return resultMap;
5151 }
5152
5153 /**
5154 * Compute and return the inheritance path given the context of a type and a m ember that is
5155 * overridden in the inheritance path (for which the type is in the path).
5156 *
5157 * @param chain the inheritance path that is built up as this method calls its elf recursively,
5158 * when this method is called an empty [LinkedList] should be provide d
5159 * @param currentType the current type in the inheritance path
5160 * @param memberName the name of the member that is being looked up the inheri tance path
5161 */
5162 void _computeInheritancePath(Queue<InterfaceType> chain,
5163 InterfaceType currentType, String memberName) {
5164 // TODO (jwren) create a public version of this method which doesn't require
5165 // the initial chain to be provided, then provided tests for this
5166 // functionality in InheritanceManagerTest
5167 chain.add(currentType);
5168 ClassElement classElt = currentType.element;
5169 InterfaceType supertype = classElt.supertype;
5170 // Base case- reached Object
5171 if (supertype == null) {
5172 // Looked up the chain all the way to Object, return null.
5173 // This should never happen.
5174 return;
5175 }
5176 // If we are done, return the chain
5177 // We are not done if this is the first recursive call on this method.
5178 if (chain.length != 1) {
5179 // We are done however if the member is in this classElt
5180 if (_lookupMemberInClass(classElt, memberName) != null) {
5181 return;
5182 }
5183 }
5184 // Mixins- note that mixins call lookupMemberInClass, not lookupMember
5185 List<InterfaceType> mixins = classElt.mixins;
5186 for (int i = mixins.length - 1; i >= 0; i--) {
5187 ClassElement mixinElement = mixins[i].element;
5188 if (mixinElement != null) {
5189 ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
5190 if (elt != null) {
5191 // this is equivalent (but faster than) calling this method
5192 // recursively
5193 // (return computeInheritancePath(chain, mixins[i], memberName);)
5194 chain.add(mixins[i]);
5195 return;
5196 }
5197 }
5198 }
5199 // Superclass
5200 ClassElement superclassElt = supertype.element;
5201 if (lookupMember(superclassElt, memberName) != null) {
5202 _computeInheritancePath(chain, supertype, memberName);
5203 return;
5204 }
5205 // Interfaces
5206 List<InterfaceType> interfaces = classElt.interfaces;
5207 for (InterfaceType interfaceType in interfaces) {
5208 ClassElement interfaceElement = interfaceType.element;
5209 if (interfaceElement != null &&
5210 lookupMember(interfaceElement, memberName) != null) {
5211 _computeInheritancePath(chain, interfaceType, memberName);
5212 return;
5213 }
5214 }
5215 }
5216
5217 /**
5218 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5219 * the passed [ClassElement] interface hierarchy, and the associated
5220 * [ExecutableElement].
5221 *
5222 * @param classElt the class element to query
5223 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
5224 * itself recursively
5225 * @return a mapping between the set of all string names of the members inheri ted from the passed
5226 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement]
5227 */
5228 MemberMap _computeInterfaceLookupMap(
5229 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
5230 MemberMap resultMap = _interfaceLookup[classElt];
5231 if (resultMap != null) {
5232 return resultMap;
5233 }
5234 List<MemberMap> lookupMaps =
5235 _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
5236 if (lookupMaps == null) {
5237 resultMap = new MemberMap();
5238 } else {
5239 HashMap<String, List<ExecutableElement>> unionMap =
5240 _unionInterfaceLookupMaps(lookupMaps);
5241 resultMap = _resolveInheritanceLookup(classElt, unionMap);
5242 }
5243 _interfaceLookup[classElt] = resultMap;
5244 return resultMap;
5245 }
5246
5247 /**
5248 * Collect a list of interface lookup maps whose elements correspond to all of the classes
5249 * directly above [classElt] in the class hierarchy (the direct superclass if any, all
5250 * mixins, and all direct superinterfaces). Each item in the list is the inter face lookup map
5251 * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
5252 * parameters appropriately substituted.
5253 *
5254 * @param classElt the class element to query
5255 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
5256 * itself recursively
5257 * @return `null` if there was a problem (such as a loop in the class hierarch y) or if there
5258 * are no classes above this one in the class hierarchy. Otherwise, a list of interface
5259 * lookup maps.
5260 */
5261 List<MemberMap> _gatherInterfaceLookupMaps(
5262 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
5263 InterfaceType supertype = classElt.supertype;
5264 ClassElement superclassElement =
5265 supertype != null ? supertype.element : null;
5266 List<InterfaceType> mixins = classElt.mixins;
5267 List<InterfaceType> interfaces = classElt.interfaces;
5268 // Recursively collect the list of mappings from all of the interface types
5269 List<MemberMap> lookupMaps = new List<MemberMap>();
5270 //
5271 // Superclass element
5272 //
5273 if (superclassElement != null) {
5274 if (!visitedInterfaces.contains(superclassElement)) {
5275 try {
5276 visitedInterfaces.add(superclassElement);
5277 //
5278 // Recursively compute the map for the super type.
5279 //
5280 MemberMap map =
5281 _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
5282 map = new MemberMap.from(map);
5283 //
5284 // Substitute the super type down the hierarchy.
5285 //
5286 _substituteTypeParametersDownHierarchy(supertype, map);
5287 //
5288 // Add any members from the super type into the map as well.
5289 //
5290 _recordMapWithClassMembers(map, supertype, true);
5291 lookupMaps.add(map);
5292 } finally {
5293 visitedInterfaces.remove(superclassElement);
5294 }
5295 } else {
5296 return null;
5297 }
5298 }
5299 //
5300 // Mixin elements
5301 //
5302 for (int i = mixins.length - 1; i >= 0; i--) {
5303 InterfaceType mixinType = mixins[i];
5304 ClassElement mixinElement = mixinType.element;
5305 if (mixinElement != null) {
5306 if (!visitedInterfaces.contains(mixinElement)) {
5307 try {
5308 visitedInterfaces.add(mixinElement);
5309 //
5310 // Recursively compute the map for the mixin.
5311 //
5312 MemberMap map =
5313 _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
5314 map = new MemberMap.from(map);
5315 //
5316 // Substitute the mixin type down the hierarchy.
5317 //
5318 _substituteTypeParametersDownHierarchy(mixinType, map);
5319 //
5320 // Add any members from the mixin type into the map as well.
5321 //
5322 _recordMapWithClassMembers(map, mixinType, true);
5323 lookupMaps.add(map);
5324 } finally {
5325 visitedInterfaces.remove(mixinElement);
5326 }
5327 } else {
5328 return null;
5329 }
5330 }
5331 }
5332 //
5333 // Interface elements
5334 //
5335 for (InterfaceType interfaceType in interfaces) {
5336 ClassElement interfaceElement = interfaceType.element;
5337 if (interfaceElement != null) {
5338 if (!visitedInterfaces.contains(interfaceElement)) {
5339 try {
5340 visitedInterfaces.add(interfaceElement);
5341 //
5342 // Recursively compute the map for the interfaces.
5343 //
5344 MemberMap map =
5345 _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
5346 map = new MemberMap.from(map);
5347 //
5348 // Substitute the supertypes down the hierarchy
5349 //
5350 _substituteTypeParametersDownHierarchy(interfaceType, map);
5351 //
5352 // And add any members from the interface into the map as well.
5353 //
5354 _recordMapWithClassMembers(map, interfaceType, true);
5355 lookupMaps.add(map);
5356 } finally {
5357 visitedInterfaces.remove(interfaceElement);
5358 }
5359 } else {
5360 return null;
5361 }
5362 }
5363 }
5364 if (lookupMaps.length == 0) {
5365 return null;
5366 }
5367 return lookupMaps;
5368 }
5369
5370 /**
5371 * Given some [ClassElement], this method finds and returns the [ExecutableEle ment] of
5372 * the passed name in the class element. Static members, members in super type s and members not
5373 * accessible from the current library are not considered.
5374 *
5375 * @param classElt the class element to query
5376 * @param memberName the name of the member to lookup in the class
5377 * @return the found [ExecutableElement], or `null` if no such member was foun d
5378 */
5379 ExecutableElement _lookupMemberInClass(
5380 ClassElement classElt, String memberName) {
5381 List<MethodElement> methods = classElt.methods;
5382 for (MethodElement method in methods) {
5383 if (memberName == method.name &&
5384 method.isAccessibleIn(_library) &&
5385 !method.isStatic) {
5386 return method;
5387 }
5388 }
5389 List<PropertyAccessorElement> accessors = classElt.accessors;
5390 for (PropertyAccessorElement accessor in accessors) {
5391 if (memberName == accessor.name &&
5392 accessor.isAccessibleIn(_library) &&
5393 !accessor.isStatic) {
5394 return accessor;
5395 }
5396 }
5397 return null;
5398 }
5399
5400 /**
5401 * Record the passed map with the set of all members (methods, getters and set ters) in the type
5402 * into the passed map.
5403 *
5404 * @param map some non-`null` map to put the methods and accessors from the pa ssed
5405 * [ClassElement] into
5406 * @param type the type that will be recorded into the passed map
5407 * @param doIncludeAbstract `true` if abstract members will be put into the ma p
5408 */
5409 void _recordMapWithClassMembers(
5410 MemberMap map, InterfaceType type, bool doIncludeAbstract) {
5411 List<MethodElement> methods = type.methods;
5412 for (MethodElement method in methods) {
5413 if (method.isAccessibleIn(_library) &&
5414 !method.isStatic &&
5415 (doIncludeAbstract || !method.isAbstract)) {
5416 map.put(method.name, method);
5417 }
5418 }
5419 List<PropertyAccessorElement> accessors = type.accessors;
5420 for (PropertyAccessorElement accessor in accessors) {
5421 if (accessor.isAccessibleIn(_library) &&
5422 !accessor.isStatic &&
5423 (doIncludeAbstract || !accessor.isAbstract)) {
5424 map.put(accessor.name, accessor);
5425 }
5426 }
5427 }
5428
5429 /**
5430 * This method is used to report errors on when they are found computing inher itance information.
5431 * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where thes e generated
5432 * error codes are reported back into the analysis engine.
5433 *
5434 * @param classElt the location of the source for which the exception occurred
5435 * @param offset the offset of the location of the error
5436 * @param length the length of the location of the error
5437 * @param errorCode the error code to be associated with this error
5438 * @param arguments the arguments used to build the error message
5439 */
5440 void _reportError(ClassElement classElt, int offset, int length,
5441 ErrorCode errorCode, List<Object> arguments) {
5442 HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
5443 if (errorSet == null) {
5444 errorSet = new HashSet<AnalysisError>();
5445 _errorsInClassElement[classElt] = errorSet;
5446 }
5447 errorSet.add(new AnalysisError(
5448 classElt.source, offset, length, errorCode, arguments));
5449 }
5450
5451 /**
5452 * Given the set of methods defined by classes above [classElt] in the class h ierarchy,
5453 * apply the appropriate inheritance rules to determine those methods inherite d by or overridden
5454 * by [classElt]. Also report static warnings
5455 * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
5456 * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if ap propriate.
5457 *
5458 * @param classElt the class element to query.
5459 * @param unionMap a mapping from method name to the set of unique (in terms o f signature) methods
5460 * defined in superclasses of [classElt].
5461 * @return the inheritance lookup map for [classElt].
5462 */
5463 MemberMap _resolveInheritanceLookup(ClassElement classElt,
5464 HashMap<String, List<ExecutableElement>> unionMap) {
5465 MemberMap resultMap = new MemberMap();
5466 unionMap.forEach((String key, List<ExecutableElement> list) {
5467 int numOfEltsWithMatchingNames = list.length;
5468 if (numOfEltsWithMatchingNames == 1) {
5469 //
5470 // Example: class A inherits only 1 method named 'm'.
5471 // Since it is the only such method, it is inherited.
5472 // Another example: class A inherits 2 methods named 'm' from 2
5473 // different interfaces, but they both have the same signature, so it is
5474 // the method inherited.
5475 //
5476 resultMap.put(key, list[0]);
5477 } else {
5478 //
5479 // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
5480 //
5481 bool allMethods = true;
5482 bool allSetters = true;
5483 bool allGetters = true;
5484 for (ExecutableElement executableElement in list) {
5485 if (executableElement is PropertyAccessorElement) {
5486 allMethods = false;
5487 if (executableElement.isSetter) {
5488 allGetters = false;
5489 } else {
5490 allSetters = false;
5491 }
5492 } else {
5493 allGetters = false;
5494 allSetters = false;
5495 }
5496 }
5497 //
5498 // If there isn't a mixture of methods with getters, then continue,
5499 // otherwise create a warning.
5500 //
5501 if (allMethods || allGetters || allSetters) {
5502 //
5503 // Compute the element whose type is the subtype of all of the other
5504 // types.
5505 //
5506 List<ExecutableElement> elements = new List.from(list);
5507 List<FunctionType> executableElementTypes =
5508 new List<FunctionType>(numOfEltsWithMatchingNames);
5509 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
5510 executableElementTypes[i] = elements[i].type;
5511 }
5512 List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
5513 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
5514 FunctionType subtype = executableElementTypes[i];
5515 if (subtype == null) {
5516 continue;
5517 }
5518 bool subtypeOfAllTypes = true;
5519 TypeSystem typeSystem = _library.context.typeSystem;
5520 for (int j = 0;
5521 j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
5522 j++) {
5523 if (i != j) {
5524 if (!typeSystem.isSubtypeOf(
5525 subtype, executableElementTypes[j])) {
5526 subtypeOfAllTypes = false;
5527 break;
5528 }
5529 }
5530 }
5531 if (subtypeOfAllTypes) {
5532 subtypesOfAllOtherTypesIndexes.add(i);
5533 }
5534 }
5535 //
5536 // The following is split into three cases determined by the number of
5537 // elements in subtypesOfAllOtherTypes
5538 //
5539 if (subtypesOfAllOtherTypesIndexes.length == 1) {
5540 //
5541 // Example: class A inherited only 2 method named 'm'.
5542 // One has the function type '() -> dynamic' and one has the
5543 // function type '([int]) -> dynamic'. Since the second method is a
5544 // subtype of all the others, it is the inherited method.
5545 // Tests: InheritanceManagerTest.
5546 // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
5547 //
5548 resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
5549 } else {
5550 if (subtypesOfAllOtherTypesIndexes.isEmpty) {
5551 //
5552 // Determine if the current class has a method or accessor with
5553 // the member name, if it does then then this class does not
5554 // "inherit" from any of the supertypes. See issue 16134.
5555 //
5556 bool classHasMember = false;
5557 if (allMethods) {
5558 classHasMember = classElt.getMethod(key) != null;
5559 } else {
5560 List<PropertyAccessorElement> accessors = classElt.accessors;
5561 for (int i = 0; i < accessors.length; i++) {
5562 if (accessors[i].name == key) {
5563 classHasMember = true;
5564 }
5565 }
5566 }
5567 //
5568 // Example: class A inherited only 2 method named 'm'.
5569 // One has the function type '() -> int' and one has the function
5570 // type '() -> String'. Since neither is a subtype of the other,
5571 // we create a warning, and have this class inherit nothing.
5572 //
5573 if (!classHasMember) {
5574 String firstTwoFuntionTypesStr =
5575 "${executableElementTypes[0]}, ${executableElementTypes[1]}" ;
5576 _reportError(
5577 classElt,
5578 classElt.nameOffset,
5579 classElt.nameLength,
5580 StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
5581 [key, firstTwoFuntionTypesStr]);
5582 }
5583 } else {
5584 //
5585 // Example: class A inherits 2 methods named 'm'.
5586 // One has the function type '(int) -> dynamic' and one has the
5587 // function type '(num) -> dynamic'. Since they are both a subtype
5588 // of the other, a synthetic function '(dynamic) -> dynamic' is
5589 // inherited.
5590 // Tests: test_getMapOfMembersInheritedFromInterfaces_
5591 // union_multipleSubtypes_*
5592 //
5593 List<ExecutableElement> elementArrayToMerge =
5594 new List<ExecutableElement>(
5595 subtypesOfAllOtherTypesIndexes.length);
5596 for (int i = 0; i < elementArrayToMerge.length; i++) {
5597 elementArrayToMerge[i] =
5598 elements[subtypesOfAllOtherTypesIndexes[i]];
5599 }
5600 ExecutableElement mergedExecutableElement =
5601 _computeMergedExecutableElement(elementArrayToMerge);
5602 resultMap.put(key, mergedExecutableElement);
5603 }
5604 }
5605 } else {
5606 _reportError(
5607 classElt,
5608 classElt.nameOffset,
5609 classElt.nameLength,
5610 StaticWarningCode
5611 .INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD,
5612 [key]);
5613 }
5614 }
5615 });
5616 return resultMap;
5617 }
5618
5619 /**
5620 * Loop through all of the members in some [MemberMap], performing type parame ter
5621 * substitutions using a passed supertype.
5622 *
5623 * @param superType the supertype to substitute into the members of the [Membe rMap]
5624 * @param map the MemberMap to perform the substitutions on
5625 */
5626 void _substituteTypeParametersDownHierarchy(
5627 InterfaceType superType, MemberMap map) {
5628 for (int i = 0; i < map.size; i++) {
5629 ExecutableElement executableElement = map.getValue(i);
5630 if (executableElement is MethodMember) {
5631 executableElement =
5632 MethodMember.from(executableElement as MethodMember, superType);
5633 map.setValue(i, executableElement);
5634 } else if (executableElement is PropertyAccessorMember) {
5635 executableElement = PropertyAccessorMember.from(
5636 executableElement as PropertyAccessorMember, superType);
5637 map.setValue(i, executableElement);
5638 }
5639 }
5640 }
5641
5642 /**
5643 * Union all of the [lookupMaps] together into a single map, grouping the Exec utableElements
5644 * into a list where none of the elements are equal where equality is determin ed by having equal
5645 * function types. (We also take note too of the kind of the element: ()->int and () -> int may
5646 * not be equal if one is a getter and the other is a method.)
5647 *
5648 * @param lookupMaps the maps to be unioned together.
5649 * @return the resulting union map.
5650 */
5651 HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
5652 List<MemberMap> lookupMaps) {
5653 HashMap<String, List<ExecutableElement>> unionMap =
5654 new HashMap<String, List<ExecutableElement>>();
5655 for (MemberMap lookupMap in lookupMaps) {
5656 int lookupMapSize = lookupMap.size;
5657 for (int i = 0; i < lookupMapSize; i++) {
5658 // Get the string key, if null, break.
5659 String key = lookupMap.getKey(i);
5660 if (key == null) {
5661 break;
5662 }
5663 // Get the list value out of the unionMap
5664 List<ExecutableElement> list = unionMap[key];
5665 // If we haven't created such a map for this key yet, do create it and
5666 // put the list entry into the unionMap.
5667 if (list == null) {
5668 list = new List<ExecutableElement>();
5669 unionMap[key] = list;
5670 }
5671 // Fetch the entry out of this lookupMap
5672 ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
5673 if (list.isEmpty) {
5674 // If the list is empty, just the new value
5675 list.add(newExecutableElementEntry);
5676 } else {
5677 // Otherwise, only add the newExecutableElementEntry if it isn't
5678 // already in the list, this covers situation where a class inherits
5679 // two methods (or two getters) that are identical.
5680 bool alreadyInList = false;
5681 bool isMethod1 = newExecutableElementEntry is MethodElement;
5682 for (ExecutableElement executableElementInList in list) {
5683 bool isMethod2 = executableElementInList is MethodElement;
5684 if (isMethod1 == isMethod2 &&
5685 executableElementInList.type ==
5686 newExecutableElementEntry.type) {
5687 alreadyInList = true;
5688 break;
5689 }
5690 }
5691 if (!alreadyInList) {
5692 list.add(newExecutableElementEntry);
5693 }
5694 }
5695 }
5696 }
5697 return unionMap;
5698 }
5699
5700 /**
5701 * Given some array of [ExecutableElement]s, this method creates a synthetic e lement as
5702 * described in 8.1.1:
5703 *
5704 * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional pa rameters of a
5705 * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote t he number of
5706 * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denot e the set of all
5707 * named parameters of the <i>m<sub>1</sub>, &hellip;, m<sub>k</sub></i>. Then let
5708 * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
5709 * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
5710 * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameter s of type
5711 * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, name d parameters
5712 * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
5713 *
5714 */
5715 static ExecutableElement _computeMergedExecutableElement(
5716 List<ExecutableElement> elementArrayToMerge) {
5717 int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
5718 int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
5719 Set<String> namedParametersList = new HashSet<String>();
5720 for (int i = 1; i < elementArrayToMerge.length; i++) {
5721 ExecutableElement element = elementArrayToMerge[i];
5722 int numOfPositionalParams = _getNumOfPositionalParameters(element);
5723 if (h < numOfPositionalParams) {
5724 h = numOfPositionalParams;
5725 }
5726 int numOfRequiredParams = _getNumOfRequiredParameters(element);
5727 if (r > numOfRequiredParams) {
5728 r = numOfRequiredParams;
5729 }
5730 namedParametersList.addAll(_getNamedParameterNames(element));
5731 }
5732 return _createSyntheticExecutableElement(
5733 elementArrayToMerge,
5734 elementArrayToMerge[0].displayName,
5735 r,
5736 h - r,
5737 new List.from(namedParametersList));
5738 }
5739
5740 /**
5741 * Used by [computeMergedExecutableElement] to actually create the
5742 * synthetic element.
5743 *
5744 * @param elementArrayToMerge the array used to create the synthetic element
5745 * @param name the name of the method, getter or setter
5746 * @param numOfRequiredParameters the number of required parameters
5747 * @param numOfPositionalParameters the number of positional parameters
5748 * @param namedParameters the list of [String]s that are the named parameters
5749 * @return the created synthetic element
5750 */
5751 static ExecutableElement _createSyntheticExecutableElement(
5752 List<ExecutableElement> elementArrayToMerge,
5753 String name,
5754 int numOfRequiredParameters,
5755 int numOfPositionalParameters,
5756 List<String> namedParameters) {
5757 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
5758 SimpleIdentifier nameIdentifier =
5759 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0));
5760 ExecutableElementImpl executable;
5761 if (elementArrayToMerge[0] is MethodElement) {
5762 MultiplyInheritedMethodElementImpl unionedMethod =
5763 new MultiplyInheritedMethodElementImpl(nameIdentifier);
5764 unionedMethod.inheritedElements = elementArrayToMerge;
5765 executable = unionedMethod;
5766 } else {
5767 MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
5768 new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
5769 unionedPropertyAccessor.getter =
5770 (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
5771 unionedPropertyAccessor.setter =
5772 (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
5773 unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
5774 executable = unionedPropertyAccessor;
5775 }
5776 int numOfParameters = numOfRequiredParameters +
5777 numOfPositionalParameters +
5778 namedParameters.length;
5779 List<ParameterElement> parameters =
5780 new List<ParameterElement>(numOfParameters);
5781 int i = 0;
5782 for (int j = 0; j < numOfRequiredParameters; j++, i++) {
5783 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
5784 parameter.type = dynamicType;
5785 parameter.parameterKind = ParameterKind.REQUIRED;
5786 parameters[i] = parameter;
5787 }
5788 for (int k = 0; k < numOfPositionalParameters; k++, i++) {
5789 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
5790 parameter.type = dynamicType;
5791 parameter.parameterKind = ParameterKind.POSITIONAL;
5792 parameters[i] = parameter;
5793 }
5794 for (int m = 0; m < namedParameters.length; m++, i++) {
5795 ParameterElementImpl parameter =
5796 new ParameterElementImpl(namedParameters[m], 0);
5797 parameter.type = dynamicType;
5798 parameter.parameterKind = ParameterKind.NAMED;
5799 parameters[i] = parameter;
5800 }
5801 executable.returnType = dynamicType;
5802 executable.parameters = parameters;
5803 FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
5804 executable.type = methodType;
5805 return executable;
5806 }
5807
5808 /**
5809 * Given some [ExecutableElement], return the list of named parameters.
5810 */
5811 static List<String> _getNamedParameterNames(
5812 ExecutableElement executableElement) {
5813 List<String> namedParameterNames = new List<String>();
5814 List<ParameterElement> parameters = executableElement.parameters;
5815 for (int i = 0; i < parameters.length; i++) {
5816 ParameterElement parameterElement = parameters[i];
5817 if (parameterElement.parameterKind == ParameterKind.NAMED) {
5818 namedParameterNames.add(parameterElement.name);
5819 }
5820 }
5821 return namedParameterNames;
5822 }
5823
5824 /**
5825 * Given some [ExecutableElement] return the number of parameters of the speci fied kind.
5826 */
5827 static int _getNumOfParameters(
5828 ExecutableElement executableElement, ParameterKind parameterKind) {
5829 int parameterCount = 0;
5830 List<ParameterElement> parameters = executableElement.parameters;
5831 for (int i = 0; i < parameters.length; i++) {
5832 ParameterElement parameterElement = parameters[i];
5833 if (parameterElement.parameterKind == parameterKind) {
5834 parameterCount++;
5835 }
5836 }
5837 return parameterCount;
5838 }
5839
5840 /**
5841 * Given some [ExecutableElement] return the number of positional parameters.
5842 *
5843 * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSI TIONAL].
5844 */
5845 static int _getNumOfPositionalParameters(
5846 ExecutableElement executableElement) =>
5847 _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
5848 _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
5849
5850 /**
5851 * Given some [ExecutableElement] return the number of required parameters.
5852 */
5853 static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
5854 _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
5855
5856 /**
5857 * Given some [ExecutableElement] returns `true` if it is an abstract member o f a
5858 * class.
5859 *
5860 * @param executableElement some [ExecutableElement] to evaluate
5861 * @return `true` if the given element is an abstract member of a class
5862 */
5863 static bool _isAbstract(ExecutableElement executableElement) {
5864 if (executableElement is MethodElement) {
5865 return executableElement.isAbstract;
5866 } else if (executableElement is PropertyAccessorElement) {
5867 return executableElement.isAbstract;
5868 }
5869 return false;
5870 }
5871 }
5872
5873 /**
5874 * This enum holds one of four states of a field initialization state through a constructor 4840 * This enum holds one of four states of a field initialization state through a constructor
5875 * signature, not initialized, initialized in the field declaration, initialized in the field 4841 * signature, not initialized, initialized in the field declaration, initialized in the field
5876 * formal, and finally, initialized in the initializers list. 4842 * formal, and finally, initialized in the initializers list.
5877 */ 4843 */
5878 class INIT_STATE extends Enum<INIT_STATE> { 4844 class INIT_STATE extends Enum<INIT_STATE> {
5879 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0); 4845 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0);
5880 4846
5881 static const INIT_STATE INIT_IN_DECLARATION = 4847 static const INIT_STATE INIT_IN_DECLARATION =
5882 const INIT_STATE('INIT_IN_DECLARATION', 1); 4848 const INIT_STATE('INIT_IN_DECLARATION', 1);
5883 4849
5884 static const INIT_STATE INIT_IN_FIELD_FORMAL = 4850 static const INIT_STATE INIT_IN_FIELD_FORMAL =
5885 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2); 4851 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2);
5886 4852
5887 static const INIT_STATE INIT_IN_INITIALIZERS = 4853 static const INIT_STATE INIT_IN_INITIALIZERS =
5888 const INIT_STATE('INIT_IN_INITIALIZERS', 3); 4854 const INIT_STATE('INIT_IN_INITIALIZERS', 3);
5889 4855
5890 static const List<INIT_STATE> values = const [ 4856 static const List<INIT_STATE> values = const [
5891 NOT_INIT, 4857 NOT_INIT,
5892 INIT_IN_DECLARATION, 4858 INIT_IN_DECLARATION,
5893 INIT_IN_FIELD_FORMAL, 4859 INIT_IN_FIELD_FORMAL,
5894 INIT_IN_INITIALIZERS 4860 INIT_IN_INITIALIZERS
5895 ]; 4861 ];
5896 4862
5897 const INIT_STATE(String name, int ordinal) : super(name, ordinal); 4863 const INIT_STATE(String name, int ordinal) : super(name, ordinal);
5898 } 4864 }
5899 4865
5900 /** 4866 /**
5901 * This class is used to replace uses of `HashMap<String, ExecutableElement>`
5902 * which are not as performant as this class.
5903 */
5904 class MemberMap {
5905 /**
5906 * The current size of this map.
5907 */
5908 int _size = 0;
5909
5910 /**
5911 * The array of keys.
5912 */
5913 List<String> _keys;
5914
5915 /**
5916 * The array of ExecutableElement values.
5917 */
5918 List<ExecutableElement> _values;
5919
5920 /**
5921 * Initialize a newly created member map to have the given [initialCapacity].
5922 * The map will grow if needed.
5923 */
5924 MemberMap([int initialCapacity = 10]) {
5925 _initArrays(initialCapacity);
5926 }
5927
5928 /**
5929 * Initialize a newly created member map to contain the same members as the
5930 * given [memberMap].
5931 */
5932 MemberMap.from(MemberMap memberMap) {
5933 _initArrays(memberMap._size + 5);
5934 for (int i = 0; i < memberMap._size; i++) {
5935 _keys[i] = memberMap._keys[i];
5936 _values[i] = memberMap._values[i];
5937 }
5938 _size = memberMap._size;
5939 }
5940
5941 /**
5942 * The size of the map.
5943 *
5944 * @return the size of the map.
5945 */
5946 int get size => _size;
5947
5948 /**
5949 * Given some key, return the ExecutableElement value from the map, if the key does not exist in
5950 * the map, `null` is returned.
5951 *
5952 * @param key some key to look up in the map
5953 * @return the associated ExecutableElement value from the map, if the key doe s not exist in the
5954 * map, `null` is returned
5955 */
5956 ExecutableElement get(String key) {
5957 for (int i = 0; i < _size; i++) {
5958 if (_keys[i] != null && _keys[i] == key) {
5959 return _values[i];
5960 }
5961 }
5962 return null;
5963 }
5964
5965 /**
5966 * Get and return the key at the specified location. If the key/value pair has been removed from
5967 * the set, then `null` is returned.
5968 *
5969 * @param i some non-zero value less than size
5970 * @return the key at the passed index
5971 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
5972 * zero or greater than or equal to the capacity of the arrays
5973 */
5974 String getKey(int i) => _keys[i];
5975
5976 /**
5977 * Get and return the ExecutableElement at the specified location. If the key/ value pair has been
5978 * removed from the set, then then `null` is returned.
5979 *
5980 * @param i some non-zero value less than size
5981 * @return the key at the passed index
5982 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
5983 * zero or greater than or equal to the capacity of the arrays
5984 */
5985 ExecutableElement getValue(int i) => _values[i];
5986
5987 /**
5988 * Given some key/value pair, store the pair in the map. If the key exists alr eady, then the new
5989 * value overrides the old value.
5990 *
5991 * @param key the key to store in the map
5992 * @param value the ExecutableElement value to store in the map
5993 */
5994 void put(String key, ExecutableElement value) {
5995 // If we already have a value with this key, override the value
5996 for (int i = 0; i < _size; i++) {
5997 if (_keys[i] != null && _keys[i] == key) {
5998 _values[i] = value;
5999 return;
6000 }
6001 }
6002 // If needed, double the size of our arrays and copy values over in both
6003 // arrays
6004 if (_size == _keys.length) {
6005 int newArrayLength = _size * 2;
6006 List<String> keys_new_array = new List<String>(newArrayLength);
6007 List<ExecutableElement> values_new_array =
6008 new List<ExecutableElement>(newArrayLength);
6009 for (int i = 0; i < _size; i++) {
6010 keys_new_array[i] = _keys[i];
6011 }
6012 for (int i = 0; i < _size; i++) {
6013 values_new_array[i] = _values[i];
6014 }
6015 _keys = keys_new_array;
6016 _values = values_new_array;
6017 }
6018 // Put new value at end of array
6019 _keys[_size] = key;
6020 _values[_size] = value;
6021 _size++;
6022 }
6023
6024 /**
6025 * Given some [String] key, this method replaces the associated key and value pair with
6026 * `null`. The size is not decremented with this call, instead it is expected that the users
6027 * check for `null`.
6028 *
6029 * @param key the key of the key/value pair to remove from the map
6030 */
6031 void remove(String key) {
6032 for (int i = 0; i < _size; i++) {
6033 if (_keys[i] == key) {
6034 _keys[i] = null;
6035 _values[i] = null;
6036 return;
6037 }
6038 }
6039 }
6040
6041 /**
6042 * Sets the ExecutableElement at the specified location.
6043 *
6044 * @param i some non-zero value less than size
6045 * @param value the ExecutableElement value to store in the map
6046 */
6047 void setValue(int i, ExecutableElement value) {
6048 _values[i] = value;
6049 }
6050
6051 /**
6052 * Initializes [keys] and [values].
6053 */
6054 void _initArrays(int initialCapacity) {
6055 _keys = new List<String>(initialCapacity);
6056 _values = new List<ExecutableElement>(initialCapacity);
6057 }
6058 }
6059
6060 /**
6061 * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation 4867 * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
6062 * unit to verify that if they have an override annotation it is being used corr ectly. 4868 * unit to verify that if they have an override annotation it is being used corr ectly.
6063 */ 4869 */
6064 class OverrideVerifier extends RecursiveAstVisitor<Object> { 4870 class OverrideVerifier extends RecursiveAstVisitor<Object> {
6065 /** 4871 /**
6066 * The error reporter used to report errors. 4872 * The error reporter used to report errors.
6067 */ 4873 */
6068 final ErrorReporter _errorReporter; 4874 final ErrorReporter _errorReporter;
6069 4875
6070 /** 4876 /**
(...skipping 5884 matching lines...) Expand 10 before | Expand all | Expand 10 after
11955 nonFields.add(node); 10761 nonFields.add(node);
11956 return null; 10762 return null;
11957 } 10763 }
11958 10764
11959 @override 10765 @override
11960 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); 10766 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
11961 10767
11962 @override 10768 @override
11963 Object visitWithClause(WithClause node) => null; 10769 Object visitWithClause(WithClause node) => null;
11964 } 10770 }
OLDNEW
« 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