options map support scaffolding in driver
Konstantin and I chatted a bit about this so at least some of it shouldn't be too surprising to him but please do feel free to grab me to chat. That said a few pointers would be handy. Notably, this change: * introduces a new `SharedOptionsOptionsMap` for use in SDK drivers (and preserve current semantics) * this is currently public but will be private once driver is more evolved to accommodate multiple options files * removes the shared `_analysisOptions` from the analysis driver with a baby step to using the one shared in SharedOptionsOptionsMap * removes context_builder and collection v2 experiments (and tests) * I'll harvest some more functionality from these in future changes but for now they're distracting and hard to maintain This work is all to setup moving analysis options awareness into file state objects which will allow us to remove `sdkVersionConstraint` info from options (finally) and a host of other good stuff (see https://github.com/dart-lang/sdk/issues/54124). Change-Id: Ic4278184016d1018b4b5b1c6ac5ba9e2546927a5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/344860 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import 'dart:typed_data';
|
||||
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_options_map.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
|
||||
@@ -49,6 +50,7 @@ Future<Uint8List> buildSdkSummary({
|
||||
|
||||
final logger = PerformanceLog(StringBuffer());
|
||||
final scheduler = AnalysisDriverScheduler(logger);
|
||||
final optionsMap = AnalysisOptionsMap.forSharedOptions(AnalysisOptionsImpl());
|
||||
final analysisDriver = AnalysisDriver(
|
||||
scheduler: scheduler,
|
||||
logger: logger,
|
||||
@@ -57,7 +59,7 @@ Future<Uint8List> buildSdkSummary({
|
||||
sourceFactory: SourceFactory([
|
||||
DartUriResolver(sdk),
|
||||
]),
|
||||
analysisOptions: AnalysisOptionsImpl(),
|
||||
analysisOptionsMap: optionsMap,
|
||||
packages: Packages({}),
|
||||
);
|
||||
scheduler.start();
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_options_map.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
|
||||
@@ -53,13 +54,15 @@ AnalysisDriverForPackageBuild createAnalysisDriver({
|
||||
|
||||
var logger = PerformanceLog(null);
|
||||
var scheduler = AnalysisDriverScheduler(logger);
|
||||
var sharedOptions = analysisOptions as AnalysisOptionsImpl;
|
||||
var optionsMap = AnalysisOptionsMap.forSharedOptions(sharedOptions);
|
||||
var driver = AnalysisDriver(
|
||||
scheduler: scheduler,
|
||||
logger: logger,
|
||||
resourceProvider: resourceProvider,
|
||||
byteStore: byteStore ?? MemoryByteStore(),
|
||||
sourceFactory: sourceFactory,
|
||||
analysisOptions: analysisOptions as AnalysisOptionsImpl,
|
||||
analysisOptionsMap: optionsMap,
|
||||
externalSummaries: dataStore,
|
||||
packages: packages,
|
||||
);
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
// 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 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_builder2.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_locator2.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
|
||||
import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
|
||||
import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
|
||||
import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
import 'package:analyzer/src/summary2/kernel_compilation_service.dart';
|
||||
import 'package:analyzer/src/summary2/macro.dart';
|
||||
import 'package:analyzer/src/util/sdk.dart';
|
||||
|
||||
/// An implementation of [AnalysisContextCollection].
|
||||
class AnalysisContextCollectionImpl2 implements AnalysisContextCollection {
|
||||
/// The resource provider used to access the file system.
|
||||
final ResourceProvider resourceProvider;
|
||||
|
||||
/// The support for executing macros.
|
||||
late final MacroSupport macroSupport;
|
||||
|
||||
/// The shared container into which drivers record files ownership.
|
||||
final OwnedFiles ownedFiles = OwnedFiles();
|
||||
|
||||
/// The list of analysis contexts.
|
||||
@override
|
||||
final List<DriverBasedAnalysisContext> contexts = [];
|
||||
|
||||
/// Initialize a newly created analysis context manager.
|
||||
AnalysisContextCollectionImpl2({
|
||||
ByteStore? byteStore,
|
||||
Map<String, String>? declaredVariables,
|
||||
bool drainStreams = true,
|
||||
bool enableIndex = false,
|
||||
required List<String> includedPaths,
|
||||
List<String>? excludedPaths,
|
||||
List<String>? librarySummaryPaths,
|
||||
String? optionsFile,
|
||||
String? packagesFile,
|
||||
PerformanceLog? performanceLog,
|
||||
ResourceProvider? resourceProvider,
|
||||
bool retainDataForTesting = false,
|
||||
String? sdkPath,
|
||||
String? sdkSummaryPath,
|
||||
AnalysisDriverScheduler? scheduler,
|
||||
FileContentCache? fileContentCache,
|
||||
UnlinkedUnitStore? unlinkedUnitStore,
|
||||
InfoDeclarationStore? infoDeclarationStore,
|
||||
@Deprecated('Use updateAnalysisOptions2, which must be a function that '
|
||||
'accepts a second parameter')
|
||||
void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
|
||||
void Function({
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk,
|
||||
})? updateAnalysisOptions2,
|
||||
MacroSupport? macroSupport,
|
||||
}) : resourceProvider =
|
||||
resourceProvider ?? PhysicalResourceProvider.INSTANCE {
|
||||
sdkPath ??= getSdkPath();
|
||||
|
||||
_throwIfAnyNotAbsoluteNormalizedPath(includedPaths);
|
||||
_throwIfNotAbsoluteNormalizedPath(sdkPath);
|
||||
|
||||
if (updateAnalysisOptions != null && updateAnalysisOptions2 != null) {
|
||||
throw ArgumentError(
|
||||
'Either updateAnalysisOptions or updateAnalysisOptions2 must be '
|
||||
'given, but not both.');
|
||||
}
|
||||
|
||||
this.macroSupport = macroSupport ??= KernelMacroSupport();
|
||||
|
||||
var contextLocator = ContextLocatorImpl2(
|
||||
resourceProvider: this.resourceProvider,
|
||||
);
|
||||
var roots = contextLocator.locateRoots(
|
||||
includedPaths: includedPaths,
|
||||
excludedPaths: excludedPaths,
|
||||
optionsFile: optionsFile,
|
||||
packagesFile: packagesFile,
|
||||
);
|
||||
for (var root in roots) {
|
||||
var contextBuilder = ContextBuilderImpl2(
|
||||
resourceProvider: this.resourceProvider,
|
||||
);
|
||||
var context = contextBuilder.createContext(
|
||||
byteStore: byteStore,
|
||||
contextRoot: root,
|
||||
declaredVariables: DeclaredVariables.fromMap(declaredVariables ?? {}),
|
||||
drainStreams: drainStreams,
|
||||
enableIndex: enableIndex,
|
||||
librarySummaryPaths: librarySummaryPaths,
|
||||
performanceLog: performanceLog,
|
||||
retainDataForTesting: retainDataForTesting,
|
||||
sdkPath: sdkPath,
|
||||
sdkSummaryPath: sdkSummaryPath,
|
||||
scheduler: scheduler,
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
updateAnalysisOptions: updateAnalysisOptions,
|
||||
updateAnalysisOptions2: updateAnalysisOptions2,
|
||||
fileContentCache: fileContentCache,
|
||||
unlinkedUnitStore: unlinkedUnitStore ?? UnlinkedUnitStoreImpl(),
|
||||
infoDeclarationStore: infoDeclarationStore,
|
||||
macroSupport: macroSupport,
|
||||
ownedFiles: ownedFiles,
|
||||
);
|
||||
contexts.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the read state of configuration files is consistent
|
||||
/// with their current state on the file system. We use this as a work
|
||||
/// around an issue with watching for file system changes.
|
||||
bool get areWorkspacesConsistent {
|
||||
for (var analysisContext in contexts) {
|
||||
var contextRoot = analysisContext.contextRoot;
|
||||
var workspace = contextRoot.workspace;
|
||||
if (!workspace.isConsistentWithFileSystem) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
DriverBasedAnalysisContext contextFor(String path) {
|
||||
_throwIfNotAbsoluteNormalizedPath(path);
|
||||
|
||||
for (var context in contexts) {
|
||||
if (context.contextRoot.isAnalyzed(path)) {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
throw StateError('Unable to find the context to $path');
|
||||
}
|
||||
|
||||
Future<void> dispose({
|
||||
bool forTesting = false,
|
||||
}) async {
|
||||
for (final analysisContext in contexts) {
|
||||
await analysisContext.driver.dispose2();
|
||||
}
|
||||
await macroSupport.dispose();
|
||||
// If there are other collections, they will have to start it again.
|
||||
if (!forTesting) {
|
||||
await KernelCompilationService.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// Check every element with [_throwIfNotAbsoluteNormalizedPath].
|
||||
void _throwIfAnyNotAbsoluteNormalizedPath(List<String> paths) {
|
||||
for (var path in paths) {
|
||||
_throwIfNotAbsoluteNormalizedPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// The driver supports only absolute normalized paths, this method is used
|
||||
/// to validate any input paths to prevent errors later.
|
||||
void _throwIfNotAbsoluteNormalizedPath(String path) {
|
||||
var pathContext = resourceProvider.pathContext;
|
||||
if (!pathContext.isAbsolute(path) || pathContext.normalize(path) != path) {
|
||||
throw ArgumentError(
|
||||
'Only absolute normalized paths are supported: $path');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,29 +2,61 @@
|
||||
// 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 'package:analyzer/dart/analysis/analysis_options.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/clients/build_resolvers/build_resolvers.dart';
|
||||
|
||||
/// Instances of the class [AnalysisOptionsMap] map [File]s under analysis to their
|
||||
/// corresponding [AnalysisOptions].
|
||||
/// Instances of the class [AnalysisOptionsMap] map [File]s under analysis to
|
||||
/// their corresponding [AnalysisOptions].
|
||||
class AnalysisOptionsMap {
|
||||
// TODO(pq): final backing representation TBD.
|
||||
final List<({Folder folder, AnalysisOptions options})> _entries = [];
|
||||
final List<OptionsMapEntry> entries = [];
|
||||
|
||||
/// Create an empty [AnalysisOptionsMap] instance.
|
||||
AnalysisOptionsMap();
|
||||
|
||||
/// Map this [folder] to the given [options].
|
||||
void add(Folder folder, AnalysisOptions options) {
|
||||
_entries.add((folder: folder, options: options));
|
||||
entries.add(OptionsMapEntry(folder, options));
|
||||
// Sort entries by (reverse) containment (for now).
|
||||
_entries.sort((e1, e2) => e1.folder.contains(e2.folder.path) ? 1 : -1);
|
||||
entries.sort((e1, e2) => e1.folder.contains(e2.folder.path) ? 1 : -1);
|
||||
}
|
||||
|
||||
/// Get the [AnalysisOptions] instance for the given [file] (or `null` if none
|
||||
/// has been set).
|
||||
AnalysisOptions? getOptions(File file) {
|
||||
for (var entry in _entries) {
|
||||
for (var entry in entries) {
|
||||
if (entry.folder.contains(file.path)) return entry.options;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Create an [AnalysisOptionsMap] that holds one set of [sharedOptions] for all
|
||||
/// associated files.
|
||||
// TODO(pq): replace w/ a factory constructor when SharedOptionsOptionsMap is made private
|
||||
static SharedOptionsOptionsMap forSharedOptions(
|
||||
AnalysisOptionsImpl sharedOptions) =>
|
||||
SharedOptionsOptionsMap(sharedOptions);
|
||||
}
|
||||
|
||||
/// Instances of [OptionsMapEntry] associate [Folder]s with their
|
||||
/// corresponding [AnalysisOptions].
|
||||
class OptionsMapEntry {
|
||||
/// The folder containing an options file.
|
||||
final Folder folder;
|
||||
|
||||
/// The corresponding options object.
|
||||
final AnalysisOptions options;
|
||||
|
||||
/// Create a new entry for the give [folder] and corresponding [options];
|
||||
OptionsMapEntry(this.folder, this.options);
|
||||
}
|
||||
|
||||
// TODO(pq): make private when no longer referenced.
|
||||
class SharedOptionsOptionsMap extends AnalysisOptionsMap {
|
||||
/// The [entries] list is empty but that's OK. We'll always just return
|
||||
/// the shared options.
|
||||
final AnalysisOptionsImpl sharedOptions;
|
||||
SharedOptionsOptionsMap(this.sharedOptions);
|
||||
@override
|
||||
AnalysisOptions getOptions(File file) => sharedOptions;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
|
||||
import 'package:analyzer/src/analysis_options/apply_options.dart';
|
||||
import 'package:analyzer/src/context/builder.dart' show EmbedderYamlLocator;
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_options_map.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart'
|
||||
show ByteStore, MemoryByteStore;
|
||||
import 'package:analyzer/src/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart'
|
||||
show
|
||||
AnalysisDriver,
|
||||
@@ -128,17 +130,18 @@ class ContextBuilderImpl implements ContextBuilder {
|
||||
sdk: sdk,
|
||||
);
|
||||
}
|
||||
// TODO(pq): replace w/ a map created directly via `_createOptionsMap`
|
||||
var analysisOptionsMap = AnalysisOptionsMap.forSharedOptions(options);
|
||||
|
||||
final analysisContext =
|
||||
DriverBasedAnalysisContext(resourceProvider, contextRoot);
|
||||
|
||||
var driver = AnalysisDriver(
|
||||
scheduler: scheduler,
|
||||
logger: performanceLog,
|
||||
resourceProvider: resourceProvider,
|
||||
byteStore: byteStore,
|
||||
sourceFactory: sourceFactory,
|
||||
analysisOptions: options,
|
||||
analysisOptionsMap: analysisOptionsMap,
|
||||
packages: _createPackageMap(
|
||||
contextRoot: contextRoot,
|
||||
),
|
||||
@@ -165,6 +168,66 @@ class ContextBuilderImpl implements ContextBuilder {
|
||||
return analysisContext;
|
||||
}
|
||||
|
||||
/// Create an [AnalysisOptionsMap] for the given [contextRoot].
|
||||
// ignore: unused_element
|
||||
AnalysisOptionsMap _createOptionsMap(
|
||||
ContextRoot contextRoot,
|
||||
SourceFactory sourceFactory,
|
||||
@Deprecated("Use 'updateAnalysisOptions2' instead")
|
||||
void Function(AnalysisOptionsImpl p1)? updateAnalysisOptions,
|
||||
void Function(
|
||||
{required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk})?
|
||||
updateAnalysisOptions2,
|
||||
DartSdk sdk) {
|
||||
var map = AnalysisOptionsMap();
|
||||
var provider = AnalysisOptionsProvider(sourceFactory);
|
||||
var pubspecFile = _findPubspecFile(contextRoot);
|
||||
|
||||
void updateOptions(AnalysisOptionsImpl options) {
|
||||
if (pubspecFile != null) {
|
||||
var extractor = SdkConstraintExtractor(pubspecFile);
|
||||
var sdkVersionConstraint = extractor.constraint();
|
||||
if (sdkVersionConstraint != null) {
|
||||
// TODO(pq): remove
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
options.sdkVersionConstraint = sdkVersionConstraint;
|
||||
}
|
||||
}
|
||||
if (updateAnalysisOptions != null) {
|
||||
updateAnalysisOptions(options);
|
||||
} else if (updateAnalysisOptions2 != null) {
|
||||
updateAnalysisOptions2(
|
||||
analysisOptions: options,
|
||||
contextRoot: contextRoot,
|
||||
sdk: sdk,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var optionsMappings =
|
||||
(contextRoot as ContextRootImpl).optionsFileMap.entries;
|
||||
|
||||
// If there are no options files, we still want to propagate sdk constraints
|
||||
// and options updates to the context root.
|
||||
if (optionsMappings.isEmpty) {
|
||||
var options = AnalysisOptionsImpl();
|
||||
updateOptions(options);
|
||||
map.add(contextRoot.root, options);
|
||||
} else {
|
||||
for (var entry in optionsMappings) {
|
||||
var options = AnalysisOptionsImpl();
|
||||
var optionsYaml = provider.getOptionsFromFile(entry.value);
|
||||
options.applyOptions(optionsYaml);
|
||||
updateOptions(options);
|
||||
map.add(entry.key, options);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/// Return [Packages] to analyze the [contextRoot].
|
||||
///
|
||||
// TODO(scheglov): Get [Packages] from [Workspace]?
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
// 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 'package:analyzer/dart/analysis/context_builder.dart';
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
|
||||
import 'package:analyzer/src/analysis_options/apply_options.dart';
|
||||
import 'package:analyzer/src/context/builder.dart' show EmbedderYamlLocator;
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_options_map.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart'
|
||||
show ByteStore, MemoryByteStore;
|
||||
import 'package:analyzer/src/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart'
|
||||
show
|
||||
AnalysisDriver,
|
||||
AnalysisDriverScheduler,
|
||||
AnalysisDriverTestView,
|
||||
OwnedFiles;
|
||||
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
|
||||
import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
|
||||
import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/performance_logger.dart'
|
||||
show PerformanceLog;
|
||||
import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
|
||||
import 'package:analyzer/src/dart/sdk/sdk.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
|
||||
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/hint/sdk_constraint_extractor.dart';
|
||||
import 'package:analyzer/src/summary/package_bundle_reader.dart';
|
||||
import 'package:analyzer/src/summary/summary_sdk.dart';
|
||||
import 'package:analyzer/src/summary2/macro.dart';
|
||||
import 'package:analyzer/src/summary2/package_bundle_format.dart';
|
||||
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
||||
import 'package:analyzer/src/util/sdk.dart';
|
||||
import 'package:analyzer/src/workspace/workspace.dart';
|
||||
|
||||
/// An implementation of a context builder.
|
||||
class ContextBuilderImpl2 implements ContextBuilder {
|
||||
/// The resource provider used to access the file system.
|
||||
final ResourceProvider resourceProvider;
|
||||
|
||||
/// Initialize a newly created context builder. If a [resourceProvider] is
|
||||
/// given, then it will be used to access the file system, otherwise the
|
||||
/// default resource provider will be used.
|
||||
ContextBuilderImpl2({ResourceProvider? resourceProvider})
|
||||
: resourceProvider =
|
||||
resourceProvider ?? PhysicalResourceProvider.INSTANCE;
|
||||
|
||||
@override
|
||||
DriverBasedAnalysisContext createContext({
|
||||
ByteStore? byteStore,
|
||||
required ContextRoot contextRoot,
|
||||
DeclaredVariables? declaredVariables,
|
||||
bool drainStreams = true,
|
||||
bool enableIndex = false,
|
||||
List<String>? librarySummaryPaths,
|
||||
PerformanceLog? performanceLog,
|
||||
bool retainDataForTesting = false,
|
||||
AnalysisDriverScheduler? scheduler,
|
||||
String? sdkPath,
|
||||
String? sdkSummaryPath,
|
||||
@Deprecated('Use updateAnalysisOptions2')
|
||||
void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
|
||||
void Function({
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk,
|
||||
})? updateAnalysisOptions2,
|
||||
FileContentCache? fileContentCache,
|
||||
UnlinkedUnitStore? unlinkedUnitStore,
|
||||
InfoDeclarationStore? infoDeclarationStore,
|
||||
MacroSupport? macroSupport,
|
||||
OwnedFiles? ownedFiles,
|
||||
}) {
|
||||
// TODO(scheglov): Remove this, and make `sdkPath` required.
|
||||
sdkPath ??= getSdkPath();
|
||||
ArgumentError.checkNotNull(sdkPath, 'sdkPath');
|
||||
if (updateAnalysisOptions != null && updateAnalysisOptions2 != null) {
|
||||
throw ArgumentError(
|
||||
'Either updateAnalysisOptions or updateAnalysisOptions2 must be '
|
||||
'given, but not both.');
|
||||
}
|
||||
|
||||
byteStore ??= MemoryByteStore();
|
||||
performanceLog ??= PerformanceLog(null);
|
||||
|
||||
if (scheduler == null) {
|
||||
scheduler = AnalysisDriverScheduler(performanceLog);
|
||||
scheduler.start();
|
||||
}
|
||||
|
||||
SummaryDataStore? summaryData;
|
||||
if (librarySummaryPaths != null) {
|
||||
summaryData = SummaryDataStore();
|
||||
for (var summaryPath in librarySummaryPaths) {
|
||||
var bytes = resourceProvider.getFile(summaryPath).readAsBytesSync();
|
||||
var bundle = PackageBundleReader(bytes);
|
||||
summaryData.addBundle(summaryPath, bundle);
|
||||
}
|
||||
}
|
||||
|
||||
var workspace = contextRoot.workspace;
|
||||
var sdk = _createSdk(
|
||||
workspace: workspace,
|
||||
sdkPath: sdkPath,
|
||||
sdkSummaryPath: sdkSummaryPath,
|
||||
);
|
||||
|
||||
// TODO(scheglov): Ensure that "librarySummaryPaths" not null only
|
||||
// when "sdkSummaryPath" is not null.
|
||||
if (sdk is SummaryBasedDartSdk) {
|
||||
summaryData?.addBundle(null, sdk.bundle);
|
||||
}
|
||||
|
||||
var sourceFactory = workspace.createSourceFactory(sdk, summaryData);
|
||||
|
||||
// TODO(pq): remove
|
||||
var options = _getAnalysisOptions(contextRoot, sourceFactory);
|
||||
if (updateAnalysisOptions != null) {
|
||||
updateAnalysisOptions(options);
|
||||
} else if (updateAnalysisOptions2 != null) {
|
||||
updateAnalysisOptions2(
|
||||
analysisOptions: options,
|
||||
contextRoot: contextRoot,
|
||||
sdk: sdk,
|
||||
);
|
||||
}
|
||||
|
||||
final analysisContext =
|
||||
DriverBasedAnalysisContext(resourceProvider, contextRoot);
|
||||
|
||||
var analysisOptionsMap = _createOptionsMap(contextRoot, sourceFactory,
|
||||
updateAnalysisOptions, updateAnalysisOptions2, sdk);
|
||||
|
||||
var driver = AnalysisDriver(
|
||||
scheduler: scheduler,
|
||||
logger: performanceLog,
|
||||
resourceProvider: resourceProvider,
|
||||
byteStore: byteStore,
|
||||
sourceFactory: sourceFactory,
|
||||
analysisOptions: options,
|
||||
analysisOptionsMap: analysisOptionsMap,
|
||||
packages: _createPackageMap(
|
||||
contextRoot: contextRoot,
|
||||
),
|
||||
analysisContext: analysisContext,
|
||||
enableIndex: enableIndex,
|
||||
externalSummaries: summaryData,
|
||||
retainDataForTesting: retainDataForTesting,
|
||||
fileContentCache: fileContentCache,
|
||||
unlinkedUnitStore: unlinkedUnitStore,
|
||||
infoDeclarationStore: infoDeclarationStore,
|
||||
macroSupport: macroSupport,
|
||||
declaredVariables: declaredVariables,
|
||||
testView: retainDataForTesting ? AnalysisDriverTestView() : null,
|
||||
ownedFiles: ownedFiles,
|
||||
);
|
||||
|
||||
// AnalysisDriver reports results into streams.
|
||||
// We need to drain these streams to avoid memory leak.
|
||||
if (drainStreams) {
|
||||
driver.results.drain<void>();
|
||||
driver.exceptions.drain<void>();
|
||||
}
|
||||
|
||||
return analysisContext;
|
||||
}
|
||||
|
||||
AnalysisOptionsMap _createOptionsMap(
|
||||
ContextRoot contextRoot,
|
||||
SourceFactory sourceFactory,
|
||||
void Function(AnalysisOptionsImpl p1)? updateAnalysisOptions,
|
||||
void Function(
|
||||
{required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk})?
|
||||
updateAnalysisOptions2,
|
||||
DartSdk sdk) {
|
||||
var map = AnalysisOptionsMap();
|
||||
var provider = AnalysisOptionsProvider(sourceFactory);
|
||||
var pubspecFile = _findPubspecFile(contextRoot);
|
||||
|
||||
void updateOptions(AnalysisOptionsImpl options) {
|
||||
if (pubspecFile != null) {
|
||||
var extractor = SdkConstraintExtractor(pubspecFile);
|
||||
var sdkVersionConstraint = extractor.constraint();
|
||||
if (sdkVersionConstraint != null) {
|
||||
// TODO(pq): remove
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
options.sdkVersionConstraint = sdkVersionConstraint;
|
||||
}
|
||||
}
|
||||
if (updateAnalysisOptions != null) {
|
||||
updateAnalysisOptions(options);
|
||||
} else if (updateAnalysisOptions2 != null) {
|
||||
updateAnalysisOptions2(
|
||||
analysisOptions: options,
|
||||
contextRoot: contextRoot,
|
||||
sdk: sdk,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var optionsMappings =
|
||||
(contextRoot as ContextRootImpl).optionsFileMap.entries;
|
||||
|
||||
// If there are no options files, we still want to propagate sdk constraints
|
||||
// and options updates to the context root.
|
||||
if (optionsMappings.isEmpty) {
|
||||
var options = AnalysisOptionsImpl();
|
||||
updateOptions(options);
|
||||
map.add(contextRoot.root, options);
|
||||
} else {
|
||||
for (var entry in optionsMappings) {
|
||||
var options = AnalysisOptionsImpl();
|
||||
var optionsYaml = provider.getOptionsFromFile(entry.value);
|
||||
options.applyOptions(optionsYaml);
|
||||
updateOptions(options);
|
||||
map.add(entry.key, options);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/// Return [Packages] to analyze the [contextRoot].
|
||||
///
|
||||
// TODO(scheglov): Get [Packages] from [Workspace]?
|
||||
Packages _createPackageMap({
|
||||
required ContextRoot contextRoot,
|
||||
}) {
|
||||
var packagesFile = contextRoot.packagesFile;
|
||||
if (packagesFile != null) {
|
||||
return parsePackageConfigJsonFile(resourceProvider, packagesFile);
|
||||
} else {
|
||||
return Packages.empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the SDK that should be used to analyze code.
|
||||
DartSdk _createSdk({
|
||||
required Workspace workspace,
|
||||
String? sdkPath,
|
||||
String? sdkSummaryPath,
|
||||
}) {
|
||||
if (sdkSummaryPath != null) {
|
||||
var file = resourceProvider.getFile(sdkSummaryPath);
|
||||
var bytes = file.readAsBytesSync();
|
||||
return SummaryBasedDartSdk.forBundle(
|
||||
PackageBundleReader(bytes),
|
||||
);
|
||||
}
|
||||
|
||||
var folderSdk = FolderBasedDartSdk(
|
||||
resourceProvider,
|
||||
resourceProvider.getFolder(sdkPath!),
|
||||
);
|
||||
|
||||
{
|
||||
// TODO(scheglov): We already had partial SourceFactory in ContextLocatorImpl.
|
||||
var partialSourceFactory = workspace.createSourceFactory(null, null);
|
||||
var embedderYamlSource = partialSourceFactory.forUri(
|
||||
'package:sky_engine/_embedder.yaml',
|
||||
);
|
||||
if (embedderYamlSource != null) {
|
||||
var embedderYamlPath = embedderYamlSource.fullName;
|
||||
var libFolder = resourceProvider.getFile(embedderYamlPath).parent;
|
||||
var locator = EmbedderYamlLocator.forLibFolder(libFolder);
|
||||
var embedderMap = locator.embedderYamls;
|
||||
if (embedderMap.isNotEmpty) {
|
||||
return EmbedderSdk(
|
||||
resourceProvider,
|
||||
embedderMap,
|
||||
languageVersion: folderSdk.languageVersion,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return folderSdk;
|
||||
}
|
||||
|
||||
/// Return the `pubspec.yaml` file that should be used when analyzing code in
|
||||
/// the [contextRoot], possibly `null`.
|
||||
///
|
||||
// TODO(scheglov): Get it from [Workspace]?
|
||||
File? _findPubspecFile(ContextRoot contextRoot) {
|
||||
for (var current in contextRoot.root.withAncestors) {
|
||||
var file = current.getChildAssumingFile(file_paths.pubspecYaml);
|
||||
if (file.exists) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Return the analysis options that should be used to analyze code in the
|
||||
/// [contextRoot].
|
||||
///
|
||||
// TODO(scheglov): We have already loaded it once in [ContextLocatorImpl].
|
||||
AnalysisOptionsImpl _getAnalysisOptions(
|
||||
ContextRoot contextRoot,
|
||||
SourceFactory sourceFactory,
|
||||
) {
|
||||
var options = AnalysisOptionsImpl();
|
||||
|
||||
var optionsFile = contextRoot.optionsFile;
|
||||
if (optionsFile != null) {
|
||||
try {
|
||||
var provider = AnalysisOptionsProvider(sourceFactory);
|
||||
var optionsMap = provider.getOptionsFromFile(optionsFile);
|
||||
options.applyOptions(optionsMap);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
var pubspecFile = _findPubspecFile(contextRoot);
|
||||
if (pubspecFile != null) {
|
||||
var extractor = SdkConstraintExtractor(pubspecFile);
|
||||
var sdkVersionConstraint = extractor.constraint();
|
||||
if (sdkVersionConstraint != null) {
|
||||
// TODO(pq): remove
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
options.sdkVersionConstraint = sdkVersionConstraint;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import 'package:analyzer/src/diagnostic/diagnostic.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/exception/exception.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart'
|
||||
show AnalysisContext, AnalysisEngine, AnalysisOptions, AnalysisOptionsImpl;
|
||||
show AnalysisContext, AnalysisEngine, AnalysisOptions;
|
||||
import 'package:analyzer/src/generated/source.dart' show SourceFactory;
|
||||
import 'package:analyzer/src/lint/registry.dart' as linter;
|
||||
import 'package:analyzer/src/summary/api_signature.dart';
|
||||
@@ -130,9 +130,6 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
|
||||
late final StoredFileContentStrategy _fileContentStrategy;
|
||||
|
||||
/// The analysis options to analyze with.
|
||||
final AnalysisOptionsImpl _analysisOptions;
|
||||
|
||||
/// The [Packages] object with packages and their language versions.
|
||||
final Packages _packages;
|
||||
|
||||
@@ -241,6 +238,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
|
||||
final AnalysisDriverTestView? testView;
|
||||
|
||||
// TODO(pq): replace with an analysis options map.
|
||||
late FeatureSetProvider featureSetProvider;
|
||||
|
||||
late FileSystemState _fsState;
|
||||
@@ -269,9 +267,8 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
bool _disposed = false;
|
||||
|
||||
/// A map that associates files to corresponding analysis options.
|
||||
// TODO(pq): his will replace the single [_analysisOptions] instance.
|
||||
// ignore: unused_field
|
||||
final AnalysisOptionsMap? _analysisOptionsMap;
|
||||
// TODO(pq): retype to OptionsOptionsMap
|
||||
final SharedOptionsOptionsMap analysisOptionsMap;
|
||||
|
||||
/// Create a new instance of [AnalysisDriver].
|
||||
///
|
||||
@@ -283,13 +280,11 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
required ResourceProvider resourceProvider,
|
||||
required ByteStore byteStore,
|
||||
required SourceFactory sourceFactory,
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required Packages packages,
|
||||
required this.analysisOptionsMap,
|
||||
this.macroSupport,
|
||||
this.ownedFiles,
|
||||
this.analysisContext,
|
||||
// TODO(pq): to replace analysis options instance
|
||||
AnalysisOptionsMap? analysisOptionsMap,
|
||||
FileContentCache? fileContentCache,
|
||||
UnlinkedUnitStore? unlinkedUnitStore,
|
||||
InfoDeclarationStore? infoDeclarationStore,
|
||||
@@ -306,8 +301,6 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
_unlinkedUnitStore = unlinkedUnitStore ?? UnlinkedUnitStoreImpl(),
|
||||
_infoDeclarationStore =
|
||||
infoDeclarationStore ?? NoOpInfoDeclarationStore(),
|
||||
_analysisOptions = analysisOptions,
|
||||
_analysisOptionsMap = analysisOptionsMap,
|
||||
_logger = logger,
|
||||
_packages = packages,
|
||||
_sourceFactory = sourceFactory,
|
||||
@@ -330,7 +323,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
|
||||
/// Return the analysis options used to control analysis.
|
||||
@Deprecated("Use 'getAnalysisOptionsForFile(file)' instead")
|
||||
AnalysisOptions get analysisOptions => _analysisOptions;
|
||||
AnalysisOptions get analysisOptions => analysisOptionsMap.sharedOptions;
|
||||
|
||||
/// Return the current analysis session.
|
||||
AnalysisSessionImpl get currentSession {
|
||||
@@ -340,8 +333,8 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
/// Return a list of the names of all the plugins enabled in analysis options
|
||||
/// in this driver.
|
||||
List<String> get enabledPluginNames =>
|
||||
// TODO(pq): get this value from a union of all the plugins enabled in the `_analysisOptionsMap`
|
||||
_analysisOptions.enabledPluginNames;
|
||||
// TODO(pq): get this value from a union of all the plugins enabled in the `analysisOptionsMap`
|
||||
analysisOptionsMap.sharedOptions.enabledPluginNames;
|
||||
|
||||
/// Return the stream that produces [ExceptionResult]s.
|
||||
Stream<ExceptionResult> get exceptions => _exceptionController.stream;
|
||||
@@ -372,7 +365,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
logger: _logger,
|
||||
byteStore: _byteStore,
|
||||
infoDeclarationStore: _infoDeclarationStore,
|
||||
analysisOptions: _analysisOptions,
|
||||
analysisOptions: analysisOptionsMap.sharedOptions,
|
||||
declaredVariables: declaredVariables,
|
||||
sourceFactory: _sourceFactory,
|
||||
macroSupport: macroSupport,
|
||||
@@ -677,8 +670,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
}
|
||||
|
||||
AnalysisOptions getAnalysisOptionsForFile(File file) =>
|
||||
// TODO(pq): replace w/ _analysisOptionsMap?.getOptions(file)
|
||||
_analysisOptions;
|
||||
analysisOptionsMap.getOptions(file);
|
||||
|
||||
/// Return the cached [ResolvedUnitResult] for the Dart file with the given
|
||||
/// [path]. If there is no cached result, return `null`. Usually only results
|
||||
@@ -1576,14 +1568,14 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
void _createFileTracker() {
|
||||
_fillSalt();
|
||||
|
||||
var sharedOptions = analysisOptionsMap.sharedOptions;
|
||||
featureSetProvider = FeatureSetProvider.build(
|
||||
sourceFactory: sourceFactory,
|
||||
resourceProvider: _resourceProvider,
|
||||
packages: _packages,
|
||||
packageDefaultFeatureSet: _analysisOptions.contextFeatures,
|
||||
nonPackageDefaultLanguageVersion:
|
||||
_analysisOptions.nonPackageLanguageVersion,
|
||||
nonPackageDefaultFeatureSet: _analysisOptions.nonPackageFeatureSet,
|
||||
packageDefaultFeatureSet: sharedOptions.contextFeatures,
|
||||
nonPackageDefaultLanguageVersion: sharedOptions.nonPackageLanguageVersion,
|
||||
nonPackageDefaultFeatureSet: sharedOptions.nonPackageFeatureSet,
|
||||
);
|
||||
|
||||
_fsState = FileSystemState(
|
||||
@@ -1675,7 +1667,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
void _fillSaltForElements() {
|
||||
var buffer = ApiSignature();
|
||||
buffer.addInt(DATA_VERSION);
|
||||
buffer.addUint32List(_analysisOptions.signatureForElements);
|
||||
buffer.addUint32List(analysisOptionsMap.sharedOptions.signatureForElements);
|
||||
_addDeclaredVariablesToSignature(buffer);
|
||||
_saltForElements = buffer.toUint32List();
|
||||
}
|
||||
@@ -1685,7 +1677,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
buffer.addInt(DATA_VERSION);
|
||||
buffer.addBool(enableIndex);
|
||||
buffer.addBool(enableDebugResolutionMarkers);
|
||||
buffer.addUint32List(_analysisOptions.signature);
|
||||
buffer.addUint32List(analysisOptionsMap.sharedOptions.signature);
|
||||
_addDeclaredVariablesToSignature(buffer);
|
||||
|
||||
var workspace = analysisContext?.contextRoot.workspace;
|
||||
@@ -1698,7 +1690,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
var buffer = ApiSignature();
|
||||
buffer.addInt(DATA_VERSION);
|
||||
buffer.addBool(enableIndex);
|
||||
buffer.addUint32List(_analysisOptions.unlinkedSignature);
|
||||
buffer.addUint32List(analysisOptionsMap.sharedOptions.unlinkedSignature);
|
||||
_saltForUnlinked = buffer.toUint32List();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
// 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 'package:analyzer/dart/analysis/analysis_options.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_context_collection2.dart';
|
||||
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:linter/src/rules.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(AnalysisContextCollection2Test);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class AnalysisContextCollection2Test with ResourceProviderMixin {
|
||||
Folder get sdkRoot => newFolder('/sdk');
|
||||
|
||||
void setUp() {
|
||||
createMockSdk(
|
||||
resourceProvider: resourceProvider,
|
||||
root: sdkRoot,
|
||||
);
|
||||
registerLintRules();
|
||||
}
|
||||
|
||||
test_contextFor_noContext() {
|
||||
var collection = _newCollection(includedPaths: [convertPath('/root')]);
|
||||
expect(
|
||||
() => collection.contextFor(convertPath('/other/test.dart')),
|
||||
throwsStateError,
|
||||
);
|
||||
}
|
||||
|
||||
test_contextFor_notAbsolute() {
|
||||
var collection = _newCollection(includedPaths: [convertPath('/root')]);
|
||||
expect(
|
||||
() => collection.contextFor(convertPath('test.dart')),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
test_contextFor_notNormalized() {
|
||||
var collection = _newCollection(includedPaths: [convertPath('/root')]);
|
||||
expect(
|
||||
() => collection.contextFor(convertPath('/test/lib/../lib/test.dart')),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
test_new_analysisOptions_includes() {
|
||||
var rootFolder = newFolder('/home/test');
|
||||
var fooFolder = newFolder('/home/packages/foo');
|
||||
newFile('${fooFolder.path}/lib/included.yaml', r'''
|
||||
linter:
|
||||
rules:
|
||||
- empty_statements
|
||||
''');
|
||||
|
||||
var packageConfigFileBuilder = PackageConfigFileBuilder()
|
||||
..add(name: 'foo', rootPath: fooFolder.path);
|
||||
newPackageConfigJsonFile(
|
||||
rootFolder.path,
|
||||
packageConfigFileBuilder.toContent(toUriStr: toUriStr),
|
||||
);
|
||||
|
||||
var optionsFile = newAnalysisOptionsYamlFile(rootFolder.path, r'''
|
||||
include: package:foo/included.yaml
|
||||
|
||||
linter:
|
||||
rules:
|
||||
- unnecessary_parenthesis
|
||||
''');
|
||||
|
||||
var collection = _newCollection(includedPaths: [rootFolder.path]);
|
||||
var analysisContext = collection.contextFor(rootFolder.path);
|
||||
var analysisOptions =
|
||||
analysisContext.getAnalysisOptionsForFile(optionsFile);
|
||||
|
||||
expect(
|
||||
analysisOptions.lintRules.map((e) => e.name),
|
||||
unorderedEquals(['empty_statements', 'unnecessary_parenthesis']),
|
||||
);
|
||||
}
|
||||
|
||||
test_new_analysisOptions_lintRules() {
|
||||
var rootFolder = newFolder('/home/test');
|
||||
var optionsFile = newAnalysisOptionsYamlFile(rootFolder.path, r'''
|
||||
linter:
|
||||
rules:
|
||||
- non_existent_lint_rule
|
||||
- unnecessary_parenthesis
|
||||
''');
|
||||
|
||||
var collection = _newCollection(includedPaths: [rootFolder.path]);
|
||||
var analysisContext = collection.contextFor(rootFolder.path);
|
||||
var analysisOptions =
|
||||
analysisContext.getAnalysisOptionsForFile(optionsFile);
|
||||
|
||||
expect(
|
||||
analysisOptions.lintRules.map((e) => e.name),
|
||||
unorderedEquals(['unnecessary_parenthesis']),
|
||||
);
|
||||
}
|
||||
|
||||
test_new_includedPaths_notAbsolute() {
|
||||
expect(
|
||||
() => AnalysisContextCollectionImpl(includedPaths: ['root']),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
test_new_includedPaths_notNormalized() {
|
||||
expect(
|
||||
() => AnalysisContextCollectionImpl(
|
||||
includedPaths: [convertPath('/root/lib/../lib')]),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
@FailingTest(reason: 'Pending analysis options map implementation')
|
||||
test_new_outer_inner() {
|
||||
// OUTER
|
||||
var outerFolder = newFolder('/test/outer');
|
||||
newAnalysisOptionsYamlFile('/test/outer', r'''
|
||||
linter:
|
||||
rules:
|
||||
- always_specify_types
|
||||
''');
|
||||
var outerFile = newFile('/test/outer/lib/outer.dart', '');
|
||||
|
||||
// INNER
|
||||
newFolder('/test/outer/inner');
|
||||
newAnalysisOptionsYamlFile('/test/outer/inner', r'''
|
||||
linter:
|
||||
rules:
|
||||
- camel_case_types
|
||||
''');
|
||||
var innerFile = newFile('/test/outer/inner/inner.dart', '');
|
||||
|
||||
var collection = _newCollection(includedPaths: [outerFolder.path]);
|
||||
expect(collection.contexts, hasLength(1));
|
||||
var context = collection.contexts.first;
|
||||
|
||||
// Files with different analysis options, share a single context.
|
||||
expect(collection.contextFor(convertPath('/test/outer/lib/outer.dart')),
|
||||
same(context));
|
||||
expect(collection.contextFor(convertPath('/test/outer/inner/inner.dart')),
|
||||
same(context));
|
||||
|
||||
// But have their own analysis options.
|
||||
var outerOptions = context.getAnalysisOptionsForFile(outerFile);
|
||||
expectContainsExactly(
|
||||
outerOptions,
|
||||
lints: ['always_specify_types'],
|
||||
);
|
||||
|
||||
var innerOptions = context.getAnalysisOptionsForFile(innerFile);
|
||||
expectContainsExactly(
|
||||
innerOptions,
|
||||
lints: ['camel_case_types'],
|
||||
);
|
||||
|
||||
// Files do not have to exist, during creation, or at all.
|
||||
expect(collection.contextFor(convertPath('/test/outer/lib/outer2.dart')),
|
||||
same(context));
|
||||
expect(collection.contextFor(convertPath('/test/outer/inner/inner2.dart')),
|
||||
same(context));
|
||||
}
|
||||
|
||||
test_new_sdkPath_notAbsolute() {
|
||||
expect(
|
||||
() => AnalysisContextCollectionImpl(
|
||||
includedPaths: ['/root'], sdkPath: 'sdk'),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
test_new_sdkPath_notNormalized() {
|
||||
expect(
|
||||
() => AnalysisContextCollectionImpl(
|
||||
includedPaths: [convertPath('/root')], sdkPath: '/home/sdk/../sdk'),
|
||||
throwsArgumentError,
|
||||
);
|
||||
}
|
||||
|
||||
AnalysisContextCollectionImpl2 _newCollection(
|
||||
{required List<String> includedPaths}) {
|
||||
return AnalysisContextCollectionImpl2(
|
||||
resourceProvider: resourceProvider,
|
||||
includedPaths: includedPaths,
|
||||
sdkPath: sdkRoot.path,
|
||||
);
|
||||
}
|
||||
|
||||
static void expectContainsExactly(AnalysisOptions? options,
|
||||
{List<String>? lints}) {
|
||||
expect(options, isNotNull);
|
||||
if (lints != null) {
|
||||
var rules = options!.lintRules.map((e) => e.name);
|
||||
expect(rules, unorderedEquals(lints));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/source/source.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_options_map.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
|
||||
@@ -77,7 +78,8 @@ class BaseAnalysisDriverTest with ResourceProviderMixin {
|
||||
PackageMapUriResolver(resourceProvider, packageMap),
|
||||
ResourceUriResolver(resourceProvider)
|
||||
]),
|
||||
analysisOptions: createAnalysisOptions(),
|
||||
analysisOptionsMap:
|
||||
AnalysisOptionsMap.forSharedOptions(createAnalysisOptions()),
|
||||
packages: Packages({
|
||||
'test': Package(
|
||||
name: 'test',
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
// 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 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/context/source.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_builder2.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_locator2.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/source/package_map_resolver.dart';
|
||||
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
||||
import 'package:analyzer/src/workspace/basic.dart';
|
||||
import 'package:analyzer/src/workspace/blaze.dart';
|
||||
import 'package:analyzer/src/workspace/pub.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(ContextBuilderImplTest2);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class ContextBuilderImplTest2 with ResourceProviderMixin {
|
||||
late final ContextBuilderImpl2 contextBuilder;
|
||||
late final ContextRoot contextRoot;
|
||||
|
||||
Folder get sdkRoot => newFolder('/sdk');
|
||||
|
||||
void assertEquals(DeclaredVariables actual, DeclaredVariables expected) {
|
||||
Iterable<String> actualNames = actual.variableNames;
|
||||
Iterable<String> expectedNames = expected.variableNames;
|
||||
expect(actualNames, expectedNames);
|
||||
for (String name in expectedNames) {
|
||||
expect(actual.get(name), expected.get(name));
|
||||
}
|
||||
}
|
||||
|
||||
void setUp() {
|
||||
createMockSdk(
|
||||
resourceProvider: resourceProvider,
|
||||
root: sdkRoot,
|
||||
);
|
||||
|
||||
var folder = newFolder('/home/test');
|
||||
contextBuilder = ContextBuilderImpl2(resourceProvider: resourceProvider);
|
||||
var workspace =
|
||||
BasicWorkspace.find(resourceProvider, Packages.empty, folder.path);
|
||||
contextRoot = ContextRootImpl(resourceProvider, folder, workspace);
|
||||
}
|
||||
|
||||
void test_analysisOptions_invalid() {
|
||||
var projectPath = convertPath('/home/test');
|
||||
var optionsFile = newAnalysisOptionsYamlFile(projectPath, ';');
|
||||
|
||||
var analysisContext = _createSingleAnalysisContext(projectPath);
|
||||
var analysisOptions =
|
||||
analysisContext.getAnalysisOptionsImplForFile(optionsFile);
|
||||
_expectEqualOptions(analysisOptions, AnalysisOptionsImpl());
|
||||
}
|
||||
|
||||
void test_analysisOptions_languageOptions() {
|
||||
var projectPath = convertPath('/home/test');
|
||||
var optionsFile = newAnalysisOptionsYamlFile(
|
||||
projectPath,
|
||||
AnalysisOptionsFileConfig(
|
||||
strictRawTypes: true,
|
||||
).toContent(),
|
||||
);
|
||||
|
||||
var analysisContext = _createSingleAnalysisContext(projectPath);
|
||||
var analysisOptions =
|
||||
analysisContext.getAnalysisOptionsImplForFile(optionsFile);
|
||||
_expectEqualOptions(
|
||||
analysisOptions,
|
||||
AnalysisOptionsImpl()..strictRawTypes = true,
|
||||
);
|
||||
}
|
||||
|
||||
test_createContext_declaredVariables() {
|
||||
DeclaredVariables declaredVariables =
|
||||
DeclaredVariables.fromMap({'foo': 'true'});
|
||||
var context = contextBuilder.createContext(
|
||||
contextRoot: contextRoot,
|
||||
declaredVariables: declaredVariables,
|
||||
sdkPath: sdkRoot.path,
|
||||
);
|
||||
expect(context.contextRoot, contextRoot);
|
||||
assertEquals(context.driver.declaredVariables, declaredVariables);
|
||||
}
|
||||
|
||||
test_createContext_declaredVariables_sdkPath() {
|
||||
DeclaredVariables declaredVariables =
|
||||
DeclaredVariables.fromMap({'bar': 'true'});
|
||||
var context = contextBuilder.createContext(
|
||||
contextRoot: contextRoot,
|
||||
declaredVariables: declaredVariables,
|
||||
sdkPath: sdkRoot.path,
|
||||
);
|
||||
expect(context.allAnalysisOptions, hasLength(1));
|
||||
expect(context.contextRoot, contextRoot);
|
||||
assertEquals(context.driver.declaredVariables, declaredVariables);
|
||||
expect(
|
||||
context.driver.sourceFactory.dartSdk!.mapDartUri('dart:core')!.fullName,
|
||||
sdkRoot.getChildAssumingFile('lib/core/core.dart').path,
|
||||
);
|
||||
}
|
||||
|
||||
test_createContext_defaults() {
|
||||
var context = contextBuilder.createContext(
|
||||
contextRoot: contextRoot,
|
||||
sdkPath: sdkRoot.path,
|
||||
);
|
||||
expect(context.allAnalysisOptions, hasLength(1));
|
||||
expect(context.contextRoot, contextRoot);
|
||||
}
|
||||
|
||||
test_createContext_sdkPath() {
|
||||
var context = contextBuilder.createContext(
|
||||
contextRoot: contextRoot,
|
||||
sdkPath: sdkRoot.path,
|
||||
);
|
||||
expect(context.allAnalysisOptions, hasLength(1));
|
||||
expect(context.contextRoot, contextRoot);
|
||||
expect(
|
||||
context.driver.sourceFactory.dartSdk!.mapDartUri('dart:core')!.fullName,
|
||||
sdkRoot.getChildAssumingFile('lib/core/core.dart').path,
|
||||
);
|
||||
}
|
||||
|
||||
test_createContext_sdkRoot() {
|
||||
var context = contextBuilder.createContext(
|
||||
contextRoot: contextRoot, sdkPath: sdkRoot.path);
|
||||
expect(context.allAnalysisOptions, hasLength(1));
|
||||
expect(context.contextRoot, contextRoot);
|
||||
expect(context.sdkRoot, sdkRoot);
|
||||
}
|
||||
|
||||
void test_sourceFactory_blazeWorkspace() {
|
||||
var projectPath = convertPath('/workspace/my/module');
|
||||
newFile('/workspace/${file_paths.blazeWorkspaceMarker}', '');
|
||||
newFolder('/workspace/blaze-bin');
|
||||
newFolder('/workspace/blaze-genfiles');
|
||||
|
||||
var analysisContext = _createSingleAnalysisContext(projectPath);
|
||||
expect(analysisContext.contextRoot.workspace, isA<BlazeWorkspace>());
|
||||
|
||||
expect(
|
||||
analysisContext.uriResolvers,
|
||||
unorderedEquals([
|
||||
isA<DartUriResolver>(),
|
||||
isA<BlazePackageUriResolver>(),
|
||||
isA<BlazeFileUriResolver>(),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_sourceFactory_pubWorkspace() {
|
||||
var projectPath = convertPath('/home/my');
|
||||
newFile('/home/my/pubspec.yaml', '');
|
||||
|
||||
var analysisContext = _createSingleAnalysisContext(projectPath);
|
||||
expect(analysisContext.contextRoot.workspace, isA<PubWorkspace>());
|
||||
|
||||
expect(
|
||||
analysisContext.uriResolvers,
|
||||
unorderedEquals([
|
||||
isA<DartUriResolver>(),
|
||||
isA<PackageMapUriResolver>(),
|
||||
isA<ResourceUriResolver>(),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
/// Return a single expected analysis context at the [path].
|
||||
DriverBasedAnalysisContext _createSingleAnalysisContext(String path) {
|
||||
var roots = ContextLocatorImpl2(
|
||||
resourceProvider: resourceProvider,
|
||||
).locateRoots(includedPaths: [path]);
|
||||
|
||||
return ContextBuilderImpl2(
|
||||
resourceProvider: resourceProvider,
|
||||
).createContext(
|
||||
contextRoot: roots.single,
|
||||
sdkPath: sdkRoot.path,
|
||||
);
|
||||
}
|
||||
|
||||
static void _expectEqualOptions(
|
||||
AnalysisOptionsImpl actual,
|
||||
AnalysisOptionsImpl expected,
|
||||
) {
|
||||
// TODO(brianwilkerson): Consider moving this to AnalysisOptionsImpl.==.
|
||||
expect(actual.enableTiming, expected.enableTiming);
|
||||
expect(actual.lint, expected.lint);
|
||||
expect(actual.warning, expected.warning);
|
||||
expect(
|
||||
actual.lintRules.map((l) => l.name),
|
||||
unorderedEquals(expected.lintRules.map((l) => l.name)),
|
||||
);
|
||||
expect(
|
||||
actual.propagateLinterExceptions, expected.propagateLinterExceptions);
|
||||
expect(actual.strictInference, expected.strictInference);
|
||||
expect(actual.strictRawTypes, expected.strictRawTypes);
|
||||
}
|
||||
}
|
||||
|
||||
extension on DriverBasedAnalysisContext {
|
||||
List<UriResolver> get uriResolvers {
|
||||
return (driver.sourceFactory as SourceFactoryImpl).resolvers;
|
||||
}
|
||||
|
||||
AnalysisOptionsImpl getAnalysisOptionsImplForFile(File file) =>
|
||||
getAnalysisOptionsForFile(file) as AnalysisOptionsImpl;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/source/source.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_options_map.dart';
|
||||
import 'package:analyzer/src/dart/analysis/byte_store.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
|
||||
@@ -498,7 +499,8 @@ class AnalysisDriverSchedulerTest with ResourceProviderMixin {
|
||||
sourceFactory: SourceFactory(
|
||||
[DartUriResolver(sdk), ResourceUriResolver(resourceProvider)],
|
||||
),
|
||||
analysisOptions: AnalysisOptionsImpl(),
|
||||
analysisOptionsMap:
|
||||
AnalysisOptionsMap.forSharedOptions(AnalysisOptionsImpl()),
|
||||
packages: Packages.empty,
|
||||
);
|
||||
driver.results.listen((result) {
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'analysis_context_collection2_test.dart' as analysis_context_collection2;
|
||||
import 'analysis_context_collection_test.dart' as analysis_context_collection;
|
||||
import 'analysis_options_map_test.dart' as analysis_options_map;
|
||||
import 'byte_store_test.dart' as byte_store_test;
|
||||
import 'cache_test.dart' as cache_test;
|
||||
import 'context_builder2_test.dart' as context_builder2;
|
||||
import 'context_builder_test.dart' as context_builder;
|
||||
import 'context_locator2_test.dart' as context_locator2;
|
||||
import 'context_locator_test.dart' as context_locator;
|
||||
@@ -37,12 +35,10 @@ import 'uri_converter_test.dart' as uri_converter;
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
analysis_context_collection.main();
|
||||
analysis_context_collection2.main();
|
||||
analysis_options_map.main();
|
||||
byte_store_test.main();
|
||||
cache_test.main();
|
||||
context_builder.main();
|
||||
context_builder2.main();
|
||||
context_locator.main();
|
||||
context_locator2.main();
|
||||
context_root.main();
|
||||
|
||||
Reference in New Issue
Block a user