| OLD | NEW |
| (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 library analyzer.src.generated.sdk2; |
| 6 |
| 7 import 'dart:collection'; |
| 8 import 'dart:convert'; |
| 9 import 'dart:io' as io; |
| 10 |
| 11 import 'package:analyzer/dart/ast/ast.dart'; |
| 12 import 'package:analyzer/error/listener.dart'; |
| 13 import 'package:analyzer/exception/exception.dart'; |
| 14 import 'package:analyzer/file_system/file_system.dart'; |
| 15 import 'package:analyzer/file_system/memory_file_system.dart'; |
| 16 import 'package:analyzer/src/context/context.dart'; |
| 17 import 'package:analyzer/src/dart/scanner/reader.dart'; |
| 18 import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| 19 import 'package:analyzer/src/generated/engine.dart'; |
| 20 import 'package:analyzer/src/generated/java_engine_io.dart'; |
| 21 import 'package:analyzer/src/generated/parser.dart'; |
| 22 import 'package:analyzer/src/generated/sdk.dart'; |
| 23 import 'package:analyzer/src/generated/source_io.dart'; |
| 24 import 'package:analyzer/src/summary/idl.dart' show PackageBundle; |
| 25 import 'package:analyzer/src/summary/summary_sdk.dart'; |
| 26 import 'package:path/path.dart' as pathos; |
| 27 import 'package:yaml/yaml.dart'; |
| 28 |
| 29 /** |
| 30 * An abstract implementation of a Dart SDK in which the available libraries are |
| 31 * stored in a library map. Subclasses are responsible for populating the |
| 32 * library map. |
| 33 */ |
| 34 abstract class AbstractDartSdk implements DartSdk { |
| 35 /** |
| 36 * The resource provider used to access the file system. |
| 37 */ |
| 38 ResourceProvider resourceProvider; |
| 39 |
| 40 /** |
| 41 * A mapping from Dart library URI's to the library represented by that URI. |
| 42 */ |
| 43 LibraryMap libraryMap = new LibraryMap(); |
| 44 |
| 45 /** |
| 46 * The [AnalysisOptions] to use to create the [context]. |
| 47 */ |
| 48 AnalysisOptions _analysisOptions; |
| 49 |
| 50 /** |
| 51 * The flag that specifies whether an SDK summary should be used. This is a |
| 52 * temporary flag until summaries are enabled by default. |
| 53 */ |
| 54 bool _useSummary = false; |
| 55 |
| 56 /** |
| 57 * The [AnalysisContext] which is used for all of the sources in this SDK. |
| 58 */ |
| 59 InternalAnalysisContext _analysisContext; |
| 60 |
| 61 /** |
| 62 * The mapping from Dart URI's to the corresponding sources. |
| 63 */ |
| 64 Map<String, Source> _uriToSourceMap = new HashMap<String, Source>(); |
| 65 |
| 66 PackageBundle _sdkBundle; |
| 67 |
| 68 /** |
| 69 * Set the [options] for this SDK analysis context. Throw [StateError] if the |
| 70 * context has been already created. |
| 71 */ |
| 72 void set analysisOptions(AnalysisOptions options) { |
| 73 if (_analysisContext != null) { |
| 74 throw new StateError( |
| 75 'Analysis options cannot be changed after context creation.'); |
| 76 } |
| 77 _analysisOptions = options; |
| 78 } |
| 79 |
| 80 @override |
| 81 AnalysisContext get context { |
| 82 if (_analysisContext == null) { |
| 83 _analysisContext = new SdkAnalysisContext(_analysisOptions); |
| 84 SourceFactory factory = new SourceFactory([new DartUriResolver(this)]); |
| 85 _analysisContext.sourceFactory = factory; |
| 86 if (_useSummary) { |
| 87 bool strongMode = _analysisOptions?.strongMode ?? false; |
| 88 PackageBundle sdkBundle = getLinkedBundle(); |
| 89 if (sdkBundle != null) { |
| 90 _analysisContext.resultProvider = new SdkSummaryResultProvider( |
| 91 _analysisContext, sdkBundle, strongMode); |
| 92 } |
| 93 } |
| 94 } |
| 95 return _analysisContext; |
| 96 } |
| 97 |
| 98 @override |
| 99 List<SdkLibrary> get sdkLibraries => libraryMap.sdkLibraries; |
| 100 |
| 101 /** |
| 102 * Return the path separator used by the resource provider. |
| 103 */ |
| 104 String get separator => resourceProvider.pathContext.separator; |
| 105 |
| 106 @override |
| 107 List<String> get uris => libraryMap.uris; |
| 108 |
| 109 /** |
| 110 * Return `true` if the SDK summary will be used when available. |
| 111 */ |
| 112 bool get useSummary => _useSummary; |
| 113 |
| 114 /** |
| 115 * Specify whether SDK summary should be used. |
| 116 */ |
| 117 void set useSummary(bool use) { |
| 118 if (_analysisContext != null) { |
| 119 throw new StateError( |
| 120 'The "useSummary" flag cannot be changed after context creation.'); |
| 121 } |
| 122 _useSummary = use; |
| 123 } |
| 124 |
| 125 /** |
| 126 * Add the extensions from one or more sdk extension files to this sdk. The |
| 127 * [extensions] should be a table mapping the names of extensions to the paths |
| 128 * where those extensions can be found. |
| 129 */ |
| 130 void addExtensions(Map<String, String> extensions) { |
| 131 extensions.forEach((String uri, String path) { |
| 132 SdkLibraryImpl library = new SdkLibraryImpl(uri); |
| 133 library.path = path; |
| 134 libraryMap.setLibrary(uri, library); |
| 135 }); |
| 136 } |
| 137 |
| 138 @override |
| 139 Source fromFileUri(Uri uri) { |
| 140 File file = |
| 141 resourceProvider.getFile(resourceProvider.pathContext.fromUri(uri)); |
| 142 String path = _getPath(file); |
| 143 if (path == null) { |
| 144 return null; |
| 145 } |
| 146 try { |
| 147 return file.createSource(Uri.parse(path)); |
| 148 } on FormatException catch (exception, stackTrace) { |
| 149 AnalysisEngine.instance.logger.logInformation( |
| 150 "Failed to create URI: $path", |
| 151 new CaughtException(exception, stackTrace)); |
| 152 } |
| 153 return null; |
| 154 } |
| 155 |
| 156 @override |
| 157 PackageBundle getLinkedBundle() { |
| 158 if (_useSummary) { |
| 159 bool strongMode = _analysisOptions?.strongMode ?? false; |
| 160 _sdkBundle ??= getSummarySdkBundle(strongMode); |
| 161 return _sdkBundle; |
| 162 } |
| 163 return null; |
| 164 } |
| 165 |
| 166 String getRelativePathFromFile(File file); |
| 167 |
| 168 @override |
| 169 SdkLibrary getSdkLibrary(String dartUri) => libraryMap.getLibrary(dartUri); |
| 170 |
| 171 /** |
| 172 * Return the [PackageBundle] for this SDK, if it exists, or `null` otherwise. |
| 173 * This method should not be used outside of `analyzer` and `analyzer_cli` |
| 174 * packages. |
| 175 */ |
| 176 PackageBundle getSummarySdkBundle(bool strongMode); |
| 177 |
| 178 Source internalMapDartUri(String dartUri) { |
| 179 // TODO(brianwilkerson) Figure out how to unify the implementations in the |
| 180 // two subclasses. |
| 181 String libraryName; |
| 182 String relativePath; |
| 183 int index = dartUri.indexOf('/'); |
| 184 if (index >= 0) { |
| 185 libraryName = dartUri.substring(0, index); |
| 186 relativePath = dartUri.substring(index + 1); |
| 187 } else { |
| 188 libraryName = dartUri; |
| 189 relativePath = ""; |
| 190 } |
| 191 SdkLibrary library = getSdkLibrary(libraryName); |
| 192 if (library == null) { |
| 193 return null; |
| 194 } |
| 195 String srcPath; |
| 196 if (relativePath.isEmpty) { |
| 197 srcPath = library.path; |
| 198 } else { |
| 199 String libraryPath = library.path; |
| 200 int index = libraryPath.lastIndexOf(separator); |
| 201 if (index == -1) { |
| 202 index = libraryPath.lastIndexOf('/'); |
| 203 if (index == -1) { |
| 204 return null; |
| 205 } |
| 206 } |
| 207 String prefix = libraryPath.substring(0, index + 1); |
| 208 srcPath = '$prefix$relativePath'; |
| 209 } |
| 210 String filePath = srcPath.replaceAll('/', separator); |
| 211 try { |
| 212 File file = resourceProvider.getFile(filePath); |
| 213 return file.createSource(Uri.parse(dartUri)); |
| 214 } on FormatException { |
| 215 return null; |
| 216 } |
| 217 } |
| 218 |
| 219 @override |
| 220 Source mapDartUri(String dartUri) { |
| 221 Source source = _uriToSourceMap[dartUri]; |
| 222 if (source == null) { |
| 223 source = internalMapDartUri(dartUri); |
| 224 _uriToSourceMap[dartUri] = source; |
| 225 } |
| 226 return source; |
| 227 } |
| 228 |
| 229 String _getPath(File file) { |
| 230 List<SdkLibrary> libraries = libraryMap.sdkLibraries; |
| 231 int length = libraries.length; |
| 232 List<String> paths = new List(length); |
| 233 String filePath = getRelativePathFromFile(file); |
| 234 if (filePath == null) { |
| 235 return null; |
| 236 } |
| 237 for (int i = 0; i < length; i++) { |
| 238 SdkLibrary library = libraries[i]; |
| 239 String libraryPath = library.path.replaceAll('/', separator); |
| 240 if (filePath == libraryPath) { |
| 241 return library.shortName; |
| 242 } |
| 243 paths[i] = libraryPath; |
| 244 } |
| 245 for (int i = 0; i < length; i++) { |
| 246 SdkLibrary library = libraries[i]; |
| 247 String libraryPath = paths[i]; |
| 248 int index = libraryPath.lastIndexOf(separator); |
| 249 if (index >= 0) { |
| 250 String prefix = libraryPath.substring(0, index + 1); |
| 251 if (filePath.startsWith(prefix)) { |
| 252 String relPath = |
| 253 filePath.substring(prefix.length).replaceAll(separator, '/'); |
| 254 return '${library.shortName}/$relPath'; |
| 255 } |
| 256 } |
| 257 } |
| 258 return null; |
| 259 } |
| 260 } |
| 261 |
| 262 /** |
| 263 * An SDK backed by URI mappings derived from an `_embedder.yaml` file. |
| 264 */ |
| 265 class EmbedderSdk extends AbstractDartSdk { |
| 266 static const String _DART_COLON_PREFIX = 'dart:'; |
| 267 |
| 268 static const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs'; |
| 269 final Map<String, String> _urlMappings = new HashMap<String, String>(); |
| 270 |
| 271 PackageBundle _embedderBundle; |
| 272 |
| 273 EmbedderSdk( |
| 274 ResourceProvider resourceProvider, Map<Folder, YamlMap> embedderYamls) { |
| 275 this.resourceProvider = resourceProvider; |
| 276 embedderYamls?.forEach(_processEmbedderYaml); |
| 277 if (embedderYamls?.length == 1) { |
| 278 Folder libFolder = embedderYamls.keys.first; |
| 279 _loadEmbedderBundle(libFolder); |
| 280 } |
| 281 } |
| 282 |
| 283 @override |
| 284 // TODO(danrubel) Determine SDK version |
| 285 String get sdkVersion => '0'; |
| 286 |
| 287 /** |
| 288 * The url mappings for this SDK. |
| 289 */ |
| 290 Map<String, String> get urlMappings => _urlMappings; |
| 291 |
| 292 @override |
| 293 String getRelativePathFromFile(File file) => file.path; |
| 294 |
| 295 @override |
| 296 PackageBundle getSummarySdkBundle(bool strongMode) { |
| 297 if (strongMode) { |
| 298 return _embedderBundle; |
| 299 } |
| 300 return null; |
| 301 } |
| 302 |
| 303 @override |
| 304 Source internalMapDartUri(String dartUri) { |
| 305 String libraryName; |
| 306 String relativePath; |
| 307 int index = dartUri.indexOf('/'); |
| 308 if (index >= 0) { |
| 309 libraryName = dartUri.substring(0, index); |
| 310 relativePath = dartUri.substring(index + 1); |
| 311 } else { |
| 312 libraryName = dartUri; |
| 313 relativePath = ""; |
| 314 } |
| 315 SdkLibrary library = getSdkLibrary(libraryName); |
| 316 if (library == null) { |
| 317 return null; |
| 318 } |
| 319 String srcPath; |
| 320 if (relativePath.isEmpty) { |
| 321 srcPath = library.path; |
| 322 } else { |
| 323 String libraryPath = library.path; |
| 324 int index = libraryPath.lastIndexOf(separator); |
| 325 if (index == -1) { |
| 326 index = libraryPath.lastIndexOf('/'); |
| 327 if (index == -1) { |
| 328 return null; |
| 329 } |
| 330 } |
| 331 String prefix = libraryPath.substring(0, index + 1); |
| 332 srcPath = '$prefix$relativePath'; |
| 333 } |
| 334 String filePath = srcPath.replaceAll('/', separator); |
| 335 try { |
| 336 File file = resourceProvider.getFile(filePath); |
| 337 return file.createSource(Uri.parse(dartUri)); |
| 338 } on FormatException { |
| 339 return null; |
| 340 } |
| 341 } |
| 342 |
| 343 void _loadEmbedderBundle(Folder libFolder) { |
| 344 File bundleFile = libFolder.parent.getChildAssumingFile('sdk.ds'); |
| 345 if (bundleFile.exists) { |
| 346 try { |
| 347 List<int> bytes = bundleFile.readAsBytesSync(); |
| 348 _embedderBundle = new PackageBundle.fromBuffer(bytes); |
| 349 } on FileSystemException {} |
| 350 } |
| 351 } |
| 352 |
| 353 /** |
| 354 * Install the mapping from [name] to [libDir]/[file]. |
| 355 */ |
| 356 void _processEmbeddedLibs(String name, String file, Folder libDir) { |
| 357 if (!name.startsWith(_DART_COLON_PREFIX)) { |
| 358 // SDK libraries must begin with 'dart:'. |
| 359 return; |
| 360 } |
| 361 String libPath = libDir.canonicalizePath(file); |
| 362 _urlMappings[name] = libPath; |
| 363 SdkLibraryImpl library = new SdkLibraryImpl(name); |
| 364 library.path = libPath; |
| 365 libraryMap.setLibrary(name, library); |
| 366 } |
| 367 |
| 368 /** |
| 369 * Given the 'embedderYamls' from [EmbedderYamlLocator] check each one for the |
| 370 * top level key 'embedded_libs'. Under the 'embedded_libs' key are key value |
| 371 * pairs. Each key is a 'dart:' library uri and each value is a path |
| 372 * (relative to the directory containing `_embedder.yaml`) to a dart script |
| 373 * for the given library. For example: |
| 374 * |
| 375 * embedded_libs: |
| 376 * 'dart:io': '../../sdk/io/io.dart' |
| 377 * |
| 378 * If a key doesn't begin with `dart:` it is ignored. |
| 379 */ |
| 380 void _processEmbedderYaml(Folder libDir, YamlMap map) { |
| 381 YamlNode embedded_libs = map[_EMBEDDED_LIB_MAP_KEY]; |
| 382 if (embedded_libs is YamlMap) { |
| 383 embedded_libs.forEach((k, v) => _processEmbeddedLibs(k, v, libDir)); |
| 384 } |
| 385 } |
| 386 } |
| 387 |
| 388 /** |
| 389 * A Dart SDK installed in a specified directory. Typical Dart SDK layout is |
| 390 * something like... |
| 391 * |
| 392 * dart-sdk/ |
| 393 * bin/ |
| 394 * dart[.exe] <-- VM |
| 395 * lib/ |
| 396 * core/ |
| 397 * core.dart |
| 398 * ... other core library files ... |
| 399 * ... other libraries ... |
| 400 * util/ |
| 401 * ... Dart utilities ... |
| 402 * Chromium/ <-- Dartium typically exists in a sibling directory |
| 403 */ |
| 404 class FolderBasedDartSdk extends AbstractDartSdk { |
| 405 /** |
| 406 * The name of the directory within the SDK directory that contains |
| 407 * executables. |
| 408 */ |
| 409 static String _BIN_DIRECTORY_NAME = "bin"; |
| 410 |
| 411 /** |
| 412 * The name of the directory within the SDK directory that contains |
| 413 * documentation for the libraries. |
| 414 */ |
| 415 static String _DOCS_DIRECTORY_NAME = "docs"; |
| 416 |
| 417 /** |
| 418 * The name of the directory within the SDK directory that contains the |
| 419 * sdk_library_metadata directory. |
| 420 */ |
| 421 static String _INTERNAL_DIR = "_internal"; |
| 422 |
| 423 /** |
| 424 * The name of the sdk_library_metadata directory that contains the package |
| 425 * holding the libraries.dart file. |
| 426 */ |
| 427 static String _SDK_LIBRARY_METADATA_DIR = "sdk_library_metadata"; |
| 428 |
| 429 /** |
| 430 * The name of the directory within the sdk_library_metadata that contains |
| 431 * libraries.dart. |
| 432 */ |
| 433 static String _SDK_LIBRARY_METADATA_LIB_DIR = "lib"; |
| 434 |
| 435 /** |
| 436 * The name of the directory within the SDK directory that contains the |
| 437 * libraries. |
| 438 */ |
| 439 static String _LIB_DIRECTORY_NAME = "lib"; |
| 440 |
| 441 /** |
| 442 * The name of the libraries file. |
| 443 */ |
| 444 static String _LIBRARIES_FILE = "libraries.dart"; |
| 445 |
| 446 /** |
| 447 * The name of the pub executable on windows. |
| 448 */ |
| 449 static String _PUB_EXECUTABLE_NAME_WIN = "pub.bat"; |
| 450 |
| 451 /** |
| 452 * The name of the pub executable on non-windows operating systems. |
| 453 */ |
| 454 static String _PUB_EXECUTABLE_NAME = "pub"; |
| 455 |
| 456 /** |
| 457 * The name of the file within the SDK directory that contains the version |
| 458 * number of the SDK. |
| 459 */ |
| 460 static String _VERSION_FILE_NAME = "version"; |
| 461 |
| 462 /** |
| 463 * The directory containing the SDK. |
| 464 */ |
| 465 Folder _sdkDirectory; |
| 466 |
| 467 /** |
| 468 * The directory within the SDK directory that contains the libraries. |
| 469 */ |
| 470 Folder _libraryDirectory; |
| 471 |
| 472 /** |
| 473 * The revision number of this SDK, or `"0"` if the revision number cannot be |
| 474 * discovered. |
| 475 */ |
| 476 String _sdkVersion; |
| 477 |
| 478 /** |
| 479 * The file containing the pub executable. |
| 480 */ |
| 481 File _pubExecutable; |
| 482 |
| 483 /** |
| 484 * Initialize a newly created SDK to represent the Dart SDK installed in the |
| 485 * [sdkDirectory]. The flag [useDart2jsPaths] is `true` if the dart2js path |
| 486 * should be used when it is available |
| 487 */ |
| 488 FolderBasedDartSdk(ResourceProvider resourceProvider, this._sdkDirectory, |
| 489 [bool useDart2jsPaths = false]) { |
| 490 this.resourceProvider = resourceProvider; |
| 491 libraryMap = initialLibraryMap(useDart2jsPaths); |
| 492 } |
| 493 |
| 494 /** |
| 495 * Return the directory containing the SDK. |
| 496 */ |
| 497 Folder get directory => _sdkDirectory; |
| 498 |
| 499 /** |
| 500 * Return the directory containing documentation for the SDK. |
| 501 */ |
| 502 Folder get docDirectory => |
| 503 _sdkDirectory.getChildAssumingFolder(_DOCS_DIRECTORY_NAME); |
| 504 |
| 505 /** |
| 506 * Return the directory within the SDK directory that contains the libraries. |
| 507 */ |
| 508 Folder get libraryDirectory { |
| 509 if (_libraryDirectory == null) { |
| 510 _libraryDirectory = |
| 511 _sdkDirectory.getChildAssumingFolder(_LIB_DIRECTORY_NAME); |
| 512 } |
| 513 return _libraryDirectory; |
| 514 } |
| 515 |
| 516 /** |
| 517 * Return the file containing the Pub executable, or `null` if it does not exi
st. |
| 518 */ |
| 519 File get pubExecutable { |
| 520 if (_pubExecutable == null) { |
| 521 _pubExecutable = _sdkDirectory |
| 522 .getChildAssumingFolder(_BIN_DIRECTORY_NAME) |
| 523 .getChildAssumingFile(OSUtilities.isWindows() |
| 524 ? _PUB_EXECUTABLE_NAME_WIN |
| 525 : _PUB_EXECUTABLE_NAME); |
| 526 } |
| 527 return _pubExecutable; |
| 528 } |
| 529 |
| 530 /** |
| 531 * Return the revision number of this SDK, or `"0"` if the revision number |
| 532 * cannot be discovered. |
| 533 */ |
| 534 @override |
| 535 String get sdkVersion { |
| 536 if (_sdkVersion == null) { |
| 537 _sdkVersion = DartSdk.DEFAULT_VERSION; |
| 538 File revisionFile = |
| 539 _sdkDirectory.getChildAssumingFile(_VERSION_FILE_NAME); |
| 540 try { |
| 541 String revision = revisionFile.readAsStringSync(); |
| 542 if (revision != null) { |
| 543 _sdkVersion = revision.trim(); |
| 544 } |
| 545 } on FileSystemException { |
| 546 // Fall through to return the default. |
| 547 } |
| 548 } |
| 549 return _sdkVersion; |
| 550 } |
| 551 |
| 552 /** |
| 553 * Determine the search order for trying to locate the [_LIBRARIES_FILE]. |
| 554 */ |
| 555 Iterable<File> get _libraryMapLocations sync* { |
| 556 yield libraryDirectory |
| 557 .getChildAssumingFolder(_INTERNAL_DIR) |
| 558 .getChildAssumingFolder(_SDK_LIBRARY_METADATA_DIR) |
| 559 .getChildAssumingFolder(_SDK_LIBRARY_METADATA_LIB_DIR) |
| 560 .getChildAssumingFile(_LIBRARIES_FILE); |
| 561 yield libraryDirectory |
| 562 .getChildAssumingFolder(_INTERNAL_DIR) |
| 563 .getChildAssumingFile(_LIBRARIES_FILE); |
| 564 } |
| 565 |
| 566 @override |
| 567 String getRelativePathFromFile(File file) { |
| 568 String filePath = file.path; |
| 569 String libPath = libraryDirectory.path; |
| 570 if (!filePath.startsWith("$libPath$separator")) { |
| 571 return null; |
| 572 } |
| 573 return filePath.substring(libPath.length + 1); |
| 574 } |
| 575 |
| 576 /** |
| 577 * Return the [PackageBundle] for this SDK, if it exists, or `null` otherwise. |
| 578 * This method should not be used outside of `analyzer` and `analyzer_cli` |
| 579 * packages. |
| 580 */ |
| 581 PackageBundle getSummarySdkBundle(bool strongMode) { |
| 582 String rootPath = directory.path; |
| 583 String name = strongMode ? 'strong.sum' : 'spec.sum'; |
| 584 String path = |
| 585 resourceProvider.pathContext.join(rootPath, 'lib', '_internal', name); |
| 586 try { |
| 587 File file = resourceProvider.getFile(path); |
| 588 if (file.exists) { |
| 589 List<int> bytes = file.readAsBytesSync(); |
| 590 return new PackageBundle.fromBuffer(bytes); |
| 591 } |
| 592 } catch (exception, stackTrace) { |
| 593 AnalysisEngine.instance.logger.logError( |
| 594 'Failed to load SDK analysis summary from $path', |
| 595 new CaughtException(exception, stackTrace)); |
| 596 } |
| 597 return null; |
| 598 } |
| 599 |
| 600 /** |
| 601 * Read all of the configuration files to initialize the library maps. The |
| 602 * flag [useDart2jsPaths] is `true` if the dart2js path should be used when it |
| 603 * is available. Return the initialized library map. |
| 604 */ |
| 605 LibraryMap initialLibraryMap(bool useDart2jsPaths) { |
| 606 List<String> searchedPaths = <String>[]; |
| 607 var lastStackTrace = null; |
| 608 var lastException = null; |
| 609 for (File librariesFile in _libraryMapLocations) { |
| 610 try { |
| 611 String contents = librariesFile.readAsStringSync(); |
| 612 return new SdkLibrariesReader(useDart2jsPaths) |
| 613 .readFromFile(librariesFile, contents); |
| 614 } catch (exception, stackTrace) { |
| 615 searchedPaths.add(librariesFile.path); |
| 616 lastException = exception; |
| 617 lastStackTrace = stackTrace; |
| 618 } |
| 619 } |
| 620 StringBuffer buffer = new StringBuffer(); |
| 621 buffer.writeln('Could not initialize the library map from $searchedPaths'); |
| 622 if (resourceProvider is MemoryResourceProvider) { |
| 623 (resourceProvider as MemoryResourceProvider).writeOn(buffer); |
| 624 } |
| 625 AnalysisEngine.instance.logger.logError( |
| 626 buffer.toString(), new CaughtException(lastException, lastStackTrace)); |
| 627 return new LibraryMap(); |
| 628 } |
| 629 |
| 630 @override |
| 631 Source internalMapDartUri(String dartUri) { |
| 632 String libraryName; |
| 633 String relativePath; |
| 634 int index = dartUri.indexOf('/'); |
| 635 if (index >= 0) { |
| 636 libraryName = dartUri.substring(0, index); |
| 637 relativePath = dartUri.substring(index + 1); |
| 638 } else { |
| 639 libraryName = dartUri; |
| 640 relativePath = ""; |
| 641 } |
| 642 SdkLibrary library = getSdkLibrary(libraryName); |
| 643 if (library == null) { |
| 644 return null; |
| 645 } |
| 646 try { |
| 647 File file = libraryDirectory.getChildAssumingFile(library.path); |
| 648 if (!relativePath.isEmpty) { |
| 649 file = file.parent.getChildAssumingFile(relativePath); |
| 650 } |
| 651 return file.createSource(Uri.parse(dartUri)); |
| 652 } on FormatException { |
| 653 return null; |
| 654 } |
| 655 } |
| 656 |
| 657 /** |
| 658 * Return the default directory for the Dart SDK, or `null` if the directory |
| 659 * cannot be determined (or does not exist). The default directory is provided |
| 660 * by a system property named `com.google.dart.sdk`. |
| 661 */ |
| 662 static Folder defaultSdkDirectory(ResourceProvider resourceProvider) { |
| 663 // TODO(brianwilkerson) This is currently only being used in the analysis |
| 664 // server's Driver class to find the default SDK. The command-line analyzer |
| 665 // uses cli_utils to find the SDK. Not sure why they're different. |
| 666 String sdkProperty = getSdkProperty(resourceProvider); |
| 667 if (sdkProperty == null) { |
| 668 return null; |
| 669 } |
| 670 Folder sdkDirectory = resourceProvider.getFolder(sdkProperty); |
| 671 if (!sdkDirectory.exists) { |
| 672 return null; |
| 673 } |
| 674 return sdkDirectory; |
| 675 } |
| 676 |
| 677 static String getSdkProperty(ResourceProvider resourceProvider) { |
| 678 String exec = io.Platform.resolvedExecutable; |
| 679 if (exec.length == 0) { |
| 680 return null; |
| 681 } |
| 682 pathos.Context pathContext = resourceProvider.pathContext; |
| 683 if (pathContext.style != pathos.context.style) { |
| 684 // This will only be true if pathContext == posix and |
| 685 // pathos.context == windows, which only happens when running tests. |
| 686 if (exec.startsWith(new RegExp('[a-zA-Z]:'))) { |
| 687 exec = exec.substring(2); |
| 688 } |
| 689 exec = pathContext.fromUri(pathos.context.toUri(exec)); |
| 690 } |
| 691 // Might be "xcodebuild/ReleaseIA32/dart" with "sdk" sibling |
| 692 String outDir = pathContext.dirname(pathContext.dirname(exec)); |
| 693 String sdkPath = pathContext.join(pathContext.dirname(outDir), "sdk"); |
| 694 if (resourceProvider.getFolder(sdkPath).exists) { |
| 695 return sdkPath; |
| 696 } |
| 697 // probably be "dart-sdk/bin/dart" |
| 698 return pathContext.dirname(pathContext.dirname(exec)); |
| 699 } |
| 700 } |
| 701 |
| 702 /** |
| 703 * An object used to locate SDK extensions. |
| 704 * |
| 705 * Given a package map, it will check in each package's `lib` directory for the |
| 706 * existence of a `_sdkext` file. This file must contain a JSON encoded map. |
| 707 * Each key in the map is a `dart:` library name. Each value is a path (relative |
| 708 * to the directory containing `_sdkext`) to a dart script for the given |
| 709 * library. For example: |
| 710 * ``` |
| 711 * { |
| 712 * "dart:sky": "../sdk_ext/dart_sky.dart" |
| 713 * } |
| 714 * ``` |
| 715 * If a key doesn't begin with `dart:` it is ignored. |
| 716 */ |
| 717 class SdkExtensionFinder { |
| 718 /** |
| 719 * The name of the extension file. |
| 720 */ |
| 721 static const String SDK_EXT_NAME = '_sdkext'; |
| 722 |
| 723 /** |
| 724 * The prefix required for all keys in an extension file that will not be |
| 725 * ignored. |
| 726 */ |
| 727 static const String DART_COLON_PREFIX = 'dart:'; |
| 728 |
| 729 /** |
| 730 * A table mapping the names of extensions to the paths where those extensions |
| 731 * can be found. |
| 732 */ |
| 733 final Map<String, String> _urlMappings = <String, String>{}; |
| 734 |
| 735 /** |
| 736 * The absolute paths of the extension files that contributed to the |
| 737 * [_urlMappings]. |
| 738 */ |
| 739 final List<String> extensionFilePaths = <String>[]; |
| 740 |
| 741 /** |
| 742 * Initialize a newly created finder to look in the packages in the given |
| 743 * [packageMap] for SDK extension files. |
| 744 */ |
| 745 SdkExtensionFinder(Map<String, List<Folder>> packageMap) { |
| 746 if (packageMap == null) { |
| 747 return; |
| 748 } |
| 749 packageMap.forEach(_processPackage); |
| 750 } |
| 751 |
| 752 /** |
| 753 * Return a table mapping the names of extensions to the paths where those |
| 754 * extensions can be found. |
| 755 */ |
| 756 Map<String, String> get urlMappings => |
| 757 new Map<String, String>.from(_urlMappings); |
| 758 |
| 759 /** |
| 760 * Given a package [name] and a list of folders ([libDirs]), add any found sdk |
| 761 * extensions. |
| 762 */ |
| 763 void _processPackage(String name, List<Folder> libDirs) { |
| 764 for (var libDir in libDirs) { |
| 765 var sdkExt = _readDotSdkExt(libDir); |
| 766 if (sdkExt != null) { |
| 767 _processSdkExt(sdkExt, libDir); |
| 768 } |
| 769 } |
| 770 } |
| 771 |
| 772 /** |
| 773 * Given the JSON for an SDK extension ([sdkExtJSON]) and a folder ([libDir]), |
| 774 * setup the uri mapping. |
| 775 */ |
| 776 void _processSdkExt(String sdkExtJSON, Folder libDir) { |
| 777 var sdkExt; |
| 778 try { |
| 779 sdkExt = JSON.decode(sdkExtJSON); |
| 780 } catch (e) { |
| 781 return; |
| 782 } |
| 783 if ((sdkExt == null) || (sdkExt is! Map)) { |
| 784 return; |
| 785 } |
| 786 bool contributed = false; |
| 787 sdkExt.forEach((k, v) { |
| 788 if (k is String && v is String && _processSdkExtension(libDir, k, v)) { |
| 789 contributed = true; |
| 790 } |
| 791 }); |
| 792 if (contributed) { |
| 793 extensionFilePaths.add(libDir.getChild(SDK_EXT_NAME).path); |
| 794 } |
| 795 } |
| 796 |
| 797 /** |
| 798 * Install the mapping from [name] to [libDir]/[file]. |
| 799 */ |
| 800 bool _processSdkExtension(Folder libDir, String name, String file) { |
| 801 if (!name.startsWith(DART_COLON_PREFIX)) { |
| 802 // SDK extensions must begin with 'dart:'. |
| 803 return false; |
| 804 } |
| 805 _urlMappings[name] = libDir.canonicalizePath(file); |
| 806 return true; |
| 807 } |
| 808 |
| 809 /** |
| 810 * Read the contents of [libDir]/[SDK_EXT_NAME] as a string, or `null` if the |
| 811 * file doesn't exist. |
| 812 */ |
| 813 String _readDotSdkExt(Folder libDir) { |
| 814 File file = libDir.getChild(SDK_EXT_NAME); |
| 815 try { |
| 816 return file.readAsStringSync(); |
| 817 } on FileSystemException { |
| 818 // File can't be read. |
| 819 return null; |
| 820 } |
| 821 } |
| 822 } |
| 823 |
| 824 /** |
| 825 * An object used to read and parse the libraries file |
| 826 * (dart-sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart) for informat
ion |
| 827 * about the libraries in an SDK. The library information is represented as a |
| 828 * Dart file containing a single top-level variable whose value is a const map. |
| 829 * The keys of the map are the names of libraries defined in the SDK and the |
| 830 * values in the map are info objects defining the library. For example, a |
| 831 * subset of a typical SDK might have a libraries file that looks like the |
| 832 * following: |
| 833 * |
| 834 * final Map<String, LibraryInfo> LIBRARIES = const <LibraryInfo> { |
| 835 * // Used by VM applications |
| 836 * "builtin" : const LibraryInfo( |
| 837 * "builtin/builtin_runtime.dart", |
| 838 * category: "Server", |
| 839 * platforms: VM_PLATFORM), |
| 840 * |
| 841 * "compiler" : const LibraryInfo( |
| 842 * "compiler/compiler.dart", |
| 843 * category: "Tools", |
| 844 * platforms: 0), |
| 845 * }; |
| 846 */ |
| 847 class SdkLibrariesReader { |
| 848 /** |
| 849 * A flag indicating whether the dart2js path should be used when it is |
| 850 * available. |
| 851 */ |
| 852 final bool _useDart2jsPaths; |
| 853 |
| 854 /** |
| 855 * Initialize a newly created library reader to use the dart2js path if |
| 856 * [_useDart2jsPaths] is `true`. |
| 857 */ |
| 858 SdkLibrariesReader(this._useDart2jsPaths); |
| 859 |
| 860 /** |
| 861 * Return the library map read from the given [file], given that the content |
| 862 * of the file is already known to be [libraryFileContents]. |
| 863 */ |
| 864 LibraryMap readFromFile(File file, String libraryFileContents) => |
| 865 readFromSource(file.createSource(), libraryFileContents); |
| 866 |
| 867 /** |
| 868 * Return the library map read from the given [source], given that the content |
| 869 * of the file is already known to be [libraryFileContents]. |
| 870 */ |
| 871 LibraryMap readFromSource(Source source, String libraryFileContents) { |
| 872 BooleanErrorListener errorListener = new BooleanErrorListener(); |
| 873 Scanner scanner = new Scanner( |
| 874 source, new CharSequenceReader(libraryFileContents), errorListener); |
| 875 Parser parser = new Parser(source, errorListener); |
| 876 CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize()); |
| 877 SdkLibrariesReader_LibraryBuilder libraryBuilder = |
| 878 new SdkLibrariesReader_LibraryBuilder(_useDart2jsPaths); |
| 879 // If any syntactic errors were found then don't try to visit the AST |
| 880 // structure. |
| 881 if (!errorListener.errorReported) { |
| 882 unit.accept(libraryBuilder); |
| 883 } |
| 884 return libraryBuilder.librariesMap; |
| 885 } |
| 886 } |
| OLD | NEW |