OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, 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 analysis_server.analysis.index.index_core; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:collection'; | |
9 | |
10 import 'package:analysis_server/src/services/index/index.dart'; | |
11 import 'package:analyzer/src/generated/engine.dart'; | |
12 import 'package:analyzer/src/generated/source.dart'; | |
13 | |
14 /** | |
15 * An object that can have a [Relationship] with various [Location]s in a code | |
16 * base. The object is abstractly represented by a [kind] and an [offset] within | |
17 * a [source]. | |
18 * | |
19 * Clients must ensure that two distinct objects in the same source cannot have | |
20 * the same kind and offset. Failure to do so will make it impossible for | |
21 * clients to identify the model element corresponding to the indexable object. | |
22 * | |
23 * Clients are expected to subtype this class when implementing plugins. | |
24 */ | |
25 abstract class IndexableObject { | |
26 /** | |
27 * Return the kind of this object. | |
28 */ | |
29 IndexableObjectKind get kind; | |
30 | |
31 /** | |
32 * Return the length of the indexable object within its source. | |
33 */ | |
34 int get length; | |
35 | |
36 /** | |
37 * Return the name of this element. | |
38 */ | |
39 // TODO(brianwilkerson) Remove the need for this getter. | |
40 String get name; | |
41 | |
42 /** | |
43 * Return the offset of the indexable object within its source. | |
44 */ | |
45 int get offset; | |
46 | |
47 /** | |
48 * Return the source containing the indexable object. | |
49 */ | |
50 Source get source; | |
51 } | |
52 | |
53 /** | |
54 * The kind associated with an [IndexableObject]. | |
55 * | |
56 * Clients are expected to implement this class when implementing plugins. | |
57 */ | |
58 abstract class IndexableObjectKind { | |
59 /** | |
60 * The next available index for a newly created kind of indexable object. | |
61 */ | |
62 static int _nextIndex = 0; | |
63 | |
64 /** | |
65 * A table mapping indexes to object kinds. | |
66 */ | |
67 static Map<int, IndexableObjectKind> _registry = | |
68 new HashMap<int, IndexableObjectKind>(); | |
69 | |
70 /** | |
71 * Return the next available index for a newly created kind of indexable | |
72 * object. | |
73 */ | |
74 static int get nextIndex => _nextIndex++; | |
75 | |
76 /** | |
77 * Return the unique index for this kind of indexable object. Implementations | |
78 * should invoke [nextIndex] to allocate an index that cannot be used by any | |
79 * other object kind. | |
80 */ | |
81 int get index; | |
82 | |
83 /** | |
84 * Return the indexable object of this kind that exists in the given | |
85 * [context], in the source with the given [filePath], and at the given | |
86 * [offset]. | |
87 */ | |
88 IndexableObject decode(AnalysisContext context, String filePath, int offset); | |
89 | |
90 /** | |
91 * Return the object kind with the given [index]. | |
92 */ | |
93 static IndexableObjectKind getKind(int index) { | |
94 return _registry[index]; | |
95 } | |
96 | |
97 /** | |
98 * Register the given object [kind] so that it can be found by it's unique | |
99 * index. The index of the [kind] must not be changed after it is passed to | |
100 * this method. | |
101 */ | |
102 static void register(IndexableObjectKind kind) { | |
103 int index = kind.index; | |
104 if (_registry.containsKey(index)) { | |
105 throw new ArgumentError('duplicate index for kind: $index'); | |
106 } | |
107 _registry[index] = kind; | |
108 } | |
109 } | |
110 | |
111 /** | |
112 * An object used to add relationships to the index. | |
113 * | |
114 * Clients are expected to subtype this class when implementing plugins. | |
115 */ | |
116 abstract class IndexContributor { | |
117 /** | |
118 * Contribute relationships to the given index [store] as a result of | |
119 * analyzing the given [source] in the given [context]. | |
120 */ | |
121 void contributeTo(IndexStore store, AnalysisContext context, Source source); | |
122 } | |
123 | |
124 // A sketch of what the driver routine might look like: | |
125 // | |
126 //void buildIndexForSource(AnalysisContext context, Source source) { | |
127 // IndexStoreImpl store; | |
128 // store.aboutToIndex(context, source); | |
129 // try { | |
130 // for (IndexContributor contributor in contributors) { | |
131 // contributor.contributeTo(store, context, source); | |
132 // } | |
133 // } finally { | |
134 // store.doneIndexing(); | |
135 // } | |
136 //} | |
137 | |
138 /** | |
139 * An object that stores information about the relationships between locations | |
140 * in a code base. | |
141 * | |
142 * Clients are not expected to subtype this class. | |
143 */ | |
144 abstract class IndexStore { | |
145 /** | |
146 * Remove all of the information from the index. | |
147 */ | |
148 void clear(); | |
149 | |
150 /** | |
151 * Return a future that completes with the locations that have the given | |
152 * [relationship] with the given [indexable] object. | |
153 * | |
154 * For example, if the [indexable] object represents a function and the | |
155 * relationship is the `is-invoked-by` relationship, then the returned | |
156 * locations will be all of the places where the function is invoked. | |
157 */ | |
158 Future<List<Location>> getRelationships( | |
159 IndexableObject indexable, Relationship relationship); | |
160 | |
161 /** | |
162 * Record that the given [indexable] object and [location] have the given | |
163 * [relationship]. | |
164 * | |
165 * For example, if the [relationship] is the `is-invoked-by` relationship, | |
166 * then the [indexable] object would be the function being invoked and | |
167 * [location] would be the point at which it is invoked. Each indexable object | |
168 * can have the same relationship with multiple locations. In other words, if | |
169 * the following code were executed | |
170 * | |
171 * recordRelationship(indexable, isReferencedBy, location1); | |
172 * recordRelationship(indexable, isReferencedBy, location2); | |
173 * | |
174 * (where `location1 != location2`) then both relationships would be | |
175 * maintained in the index and the result of executing | |
176 * | |
177 * getRelationship(indexable, isReferencedBy); | |
178 * | |
179 * would be a list containing both `location1` and `location2`. | |
180 */ | |
181 void recordRelationship( | |
182 IndexableObject indexable, Relationship relationship, Location location); | |
183 | |
184 /** | |
185 * Remove from the index all of the information associated with the given | |
186 * [context]. | |
187 * | |
188 * This method should be invoked when the [context] is disposed. | |
189 */ | |
190 void removeContext(AnalysisContext context); | |
191 | |
192 /** | |
193 * Remove from the index all of the information associated with indexable | |
194 * objects or locations in the given [source]. This includes relationships | |
195 * between an indexable object in [source] and any other locations, as well as | |
196 * relationships between any other indexable objects and locations within | |
197 * the [source]. | |
198 * | |
199 * This method should be invoked when [source] is no longer part of the given | |
200 * [context]. | |
201 */ | |
202 void removeSource(AnalysisContext context, Source source); | |
203 | |
204 /** | |
205 * Remove from the index all of the information associated with indexable | |
206 * objects or locations in the given sources. This includes relationships | |
207 * between an indexable object in the given sources and any other locations, | |
208 * as well as relationships between any other indexable objects and a location | |
209 * within the given sources. | |
210 * | |
211 * This method should be invoked when the sources described by the given | |
212 * [container] are no longer part of the given [context]. | |
213 */ | |
214 void removeSources(AnalysisContext context, SourceContainer container); | |
215 } | |
216 | |
217 /** | |
218 * Instances of the class [Location] represent a location related to an | |
219 * indexable object. | |
220 * | |
221 * The location is expressed as an offset and length, but the offset is relative | |
222 * to the source containing the indexable object rather than the start of the | |
223 * indexable object within that source. | |
224 * | |
225 * Clients are not expected to subtype this class. | |
226 */ | |
227 abstract class Location { | |
228 /** | |
229 * An empty list of locations. | |
230 */ | |
231 static const List<Location> EMPTY_LIST = const <Location>[]; | |
232 | |
233 /** | |
234 * Return the indexable object containing this location. | |
235 */ | |
236 IndexableObject get indexable; | |
237 | |
238 /** | |
239 * Return `true` if this location is a qualified reference. | |
240 */ | |
241 bool get isQualified; | |
242 | |
243 /** | |
244 * Return `true` if this location is a resolved reference. | |
245 */ | |
246 bool get isResolved; | |
247 | |
248 /** | |
249 * Return the length of this location. | |
250 */ | |
251 int get length; | |
252 | |
253 /** | |
254 * Return the offset of this location within the source containing the | |
255 * indexable object. | |
256 */ | |
257 int get offset; | |
258 } | |
259 | |
260 /** | |
261 * A relationship between an indexable object and a location. Relationships are | |
262 * identified by a globally unique identifier. | |
263 * | |
264 * Clients are not expected to subtype this class. | |
265 */ | |
266 abstract class Relationship { | |
267 /** | |
268 * Return a relationship that has the given [identifier]. If the relationship | |
269 * has already been created, then it will be returned, otherwise a new | |
270 * relationship will be created | |
271 */ | |
272 factory Relationship(String identifier) => | |
273 RelationshipImpl.getRelationship(identifier); | |
274 } | |
OLD | NEW |