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 |