Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015, 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_cli.src.package_analyzer; | |
| 6 | |
| 7 import 'dart:core' hide Resource; | |
| 8 import 'dart:io' as io; | |
| 9 | |
| 10 import 'package:analyzer/dart/element/element.dart'; | |
| 11 import 'package:analyzer/file_system/file_system.dart'; | |
| 12 import 'package:analyzer/file_system/physical_file_system.dart'; | |
| 13 import 'package:analyzer/source/package_map_resolver.dart'; | |
| 14 import 'package:analyzer/src/context/cache.dart'; | |
| 15 import 'package:analyzer/src/context/context.dart'; | |
| 16 import 'package:analyzer/src/generated/engine.dart'; | |
| 17 import 'package:analyzer/src/generated/error.dart'; | |
| 18 import 'package:analyzer/src/generated/resolver.dart'; | |
| 19 import 'package:analyzer/src/generated/sdk_io.dart'; | |
| 20 import 'package:analyzer/src/generated/source.dart'; | |
| 21 import 'package:analyzer/src/generated/source_io.dart'; | |
| 22 import 'package:analyzer/src/summary/format.dart'; | |
| 23 import 'package:analyzer/src/summary/idl.dart'; | |
| 24 import 'package:analyzer/src/summary/resynthesize.dart'; | |
| 25 import 'package:analyzer/src/summary/summarize_elements.dart'; | |
| 26 import 'package:analyzer/src/summary/summary_sdk.dart'; | |
| 27 import 'package:analyzer/src/task/dart.dart'; | |
| 28 import 'package:analyzer/task/dart.dart'; | |
| 29 import 'package:analyzer/task/model.dart'; | |
| 30 import 'package:analyzer_cli/src/analyzer_impl.dart'; | |
| 31 import 'package:analyzer_cli/src/driver.dart'; | |
| 32 import 'package:analyzer_cli/src/error_formatter.dart'; | |
| 33 import 'package:analyzer_cli/src/options.dart'; | |
| 34 import 'package:path/path.dart' as pathos; | |
| 35 | |
| 36 /** | |
| 37 * If [uri] has the `package` scheme in form of `package:pkg/file.dart`, | |
| 38 * return the `pkg` name. Otherwise return `null`. | |
| 39 */ | |
| 40 String getPackageName(Uri uri) { | |
| 41 if (uri.scheme != 'package') { | |
| 42 return null; | |
| 43 } | |
| 44 String path = uri.path; | |
| 45 int index = path.indexOf('/'); | |
| 46 if (index == -1) { | |
| 47 return null; | |
| 48 } | |
| 49 return path.substring(0, index); | |
| 50 } | |
| 51 | |
| 52 /** | |
| 53 * A concrete resynthesizer that serves summaries from given file paths. | |
| 54 */ | |
| 55 class FileBasedSummaryResynthesizer extends SummaryResynthesizer { | |
| 56 final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{}; | |
| 57 final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{}; | |
| 58 | |
| 59 FileBasedSummaryResynthesizer( | |
| 60 SummaryResynthesizer parent, | |
| 61 AnalysisContext context, | |
| 62 TypeProvider typeProvider, | |
| 63 SourceFactory sourceFactory, | |
| 64 bool strongMode, | |
| 65 List<String> summaryPaths) | |
| 66 : super(parent, context, typeProvider, sourceFactory, strongMode) { | |
| 67 summaryPaths.forEach(_fillMaps); | |
| 68 } | |
| 69 | |
| 70 @override | |
| 71 LinkedLibrary getLinkedSummary(String uri) { | |
| 72 return linkedMap[uri]; | |
| 73 } | |
| 74 | |
| 75 @override | |
| 76 UnlinkedUnit getUnlinkedSummary(String uri) { | |
| 77 return unlinkedMap[uri]; | |
| 78 } | |
| 79 | |
| 80 @override | |
| 81 bool hasLibrarySummary(String uri) { | |
| 82 return linkedMap.containsKey(uri); | |
| 83 } | |
| 84 | |
| 85 void _fillMaps(String path) { | |
| 86 io.File file = new io.File(path); | |
| 87 List<int> buffer = file.readAsBytesSync(); | |
| 88 SdkBundle bundle = new SdkBundle.fromBuffer(buffer); | |
| 89 for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) { | |
| 90 unlinkedMap[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i]; | |
| 91 } | |
| 92 for (int i = 0; i < bundle.linkedLibraryUris.length; i++) { | |
| 93 linkedMap[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i]; | |
| 94 } | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 /** | |
| 99 * The [ResourceProvider] that provides results from input package summaries. | |
| 100 */ | |
| 101 class InputPackagesResultProvider extends ResultProvider { | |
| 102 final InternalAnalysisContext context; | |
| 103 final Map<String, String> packageSummaryInputs; | |
| 104 | |
| 105 FileBasedSummaryResynthesizer resynthesizer; | |
| 106 SummaryResultProvider sdkProvider; | |
| 107 | |
| 108 InputPackagesResultProvider(this.context, this.packageSummaryInputs) { | |
| 109 InternalAnalysisContext sdkContext = context.sourceFactory.dartSdk.context; | |
| 110 sdkProvider = sdkContext.resultProvider; | |
| 111 // Set the type provider to prevent the context from computing it. | |
| 112 context.typeProvider = sdkContext.typeProvider; | |
| 113 // Create a chained resynthesizer. | |
| 114 resynthesizer = new FileBasedSummaryResynthesizer( | |
| 115 sdkProvider.resynthesizer, | |
| 116 context, | |
| 117 context.typeProvider, | |
| 118 context.sourceFactory, | |
| 119 false, | |
| 120 packageSummaryInputs.values.toList()); | |
| 121 } | |
| 122 | |
| 123 bool compute(CacheEntry entry, ResultDescriptor result) { | |
|
Paul Berry
2016/02/23 00:59:29
It looks like some of this code is duplicated from
scheglov
2016/02/23 01:15:28
Yes, probably some of it can be shared.
I will add
| |
| 124 if (sdkProvider.compute(entry, result)) { | |
| 125 return true; | |
| 126 } | |
| 127 AnalysisTarget target = entry.target; | |
| 128 // Only library results are supported for now. | |
| 129 if (target is Source) { | |
| 130 Uri uri = target.uri; | |
| 131 // We know how to server results to input packages. | |
| 132 String sourcePackageName = getPackageName(uri); | |
| 133 if (!packageSummaryInputs.containsKey(sourcePackageName)) { | |
| 134 return false; | |
| 135 } | |
| 136 // Provide known results. | |
| 137 String uriString = uri.toString(); | |
| 138 if (result == LIBRARY_ELEMENT1 || | |
| 139 result == LIBRARY_ELEMENT2 || | |
| 140 result == LIBRARY_ELEMENT3 || | |
| 141 result == LIBRARY_ELEMENT4 || | |
| 142 result == LIBRARY_ELEMENT5 || | |
| 143 result == LIBRARY_ELEMENT6 || | |
| 144 result == LIBRARY_ELEMENT7 || | |
| 145 result == LIBRARY_ELEMENT8 || | |
| 146 result == LIBRARY_ELEMENT || | |
| 147 false) { | |
| 148 LibraryElement libraryElement = | |
| 149 resynthesizer.getLibraryElement(uriString); | |
| 150 entry.setValue(result, libraryElement, TargetedResult.EMPTY_LIST); | |
| 151 return true; | |
| 152 } else if (result == READY_LIBRARY_ELEMENT2 || | |
| 153 result == READY_LIBRARY_ELEMENT5 || | |
| 154 result == READY_LIBRARY_ELEMENT6) { | |
| 155 entry.setValue(result, true, TargetedResult.EMPTY_LIST); | |
| 156 return true; | |
| 157 } else if (result == SOURCE_KIND) { | |
| 158 if (resynthesizer.linkedMap.containsKey(uriString)) { | |
| 159 entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST); | |
| 160 return true; | |
| 161 } | |
| 162 if (resynthesizer.unlinkedMap.containsKey(uriString)) { | |
| 163 entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST); | |
| 164 return true; | |
| 165 } | |
| 166 return false; | |
| 167 } | |
| 168 } | |
| 169 return false; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 /** | |
| 174 * The [UriResolver] that knows about sources that are parts of packages which | |
| 175 * are served from their summaries. | |
| 176 */ | |
| 177 class InSummaryPackageUriResolver extends UriResolver { | |
|
Brian Wilkerson
2016/02/23 00:27:01
I don't understand the need for either this class
scheglov
2016/02/23 01:15:28
Yes, we did not get to this part offline today.
| |
| 178 final Map<String, String> packageSummaryInputs; | |
| 179 | |
| 180 InSummaryPackageUriResolver(this.packageSummaryInputs); | |
| 181 | |
| 182 @override | |
| 183 Source resolveAbsolute(Uri uri, [Uri actualUri]) { | |
| 184 actualUri ??= uri; | |
| 185 String packageName = getPackageName(actualUri); | |
| 186 if (packageSummaryInputs.containsKey(packageName)) { | |
| 187 return new InSummarySource(actualUri); | |
| 188 } | |
| 189 return null; | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 /** | |
| 194 * A placeholder of a source that is part of a package whose analysis results | |
| 195 * are served from its summary. This source uses its URI as [fullName] and has | |
| 196 * empty contents. | |
| 197 */ | |
| 198 class InSummarySource extends Source { | |
| 199 final Uri uri; | |
| 200 | |
| 201 InSummarySource(this.uri); | |
| 202 | |
| 203 @override | |
| 204 TimestampedData<String> get contents => new TimestampedData<String>(0, ''); | |
| 205 | |
| 206 @override | |
| 207 String get encoding => uri.toString(); | |
| 208 | |
| 209 @override | |
| 210 String get fullName => encoding; | |
| 211 | |
| 212 @override | |
| 213 bool get isInSystemLibrary => false; | |
| 214 | |
| 215 @override | |
| 216 int get modificationStamp => 0; | |
| 217 | |
| 218 @override | |
| 219 String get shortName => pathos.basename(fullName); | |
| 220 | |
| 221 @override | |
| 222 UriKind get uriKind => UriKind.PACKAGE_URI; | |
| 223 | |
| 224 @override | |
| 225 bool exists() => true; | |
| 226 | |
| 227 @override | |
| 228 Uri resolveRelativeUri(Uri relativeUri) { | |
| 229 Uri baseUri = uri; | |
| 230 return baseUri.resolveUri(relativeUri); | |
| 231 } | |
| 232 | |
| 233 @override | |
| 234 String toString() => uri.toString(); | |
| 235 } | |
| 236 | |
| 237 /** | |
| 238 * The hermetic whole package analyzer. | |
| 239 */ | |
| 240 class PackageAnalyzer { | |
| 241 final CommandLineOptions options; | |
| 242 | |
| 243 String packagePath; | |
| 244 String packageLibPath; | |
| 245 | |
| 246 final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; | |
| 247 InternalAnalysisContext context; | |
| 248 final List<Source> explicitSources = <Source>[]; | |
| 249 | |
| 250 final List<String> linkedLibraryUris = <String>[]; | |
| 251 final List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[]; | |
| 252 final List<String> unlinkedUnitUris = <String>[]; | |
| 253 final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[]; | |
| 254 | |
| 255 PackageAnalyzer(this.options); | |
| 256 | |
| 257 /** | |
| 258 * Perform package analysis according to the given [options]. | |
| 259 */ | |
| 260 ErrorSeverity analyze() { | |
| 261 packagePath = options.packageModePath; | |
| 262 packageLibPath = resourceProvider.pathContext.join(packagePath, 'lib'); | |
| 263 if (packageLibPath == null) { | |
| 264 errorSink.writeln('--package-mode-path must be set to the root ' | |
| 265 'folder of the package to analyze.'); | |
| 266 io.exitCode = ErrorSeverity.ERROR.ordinal; | |
| 267 return ErrorSeverity.ERROR; | |
| 268 } | |
| 269 | |
| 270 // Write the progress message. | |
| 271 if (!options.machineFormat) { | |
| 272 outSink.writeln("Analyzing sources ${options.sourceFiles}..."); | |
| 273 } | |
| 274 | |
| 275 // Prepare the analysis context. | |
| 276 _createContext(); | |
| 277 | |
| 278 // Add sources. | |
| 279 ChangeSet changeSet = new ChangeSet(); | |
| 280 for (String path in options.sourceFiles) { | |
| 281 if (AnalysisEngine.isDartFileName(path)) { | |
| 282 path = resourceProvider.pathContext.absolute(path); | |
| 283 File file = resourceProvider.getFile(path); | |
| 284 if (!file.exists) { | |
| 285 errorSink.writeln('File not found: $path'); | |
| 286 io.exitCode = ErrorSeverity.ERROR.ordinal; | |
| 287 return ErrorSeverity.ERROR; | |
| 288 } | |
| 289 Source source = _createSourceInContext(file); | |
| 290 explicitSources.add(source); | |
| 291 changeSet.addedSource(source); | |
| 292 } | |
| 293 } | |
| 294 context.applyChanges(changeSet); | |
| 295 | |
| 296 // Perform full analysis. | |
| 297 while (true) { | |
| 298 AnalysisResult analysisResult = context.performAnalysisTask(); | |
| 299 if (!analysisResult.hasMoreWork) { | |
| 300 break; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 // Write summary for Dart libraries. | |
| 305 if (options.packageSummaryOutput != null) { | |
| 306 for (Source source in context.librarySources) { | |
| 307 if (pathos.isWithin(packageLibPath, source.fullName)) { | |
| 308 LibraryElement libraryElement = context.getLibraryElement(source); | |
| 309 if (libraryElement != null) { | |
| 310 _serializeSingleLibrary(libraryElement); | |
| 311 } | |
| 312 } | |
| 313 } | |
| 314 // Write the whole package bundle. | |
| 315 SdkBundleBuilder sdkBundle = new SdkBundleBuilder( | |
|
Brian Wilkerson
2016/02/23 00:27:01
Probably ought to rename SdkBundleBuilder at some
Paul Berry
2016/02/23 00:59:29
Agreed. I have some other changes I want to make
scheglov
2016/02/23 01:15:28
Yes, it was quite obvious that we need to rename i
| |
| 316 linkedLibraryUris: linkedLibraryUris, | |
| 317 linkedLibraries: linkedLibraries, | |
| 318 unlinkedUnitUris: unlinkedUnitUris, | |
| 319 unlinkedUnits: unlinkedUnits); | |
| 320 io.File file = new io.File(options.packageSummaryOutput); | |
| 321 file.writeAsBytesSync(sdkBundle.toBuffer(), mode: io.FileMode.WRITE_ONLY); | |
| 322 } | |
| 323 | |
| 324 // Process errors. | |
| 325 _printErrors(); | |
| 326 return _computeMaxSeverity(); | |
| 327 } | |
| 328 | |
| 329 ErrorSeverity _computeMaxSeverity() { | |
| 330 ErrorSeverity maxSeverity = ErrorSeverity.NONE; | |
| 331 for (Source source in explicitSources) { | |
| 332 AnalysisErrorInfo errorInfo = context.getErrors(source); | |
| 333 for (AnalysisError error in errorInfo.errors) { | |
| 334 ProcessedSeverity processedSeverity = | |
| 335 AnalyzerImpl.processError(error, options, context); | |
| 336 if (processedSeverity != null) { | |
| 337 maxSeverity = maxSeverity.max(processedSeverity.severity); | |
| 338 } | |
| 339 } | |
| 340 } | |
| 341 return maxSeverity; | |
| 342 } | |
| 343 | |
| 344 void _createContext() { | |
| 345 DirectoryBasedDartSdk sdk = DirectoryBasedDartSdk.defaultSdk; | |
| 346 sdk.useSummary = true; | |
| 347 | |
| 348 // Create the context. | |
| 349 context = AnalysisEngine.instance.createAnalysisContext(); | |
| 350 context.typeProvider = sdk.context.typeProvider; | |
| 351 context.sourceFactory = new SourceFactory(<UriResolver>[ | |
| 352 new DartUriResolver(sdk), | |
| 353 new InSummaryPackageUriResolver(options.packageSummaryInputs), | |
| 354 new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{ | |
| 355 options.packageName: <Folder>[ | |
| 356 resourceProvider.getFolder(packageLibPath) | |
| 357 ], | |
| 358 }), | |
| 359 new FileUriResolver() | |
| 360 ]); | |
| 361 context.resultProvider = | |
| 362 new InputPackagesResultProvider(context, options.packageSummaryInputs); | |
| 363 | |
| 364 // Set context options. | |
| 365 Driver.setAnalysisContextOptions( | |
| 366 context, options, (AnalysisOptionsImpl contextOptions) {}); | |
| 367 } | |
| 368 | |
| 369 /** | |
| 370 * Create and return a source representing the given [file]. | |
| 371 */ | |
| 372 Source _createSourceInContext(File file) { | |
| 373 Source source = file.createSource(); | |
| 374 if (context == null) { | |
| 375 return source; | |
| 376 } | |
| 377 Uri uri = context.sourceFactory.restoreUri(source); | |
| 378 return file.createSource(uri); | |
| 379 } | |
| 380 | |
| 381 /** | |
| 382 * Print errors for all explicit sources. | |
| 383 */ | |
| 384 void _printErrors() { | |
| 385 StringSink sink = options.machineFormat ? errorSink : outSink; | |
| 386 ErrorFormatter formatter = new ErrorFormatter( | |
| 387 sink, | |
| 388 options, | |
| 389 (AnalysisError error) => | |
| 390 AnalyzerImpl.processError(error, options, context)); | |
| 391 for (Source source in explicitSources) { | |
| 392 AnalysisErrorInfo errorInfo = context.getErrors(source); | |
| 393 formatter.formatErrors([errorInfo]); | |
| 394 } | |
| 395 } | |
| 396 | |
| 397 /** | |
| 398 * Serialize the library with the given [element]. | |
| 399 */ | |
| 400 void _serializeSingleLibrary(LibraryElement element) { | |
| 401 String uri = element.source.uri.toString(); | |
| 402 LibrarySerializationResult libraryResult = | |
| 403 serializeLibrary(element, context.typeProvider, options.strongMode); | |
| 404 linkedLibraryUris.add(uri); | |
| 405 linkedLibraries.add(libraryResult.linked); | |
| 406 unlinkedUnitUris.addAll(libraryResult.unitUris); | |
| 407 unlinkedUnits.addAll(libraryResult.unlinkedUnits); | |
| 408 } | |
| 409 } | |
| OLD | NEW |