diff --git a/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart b/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart index abb33f8f18b0..367c8ecf7ec7 100644 --- a/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart +++ b/pkg/analyzer/lib/dart/sdk/build_sdk_summary.dart @@ -6,7 +6,6 @@ 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'; @@ -50,7 +49,6 @@ Future buildSdkSummary({ final logger = PerformanceLog(StringBuffer()); final scheduler = AnalysisDriverScheduler(logger); - final optionsMap = AnalysisOptionsMap.forSharedOptions(AnalysisOptionsImpl()); final analysisDriver = AnalysisDriver( scheduler: scheduler, logger: logger, @@ -59,7 +57,7 @@ Future buildSdkSummary({ sourceFactory: SourceFactory([ DartUriResolver(sdk), ]), - analysisOptionsMap: optionsMap, + analysisOptions: AnalysisOptionsImpl(), packages: Packages({}), ); scheduler.start(); diff --git a/pkg/analyzer/lib/src/clients/build_resolvers/build_resolvers.dart b/pkg/analyzer/lib/src/clients/build_resolvers/build_resolvers.dart index f6060dfdf0d8..2934972b6a8b 100644 --- a/pkg/analyzer/lib/src/clients/build_resolvers/build_resolvers.dart +++ b/pkg/analyzer/lib/src/clients/build_resolvers/build_resolvers.dart @@ -8,7 +8,6 @@ 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'; @@ -54,15 +53,13 @@ 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, - analysisOptionsMap: optionsMap, + analysisOptions: analysisOptions as AnalysisOptionsImpl, externalSummaries: dataStore, packages: packages, ); diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection2.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection2.dart new file mode 100644 index 000000000000..8363473a1f14 --- /dev/null +++ b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection2.dart @@ -0,0 +1,178 @@ +// 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 contexts = []; + + /// Initialize a newly created analysis context manager. + AnalysisContextCollectionImpl2({ + ByteStore? byteStore, + Map? declaredVariables, + bool drainStreams = true, + bool enableIndex = false, + required List includedPaths, + List? excludedPaths, + List? 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 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 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'); + } + } +} diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_options_map.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_options_map.dart index 69b5ea335ae3..f0d070e3a677 100644 --- a/pkg/analyzer/lib/src/dart/analysis/analysis_options_map.dart +++ b/pkg/analyzer/lib/src/dart/analysis/analysis_options_map.dart @@ -2,61 +2,29 @@ // 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 { - final List entries = []; - - /// Create an empty [AnalysisOptionsMap] instance. - AnalysisOptionsMap(); + // TODO(pq): final backing representation TBD. + final List<({Folder folder, AnalysisOptions options})> _entries = []; /// Map this [folder] to the given [options]. void add(Folder folder, AnalysisOptions options) { - entries.add(OptionsMapEntry(folder, options)); + _entries.add((folder: folder, options: 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; } diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart index 89f8428d36f8..4337a17910d1 100644 --- a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart +++ b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart @@ -11,10 +11,8 @@ 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, @@ -130,18 +128,17 @@ 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, - analysisOptionsMap: analysisOptionsMap, + analysisOptions: options, packages: _createPackageMap( contextRoot: contextRoot, ), @@ -168,66 +165,6 @@ 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]? diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder2.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder2.dart new file mode 100644 index 000000000000..920c4485ca5e --- /dev/null +++ b/pkg/analyzer/lib/src/dart/analysis/context_builder2.dart @@ -0,0 +1,337 @@ +// 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? 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(); + driver.exceptions.drain(); + } + + 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; + } +} diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart index 71ee2289328a..d1daf56be109 100644 --- a/pkg/analyzer/lib/src/dart/analysis/driver.dart +++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart @@ -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; + show AnalysisContext, AnalysisEngine, AnalysisOptions, AnalysisOptionsImpl; 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,6 +130,9 @@ class AnalysisDriver { 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; @@ -238,7 +241,6 @@ class AnalysisDriver { final AnalysisDriverTestView? testView; - // TODO(pq): replace with an analysis options map. late FeatureSetProvider featureSetProvider; late FileSystemState _fsState; @@ -267,8 +269,9 @@ class AnalysisDriver { bool _disposed = false; /// A map that associates files to corresponding analysis options. - // TODO(pq): retype to OptionsOptionsMap - final SharedOptionsOptionsMap analysisOptionsMap; + // TODO(pq): his will replace the single [_analysisOptions] instance. + // ignore: unused_field + final AnalysisOptionsMap? _analysisOptionsMap; /// Create a new instance of [AnalysisDriver]. /// @@ -280,11 +283,13 @@ class AnalysisDriver { 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, @@ -301,6 +306,8 @@ class AnalysisDriver { _unlinkedUnitStore = unlinkedUnitStore ?? UnlinkedUnitStoreImpl(), _infoDeclarationStore = infoDeclarationStore ?? NoOpInfoDeclarationStore(), + _analysisOptions = analysisOptions, + _analysisOptionsMap = analysisOptionsMap, _logger = logger, _packages = packages, _sourceFactory = sourceFactory, @@ -323,7 +330,7 @@ class AnalysisDriver { /// Return the analysis options used to control analysis. @Deprecated("Use 'getAnalysisOptionsForFile(file)' instead") - AnalysisOptions get analysisOptions => analysisOptionsMap.sharedOptions; + AnalysisOptions get analysisOptions => _analysisOptions; /// Return the current analysis session. AnalysisSessionImpl get currentSession { @@ -333,8 +340,8 @@ class AnalysisDriver { /// Return a list of the names of all the plugins enabled in analysis options /// in this driver. List get enabledPluginNames => - // TODO(pq): get this value from a union of all the plugins enabled in the `analysisOptionsMap` - analysisOptionsMap.sharedOptions.enabledPluginNames; + // TODO(pq): get this value from a union of all the plugins enabled in the `_analysisOptionsMap` + _analysisOptions.enabledPluginNames; /// Return the stream that produces [ExceptionResult]s. Stream get exceptions => _exceptionController.stream; @@ -365,7 +372,7 @@ class AnalysisDriver { logger: _logger, byteStore: _byteStore, infoDeclarationStore: _infoDeclarationStore, - analysisOptions: analysisOptionsMap.sharedOptions, + analysisOptions: _analysisOptions, declaredVariables: declaredVariables, sourceFactory: _sourceFactory, macroSupport: macroSupport, @@ -683,7 +690,8 @@ class AnalysisDriver { } AnalysisOptions getAnalysisOptionsForFile(File file) => - analysisOptionsMap.getOptions(file); + // TODO(pq): replace w/ _analysisOptionsMap?.getOptions(file) + _analysisOptions; /// Return the cached [ResolvedUnitResult] for the Dart file with the given /// [path]. If there is no cached result, return `null`. Usually only results @@ -1581,14 +1589,14 @@ class AnalysisDriver { void _createFileTracker() { _fillSalt(); - var sharedOptions = analysisOptionsMap.sharedOptions; featureSetProvider = FeatureSetProvider.build( sourceFactory: sourceFactory, resourceProvider: _resourceProvider, packages: _packages, - packageDefaultFeatureSet: sharedOptions.contextFeatures, - nonPackageDefaultLanguageVersion: sharedOptions.nonPackageLanguageVersion, - nonPackageDefaultFeatureSet: sharedOptions.nonPackageFeatureSet, + packageDefaultFeatureSet: _analysisOptions.contextFeatures, + nonPackageDefaultLanguageVersion: + _analysisOptions.nonPackageLanguageVersion, + nonPackageDefaultFeatureSet: _analysisOptions.nonPackageFeatureSet, ); _fsState = FileSystemState( @@ -1680,7 +1688,7 @@ class AnalysisDriver { void _fillSaltForElements() { var buffer = ApiSignature(); buffer.addInt(DATA_VERSION); - buffer.addUint32List(analysisOptionsMap.sharedOptions.signatureForElements); + buffer.addUint32List(_analysisOptions.signatureForElements); _addDeclaredVariablesToSignature(buffer); _saltForElements = buffer.toUint32List(); } @@ -1690,7 +1698,7 @@ class AnalysisDriver { buffer.addInt(DATA_VERSION); buffer.addBool(enableIndex); buffer.addBool(enableDebugResolutionMarkers); - buffer.addUint32List(analysisOptionsMap.sharedOptions.signature); + buffer.addUint32List(_analysisOptions.signature); _addDeclaredVariablesToSignature(buffer); var workspace = analysisContext?.contextRoot.workspace; @@ -1703,7 +1711,7 @@ class AnalysisDriver { var buffer = ApiSignature(); buffer.addInt(DATA_VERSION); buffer.addBool(enableIndex); - buffer.addUint32List(analysisOptionsMap.sharedOptions.unlinkedSignature); + buffer.addUint32List(_analysisOptions.unlinkedSignature); _saltForUnlinked = buffer.toUint32List(); } diff --git a/pkg/analyzer/test/src/dart/analysis/analysis_context_collection2_test.dart b/pkg/analyzer/test/src/dart/analysis/analysis_context_collection2_test.dart new file mode 100644 index 000000000000..be9317ea88c2 --- /dev/null +++ b/pkg/analyzer/test/src/dart/analysis/analysis_context_collection2_test.dart @@ -0,0 +1,212 @@ +// 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 includedPaths}) { + return AnalysisContextCollectionImpl2( + resourceProvider: resourceProvider, + includedPaths: includedPaths, + sdkPath: sdkRoot.path, + ); + } + + static void expectContainsExactly(AnalysisOptions? options, + {List? lints}) { + expect(options, isNotNull); + if (lints != null) { + var rules = options!.lintRules.map((e) => e.name); + expect(rules, unorderedEquals(lints)); + } + } +} diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart index 9fae7ba393c7..05c1f351d58c 100644 --- a/pkg/analyzer/test/src/dart/analysis/base.dart +++ b/pkg/analyzer/test/src/dart/analysis/base.dart @@ -7,7 +7,6 @@ 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'; @@ -78,8 +77,7 @@ class BaseAnalysisDriverTest with ResourceProviderMixin { PackageMapUriResolver(resourceProvider, packageMap), ResourceUriResolver(resourceProvider) ]), - analysisOptionsMap: - AnalysisOptionsMap.forSharedOptions(createAnalysisOptions()), + analysisOptions: createAnalysisOptions(), packages: Packages({ 'test': Package( name: 'test', diff --git a/pkg/analyzer/test/src/dart/analysis/context_builder2_test.dart b/pkg/analyzer/test/src/dart/analysis/context_builder2_test.dart new file mode 100644 index 000000000000..9b3819012ec7 --- /dev/null +++ b/pkg/analyzer/test/src/dart/analysis/context_builder2_test.dart @@ -0,0 +1,226 @@ +// 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 actualNames = actual.variableNames; + Iterable 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()); + + expect( + analysisContext.uriResolvers, + unorderedEquals([ + isA(), + isA(), + isA(), + ]), + ); + } + + void test_sourceFactory_pubWorkspace() { + var projectPath = convertPath('/home/my'); + newFile('/home/my/pubspec.yaml', ''); + + var analysisContext = _createSingleAnalysisContext(projectPath); + expect(analysisContext.contextRoot.workspace, isA()); + + expect( + analysisContext.uriResolvers, + unorderedEquals([ + isA(), + isA(), + isA(), + ]), + ); + } + + /// 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 get uriResolvers { + return (driver.sourceFactory as SourceFactoryImpl).resolvers; + } + + AnalysisOptionsImpl getAnalysisOptionsImplForFile(File file) => + getAnalysisOptionsForFile(file) as AnalysisOptionsImpl; +} diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart index 8d177c8e370b..cd692b37367a 100644 --- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart @@ -12,7 +12,6 @@ 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'; @@ -714,8 +713,7 @@ class AnalysisDriverSchedulerTest with ResourceProviderMixin { sourceFactory: SourceFactory( [DartUriResolver(sdk), ResourceUriResolver(resourceProvider)], ), - analysisOptionsMap: - AnalysisOptionsMap.forSharedOptions(AnalysisOptionsImpl()), + analysisOptions: AnalysisOptionsImpl(), packages: Packages.empty, ); driver.results.listen((result) { diff --git a/pkg/analyzer/test/src/dart/analysis/test_all.dart b/pkg/analyzer/test/src/dart/analysis/test_all.dart index 9cd9ba668175..83922b14bde9 100644 --- a/pkg/analyzer/test/src/dart/analysis/test_all.dart +++ b/pkg/analyzer/test/src/dart/analysis/test_all.dart @@ -4,10 +4,12 @@ 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; @@ -35,10 +37,12 @@ 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();