blob: ad3e479f6dcc208c914e8ee81df2d0ab8e2affce [file] [log] [blame]
// 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);
}
}