Chromium Code Reviews| 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 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'dart:core' hide Resource; | 7 import 'dart:core' hide Resource; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 import 'package:analyzer/src/summary/package_bundle_reader.dart' | 21 import 'package:analyzer/src/summary/package_bundle_reader.dart' |
| 22 show ResynthesizerResultProvider, SummaryDataStore; | 22 show ResynthesizerResultProvider, SummaryDataStore; |
| 23 import 'package:analyzer/src/summary/summarize_ast.dart' | 23 import 'package:analyzer/src/summary/summarize_ast.dart' |
| 24 show serializeAstUnlinked; | 24 show serializeAstUnlinked; |
| 25 import 'package:analyzer/src/summary/summarize_elements.dart' | 25 import 'package:analyzer/src/summary/summarize_elements.dart' |
| 26 show PackageBundleAssembler; | 26 show PackageBundleAssembler; |
| 27 import 'package:analyzer/src/util/fast_uri.dart'; | 27 import 'package:analyzer/src/util/fast_uri.dart'; |
| 28 import 'package:path/path.dart' as pathos; | 28 import 'package:path/path.dart' as pathos; |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * Unlinked and linked information about a [PubPackage]. | |
| 32 */ | |
| 33 class LinkedPubPackage { | |
| 34 final PubPackage package; | |
| 35 final PackageBundle unlinked; | |
| 36 final PackageBundle linked; | |
| 37 LinkedPubPackage(this.package, this.unlinked, this.linked); | |
| 38 } | |
| 39 | |
| 40 /** | |
| 31 * A package in the pub cache. | 41 * A package in the pub cache. |
| 32 */ | 42 */ |
| 33 class PubPackage { | 43 class PubPackage { |
| 34 final String name; | 44 final String name; |
| 35 final Folder libFolder; | 45 final Folder libFolder; |
| 36 | 46 |
| 37 PubPackage(this.name, this.libFolder); | 47 PubPackage(this.name, this.libFolder); |
| 38 | 48 |
| 39 Folder get folder => libFolder.parent; | 49 Folder get folder => libFolder.parent; |
| 40 | 50 |
| 41 @override | 51 @override |
| 42 int get hashCode => libFolder.hashCode; | 52 int get hashCode => libFolder.hashCode; |
| 43 | 53 |
| 44 @override | 54 @override |
| 45 bool operator ==(other) { | 55 bool operator ==(other) { |
| 46 return other is PubPackage && other.libFolder == libFolder; | 56 return other is PubPackage && other.libFolder == libFolder; |
| 47 } | 57 } |
| 48 | 58 |
| 49 @override | 59 @override |
| 50 String toString() => '($name in $folder)'; | 60 String toString() => '($name in $folder)'; |
| 51 } | 61 } |
| 52 | 62 |
| 53 /** | 63 /** |
| 54 * Unlinked and linked information about a [PubPackage]. | |
| 55 */ | |
| 56 class LinkedPubPackage { | |
| 57 final PubPackage package; | |
| 58 final PackageBundle unlinked; | |
| 59 final PackageBundle linked; | |
| 60 LinkedPubPackage(this.package, this.unlinked, this.linked); | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * Class that manages summaries for pub packages. | 64 * Class that manages summaries for pub packages. |
| 65 * | 65 * |
| 66 * The client should call [getLinkedBundles] after creating a new | 66 * The client should call [getLinkedBundles] after creating a new |
| 67 * [AnalysisContext] and configuring its source factory, but before computing | 67 * [AnalysisContext] and configuring its source factory, but before computing |
| 68 * any analysis results. The returned linked bundles can be used to create and | 68 * any analysis results. The returned linked bundles can be used to create and |
| 69 * configure [ResynthesizerResultProvider] for the context. | 69 * configure [ResynthesizerResultProvider] for the context. |
| 70 */ | 70 */ |
| 71 class PubSummaryManager { | 71 class PubSummaryManager { |
| 72 static const UNLINKED_BUNDLE_FILE_NAME = 'unlinked.ds'; | 72 static const UNLINKED_NAME = 'unlinked.ds'; |
| 73 static const UNLINKED_SPEC_NAME = 'unlinked_spec.ds'; | |
| 73 | 74 |
| 74 final ResourceProvider resourceProvider; | 75 final ResourceProvider resourceProvider; |
| 75 | 76 |
| 76 /** | 77 /** |
| 77 * The name of the temporary file that is used for atomic writes. | 78 * The name of the temporary file that is used for atomic writes. |
| 78 */ | 79 */ |
| 79 final String tempFileName; | 80 final String tempFileName; |
| 80 | 81 |
| 81 /** | 82 /** |
| 82 * The map from [PubPackage]s to their unlinked [PackageBundle]s in the pub | 83 * The map from [PubPackage]s to their unlinked [PackageBundle]s in the pub |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 | 179 |
| 179 // Done. | 180 // Done. |
| 180 return linkedPackages; | 181 return linkedPackages; |
| 181 } | 182 } |
| 182 | 183 |
| 183 /** | 184 /** |
| 184 * Return all available unlinked [PackageBundle]s for the given [context], | 185 * Return all available unlinked [PackageBundle]s for the given [context], |
| 185 * maybe an empty map, but not `null`. | 186 * maybe an empty map, but not `null`. |
| 186 */ | 187 */ |
| 187 Map<PubPackage, PackageBundle> getUnlinkedBundles(AnalysisContext context) { | 188 Map<PubPackage, PackageBundle> getUnlinkedBundles(AnalysisContext context) { |
| 189 bool strongMode = context.analysisOptions.strongMode; | |
| 188 Map<PubPackage, PackageBundle> unlinkedBundles = | 190 Map<PubPackage, PackageBundle> unlinkedBundles = |
| 189 new HashMap<PubPackage, PackageBundle>(); | 191 new HashMap<PubPackage, PackageBundle>(); |
| 190 Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap; | 192 Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap; |
| 191 if (packageMap != null) { | 193 if (packageMap != null) { |
| 192 packageMap.forEach((String packageName, List<Folder> libFolders) { | 194 packageMap.forEach((String packageName, List<Folder> libFolders) { |
| 193 if (libFolders.length == 1) { | 195 if (libFolders.length == 1) { |
| 194 Folder libFolder = libFolders.first; | 196 Folder libFolder = libFolders.first; |
| 195 if (isPathInPubCache(pathContext, libFolder.path)) { | 197 if (isPathInPubCache(pathContext, libFolder.path)) { |
| 196 PubPackage package = new PubPackage(packageName, libFolder); | 198 PubPackage package = new PubPackage(packageName, libFolder); |
| 197 PackageBundle unlinkedBundle = _getUnlinkedOrSchedule(package); | 199 PackageBundle unlinkedBundle = |
| 200 _getUnlinkedOrSchedule(package, strongMode); | |
| 198 if (unlinkedBundle != null) { | 201 if (unlinkedBundle != null) { |
| 199 unlinkedBundles[package] = unlinkedBundle; | 202 unlinkedBundles[package] = unlinkedBundle; |
| 200 } | 203 } |
| 201 } | 204 } |
| 202 } | 205 } |
| 203 }); | 206 }); |
| 204 } | 207 } |
| 205 return unlinkedBundles; | 208 return unlinkedBundles; |
| 206 } | 209 } |
| 207 | 210 |
| 208 /** | 211 /** |
| 209 * Compute unlinked bundle for a package from [packagesToComputeUnlinked], | 212 * Compute unlinked bundle for a package from [packagesToComputeUnlinked], |
| 210 * and schedule delayed computation for the next package, if any. | 213 * and schedule delayed computation for the next package, if any. |
| 211 */ | 214 */ |
| 212 void _computeNextUnlinked() { | 215 void _computeNextUnlinked() { |
| 213 if (packagesToComputeUnlinked.isNotEmpty) { | 216 if (packagesToComputeUnlinked.isNotEmpty) { |
| 214 PubPackage package = packagesToComputeUnlinked.first; | 217 PubPackage package = packagesToComputeUnlinked.first; |
| 215 _computeUnlinked(package); | 218 _computeUnlinked(package, false); |
| 219 _computeUnlinked(package, true); | |
| 216 packagesToComputeUnlinked.remove(package); | 220 packagesToComputeUnlinked.remove(package); |
| 217 _scheduleNextUnlinked(); | 221 _scheduleNextUnlinked(); |
| 218 } else { | 222 } else { |
| 219 if (_onUnlinkedCompleteCompleter != null) { | 223 if (_onUnlinkedCompleteCompleter != null) { |
| 220 _onUnlinkedCompleteCompleter.complete(true); | 224 _onUnlinkedCompleteCompleter.complete(true); |
| 221 _onUnlinkedCompleteCompleter = null; | 225 _onUnlinkedCompleteCompleter = null; |
| 222 } | 226 } |
| 223 } | 227 } |
| 224 } | 228 } |
| 225 | 229 |
| 226 /** | 230 /** |
| 227 * Compute the unlinked bundle for the package with the given path, put | 231 * Compute the unlinked bundle for the package with the given path, put |
| 228 * it in the [unlinkedBundleMap] and store into the [resourceProvider]. | 232 * it in the [unlinkedBundleMap] and store into the [resourceProvider]. |
| 229 * | 233 * |
| 230 * TODO(scheglov) Consider moving into separate isolate(s). | 234 * TODO(scheglov) Consider moving into separate isolate(s). |
| 231 */ | 235 */ |
| 232 void _computeUnlinked(PubPackage package) { | 236 void _computeUnlinked(PubPackage package, bool strongMode) { |
| 233 Folder libFolder = package.libFolder; | 237 Folder libFolder = package.libFolder; |
| 234 String libPath = libFolder.path + pathContext.separator; | 238 String libPath = libFolder.path + pathContext.separator; |
| 235 PackageBundleAssembler assembler = new PackageBundleAssembler(); | 239 PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| 236 | 240 |
| 237 /** | 241 /** |
| 238 * Return the `package` [Uri] for the given [path] in the `lib` folder | 242 * Return the `package` [Uri] for the given [path] in the `lib` folder |
| 239 * of the current package. | 243 * of the current package. |
| 240 */ | 244 */ |
| 241 Uri getUri(String path) { | 245 Uri getUri(String path) { |
| 242 String pathInLib = path.substring(libPath.length); | 246 String pathInLib = path.substring(libPath.length); |
| 243 String uriPath = pathos.posix.joinAll(pathContext.split(pathInLib)); | 247 String uriPath = pathos.posix.joinAll(pathContext.split(pathInLib)); |
| 244 String uriStr = 'package:${package.name}/$uriPath'; | 248 String uriStr = 'package:${package.name}/$uriPath'; |
| 245 return FastUri.parse(uriStr); | 249 return FastUri.parse(uriStr); |
| 246 } | 250 } |
| 247 | 251 |
| 248 /** | 252 /** |
| 249 * If the given [file] is a Dart file, add its unlinked unit. | 253 * If the given [file] is a Dart file, add its unlinked unit. |
| 250 */ | 254 */ |
| 251 void addDartFile(File file) { | 255 void addDartFile(File file) { |
| 252 String path = file.path; | 256 String path = file.path; |
| 253 if (AnalysisEngine.isDartFileName(path)) { | 257 if (AnalysisEngine.isDartFileName(path)) { |
| 254 Uri uri = getUri(path); | 258 Uri uri = getUri(path); |
| 255 Source source = file.createSource(uri); | 259 Source source = file.createSource(uri); |
| 256 CompilationUnit unit = _parse(source); | 260 CompilationUnit unit = _parse(source, strongMode); |
| 257 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); | 261 UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit); |
| 258 assembler.addUnlinkedUnit(source, unlinkedUnit); | 262 assembler.addUnlinkedUnit(source, unlinkedUnit); |
| 259 } | 263 } |
| 260 } | 264 } |
| 261 | 265 |
| 262 /** | 266 /** |
| 263 * Visit the [folder] recursively. | 267 * Visit the [folder] recursively. |
| 264 */ | 268 */ |
| 265 void addDartFiles(Folder folder) { | 269 void addDartFiles(Folder folder) { |
| 266 List<Resource> children = folder.getChildren(); | 270 List<Resource> children = folder.getChildren(); |
| 267 for (Resource child in children) { | 271 for (Resource child in children) { |
| 268 if (child is File) { | 272 if (child is File) { |
| 269 addDartFile(child); | 273 addDartFile(child); |
| 270 } | 274 } |
| 271 } | 275 } |
| 272 for (Resource child in children) { | 276 for (Resource child in children) { |
| 273 if (child is Folder) { | 277 if (child is Folder) { |
| 274 addDartFiles(child); | 278 addDartFiles(child); |
| 275 } | 279 } |
| 276 } | 280 } |
| 277 } | 281 } |
| 278 | 282 |
| 279 try { | 283 try { |
| 280 addDartFiles(libFolder); | 284 addDartFiles(libFolder); |
| 281 List<int> bytes = assembler.assemble().toBuffer(); | 285 List<int> bytes = assembler.assemble().toBuffer(); |
| 282 _writeAtomic(package.folder, UNLINKED_BUNDLE_FILE_NAME, bytes); | 286 String fileName = _getUnlinkedName(strongMode); |
| 287 _writeAtomic(package.folder, fileName, bytes); | |
| 283 } on FileSystemException { | 288 } on FileSystemException { |
| 284 // Ignore file system exceptions. | 289 // Ignore file system exceptions. |
| 285 } | 290 } |
| 286 } | 291 } |
| 287 | 292 |
| 288 /** | 293 /** |
| 294 * Return the name of the file for an unlinked bundle, in strong or spec mode. | |
| 295 */ | |
| 296 String _getUnlinkedName(bool strongMode) { | |
| 297 if (strongMode) { | |
| 298 return UNLINKED_NAME; | |
| 299 } else { | |
| 300 return UNLINKED_SPEC_NAME; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 /** | |
| 289 * Return the unlinked [PackageBundle] for the given [package]. If the bundle | 305 * Return the unlinked [PackageBundle] for the given [package]. If the bundle |
| 290 * has not been compute yet, return `null` and schedule its computation. | 306 * has not been compute yet, return `null` and schedule its computation. |
| 291 */ | 307 */ |
| 292 PackageBundle _getUnlinkedOrSchedule(PubPackage package) { | 308 PackageBundle _getUnlinkedOrSchedule(PubPackage package, bool strongMode) { |
| 293 // Try to find in the cache. | 309 // Try to find in the cache. |
| 294 PackageBundle bundle = unlinkedBundleMap[package]; | 310 PackageBundle bundle = unlinkedBundleMap[package]; |
| 295 if (bundle != null) { | 311 if (bundle != null) { |
| 296 return bundle; | 312 return bundle; |
| 297 } | 313 } |
| 298 // Try to read from the file system. | 314 // Try to read from the file system. |
| 299 File unlinkedFile = | 315 String fileName = _getUnlinkedName(strongMode); |
| 300 package.folder.getChildAssumingFile(UNLINKED_BUNDLE_FILE_NAME); | 316 File unlinkedFile = package.folder.getChildAssumingFile(fileName); |
| 301 if (unlinkedFile.exists) { | 317 if (unlinkedFile.exists) { |
| 302 try { | 318 try { |
| 303 List<int> bytes = unlinkedFile.readAsBytesSync(); | 319 List<int> bytes = unlinkedFile.readAsBytesSync(); |
| 304 bundle = new PackageBundle.fromBuffer(bytes); | 320 bundle = new PackageBundle.fromBuffer(bytes); |
| 305 unlinkedBundleMap[package] = bundle; | 321 unlinkedBundleMap[package] = bundle; |
| 306 return bundle; | 322 return bundle; |
| 307 } on FileSystemException { | 323 } on FileSystemException { |
| 308 // Ignore file system exceptions. | 324 // Ignore file system exceptions. |
| 309 } | 325 } |
| 310 } | 326 } |
| 311 // Schedule computation in the background. | 327 // Schedule computation in the background. |
| 312 if (package != null && seenPackages.add(package)) { | 328 if (package != null && seenPackages.add(package)) { |
| 313 if (packagesToComputeUnlinked.isEmpty) { | 329 if (packagesToComputeUnlinked.isEmpty) { |
| 314 _scheduleNextUnlinked(); | 330 _scheduleNextUnlinked(); |
| 315 } | 331 } |
| 316 packagesToComputeUnlinked.add(package); | 332 packagesToComputeUnlinked.add(package); |
| 317 } | 333 } |
| 318 // The bundle is for available. | 334 // The bundle is for available. |
| 319 return null; | 335 return null; |
| 320 } | 336 } |
| 321 | 337 |
| 322 /** | 338 /** |
| 323 * Parse the given [source] into AST. | 339 * Parse the given [source] into AST. |
| 324 */ | 340 */ |
| 325 CompilationUnit _parse(Source source) { | 341 CompilationUnit _parse(Source source, bool strongMode) { |
| 326 String code = source.contents.data; | 342 String code = source.contents.data; |
| 327 AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER; | 343 AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER; |
| 328 CharSequenceReader reader = new CharSequenceReader(code); | 344 CharSequenceReader reader = new CharSequenceReader(code); |
| 329 Scanner scanner = new Scanner(source, reader, errorListener); | 345 Scanner scanner = new Scanner(source, reader, errorListener); |
| 346 scanner.scanGenericMethodComments = strongMode; | |
| 330 Token token = scanner.tokenize(); | 347 Token token = scanner.tokenize(); |
| 331 LineInfo lineInfo = new LineInfo(scanner.lineStarts); | 348 LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
| 332 Parser parser = new Parser(source, errorListener); | 349 Parser parser = new Parser(source, errorListener); |
| 350 parser.parseGenericMethodComments = strongMode; | |
| 333 CompilationUnit unit = parser.parseCompilationUnit(token); | 351 CompilationUnit unit = parser.parseCompilationUnit(token); |
| 334 unit.lineInfo = lineInfo; | 352 unit.lineInfo = lineInfo; |
| 335 return unit; | 353 return unit; |
| 336 } | 354 } |
| 337 | 355 |
| 338 /** | 356 /** |
| 339 * Schedule delayed computation of the next package unlinked bundle from the | 357 * Schedule delayed computation of the next package unlinked bundle from the |
| 340 * set of [packagesToComputeUnlinked]. We delay each computation because we | 358 * set of [packagesToComputeUnlinked]. We delay each computation because we |
| 341 * want operations in analysis server to proceed, and computing bundles of | 359 * want operations in analysis server to proceed, and computing bundles of |
| 342 * packages is a background task. | 360 * packages is a background task. |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 v.failed = true; | 448 v.failed = true; |
| 431 } | 449 } |
| 432 return dependencyLibrary; | 450 return dependencyLibrary; |
| 433 }, (String absUri) { | 451 }, (String absUri) { |
| 434 UnlinkedUnit unlinkedUnit = store.unlinkedMap[absUri]; | 452 UnlinkedUnit unlinkedUnit = store.unlinkedMap[absUri]; |
| 435 if (unlinkedUnit == null) { | 453 if (unlinkedUnit == null) { |
| 436 // TODO(scheglov) add test | 454 // TODO(scheglov) add test |
| 437 v.failed = true; | 455 v.failed = true; |
| 438 } | 456 } |
| 439 return unlinkedUnit; | 457 return unlinkedUnit; |
| 440 }, false); | 458 }, false); |
|
Paul Berry
2016/08/10 21:34:42
Need to pass true when linking in strong mode.
scheglov
2016/08/10 21:41:37
Done.
| |
| 441 if (!v.failed) { | 459 if (!v.failed) { |
| 442 PackageBundleAssembler assembler = new PackageBundleAssembler(); | 460 PackageBundleAssembler assembler = new PackageBundleAssembler(); |
| 443 map.forEach((uri, linkedLibrary) { | 461 map.forEach((uri, linkedLibrary) { |
| 444 assembler.addLinkedLibrary(uri, linkedLibrary); | 462 assembler.addLinkedLibrary(uri, linkedLibrary); |
| 445 }); | 463 }); |
| 446 v.linkedBuilder = assembler.assemble(); | 464 v.linkedBuilder = assembler.assemble(); |
| 447 store.addBundle(null, v.linkedBuilder); | 465 store.addBundle(null, v.linkedBuilder); |
| 448 } | 466 } |
| 449 } | 467 } |
| 450 | 468 |
| 451 @override | 469 @override |
| 452 void evaluateScc(List<_LinkedNode> scc) { | 470 void evaluateScc(List<_LinkedNode> scc) { |
| 453 print('evaluateScc: $scc'); | 471 print('evaluateScc: $scc'); |
| 454 // TODO(scheglov): implement evaluateScc | 472 // TODO(scheglov): implement evaluateScc |
| 455 } | 473 } |
| 456 } | 474 } |
| OLD | NEW |