| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library services.hierarchy; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:collection'; | |
| 9 | |
| 10 import 'package:analysis_services/search/element_visitors.dart'; | |
| 11 import 'package:analysis_services/search/search_engine.dart'; | |
| 12 import 'package:analyzer/src/generated/element.dart'; | |
| 13 | |
| 14 | |
| 15 /** | |
| 16 * Returns direct children of [parent]. | |
| 17 */ | |
| 18 List<Element> getChildren(Element parent, [String name]) { | |
| 19 List<Element> children = <Element>[]; | |
| 20 visitChildren(parent, (Element element) { | |
| 21 if (name == null || element.displayName == name) { | |
| 22 children.add(element); | |
| 23 } | |
| 24 }); | |
| 25 return children; | |
| 26 } | |
| 27 | |
| 28 | |
| 29 /** | |
| 30 * Returns direct non-synthetic children of the given [ClassElement]. | |
| 31 * | |
| 32 * Includes: fields, accessors and methods. | |
| 33 * Excludes: constructors and synthetic elements. | |
| 34 */ | |
| 35 List<Element> getClassMembers(ClassElement clazz, [String name]) { | |
| 36 List<Element> members = <Element>[]; | |
| 37 visitChildren(clazz, (Element element) { | |
| 38 if (element.isSynthetic) { | |
| 39 return; | |
| 40 } | |
| 41 if (element is ConstructorElement) { | |
| 42 return; | |
| 43 } | |
| 44 if (name != null && element.displayName != name) { | |
| 45 return; | |
| 46 } | |
| 47 if (element is ExecutableElement) { | |
| 48 members.add(element); | |
| 49 } | |
| 50 if (element is FieldElement) { | |
| 51 members.add(element); | |
| 52 } | |
| 53 }); | |
| 54 return members; | |
| 55 } | |
| 56 | |
| 57 | |
| 58 /** | |
| 59 * Returns a [Set] with direct subclasses of [seed]. | |
| 60 */ | |
| 61 Future<Set<ClassElement>> getDirectSubClasses(SearchEngine searchEngine, | |
| 62 ClassElement seed) { | |
| 63 return searchEngine.searchSubtypes(seed).then((List<SearchMatch> matches) { | |
| 64 Set<ClassElement> subClasses = new HashSet<ClassElement>(); | |
| 65 for (SearchMatch match in matches) { | |
| 66 ClassElement subClass = match.element; | |
| 67 if (subClass.context == seed.context) { | |
| 68 subClasses.add(subClass); | |
| 69 } | |
| 70 } | |
| 71 return subClasses; | |
| 72 }); | |
| 73 } | |
| 74 | |
| 75 | |
| 76 /** | |
| 77 * @return all implementations of the given {@link ClassMemberElement} is its su
perclasses and | |
| 78 * their subclasses. | |
| 79 */ | |
| 80 Future<Set<ClassMemberElement>> getHierarchyMembers(SearchEngine searchEngine, | |
| 81 ClassMemberElement member) { | |
| 82 Set<ClassMemberElement> result = new HashSet<ClassMemberElement>(); | |
| 83 // constructor | |
| 84 if (member is ConstructorElement) { | |
| 85 result.add(member); | |
| 86 return new Future.value(result); | |
| 87 } | |
| 88 // method, field, etc | |
| 89 String name = member.displayName; | |
| 90 ClassElement memberClass = member.enclosingElement; | |
| 91 List<Future> futures = <Future>[]; | |
| 92 Set<ClassElement> searchClasses = getSuperClasses(memberClass); | |
| 93 searchClasses.add(memberClass); | |
| 94 for (ClassElement superClass in searchClasses) { | |
| 95 // ignore if super- class does not declare member | |
| 96 if (getClassMembers(superClass, name).isEmpty) { | |
| 97 continue; | |
| 98 } | |
| 99 // check all sub- classes | |
| 100 var subClassFuture = getSubClasses(searchEngine, superClass); | |
| 101 var membersFuture = subClassFuture.then((Set<ClassElement> subClasses) { | |
| 102 subClasses.add(superClass); | |
| 103 for (ClassElement subClass in subClasses) { | |
| 104 List<Element> subClassMembers = getChildren(subClass, name); | |
| 105 for (Element member in subClassMembers) { | |
| 106 if (member is ClassMemberElement) { | |
| 107 result.add(member); | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 }); | |
| 112 futures.add(membersFuture); | |
| 113 } | |
| 114 return Future.wait(futures).then((_) { | |
| 115 return result; | |
| 116 }); | |
| 117 } | |
| 118 | |
| 119 | |
| 120 /** | |
| 121 * Returns non-synthetic members of the given [ClassElement] and its super | |
| 122 * classes. | |
| 123 * | |
| 124 * Includes: fields, accessors and methods. | |
| 125 * Excludes: constructors and synthetic elements. | |
| 126 */ | |
| 127 List<Element> getMembers(ClassElement clazz) { | |
| 128 List<Element> members = <Element>[]; | |
| 129 members.addAll(getClassMembers(clazz)); | |
| 130 Set<ClassElement> superClasses = getSuperClasses(clazz); | |
| 131 for (ClassElement superClass in superClasses) { | |
| 132 members.addAll(getClassMembers(superClass)); | |
| 133 } | |
| 134 return members; | |
| 135 } | |
| 136 | |
| 137 | |
| 138 /** | |
| 139 * Returns a [Set] with all direct and indirect subclasses of [seed]. | |
| 140 */ | |
| 141 Future<Set<ClassElement>> getSubClasses(SearchEngine searchEngine, | |
| 142 ClassElement seed) { | |
| 143 Set<ClassElement> subs = new HashSet<ClassElement>(); | |
| 144 // prepare queue | |
| 145 List<ClassElement> queue = new List<ClassElement>(); | |
| 146 queue.add(seed); | |
| 147 // schedule subclasss search | |
| 148 addSubClasses() { | |
| 149 // add direct subclasses of the next class | |
| 150 while (queue.isNotEmpty) { | |
| 151 ClassElement clazz = queue.removeLast(); | |
| 152 if (subs.add(clazz)) { | |
| 153 return getDirectSubClasses(searchEngine, clazz).then((directSubs) { | |
| 154 queue.addAll(directSubs); | |
| 155 return new Future(addSubClasses); | |
| 156 }); | |
| 157 } | |
| 158 } | |
| 159 // done | |
| 160 subs.remove(seed); | |
| 161 return subs; | |
| 162 } | |
| 163 return new Future(addSubClasses); | |
| 164 } | |
| 165 | |
| 166 | |
| 167 /** | |
| 168 * Returns a [Set] with all direct and indirect superclasses of [seed]. | |
| 169 */ | |
| 170 Set<ClassElement> getSuperClasses(ClassElement seed) { | |
| 171 Set<ClassElement> result = new HashSet<ClassElement>(); | |
| 172 // prepare queue | |
| 173 List<ClassElement> queue = new List<ClassElement>(); | |
| 174 queue.add(seed); | |
| 175 // process queue | |
| 176 while (!queue.isEmpty) { | |
| 177 ClassElement current = queue.removeLast(); | |
| 178 // add if not checked already | |
| 179 if (!result.add(current)) { | |
| 180 continue; | |
| 181 } | |
| 182 // append supertype | |
| 183 { | |
| 184 InterfaceType superType = current.supertype; | |
| 185 if (superType != null) { | |
| 186 queue.add(superType.element); | |
| 187 } | |
| 188 } | |
| 189 // append interfaces | |
| 190 for (InterfaceType intf in current.interfaces) { | |
| 191 queue.add(intf.element); | |
| 192 } | |
| 193 } | |
| 194 // we don't need "seed" itself | |
| 195 result.remove(seed); | |
| 196 return result; | |
| 197 } | |
| 198 | |
| 199 | |
| 200 /** | |
| 201 * If the given [element] is a synthetic [PropertyAccessorElement] returns | |
| 202 * its variable, otherwise returns [element]. | |
| 203 */ | |
| 204 Element getSyntheticAccessorVariable(Element element) { | |
| 205 if (element is PropertyAccessorElement) { | |
| 206 if (element.isSynthetic) { | |
| 207 return element.variable; | |
| 208 } | |
| 209 } | |
| 210 return element; | |
| 211 } | |
| OLD | NEW |