OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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 import 'package:analyzer/src/summary/format.dart'; | 5 import 'package:analyzer/src/summary/format.dart'; |
6 import 'package:analyzer/src/summary/name_filter.dart'; | 6 import 'package:analyzer/src/summary/name_filter.dart'; |
7 | 7 |
8 /** | 8 /** |
9 * Create a [PrelinkedLibraryBuilder] corresponding to the given | 9 * Create a [LinkedLibraryBuilder] corresponding to the given |
10 * [definingUnit], which should be the defining compilation unit for a library. | 10 * [definingUnit], which should be the defining compilation unit for a library. |
11 * Compilation units referenced by the defining compilation unit via `part` | 11 * Compilation units referenced by the defining compilation unit via `part` |
12 * declarations will be retrieved using [getPart]. Public namespaces for | 12 * declarations will be retrieved using [getPart]. Public namespaces for |
13 * libraries referenced by the defining compilation unit via `import` | 13 * libraries referenced by the defining compilation unit via `import` |
14 * declarations (and files reachable from them via `part` and `export` | 14 * declarations (and files reachable from them via `part` and `export` |
15 * declarations) will be retrieved using [getImport]. | 15 * declarations) will be retrieved using [getImport]. |
16 */ | 16 */ |
17 PrelinkedLibraryBuilder prelink(UnlinkedUnit definingUnit, | 17 LinkedLibraryBuilder prelink(UnlinkedUnit definingUnit, GetPartCallback getPart, |
18 GetPartCallback getPart, GetImportCallback getImport) { | 18 GetImportCallback getImport) { |
19 return new _Prelinker(definingUnit, getPart, getImport).prelink(); | 19 return new _Prelinker(definingUnit, getPart, getImport).prelink(); |
20 } | 20 } |
21 | 21 |
22 /** | 22 /** |
23 * Type of the callback used by the prelinker to obtain public namespace | 23 * Type of the callback used by the prelinker to obtain public namespace |
24 * information about libraries imported by the library to be prelinked (and | 24 * information about libraries imported by the library to be prelinked (and |
25 * the transitive closure of parts and exports reachable from those libraries). | 25 * the transitive closure of parts and exports reachable from those libraries). |
26 * [relativeUri] should be interpreted relative to the defining compilation | 26 * [relativeUri] should be interpreted relative to the defining compilation |
27 * unit of the library being prelinked. | 27 * unit of the library being prelinked. |
28 * | 28 * |
(...skipping 17 matching lines...) Expand all Loading... |
46 */ | 46 */ |
47 class _Meaning { | 47 class _Meaning { |
48 /** | 48 /** |
49 * Which unit in the dependent library contains the declared entity. | 49 * Which unit in the dependent library contains the declared entity. |
50 */ | 50 */ |
51 final int unit; | 51 final int unit; |
52 | 52 |
53 /** | 53 /** |
54 * The kind of entity being referred to. | 54 * The kind of entity being referred to. |
55 */ | 55 */ |
56 final PrelinkedReferenceKind kind; | 56 final ReferenceKind kind; |
57 | 57 |
58 /** | 58 /** |
59 * Which of the dependencies of the library being prelinked contains the | 59 * Which of the dependencies of the library being prelinked contains the |
60 * declared entity. | 60 * declared entity. |
61 */ | 61 */ |
62 final int dependency; | 62 final int dependency; |
63 | 63 |
64 /** | 64 /** |
65 * If the entity being referred to is generic, the number of type parameters | 65 * If the entity being referred to is generic, the number of type parameters |
66 * it accepts. Otherwise zero. | 66 * it accepts. Otherwise zero. |
67 */ | 67 */ |
68 final int numTypeParameters; | 68 final int numTypeParameters; |
69 | 69 |
70 _Meaning(this.unit, this.kind, this.dependency, this.numTypeParameters); | 70 _Meaning(this.unit, this.kind, this.dependency, this.numTypeParameters); |
71 | 71 |
72 /** | 72 /** |
73 * Encode this [_Meaning] as a [PrelinkedExportName], using the given [name]. | 73 * Encode this [_Meaning] as a [LinkedExportName], using the given [name]. |
74 */ | 74 */ |
75 PrelinkedExportName encodeExportName(String name) { | 75 LinkedExportName encodeExportName(String name) { |
76 return new PrelinkedExportNameBuilder( | 76 return new LinkedExportNameBuilder( |
77 name: name, dependency: dependency, unit: unit, kind: kind); | 77 name: name, dependency: dependency, unit: unit, kind: kind); |
78 } | 78 } |
79 | 79 |
80 /** | 80 /** |
81 * Encode this [_Meaning] as a [PrelinkedReference]. | 81 * Encode this [_Meaning] as a [LinkedReference]. |
82 */ | 82 */ |
83 PrelinkedReferenceBuilder encodeReference() { | 83 LinkedReferenceBuilder encodeReference() { |
84 return new PrelinkedReferenceBuilder( | 84 return new LinkedReferenceBuilder( |
85 unit: unit, | 85 unit: unit, |
86 kind: kind, | 86 kind: kind, |
87 dependency: dependency, | 87 dependency: dependency, |
88 numTypeParameters: numTypeParameters); | 88 numTypeParameters: numTypeParameters); |
89 } | 89 } |
90 } | 90 } |
91 | 91 |
92 /** | 92 /** |
93 * A [_Meaning] representing a prefix introduced by an import directive. | 93 * A [_Meaning] representing a prefix introduced by an import directive. |
94 */ | 94 */ |
95 class _PrefixMeaning extends _Meaning { | 95 class _PrefixMeaning extends _Meaning { |
96 final Map<String, _Meaning> namespace = <String, _Meaning>{}; | 96 final Map<String, _Meaning> namespace = <String, _Meaning>{}; |
97 | 97 |
98 _PrefixMeaning() : super(0, PrelinkedReferenceKind.prefix, 0, 0); | 98 _PrefixMeaning() : super(0, ReferenceKind.prefix, 0, 0); |
99 } | 99 } |
100 | 100 |
101 /** | 101 /** |
102 * Helper class containing temporary data structures needed to prelink a single | 102 * Helper class containing temporary data structures needed to prelink a single |
103 * library. | 103 * library. |
104 * | 104 * |
105 * Note: throughout this class, a `null` value for a relative URI represents | 105 * Note: throughout this class, a `null` value for a relative URI represents |
106 * the defining compilation unit of the library being prelinked. | 106 * the defining compilation unit of the library being prelinked. |
107 */ | 107 */ |
108 class _Prelinker { | 108 class _Prelinker { |
109 final UnlinkedUnit definingUnit; | 109 final UnlinkedUnit definingUnit; |
110 final GetPartCallback getPart; | 110 final GetPartCallback getPart; |
111 final GetImportCallback getImport; | 111 final GetImportCallback getImport; |
112 | 112 |
113 /** | 113 /** |
114 * Cache of values returned by [getImport]. | 114 * Cache of values returned by [getImport]. |
115 */ | 115 */ |
116 final Map<String, UnlinkedPublicNamespace> importCache = | 116 final Map<String, UnlinkedPublicNamespace> importCache = |
117 <String, UnlinkedPublicNamespace>{}; | 117 <String, UnlinkedPublicNamespace>{}; |
118 | 118 |
119 /** | 119 /** |
120 * Cache of values returned by [getPart]. | 120 * Cache of values returned by [getPart]. |
121 */ | 121 */ |
122 final Map<String, UnlinkedUnit> partCache = <String, UnlinkedUnit>{}; | 122 final Map<String, UnlinkedUnit> partCache = <String, UnlinkedUnit>{}; |
123 | 123 |
124 /** | 124 /** |
125 * Names defined inside the library being prelinked. | 125 * Names defined inside the library being prelinked. |
126 */ | 126 */ |
127 final Map<String, _Meaning> privateNamespace = <String, _Meaning>{ | 127 final Map<String, _Meaning> privateNamespace = <String, _Meaning>{ |
128 '': new _Meaning(0, PrelinkedReferenceKind.classOrEnum, 0, 0) | 128 '': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0) |
129 }; | 129 }; |
130 | 130 |
131 /** | 131 /** |
132 * List of dependencies of the library being prelinked. This will be output | 132 * List of dependencies of the library being prelinked. This will be output |
133 * to [PrelinkedLibrary.dependencies]. | 133 * to [LinkedLibrary.dependencies]. |
134 */ | 134 */ |
135 final List<PrelinkedDependencyBuilder> dependencies = | 135 final List<LinkedDependencyBuilder> dependencies = <LinkedDependencyBuilder>[ |
136 <PrelinkedDependencyBuilder>[new PrelinkedDependencyBuilder()]; | 136 new LinkedDependencyBuilder() |
| 137 ]; |
137 | 138 |
138 /** | 139 /** |
139 * Map from the relative URI of a dependent library to the index of the | 140 * Map from the relative URI of a dependent library to the index of the |
140 * corresponding entry in [dependencies]. | 141 * corresponding entry in [dependencies]. |
141 */ | 142 */ |
142 final Map<String, int> uriToDependency = <String, int>{null: 0}; | 143 final Map<String, int> uriToDependency = <String, int>{null: 0}; |
143 | 144 |
144 /** | 145 /** |
145 * List of public namespaces corresponding to each entry in [dependencies]. | 146 * List of public namespaces corresponding to each entry in [dependencies]. |
146 */ | 147 */ |
(...skipping 11 matching lines...) Expand all Loading... |
158 * information from all of its parts. | 159 * information from all of its parts. |
159 */ | 160 */ |
160 Map<String, _Meaning> aggregatePublicNamespace(String relativeUri) { | 161 Map<String, _Meaning> aggregatePublicNamespace(String relativeUri) { |
161 if (uriToDependency.containsKey(relativeUri)) { | 162 if (uriToDependency.containsKey(relativeUri)) { |
162 return dependencyToPublicNamespace[uriToDependency[relativeUri]]; | 163 return dependencyToPublicNamespace[uriToDependency[relativeUri]]; |
163 } | 164 } |
164 assert(dependencies.length == dependencyToPublicNamespace.length); | 165 assert(dependencies.length == dependencyToPublicNamespace.length); |
165 int dependency = dependencies.length; | 166 int dependency = dependencies.length; |
166 uriToDependency[relativeUri] = dependency; | 167 uriToDependency[relativeUri] = dependency; |
167 List<String> unitUris = getUnitUris(relativeUri); | 168 List<String> unitUris = getUnitUris(relativeUri); |
168 PrelinkedDependencyBuilder prelinkedDependency = | 169 LinkedDependencyBuilder linkedDependency = new LinkedDependencyBuilder( |
169 new PrelinkedDependencyBuilder( | 170 uri: relativeUri, parts: unitUris.sublist(1)); |
170 uri: relativeUri, parts: unitUris.sublist(1)); | 171 dependencies.add(linkedDependency); |
171 dependencies.add(prelinkedDependency); | |
172 | 172 |
173 Map<String, _Meaning> aggregated = <String, _Meaning>{}; | 173 Map<String, _Meaning> aggregated = <String, _Meaning>{}; |
174 | 174 |
175 for (int unitNum = 0; unitNum < unitUris.length; unitNum++) { | 175 for (int unitNum = 0; unitNum < unitUris.length; unitNum++) { |
176 String unitUri = unitUris[unitNum]; | 176 String unitUri = unitUris[unitNum]; |
177 UnlinkedPublicNamespace importedNamespace = getImportCached(unitUri); | 177 UnlinkedPublicNamespace importedNamespace = getImportCached(unitUri); |
178 if (importedNamespace == null) { | 178 if (importedNamespace == null) { |
179 continue; | 179 continue; |
180 } | 180 } |
181 for (UnlinkedPublicName name in importedNamespace.names) { | 181 for (UnlinkedPublicName name in importedNamespace.names) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 | 231 |
232 /** | 232 /** |
233 * Extract all the names defined in [unit] (which is the [unitNum]th unit in | 233 * Extract all the names defined in [unit] (which is the [unitNum]th unit in |
234 * the library being prelinked) and store them in [privateNamespace]. | 234 * the library being prelinked) and store them in [privateNamespace]. |
235 * Excludes names introduced by `import` statements. | 235 * Excludes names introduced by `import` statements. |
236 */ | 236 */ |
237 void extractPrivateNames(UnlinkedUnit unit, int unitNum) { | 237 void extractPrivateNames(UnlinkedUnit unit, int unitNum) { |
238 for (UnlinkedClass cls in unit.classes) { | 238 for (UnlinkedClass cls in unit.classes) { |
239 privateNamespace.putIfAbsent( | 239 privateNamespace.putIfAbsent( |
240 cls.name, | 240 cls.name, |
241 () => new _Meaning(unitNum, PrelinkedReferenceKind.classOrEnum, 0, | 241 () => new _Meaning(unitNum, ReferenceKind.classOrEnum, 0, |
242 cls.typeParameters.length)); | 242 cls.typeParameters.length)); |
243 } | 243 } |
244 for (UnlinkedEnum enm in unit.enums) { | 244 for (UnlinkedEnum enm in unit.enums) { |
245 privateNamespace.putIfAbsent( | 245 privateNamespace.putIfAbsent(enm.name, |
246 enm.name, | 246 () => new _Meaning(unitNum, ReferenceKind.classOrEnum, 0, 0)); |
247 () => | |
248 new _Meaning(unitNum, PrelinkedReferenceKind.classOrEnum, 0, 0)); | |
249 } | 247 } |
250 for (UnlinkedExecutable executable in unit.executables) { | 248 for (UnlinkedExecutable executable in unit.executables) { |
251 privateNamespace.putIfAbsent( | 249 privateNamespace.putIfAbsent( |
252 executable.name, | 250 executable.name, |
253 () => new _Meaning( | 251 () => new _Meaning( |
254 unitNum, | 252 unitNum, |
255 executable.kind == UnlinkedExecutableKind.functionOrMethod | 253 executable.kind == UnlinkedExecutableKind.functionOrMethod |
256 ? PrelinkedReferenceKind.topLevelFunction | 254 ? ReferenceKind.topLevelFunction |
257 : PrelinkedReferenceKind.topLevelPropertyAccessor, | 255 : ReferenceKind.topLevelPropertyAccessor, |
258 0, | 256 0, |
259 executable.typeParameters.length)); | 257 executable.typeParameters.length)); |
260 } | 258 } |
261 for (UnlinkedTypedef typedef in unit.typedefs) { | 259 for (UnlinkedTypedef typedef in unit.typedefs) { |
262 privateNamespace.putIfAbsent( | 260 privateNamespace.putIfAbsent( |
263 typedef.name, | 261 typedef.name, |
264 () => new _Meaning(unitNum, PrelinkedReferenceKind.typedef, 0, | 262 () => new _Meaning(unitNum, ReferenceKind.typedef, 0, |
265 typedef.typeParameters.length)); | 263 typedef.typeParameters.length)); |
266 } | 264 } |
267 for (UnlinkedVariable variable in unit.variables) { | 265 for (UnlinkedVariable variable in unit.variables) { |
268 privateNamespace.putIfAbsent( | 266 privateNamespace.putIfAbsent( |
269 variable.name, | 267 variable.name, |
270 () => new _Meaning( | 268 () => new _Meaning( |
271 unitNum, PrelinkedReferenceKind.topLevelPropertyAccessor, 0, 0)); | 269 unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0)); |
272 if (!(variable.isConst || variable.isFinal)) { | 270 if (!(variable.isConst || variable.isFinal)) { |
273 privateNamespace.putIfAbsent( | 271 privateNamespace.putIfAbsent( |
274 variable.name + '=', | 272 variable.name + '=', |
275 () => new _Meaning(unitNum, | 273 () => new _Meaning( |
276 PrelinkedReferenceKind.topLevelPropertyAccessor, 0, 0)); | 274 unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0)); |
277 } | 275 } |
278 } | 276 } |
279 } | 277 } |
280 | 278 |
281 /** | 279 /** |
282 * Filter the export namespace for the library whose URI is reachable from | 280 * Filter the export namespace for the library whose URI is reachable from |
283 * [definingUnit] via [relativeUri], retaining only those names accepted by | 281 * [definingUnit] via [relativeUri], retaining only those names accepted by |
284 * [combinators], and store the resulting names in [result]. Names that | 282 * [combinators], and store the resulting names in [result]. Names that |
285 * already exist in [result] are not overwritten. | 283 * already exist in [result] are not overwritten. |
286 */ | 284 */ |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 targetNamespace = prefixMeaning.namespace; | 344 targetNamespace = prefixMeaning.namespace; |
347 } | 345 } |
348 } else { | 346 } else { |
349 targetNamespace = privateNamespace; | 347 targetNamespace = privateNamespace; |
350 } | 348 } |
351 filterExportNamespace(uri, import.combinators, targetNamespace); | 349 filterExportNamespace(uri, import.combinators, targetNamespace); |
352 return uriToDependency[uri]; | 350 return uriToDependency[uri]; |
353 } | 351 } |
354 | 352 |
355 /** | 353 /** |
356 * Produce a [PrelinkedUnit] for the given [unit], by resolving every one of | 354 * Produce a [LinkedUnit] for the given [unit], by resolving every one of |
357 * its references. | 355 * its references. |
358 */ | 356 */ |
359 PrelinkedUnitBuilder linkUnit(UnlinkedUnit unit) { | 357 LinkedUnitBuilder linkUnit(UnlinkedUnit unit) { |
360 if (unit == null) { | 358 if (unit == null) { |
361 return new PrelinkedUnitBuilder(); | 359 return new LinkedUnitBuilder(); |
362 } | 360 } |
363 Map<int, Map<String, _Meaning>> prefixNamespaces = | 361 Map<int, Map<String, _Meaning>> prefixNamespaces = |
364 <int, Map<String, _Meaning>>{}; | 362 <int, Map<String, _Meaning>>{}; |
365 List<PrelinkedReferenceBuilder> references = <PrelinkedReferenceBuilder>[]; | 363 List<LinkedReferenceBuilder> references = <LinkedReferenceBuilder>[]; |
366 for (int i = 0; i < unit.references.length; i++) { | 364 for (int i = 0; i < unit.references.length; i++) { |
367 UnlinkedReference reference = unit.references[i]; | 365 UnlinkedReference reference = unit.references[i]; |
368 Map<String, _Meaning> namespace; | 366 Map<String, _Meaning> namespace; |
369 if (reference.prefixReference != 0) { | 367 if (reference.prefixReference != 0) { |
370 // Prefix references must always point backward. | 368 // Prefix references must always point backward. |
371 assert(reference.prefixReference < i); | 369 assert(reference.prefixReference < i); |
372 namespace = prefixNamespaces[reference.prefixReference]; | 370 namespace = prefixNamespaces[reference.prefixReference]; |
373 // Prefix references must always point to proper prefixes. | 371 // Prefix references must always point to proper prefixes. |
374 assert(namespace != null); | 372 assert(namespace != null); |
375 } else { | 373 } else { |
376 namespace = privateNamespace; | 374 namespace = privateNamespace; |
377 } | 375 } |
378 _Meaning meaning = namespace[reference.name]; | 376 _Meaning meaning = namespace[reference.name]; |
379 if (meaning != null) { | 377 if (meaning != null) { |
380 if (meaning is _PrefixMeaning) { | 378 if (meaning is _PrefixMeaning) { |
381 prefixNamespaces[i] = meaning.namespace; | 379 prefixNamespaces[i] = meaning.namespace; |
382 } | 380 } |
383 references.add(meaning.encodeReference()); | 381 references.add(meaning.encodeReference()); |
384 } else { | 382 } else { |
385 references.add(new PrelinkedReferenceBuilder( | 383 references |
386 kind: PrelinkedReferenceKind.unresolved)); | 384 .add(new LinkedReferenceBuilder(kind: ReferenceKind.unresolved)); |
387 } | 385 } |
388 } | 386 } |
389 return new PrelinkedUnitBuilder(references: references); | 387 return new LinkedUnitBuilder(references: references); |
390 } | 388 } |
391 | 389 |
392 /** | 390 /** |
393 * Form the [PrelinkedLibrary] for the [definingUnit] that was passed to the | 391 * Form the [LinkedLibrary] for the [definingUnit] that was passed to the |
394 * constructor. | 392 * constructor. |
395 */ | 393 */ |
396 PrelinkedLibraryBuilder prelink() { | 394 LinkedLibraryBuilder prelink() { |
397 // Gather up the unlinked summaries for all the compilation units in the | 395 // Gather up the unlinked summaries for all the compilation units in the |
398 // library. | 396 // library. |
399 List<UnlinkedUnit> units = getUnitUris(null).map(getPartCached).toList(); | 397 List<UnlinkedUnit> units = getUnitUris(null).map(getPartCached).toList(); |
400 | 398 |
401 // Create the private namespace for the library by gathering all the names | 399 // Create the private namespace for the library by gathering all the names |
402 // defined in its compilation units. | 400 // defined in its compilation units. |
403 for (int unitNum = 0; unitNum < units.length; unitNum++) { | 401 for (int unitNum = 0; unitNum < units.length; unitNum++) { |
404 UnlinkedUnit unit = units[unitNum]; | 402 UnlinkedUnit unit = units[unitNum]; |
405 if (unit != null) { | 403 if (unit != null) { |
406 extractPrivateNames(unit, unitNum); | 404 extractPrivateNames(unit, unitNum); |
407 } | 405 } |
408 } | 406 } |
409 | 407 |
410 // Fill in exported names. This must be done before filling in prefixes | 408 // Fill in exported names. This must be done before filling in prefixes |
411 // defined in import declarations, because prefixes shouldn't shadow | 409 // defined in import declarations, because prefixes shouldn't shadow |
412 // exports. | 410 // exports. |
413 List<PrelinkedExportNameBuilder> exportNames = | 411 List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[]; |
414 <PrelinkedExportNameBuilder>[]; | |
415 computeExportNamespace(null).forEach((String name, _Meaning meaning) { | 412 computeExportNamespace(null).forEach((String name, _Meaning meaning) { |
416 if (!privateNamespace.containsKey(name)) { | 413 if (!privateNamespace.containsKey(name)) { |
417 exportNames.add(meaning.encodeExportName(name)); | 414 exportNames.add(meaning.encodeExportName(name)); |
418 } | 415 } |
419 }); | 416 }); |
420 | 417 |
421 // Fill in prefixes defined in import declarations. | 418 // Fill in prefixes defined in import declarations. |
422 for (UnlinkedImport import in units[0].imports) { | 419 for (UnlinkedImport import in units[0].imports) { |
423 if (import.prefixReference != 0) { | 420 if (import.prefixReference != 0) { |
424 privateNamespace.putIfAbsent( | 421 privateNamespace.putIfAbsent( |
425 units[0].references[import.prefixReference].name, | 422 units[0].references[import.prefixReference].name, |
426 () => new _PrefixMeaning()); | 423 () => new _PrefixMeaning()); |
427 } | 424 } |
428 } | 425 } |
429 | 426 |
430 // Fill in imported names. | 427 // Fill in imported names. |
431 List<int> importDependencies = | 428 List<int> importDependencies = |
432 definingUnit.imports.map(handleImport).toList(); | 429 definingUnit.imports.map(handleImport).toList(); |
433 | 430 |
434 // Link each compilation unit. | 431 // Link each compilation unit. |
435 List<PrelinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList(); | 432 List<LinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList(); |
436 | 433 |
437 return new PrelinkedLibraryBuilder( | 434 return new LinkedLibraryBuilder( |
438 units: linkedUnits, | 435 units: linkedUnits, |
439 dependencies: dependencies, | 436 dependencies: dependencies, |
440 importDependencies: importDependencies, | 437 importDependencies: importDependencies, |
441 exportNames: exportNames); | 438 exportNames: exportNames); |
442 } | 439 } |
443 | 440 |
444 /** | 441 /** |
445 * Resolve [relativeUri] relative to [sourceUri]. Works correctly if | 442 * Resolve [relativeUri] relative to [sourceUri]. Works correctly if |
446 * [sourceUri] is also relative. | 443 * [sourceUri] is also relative. |
447 */ | 444 */ |
448 String resolveUri(String sourceUri, String relativeUri) { | 445 String resolveUri(String sourceUri, String relativeUri) { |
449 if (sourceUri == null) { | 446 if (sourceUri == null) { |
450 return relativeUri; | 447 return relativeUri; |
451 } else { | 448 } else { |
452 return Uri.parse(sourceUri).resolve(relativeUri).toString(); | 449 return Uri.parse(sourceUri).resolve(relativeUri).toString(); |
453 } | 450 } |
454 } | 451 } |
455 } | 452 } |
OLD | NEW |