| OLD | NEW |
| (Empty) | |
| 1 import 'dart:io' as io; |
| 2 |
| 3 import 'package:analyzer/dart/element/element.dart'; |
| 4 import 'package:analyzer/file_system/file_system.dart'; |
| 5 import 'package:analyzer/src/context/cache.dart'; |
| 6 import 'package:analyzer/src/context/context.dart'; |
| 7 import 'package:analyzer/src/dart/element/element.dart'; |
| 8 import 'package:analyzer/src/generated/engine.dart'; |
| 9 import 'package:analyzer/src/generated/java_io.dart'; |
| 10 import 'package:analyzer/src/generated/resolver.dart'; |
| 11 import 'package:analyzer/src/generated/source.dart'; |
| 12 import 'package:analyzer/src/generated/source_io.dart'; |
| 13 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 14 import 'package:analyzer/src/source/source_resource.dart'; |
| 15 import 'package:analyzer/src/summary/format.dart'; |
| 16 import 'package:analyzer/src/summary/idl.dart'; |
| 17 import 'package:analyzer/src/summary/resynthesize.dart'; |
| 18 import 'package:analyzer/src/task/dart.dart'; |
| 19 import 'package:analyzer/src/util/fast_uri.dart'; |
| 20 import 'package:analyzer/task/dart.dart'; |
| 21 import 'package:analyzer/task/general.dart'; |
| 22 import 'package:analyzer/task/model.dart'; |
| 23 import 'package:path/path.dart' as pathos; |
| 24 |
| 25 /** |
| 26 * The [ResultProvider] that provides results from input package summaries. |
| 27 */ |
| 28 class InputPackagesResultProvider extends ResynthesizerResultProvider { |
| 29 InputPackagesResultProvider( |
| 30 InternalAnalysisContext context, SummaryDataStore dataStore) |
| 31 : super(context, dataStore) { |
| 32 AnalysisContext sdkContext = context.sourceFactory.dartSdk.context; |
| 33 createResynthesizer(sdkContext, sdkContext.typeProvider); |
| 34 } |
| 35 |
| 36 @override |
| 37 bool hasResultsForSource(Source source) { |
| 38 String uriString = source.uri.toString(); |
| 39 return resynthesizer.hasLibrarySummary(uriString); |
| 40 } |
| 41 } |
| 42 |
| 43 /** |
| 44 * The [UriResolver] that knows about sources that are served from their |
| 45 * summaries. |
| 46 */ |
| 47 @deprecated |
| 48 class InSummaryPackageUriResolver extends UriResolver { |
| 49 final SummaryDataStore _dataStore; |
| 50 |
| 51 InSummaryPackageUriResolver(this._dataStore); |
| 52 |
| 53 @override |
| 54 Source resolveAbsolute(Uri uri, [Uri actualUri]) { |
| 55 actualUri ??= uri; |
| 56 String uriString = uri.toString(); |
| 57 UnlinkedUnit unit = _dataStore.unlinkedMap[uriString]; |
| 58 if (unit != null) { |
| 59 String summaryPath = _dataStore.uriToSummaryPath[uriString]; |
| 60 if (unit.fallbackModePath.isNotEmpty) { |
| 61 return new _InSummaryFallbackSource( |
| 62 new JavaFile(unit.fallbackModePath), actualUri, summaryPath); |
| 63 } else { |
| 64 return new InSummarySource(actualUri, summaryPath); |
| 65 } |
| 66 } |
| 67 return null; |
| 68 } |
| 69 } |
| 70 |
| 71 /** |
| 72 * A placeholder of a source that is part of a package whose analysis results |
| 73 * are served from its summary. This source uses its URI as [fullName] and has |
| 74 * empty contents. |
| 75 */ |
| 76 class InSummarySource extends Source { |
| 77 final Uri uri; |
| 78 |
| 79 /** |
| 80 * The summary file where this source was defined. |
| 81 */ |
| 82 final String summaryPath; |
| 83 |
| 84 InSummarySource(this.uri, this.summaryPath); |
| 85 |
| 86 @override |
| 87 TimestampedData<String> get contents => new TimestampedData<String>(0, ''); |
| 88 |
| 89 @override |
| 90 String get encoding => uri.toString(); |
| 91 |
| 92 @override |
| 93 String get fullName => encoding; |
| 94 |
| 95 @override |
| 96 int get hashCode => uri.hashCode; |
| 97 |
| 98 @override |
| 99 bool get isInSystemLibrary => uri.scheme == DartUriResolver.DART_SCHEME; |
| 100 |
| 101 @override |
| 102 int get modificationStamp => 0; |
| 103 |
| 104 @override |
| 105 String get shortName => pathos.basename(fullName); |
| 106 |
| 107 @override |
| 108 UriKind get uriKind => UriKind.PACKAGE_URI; |
| 109 |
| 110 @override |
| 111 bool operator ==(Object object) => object is Source && object.uri == uri; |
| 112 |
| 113 @override |
| 114 bool exists() => true; |
| 115 |
| 116 @override |
| 117 String toString() => uri.toString(); |
| 118 } |
| 119 |
| 120 /** |
| 121 * The [UriResolver] that knows about sources that are served from their |
| 122 * summaries. |
| 123 */ |
| 124 class InSummaryUriResolver extends UriResolver { |
| 125 ResourceProvider resourceProvider; |
| 126 final SummaryDataStore _dataStore; |
| 127 |
| 128 InSummaryUriResolver(this.resourceProvider, this._dataStore); |
| 129 |
| 130 @override |
| 131 Source resolveAbsolute(Uri uri, [Uri actualUri]) { |
| 132 actualUri ??= uri; |
| 133 String uriString = uri.toString(); |
| 134 UnlinkedUnit unit = _dataStore.unlinkedMap[uriString]; |
| 135 if (unit != null) { |
| 136 String summaryPath = _dataStore.uriToSummaryPath[uriString]; |
| 137 if (unit.fallbackModePath.isNotEmpty) { |
| 138 return new _InSummaryFallbackFileSource( |
| 139 resourceProvider.getFile(unit.fallbackModePath), |
| 140 actualUri, |
| 141 summaryPath); |
| 142 } else { |
| 143 return new InSummarySource(actualUri, summaryPath); |
| 144 } |
| 145 } |
| 146 return null; |
| 147 } |
| 148 } |
| 149 |
| 150 /** |
| 151 * The [ResultProvider] that provides results using summary resynthesizer. |
| 152 */ |
| 153 abstract class ResynthesizerResultProvider extends ResultProvider { |
| 154 final InternalAnalysisContext context; |
| 155 final SummaryDataStore _dataStore; |
| 156 |
| 157 _FileBasedSummaryResynthesizer _resynthesizer; |
| 158 ResynthesizerResultProvider _sdkProvider; |
| 159 |
| 160 ResynthesizerResultProvider(this.context, this._dataStore); |
| 161 |
| 162 SummaryResynthesizer get resynthesizer => _resynthesizer; |
| 163 |
| 164 /** |
| 165 * Add a new [bundle] to the resynthesizer. |
| 166 */ |
| 167 void addBundle(String path, PackageBundle bundle) { |
| 168 _dataStore.addBundle(path, bundle); |
| 169 } |
| 170 |
| 171 @override |
| 172 bool compute(CacheEntry entry, ResultDescriptor result) { |
| 173 if (_sdkProvider != null && _sdkProvider.compute(entry, result)) { |
| 174 return true; |
| 175 } |
| 176 AnalysisTarget target = entry.target; |
| 177 // Check whether there are results for the source. |
| 178 if (!hasResultsForSource(target.librarySource ?? target.source)) { |
| 179 return false; |
| 180 } |
| 181 // Constant expressions are always resolved in summaries. |
| 182 if (result == CONSTANT_EXPRESSION_RESOLVED && |
| 183 target is ConstantEvaluationTarget) { |
| 184 entry.setValue( |
| 185 result as ResultDescriptor<bool>, true, TargetedResult.EMPTY_LIST); |
| 186 return true; |
| 187 } |
| 188 // Provide results for Source. |
| 189 if (target is Source) { |
| 190 String uriString = target.uri.toString(); |
| 191 // Provide known results. |
| 192 if (result == LIBRARY_ELEMENT1 || |
| 193 result == LIBRARY_ELEMENT2 || |
| 194 result == LIBRARY_ELEMENT3 || |
| 195 result == LIBRARY_ELEMENT4 || |
| 196 result == LIBRARY_ELEMENT5 || |
| 197 result == LIBRARY_ELEMENT6 || |
| 198 result == LIBRARY_ELEMENT7 || |
| 199 result == LIBRARY_ELEMENT8 || |
| 200 result == LIBRARY_ELEMENT9 || |
| 201 result == LIBRARY_ELEMENT) { |
| 202 LibraryElement libraryElement = |
| 203 resynthesizer.getLibraryElement(uriString); |
| 204 entry.setValue(result as ResultDescriptor<LibraryElement>, |
| 205 libraryElement, TargetedResult.EMPTY_LIST); |
| 206 return true; |
| 207 } else if (result == READY_LIBRARY_ELEMENT2 || |
| 208 result == READY_LIBRARY_ELEMENT6 || |
| 209 result == READY_LIBRARY_ELEMENT7) { |
| 210 entry.setValue( |
| 211 result as ResultDescriptor<bool>, true, TargetedResult.EMPTY_LIST); |
| 212 return true; |
| 213 } else if (result == MODIFICATION_TIME) { |
| 214 entry.setValue( |
| 215 result as ResultDescriptor<int>, 0, TargetedResult.EMPTY_LIST); |
| 216 return true; |
| 217 } else if (result == SOURCE_KIND) { |
| 218 if (_dataStore.linkedMap.containsKey(uriString)) { |
| 219 entry.setValue(result as ResultDescriptor<SourceKind>, |
| 220 SourceKind.LIBRARY, TargetedResult.EMPTY_LIST); |
| 221 return true; |
| 222 } |
| 223 if (_dataStore.unlinkedMap.containsKey(uriString)) { |
| 224 entry.setValue(result as ResultDescriptor<SourceKind>, |
| 225 SourceKind.PART, TargetedResult.EMPTY_LIST); |
| 226 return true; |
| 227 } |
| 228 return false; |
| 229 } else if (result == CONTAINING_LIBRARIES) { |
| 230 List<String> libraryUriStrings = |
| 231 _dataStore.getContainingLibraryUris(uriString); |
| 232 if (libraryUriStrings != null) { |
| 233 List<Source> librarySources = libraryUriStrings |
| 234 .map((libraryUriString) => |
| 235 context.sourceFactory.resolveUri(target, libraryUriString)) |
| 236 .toList(growable: false); |
| 237 entry.setValue(result as ResultDescriptor<List<Source>>, |
| 238 librarySources, TargetedResult.EMPTY_LIST); |
| 239 return true; |
| 240 } |
| 241 return false; |
| 242 } else if (result == LINE_INFO) { |
| 243 UnlinkedUnit unlinkedUnit = _dataStore.unlinkedMap[uriString]; |
| 244 List<int> lineStarts = unlinkedUnit.lineStarts; |
| 245 if (lineStarts.isNotEmpty) { |
| 246 LineInfo lineInfo = new LineInfo(lineStarts); |
| 247 entry.setValue(result as ResultDescriptor<LineInfo>, lineInfo, |
| 248 TargetedResult.EMPTY_LIST); |
| 249 return true; |
| 250 } |
| 251 return false; |
| 252 } |
| 253 } else if (target is LibrarySpecificUnit) { |
| 254 if (result == CREATED_RESOLVED_UNIT1 || |
| 255 result == CREATED_RESOLVED_UNIT2 || |
| 256 result == CREATED_RESOLVED_UNIT3 || |
| 257 result == CREATED_RESOLVED_UNIT4 || |
| 258 result == CREATED_RESOLVED_UNIT5 || |
| 259 result == CREATED_RESOLVED_UNIT6 || |
| 260 result == CREATED_RESOLVED_UNIT7 || |
| 261 result == CREATED_RESOLVED_UNIT8 || |
| 262 result == CREATED_RESOLVED_UNIT9 || |
| 263 result == CREATED_RESOLVED_UNIT10 || |
| 264 result == CREATED_RESOLVED_UNIT11) { |
| 265 entry.setValue( |
| 266 result as ResultDescriptor<bool>, true, TargetedResult.EMPTY_LIST); |
| 267 return true; |
| 268 } |
| 269 if (result == COMPILATION_UNIT_ELEMENT) { |
| 270 String libraryUri = target.library.uri.toString(); |
| 271 String unitUri = target.unit.uri.toString(); |
| 272 CompilationUnitElement unit = resynthesizer.getElement( |
| 273 new ElementLocationImpl.con3(<String>[libraryUri, unitUri])); |
| 274 if (unit != null) { |
| 275 entry.setValue(result as ResultDescriptor<CompilationUnitElement>, |
| 276 unit, TargetedResult.EMPTY_LIST); |
| 277 return true; |
| 278 } |
| 279 } |
| 280 } else if (target is VariableElement) { |
| 281 if (result == INFERRED_STATIC_VARIABLE) { |
| 282 entry.setValue(result as ResultDescriptor<VariableElement>, target, |
| 283 TargetedResult.EMPTY_LIST); |
| 284 return true; |
| 285 } |
| 286 } |
| 287 // Unknown target. |
| 288 return false; |
| 289 } |
| 290 |
| 291 /** |
| 292 * Create the [resynthesizer] instance. |
| 293 * |
| 294 * Subclasses must call this method in their constructors. |
| 295 */ |
| 296 void createResynthesizer( |
| 297 InternalAnalysisContext sdkContext, TypeProvider typeProvider) { |
| 298 // Set the type provider to prevent the context from computing it. |
| 299 context.typeProvider = typeProvider; |
| 300 // Create a chained resynthesizer. |
| 301 _sdkProvider = sdkContext?.resultProvider; |
| 302 _resynthesizer = new _FileBasedSummaryResynthesizer( |
| 303 _sdkProvider?.resynthesizer, |
| 304 context, |
| 305 typeProvider, |
| 306 context.sourceFactory, |
| 307 context.analysisOptions.strongMode, |
| 308 _dataStore); |
| 309 } |
| 310 |
| 311 /** |
| 312 * Return `true` if this result provider can provide a result for the |
| 313 * given [source]. The provider must ensure that [addBundle] is invoked for |
| 314 * every bundle that would be required to provide results for the [source]. |
| 315 */ |
| 316 bool hasResultsForSource(Source source); |
| 317 } |
| 318 |
| 319 /** |
| 320 * A [SummaryDataStore] is a container for the data extracted from a set of |
| 321 * summary package bundles. It contains maps which can be used to find linked |
| 322 * and unlinked summaries by URI. |
| 323 */ |
| 324 class SummaryDataStore { |
| 325 /** |
| 326 * List of all [PackageBundle]s. |
| 327 */ |
| 328 final List<PackageBundle> bundles = <PackageBundle>[]; |
| 329 |
| 330 /** |
| 331 * List of dependency information for the package bundles in this |
| 332 * [SummaryDataStore], in a form that is ready to store in a newly generated |
| 333 * summary. Computing this information has nonzero cost, so it is only |
| 334 * recorded if the [SummaryDataStore] is constructed with the argument |
| 335 * `recordDependencies`. Otherwise `null`. |
| 336 */ |
| 337 final List<PackageDependencyInfoBuilder> dependencies; |
| 338 |
| 339 /** |
| 340 * Map from the URI of a compilation unit to the unlinked summary of that |
| 341 * compilation unit. |
| 342 */ |
| 343 final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{}; |
| 344 |
| 345 /** |
| 346 * Map from the URI of a library to the linked summary of that library. |
| 347 */ |
| 348 final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{}; |
| 349 |
| 350 /** |
| 351 * Map from the URI of a library to the summary path that contained it. |
| 352 */ |
| 353 final Map<String, String> uriToSummaryPath = <String, String>{}; |
| 354 |
| 355 /** |
| 356 * Create a [SummaryDataStore] and populate it with the summaries in |
| 357 * [summaryPaths]. If [recordDependencyInfo] is `true`, record |
| 358 * [PackageDependencyInfo] for each summary, for later access via |
| 359 * [dependencies]. |
| 360 */ |
| 361 SummaryDataStore(Iterable<String> summaryPaths, |
| 362 {bool recordDependencyInfo: false}) |
| 363 : dependencies = |
| 364 recordDependencyInfo ? <PackageDependencyInfoBuilder>[] : null { |
| 365 summaryPaths.forEach(_fillMaps); |
| 366 } |
| 367 |
| 368 /** |
| 369 * Add the given [bundle] loaded from the file with the given [path]. |
| 370 */ |
| 371 void addBundle(String path, PackageBundle bundle) { |
| 372 bundles.add(bundle); |
| 373 if (dependencies != null) { |
| 374 Set<String> includedPackageNames = new Set<String>(); |
| 375 bool includesDartUris = false; |
| 376 bool includesFileUris = false; |
| 377 for (String uriString in bundle.unlinkedUnitUris) { |
| 378 Uri uri = FastUri.parse(uriString); |
| 379 String scheme = uri.scheme; |
| 380 if (scheme == 'package') { |
| 381 List<String> pathSegments = uri.pathSegments; |
| 382 includedPackageNames.add(pathSegments.isEmpty ? '' : pathSegments[0]); |
| 383 } else if (scheme == 'file') { |
| 384 includesFileUris = true; |
| 385 } else if (scheme == 'dart') { |
| 386 includesDartUris = true; |
| 387 } |
| 388 } |
| 389 dependencies.add(new PackageDependencyInfoBuilder( |
| 390 includedPackageNames: includedPackageNames.toList()..sort(), |
| 391 includesDartUris: includesDartUris, |
| 392 includesFileUris: includesFileUris, |
| 393 apiSignature: bundle.apiSignature, |
| 394 summaryPath: path)); |
| 395 } |
| 396 for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) { |
| 397 String uri = bundle.unlinkedUnitUris[i]; |
| 398 uriToSummaryPath[uri] = path; |
| 399 unlinkedMap[uri] = bundle.unlinkedUnits[i]; |
| 400 } |
| 401 for (int i = 0; i < bundle.linkedLibraryUris.length; i++) { |
| 402 String uri = bundle.linkedLibraryUris[i]; |
| 403 linkedMap[uri] = bundle.linkedLibraries[i]; |
| 404 } |
| 405 } |
| 406 |
| 407 /** |
| 408 * Return a list of absolute URIs of the libraries that contain the unit with |
| 409 * the given [unitUriString], or `null` if no such library is in the store. |
| 410 */ |
| 411 List<String> getContainingLibraryUris(String unitUriString) { |
| 412 // The unit is the defining unit of a library. |
| 413 if (linkedMap.containsKey(unitUriString)) { |
| 414 return <String>[unitUriString]; |
| 415 } |
| 416 // Check every unlinked unit whether it uses [unitUri] as a part. |
| 417 List<String> libraryUriStrings = <String>[]; |
| 418 unlinkedMap.forEach((unlinkedUnitUriString, unlinkedUnit) { |
| 419 Uri libraryUri = FastUri.parse(unlinkedUnitUriString); |
| 420 for (String partUriString in unlinkedUnit.publicNamespace.parts) { |
| 421 Uri partUri = FastUri.parse(partUriString); |
| 422 String partAbsoluteUriString = |
| 423 resolveRelativeUri(libraryUri, partUri).toString(); |
| 424 if (partAbsoluteUriString == unitUriString) { |
| 425 libraryUriStrings.add(unlinkedUnitUriString); |
| 426 } |
| 427 } |
| 428 }); |
| 429 return libraryUriStrings.isNotEmpty ? libraryUriStrings : null; |
| 430 } |
| 431 |
| 432 void _fillMaps(String path) { |
| 433 io.File file = new io.File(path); |
| 434 List<int> buffer = file.readAsBytesSync(); |
| 435 PackageBundle bundle = new PackageBundle.fromBuffer(buffer); |
| 436 addBundle(path, bundle); |
| 437 } |
| 438 } |
| 439 |
| 440 /** |
| 441 * A concrete resynthesizer that serves summaries from given file paths. |
| 442 */ |
| 443 class _FileBasedSummaryResynthesizer extends SummaryResynthesizer { |
| 444 final SummaryDataStore _dataStore; |
| 445 |
| 446 _FileBasedSummaryResynthesizer( |
| 447 SummaryResynthesizer parent, |
| 448 AnalysisContext context, |
| 449 TypeProvider typeProvider, |
| 450 SourceFactory sourceFactory, |
| 451 bool strongMode, |
| 452 this._dataStore) |
| 453 : super(parent, context, typeProvider, sourceFactory, strongMode); |
| 454 |
| 455 @override |
| 456 LinkedLibrary getLinkedSummary(String uri) { |
| 457 return _dataStore.linkedMap[uri]; |
| 458 } |
| 459 |
| 460 @override |
| 461 UnlinkedUnit getUnlinkedSummary(String uri) { |
| 462 return _dataStore.unlinkedMap[uri]; |
| 463 } |
| 464 |
| 465 @override |
| 466 bool hasLibrarySummary(String uri) { |
| 467 LinkedLibrary linkedLibrary = _dataStore.linkedMap[uri]; |
| 468 return linkedLibrary != null && !linkedLibrary.fallbackMode; |
| 469 } |
| 470 } |
| 471 |
| 472 /** |
| 473 * A source that is part of a package whose summary was generated in fallback |
| 474 * mode. This source behaves identically to a [FileSource] except that it also |
| 475 * provides [summaryPath]. |
| 476 */ |
| 477 class _InSummaryFallbackFileSource extends FileSource |
| 478 implements InSummarySource { |
| 479 @override |
| 480 final String summaryPath; |
| 481 |
| 482 _InSummaryFallbackFileSource(File file, Uri uri, this.summaryPath) |
| 483 : super(file, uri); |
| 484 } |
| 485 |
| 486 /** |
| 487 * A source that is part of a package whose summary was generated in fallback |
| 488 * mode. This source behaves identically to a [FileBasedSource] except that it |
| 489 * also provides [summaryPath]. |
| 490 */ |
| 491 @deprecated |
| 492 class _InSummaryFallbackSource extends FileBasedSource |
| 493 implements InSummarySource { |
| 494 @override |
| 495 final String summaryPath; |
| 496 |
| 497 _InSummaryFallbackSource(JavaFile file, Uri uri, this.summaryPath) |
| 498 : super(file, uri); |
| 499 } |
| OLD | NEW |