| // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:typed_data'; |
| |
| import 'package:analyzer/dart/analysis/declared_variables.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; |
| import 'package:analyzer/src/dart/analysis/byte_store.dart'; |
| import 'package:analyzer/src/dart/analysis/ddc.dart'; |
| import 'package:analyzer/src/dart/analysis/driver.dart' show AnalysisDriver; |
| import 'package:analyzer/src/dart/analysis/file_state.dart'; |
| import 'package:analyzer/src/dart/analysis/library_analyzer.dart'; |
| import 'package:analyzer/src/dart/analysis/performance_logger.dart'; |
| import 'package:analyzer/src/dart/element/inheritance_manager3.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| import 'package:analyzer/src/generated/sdk.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
| import 'package:analyzer/src/summary2/linked_element_factory.dart'; |
| import 'package:meta/meta.dart'; |
| |
| import '../compiler/shared_command.dart' show sdkLibraryVariables; |
| import 'context.dart' show AnalyzerOptions, createSourceFactory; |
| import 'extension_types.dart' show ExtensionTypeSet; |
| |
| /// The analysis driver for `dartdevc`. |
| /// |
| /// [linkLibraries] can be used to link input sources and input summaries, |
| /// producing a [LinkedAnalysisDriver] that can analyze those sources. |
| /// |
| /// This class can be reused to link different input files if they share the |
| /// same [analysisOptions] and [summaryData]. |
| class CompilerAnalysisDriver { |
| /// The Analyzer options used for analyzing the input sources. |
| final AnalysisOptionsImpl analysisOptions; |
| |
| /// The input summaries used for analyzing/compiling the input sources. |
| /// |
| /// This should contain the summary of all imported/exported libraries and |
| /// transitive dependencies, including the Dart SDK. |
| final SummaryDataStore summaryData; |
| |
| final ResourceProvider _resourceProvider; |
| |
| final List<String> _summaryPaths; |
| |
| @visibleForTesting |
| final DartSdk dartSdk; |
| |
| /// SDK summary path, used by [isCompatibleWith] for batch/worker mode. |
| final String _dartSdkSummaryPath; |
| |
| ExtensionTypeSet _extensionTypes; |
| |
| factory CompilerAnalysisDriver(AnalyzerOptions options, |
| {SummaryDataStore summaryData, |
| List<String> summaryPaths = const [], |
| Map<String, bool> experiments = const {}}) { |
| var resourceProvider = options.resourceProvider; |
| var contextBuilder = options.createContextBuilder(); |
| |
| var analysisOptions = contextBuilder |
| .getAnalysisOptions(options.analysisRoot) as AnalysisOptionsImpl; |
| |
| analysisOptions.enabledExperiments = |
| experiments.entries.where((e) => e.value).map((e) => e.key).toList(); |
| |
| var dartSdk = contextBuilder.findSdk(null, analysisOptions); |
| |
| // Read the summaries. |
| summaryData ??= SummaryDataStore(summaryPaths, |
| resourceProvider: resourceProvider, |
| // TODO(vsm): Reset this to true once we cleanup internal build rules. |
| disallowOverlappingSummaries: false); |
| |
| return CompilerAnalysisDriver._(dartSdk, summaryPaths, summaryData, |
| analysisOptions, resourceProvider, options.dartSdkSummaryPath); |
| } |
| |
| CompilerAnalysisDriver._(this.dartSdk, this._summaryPaths, this.summaryData, |
| this.analysisOptions, this._resourceProvider, this._dartSdkSummaryPath) { |
| var bundle = dartSdk.getLinkedBundle(); |
| if (bundle != null) summaryData.addBundle(null, bundle); |
| } |
| |
| /// Information about native extension types. |
| /// |
| /// This will be `null` until [linkLibraries] has been called (because we |
| /// could be compiling the Dart SDK, so it would not be available yet). |
| ExtensionTypeSet get extensionTypes => _extensionTypes; |
| |
| /// Whether this driver can be reused for the given [dartSdkSummaryPath] and |
| /// [summaryPaths]. |
| bool isCompatibleWith(AnalyzerOptions options, List<String> summaryPaths) { |
| return _dartSdkSummaryPath == options.dartSdkSummaryPath && |
| _summaryPaths.toSet().containsAll(summaryPaths); |
| } |
| |
| /// Parses [explicitSources] and any imports/exports/parts (that are not |
| /// included in [summaryData]), and links the results so |
| /// [LinkedAnalysisDriver.analyzeLibrary] can be called. |
| /// |
| /// The analyzer [options] are used to configure URI resolution (Analyzer's |
| /// [SourceFactory]) and declared variables, if any (`-Dfoo=bar`). |
| LinkedAnalysisDriver linkLibraries( |
| List<Uri> explicitSources, AnalyzerOptions options) { |
| /// The URI resolution logic for this build unit. |
| var sourceFactory = createSourceFactory(options, |
| sdkResolver: DartUriResolver(dartSdk), summaryData: summaryData); |
| |
| /// A fresh file system state for this list of [explicitSources]. |
| var fsState = _createFileSystemState(sourceFactory); |
| |
| var declaredVariables = DeclaredVariables.fromMap( |
| Map.of(options.declaredVariables)..addAll(sdkLibraryVariables)); |
| |
| var resynthesizerBuilder = DevCompilerResynthesizerBuilder( |
| fsState: fsState, |
| analysisOptions: analysisOptions, |
| declaredVariables: declaredVariables, |
| sourceFactory: sourceFactory, |
| summaryData: summaryData, |
| explicitSources: explicitSources, |
| ); |
| resynthesizerBuilder.build(); |
| |
| _extensionTypes ??= ExtensionTypeSet( |
| resynthesizerBuilder.context.typeProvider, |
| resynthesizerBuilder.elementFactory, |
| ); |
| |
| return LinkedAnalysisDriver( |
| analysisOptions, |
| resynthesizerBuilder.elementFactory, |
| sourceFactory, |
| resynthesizerBuilder.libraryUris, |
| declaredVariables, |
| resynthesizerBuilder.summaryBytes, |
| fsState, |
| _resourceProvider, |
| ); |
| } |
| |
| FileSystemState _createFileSystemState(SourceFactory sourceFactory) { |
| var unlinkedSalt = |
| Uint32List(1 + AnalysisOptionsImpl.unlinkedSignatureLength); |
| unlinkedSalt[0] = AnalysisDriver.DATA_VERSION; |
| unlinkedSalt.setAll(1, analysisOptions.unlinkedSignature); |
| |
| var linkedSalt = Uint32List(1 + AnalysisOptions.signatureLength); |
| linkedSalt[0] = AnalysisDriver.DATA_VERSION; |
| linkedSalt.setAll(1, analysisOptions.signature); |
| |
| return FileSystemState( |
| PerformanceLog(StringBuffer()), |
| MemoryByteStore(), |
| FileContentOverlay(), |
| _resourceProvider, |
| 'contextName', |
| sourceFactory, |
| analysisOptions, |
| unlinkedSalt, |
| linkedSalt, |
| externalSummaries: summaryData); |
| } |
| } |
| |
| /// The analysis driver used after linking all input summaries and explicit |
| /// sources, produced by [CompilerAnalysisDriver.linkLibraries]. |
| class LinkedAnalysisDriver { |
| final AnalysisOptions analysisOptions; |
| final LinkedElementFactory elementFactory; |
| final SourceFactory sourceFactory; |
| final List<String> libraryUris; |
| final DeclaredVariables declaredVariables; |
| |
| /// The summary bytes for this linked build unit. |
| final List<int> summaryBytes; |
| |
| final FileSystemState _fsState; |
| |
| final ResourceProvider _resourceProvider; |
| |
| LinkedAnalysisDriver( |
| this.analysisOptions, |
| this.elementFactory, |
| this.sourceFactory, |
| this.libraryUris, |
| this.declaredVariables, |
| this.summaryBytes, |
| this._fsState, |
| this._resourceProvider); |
| |
| TypeProvider get typeProvider { |
| return elementFactory.analysisContext.typeProvider; |
| } |
| |
| /// Analyzes the library at [uri] and returns the results of analysis for all |
| /// file(s) in that library. |
| Map<FileState, UnitAnalysisResult> analyzeLibrary(String libraryUri) { |
| if (!_isLibraryUri(libraryUri)) { |
| throw ArgumentError('"$libraryUri" is not a library'); |
| } |
| |
| var analysisContext = elementFactory.analysisContext; |
| var libraryFile = _fsState.getFileForUri(Uri.parse(libraryUri)); |
| var analyzer = LibraryAnalyzer( |
| analysisOptions as AnalysisOptionsImpl, |
| declaredVariables, |
| sourceFactory, |
| (uri) => _isLibraryUri('$uri'), |
| analysisContext, |
| elementFactory, |
| InheritanceManager3(analysisContext.typeSystem), |
| libraryFile, |
| _resourceProvider); |
| // TODO(jmesserly): ideally we'd use the existing public `analyze()` method, |
| // but it's async. We can't use `async` here because it would break our |
| // developer tools extension (see web/web_command.dart). We should be able |
| // to fix it, but it requires significant changes to code outside of this |
| // repository. |
| return analyzer.analyzeSync(); |
| } |
| |
| ClassElement getClass(String uri, String name) { |
| return getLibrary(uri).getType(name); |
| } |
| |
| LibraryElement getLibrary(String uri) { |
| return elementFactory.libraryOfUri(uri); |
| } |
| |
| /// True if [uri] refers to a Dart library (i.e. a Dart source file exists |
| /// with this uri, and it is not a part file). |
| bool _isLibraryUri(String uri) { |
| return elementFactory.isLibraryUri(uri); |
| } |
| } |