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

Side by Side Diff: packages/analyzer/lib/src/summary/prelink.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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
(Empty)
1 // Copyright (c) 2016, 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 import 'package:analyzer/src/generated/utilities_dart.dart';
6 import 'package:analyzer/src/summary/format.dart';
7 import 'package:analyzer/src/summary/idl.dart';
8 import 'package:analyzer/src/summary/name_filter.dart';
9
10 /**
11 * Create a [LinkedLibraryBuilder] corresponding to the given
12 * [definingUnit], which should be the defining compilation unit for a library.
13 * Compilation units referenced by the defining compilation unit via `part`
14 * declarations will be retrieved using [getPart]. Public namespaces for
15 * libraries referenced by the defining compilation unit via `import`
16 * declarations (and files reachable from them via `part` and `export`
17 * declarations) will be retrieved using [getImport].
18 */
19 LinkedLibraryBuilder prelink(UnlinkedUnit definingUnit, GetPartCallback getPart,
20 GetImportCallback getImport, GetDeclaredVariable getDeclaredVariable) {
21 return new _Prelinker(definingUnit, getPart, getImport, getDeclaredVariable)
22 .prelink();
23 }
24
25 /**
26 * Return the raw string value of the variable with the given [name],
27 * or `null` of the variable is not defined.
28 */
29 typedef String GetDeclaredVariable(String name);
30
31 /**
32 * Type of the callback used by the prelinker to obtain public namespace
33 * information about libraries imported by the library to be prelinked (and
34 * the transitive closure of parts and exports reachable from those libraries).
35 * [relativeUri] should be interpreted relative to the defining compilation
36 * unit of the library being prelinked.
37 *
38 * If no file exists at the given uri, `null` should be returned.
39 */
40 typedef UnlinkedPublicNamespace GetImportCallback(String relativeUri);
41
42 /**
43 * Type of the callback used by the prelinker to obtain unlinked summaries of
44 * part files of the library to be prelinked. [relativeUri] should be
45 * interpreted relative to the defining compilation unit of the library being
46 * prelinked.
47 *
48 * If no file exists at the given uri, `null` should be returned.
49 */
50 typedef UnlinkedUnit GetPartCallback(String relativeUri);
51
52 /**
53 * A [_Meaning] representing a class.
54 */
55 class _ClassMeaning extends _Meaning {
56 final Map<String, _Meaning> namespace;
57
58 _ClassMeaning(int unit, int dependency, int numTypeParameters, this.namespace)
59 : super(unit, ReferenceKind.classOrEnum, dependency, numTypeParameters);
60 }
61
62 /**
63 * A [_Meaning] stores all the information necessary to find the declaration
64 * referred to by a name in a namespace.
65 */
66 class _Meaning {
67 /**
68 * Which unit in the dependent library contains the declared entity.
69 */
70 final int unit;
71
72 /**
73 * The kind of entity being referred to.
74 */
75 final ReferenceKind kind;
76
77 /**
78 * Which of the dependencies of the library being prelinked contains the
79 * declared entity.
80 */
81 final int dependency;
82
83 /**
84 * If the entity being referred to is generic, the number of type parameters
85 * it accepts. Otherwise zero.
86 */
87 final int numTypeParameters;
88
89 _Meaning(this.unit, this.kind, this.dependency, this.numTypeParameters);
90
91 /**
92 * Encode this [_Meaning] as a [LinkedExportName], using the given [name].
93 */
94 LinkedExportName encodeExportName(String name) {
95 return new LinkedExportNameBuilder(
96 name: name, dependency: dependency, unit: unit, kind: kind);
97 }
98
99 /**
100 * Encode this [_Meaning] as a [LinkedReference].
101 */
102 LinkedReferenceBuilder encodeReference() {
103 return new LinkedReferenceBuilder(
104 unit: unit,
105 kind: kind,
106 dependency: dependency,
107 numTypeParameters: numTypeParameters);
108 }
109 }
110
111 /**
112 * A [_Meaning] representing a prefix introduced by an import directive.
113 */
114 class _PrefixMeaning extends _Meaning {
115 final Map<String, _Meaning> namespace = <String, _Meaning>{};
116
117 _PrefixMeaning() : super(0, ReferenceKind.prefix, 0, 0);
118 }
119
120 /**
121 * Helper class containing temporary data structures needed to prelink a single
122 * library.
123 *
124 * Note: throughout this class, a `null` value for a relative URI represents
125 * the defining compilation unit of the library being prelinked.
126 */
127 class _Prelinker {
128 final UnlinkedUnit definingUnit;
129 final GetPartCallback getPart;
130 final GetImportCallback getImport;
131 final GetDeclaredVariable getDeclaredVariable;
132
133 /**
134 * Cache of values returned by [getImport].
135 */
136 final Map<String, UnlinkedPublicNamespace> importCache =
137 <String, UnlinkedPublicNamespace>{};
138
139 /**
140 * Cache of values returned by [getPart].
141 */
142 final Map<String, UnlinkedUnit> partCache = <String, UnlinkedUnit>{};
143
144 /**
145 * Names defined inside the library being prelinked.
146 */
147 final Map<String, _Meaning> privateNamespace = <String, _Meaning>{
148 'dynamic': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0),
149 'void': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0)
150 };
151
152 /**
153 * List of dependencies of the library being prelinked. This will be output
154 * to [LinkedLibrary.dependencies].
155 */
156 final List<LinkedDependencyBuilder> dependencies = <LinkedDependencyBuilder>[
157 new LinkedDependencyBuilder()
158 ];
159
160 /**
161 * Map from the relative URI of a dependent library to the index of the
162 * corresponding entry in [dependencies].
163 */
164 final Map<String, int> uriToDependency = <String, int>{null: 0};
165
166 /**
167 * List of public namespaces corresponding to each entry in [dependencies].
168 */
169 final List<Map<String, _Meaning>> dependencyToPublicNamespace =
170 <Map<String, _Meaning>>[null];
171
172 _Prelinker(this.definingUnit, this.getPart, this.getImport,
173 this.getDeclaredVariable) {
174 partCache[null] = definingUnit;
175 importCache[null] = definingUnit.publicNamespace;
176 }
177
178 /**
179 * Compute the public namespace for the library whose URI is reachable from
180 * [definingUnit] via [relativeUri], by aggregating together public namespace
181 * information from all of its parts.
182 */
183 Map<String, _Meaning> aggregatePublicNamespace(String relativeUri) {
184 if (uriToDependency.containsKey(relativeUri)) {
185 return dependencyToPublicNamespace[uriToDependency[relativeUri]];
186 }
187 assert(dependencies.length == dependencyToPublicNamespace.length);
188 int dependency = dependencies.length;
189 uriToDependency[relativeUri] = dependency;
190 List<String> unitUris = getUnitUris(relativeUri);
191 LinkedDependencyBuilder linkedDependency = new LinkedDependencyBuilder(
192 uri: relativeUri, parts: unitUris.sublist(1));
193 dependencies.add(linkedDependency);
194
195 Map<String, _Meaning> aggregated = <String, _Meaning>{};
196
197 for (int unitNum = 0; unitNum < unitUris.length; unitNum++) {
198 String unitUri = unitUris[unitNum];
199 UnlinkedPublicNamespace importedNamespace = getImportCached(unitUri);
200 if (importedNamespace == null) {
201 continue;
202 }
203 for (UnlinkedPublicName name in importedNamespace.names) {
204 aggregated.putIfAbsent(name.name, () {
205 if (name.kind == ReferenceKind.classOrEnum) {
206 Map<String, _Meaning> namespace = <String, _Meaning>{};
207 name.members.forEach((executable) {
208 namespace[executable.name] = new _Meaning(
209 unitNum, executable.kind, 0, executable.numTypeParameters);
210 });
211 return new _ClassMeaning(
212 unitNum, dependency, name.numTypeParameters, namespace);
213 }
214 return new _Meaning(
215 unitNum, name.kind, dependency, name.numTypeParameters);
216 });
217 }
218 }
219
220 dependencyToPublicNamespace.add(aggregated);
221 return aggregated;
222 }
223
224 /**
225 * Compute the export namespace for the library whose URI is reachable from
226 * [definingUnit] via [relativeUri], by aggregating together public namespace
227 * information from the library and the transitive closure of its exports.
228 *
229 * If [relativeUri] is `null` (meaning the export namespace of [definingUnit]
230 * should be computed), then names defined in [definingUnit] are ignored.
231 */
232 Map<String, _Meaning> computeExportNamespace(String relativeUri) {
233 Map<String, _Meaning> exportNamespace = relativeUri == null
234 ? <String, _Meaning>{}
235 : aggregatePublicNamespace(relativeUri);
236 void chaseExports(
237 NameFilter filter, String relativeUri, Set<String> seenUris) {
238 if (seenUris.add(relativeUri)) {
239 UnlinkedPublicNamespace exportedNamespace =
240 getImportCached(relativeUri);
241 if (exportedNamespace != null) {
242 for (UnlinkedExportPublic export in exportedNamespace.exports) {
243 String relativeExportUri =
244 _selectUri(export.uri, export.configurations);
245 String exportUri = resolveUri(relativeUri, relativeExportUri);
246 NameFilter newFilter = filter.merge(
247 new NameFilter.forUnlinkedCombinators(export.combinators));
248 aggregatePublicNamespace(exportUri)
249 .forEach((String name, _Meaning meaning) {
250 if (newFilter.accepts(name) &&
251 !exportNamespace.containsKey(name)) {
252 exportNamespace[name] = meaning;
253 }
254 });
255 chaseExports(newFilter, exportUri, seenUris);
256 }
257 }
258 seenUris.remove(relativeUri);
259 }
260 }
261
262 chaseExports(NameFilter.identity, relativeUri, new Set<String>());
263 return exportNamespace;
264 }
265
266 /**
267 * Extract all the names defined in [unit] (which is the [unitNum]th unit in
268 * the library being prelinked) and store them in [privateNamespace].
269 * Excludes names introduced by `import` statements.
270 */
271 void extractPrivateNames(UnlinkedUnit unit, int unitNum) {
272 for (UnlinkedClass cls in unit.classes) {
273 privateNamespace.putIfAbsent(cls.name, () {
274 Map<String, _Meaning> namespace = <String, _Meaning>{};
275 cls.fields.forEach((field) {
276 if (field.isStatic && field.isConst) {
277 namespace[field.name] =
278 new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
279 }
280 });
281 cls.executables.forEach((executable) {
282 ReferenceKind kind = null;
283 if (executable.kind == UnlinkedExecutableKind.constructor) {
284 kind = ReferenceKind.constructor;
285 } else if (executable.kind ==
286 UnlinkedExecutableKind.functionOrMethod &&
287 executable.isStatic) {
288 kind = ReferenceKind.method;
289 } else if (executable.kind == UnlinkedExecutableKind.getter &&
290 executable.isStatic) {
291 kind = ReferenceKind.propertyAccessor;
292 }
293 if (kind != null && executable.name.isNotEmpty) {
294 namespace[executable.name] = new _Meaning(
295 unitNum, kind, 0, executable.typeParameters.length);
296 }
297 });
298 return new _ClassMeaning(
299 unitNum, 0, cls.typeParameters.length, namespace);
300 });
301 }
302 for (UnlinkedEnum enm in unit.enums) {
303 privateNamespace.putIfAbsent(enm.name, () {
304 Map<String, _Meaning> namespace = <String, _Meaning>{};
305 enm.values.forEach((UnlinkedEnumValue value) {
306 namespace[value.name] =
307 new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
308 });
309 namespace['values'] =
310 new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
311 return new _ClassMeaning(unitNum, 0, 0, namespace);
312 });
313 }
314 for (UnlinkedExecutable executable in unit.executables) {
315 privateNamespace.putIfAbsent(
316 executable.name,
317 () => new _Meaning(
318 unitNum,
319 executable.kind == UnlinkedExecutableKind.functionOrMethod
320 ? ReferenceKind.topLevelFunction
321 : ReferenceKind.topLevelPropertyAccessor,
322 0,
323 executable.typeParameters.length));
324 }
325 for (UnlinkedTypedef typedef in unit.typedefs) {
326 privateNamespace.putIfAbsent(
327 typedef.name,
328 () => new _Meaning(unitNum, ReferenceKind.typedef, 0,
329 typedef.typeParameters.length));
330 }
331 for (UnlinkedVariable variable in unit.variables) {
332 privateNamespace.putIfAbsent(
333 variable.name,
334 () => new _Meaning(
335 unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
336 if (!(variable.isConst || variable.isFinal)) {
337 privateNamespace.putIfAbsent(
338 variable.name + '=',
339 () => new _Meaning(
340 unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
341 }
342 }
343 }
344
345 /**
346 * Filter the export namespace for the library whose URI is reachable from
347 * [definingUnit] via [relativeUri], retaining only those names accepted by
348 * [combinators], and store the resulting names in [result]. Names that
349 * already exist in [result] are not overwritten.
350 */
351 void filterExportNamespace(String relativeUri,
352 List<UnlinkedCombinator> combinators, Map<String, _Meaning> result) {
353 Map<String, _Meaning> exportNamespace = computeExportNamespace(relativeUri);
354 NameFilter filter = new NameFilter.forUnlinkedCombinators(combinators);
355 exportNamespace.forEach((String name, _Meaning meaning) {
356 if (filter.accepts(name) && !result.containsKey(name)) {
357 result[name] = meaning;
358 }
359 });
360 }
361
362 /**
363 * Wrapper around [getImport] that caches the return value in [importCache].
364 */
365 UnlinkedPublicNamespace getImportCached(String relativeUri) {
366 return importCache.putIfAbsent(relativeUri, () => getImport(relativeUri));
367 }
368
369 /**
370 * Wrapper around [getPart] that caches the return value in [partCache] and
371 * updates [importCache] appropriately.
372 */
373 UnlinkedUnit getPartCached(String relativeUri) {
374 return partCache.putIfAbsent(relativeUri, () {
375 UnlinkedUnit unit = getPart(relativeUri);
376 importCache[relativeUri] = unit?.publicNamespace;
377 return unit;
378 });
379 }
380
381 /**
382 * Compute the set of relative URIs of all the compilation units in the
383 * library whose URI is reachable from [definingUnit] via [relativeUri].
384 */
385 List<String> getUnitUris(String relativeUri) {
386 List<String> result = <String>[relativeUri];
387 UnlinkedPublicNamespace publicNamespace = getImportCached(relativeUri);
388 if (publicNamespace != null) {
389 result.addAll(publicNamespace.parts
390 .map((String uri) => resolveUri(relativeUri, uri)));
391 }
392 return result;
393 }
394
395 /**
396 * Process a single `import` declaration in the library being prelinked. The
397 * return value is the index of the imported library in [dependencies].
398 */
399 int handleImport(UnlinkedImport import) {
400 String uri = import.isImplicit
401 ? 'dart:core'
402 : _selectUri(import.uri, import.configurations);
403 Map<String, _Meaning> targetNamespace = null;
404 if (import.prefixReference != 0) {
405 // The name introduced by an import declaration can't have a prefix of
406 // its own.
407 assert(
408 definingUnit.references[import.prefixReference].prefixReference == 0);
409 String prefix = definingUnit.references[import.prefixReference].name;
410 _Meaning prefixMeaning = privateNamespace[prefix];
411 if (prefixMeaning is _PrefixMeaning) {
412 targetNamespace = prefixMeaning.namespace;
413 }
414 } else {
415 targetNamespace = privateNamespace;
416 }
417 filterExportNamespace(uri, import.combinators, targetNamespace);
418 return uriToDependency[uri];
419 }
420
421 /**
422 * Produce a [LinkedUnit] for the given [unit], by resolving every one of
423 * its references.
424 */
425 LinkedUnitBuilder linkUnit(UnlinkedUnit unit) {
426 if (unit == null) {
427 return new LinkedUnitBuilder();
428 }
429 Map<int, Map<String, _Meaning>> prefixNamespaces =
430 <int, Map<String, _Meaning>>{};
431 List<LinkedReferenceBuilder> references = <LinkedReferenceBuilder>[];
432 for (int i = 0; i < unit.references.length; i++) {
433 UnlinkedReference reference = unit.references[i];
434 Map<String, _Meaning> namespace;
435 if (reference.prefixReference == 0) {
436 namespace = privateNamespace;
437 } else {
438 // Prefix references must always point backward.
439 assert(reference.prefixReference < i);
440 namespace = prefixNamespaces[reference.prefixReference];
441 // Expressions like 'a.b.c.d' cannot be prelinked.
442 namespace ??= const <String, _Meaning>{};
443 }
444 _Meaning meaning = namespace[reference.name];
445 if (meaning != null) {
446 if (meaning is _PrefixMeaning) {
447 prefixNamespaces[i] = meaning.namespace;
448 } else if (meaning is _ClassMeaning) {
449 prefixNamespaces[i] = meaning.namespace;
450 }
451 references.add(meaning.encodeReference());
452 } else {
453 references
454 .add(new LinkedReferenceBuilder(kind: ReferenceKind.unresolved));
455 }
456 }
457 return new LinkedUnitBuilder(references: references);
458 }
459
460 /**
461 * Form the [LinkedLibrary] for the [definingUnit] that was passed to the
462 * constructor.
463 */
464 LinkedLibraryBuilder prelink() {
465 // Gather up the unlinked summaries for all the compilation units in the
466 // library.
467 List<UnlinkedUnit> units = getUnitUris(null).map(getPartCached).toList();
468
469 // Create the private namespace for the library by gathering all the names
470 // defined in its compilation units.
471 for (int unitNum = 0; unitNum < units.length; unitNum++) {
472 UnlinkedUnit unit = units[unitNum];
473 if (unit != null) {
474 extractPrivateNames(unit, unitNum);
475 }
476 }
477
478 // Fill in exported names. This must be done before filling in prefixes
479 // defined in import declarations, because prefixes shouldn't shadow
480 // exports.
481 List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
482 computeExportNamespace(null).forEach((String name, _Meaning meaning) {
483 if (!privateNamespace.containsKey(name)) {
484 exportNames.add(meaning.encodeExportName(name));
485 }
486 });
487
488 // Fill in prefixes defined in import declarations.
489 for (UnlinkedImport import in units[0].imports) {
490 if (import.prefixReference != 0) {
491 privateNamespace.putIfAbsent(
492 units[0].references[import.prefixReference].name,
493 () => new _PrefixMeaning());
494 }
495 }
496
497 // Fill in imported and exported names.
498 List<int> importDependencies =
499 definingUnit.imports.map(handleImport).toList();
500 List<int> exportDependencies =
501 definingUnit.publicNamespace.exports.map((UnlinkedExportPublic exp) {
502 String uri = _selectUri(exp.uri, exp.configurations);
503 return uriToDependency[uri];
504 }).toList();
505
506 // Link each compilation unit.
507 List<LinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList();
508
509 return new LinkedLibraryBuilder(
510 units: linkedUnits,
511 dependencies: dependencies,
512 importDependencies: importDependencies,
513 exportDependencies: exportDependencies,
514 exportNames: exportNames,
515 numPrelinkedDependencies: dependencies.length);
516 }
517
518 /**
519 * Resolve [relativeUri] relative to [sourceUri]. Works correctly if
520 * [sourceUri] is also relative.
521 */
522 String resolveUri(String sourceUri, String relativeUri) {
523 if (sourceUri == null) {
524 return relativeUri;
525 } else {
526 return resolveRelativeUri(Uri.parse(sourceUri), Uri.parse(relativeUri))
527 .toString();
528 }
529 }
530
531 /**
532 * Return the URI of the first configuration from the given [configurations]
533 * which condition is satisfied, or the [defaultUri].
534 */
535 String _selectUri(
536 String defaultUri, List<UnlinkedConfiguration> configurations) {
537 for (UnlinkedConfiguration configuration in configurations) {
538 if (getDeclaredVariable(configuration.name) == configuration.value) {
539 return configuration.uri;
540 }
541 }
542 return defaultUri;
543 }
544 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/summary/package_bundle_reader.dart ('k') | packages/analyzer/lib/src/summary/pub_summary.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698