mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:20:36 +00:00
Add the enable-experiment flag back to DAS
Bug: https://github.com/dart-lang/sdk/issues/48960 Change-Id: I6576f45e63e28902986db844df49a06a71385704 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/245202 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
6f473f0249
commit
567b45fb1d
|
@ -874,6 +874,10 @@ class AnalysisServerOptions {
|
|||
|
||||
/// If set, this string will be reported as the protocol version.
|
||||
String? reportProtocolVersion;
|
||||
|
||||
/// Experiments which have been enabled (or disabled) via the
|
||||
/// `--enable-experiment` command-line option.
|
||||
List<String> enabledExperiments = [];
|
||||
}
|
||||
|
||||
class ServerContextManagerCallbacks extends ContextManagerCallbacks {
|
||||
|
|
|
@ -228,6 +228,7 @@ abstract class AbstractAnalysisServer {
|
|||
resourceProvider,
|
||||
sdkManager,
|
||||
options.packagesFile,
|
||||
options.enabledExperiments,
|
||||
byteStore,
|
||||
fileContentCache,
|
||||
analysisPerformanceLogger,
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'dart:collection';
|
|||
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
|
||||
import 'package:analyzer/dart/analysis/features.dart';
|
||||
import 'package:analyzer/error/listener.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/instrumentation/instrumentation.dart';
|
||||
|
@ -206,6 +207,10 @@ class ContextManagerImpl implements ContextManager {
|
|||
/// clean up when we destroy a context.
|
||||
final bazelWatchedPathsPerFolder = <Folder, _BazelWatchedFiles>{};
|
||||
|
||||
/// Experiments which have been enabled (or disabled) via the
|
||||
/// `--enable-experiment` command-line option.
|
||||
final List<String> _enabledExperiments;
|
||||
|
||||
/// Information about the current/last queued context rebuild.
|
||||
///
|
||||
/// This is used when a new build is requested to cancel any in-progress
|
||||
|
@ -216,6 +221,7 @@ class ContextManagerImpl implements ContextManager {
|
|||
this.resourceProvider,
|
||||
this.sdkManager,
|
||||
this.packagesFile,
|
||||
this._enabledExperiments,
|
||||
this._byteStore,
|
||||
this._fileContentCache,
|
||||
this._performanceLog,
|
||||
|
@ -456,6 +462,18 @@ class ContextManagerImpl implements ContextManager {
|
|||
sdkPath: sdkManager.defaultSdkDirectory,
|
||||
packagesFile: packagesFile,
|
||||
fileContentCache: _fileContentCache,
|
||||
updateAnalysisOptions2: ({
|
||||
required analysisOptions,
|
||||
required contextRoot,
|
||||
required sdk,
|
||||
}) {
|
||||
if (_enabledExperiments.isNotEmpty) {
|
||||
analysisOptions.contextFeatures = FeatureSet.fromEnableFlags2(
|
||||
sdkLanguageVersion: sdk.languageVersion,
|
||||
flags: _enabledExperiments,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
for (var analysisContext in collection.contexts) {
|
||||
|
|
|
@ -65,6 +65,9 @@ class Driver implements ServerStarter {
|
|||
static const String DISABLE_SERVER_FEATURE_SEARCH =
|
||||
'disable-server-feature-search';
|
||||
|
||||
/// The name of the multi-option to enable one or more experiments.
|
||||
static const String ENABLE_EXPERIMENT = 'enable-experiment';
|
||||
|
||||
/// The name of the option used to print usage information.
|
||||
static const String HELP_OPTION = 'help';
|
||||
|
||||
|
@ -170,6 +173,11 @@ class Driver implements ServerStarter {
|
|||
analysisServerOptions.reportProtocolVersion =
|
||||
results[REPORT_PROTOCOL_VERSION] as String?;
|
||||
|
||||
analysisServerOptions.enabledExperiments =
|
||||
results.wasParsed(ENABLE_EXPERIMENT)
|
||||
? results[ENABLE_EXPERIMENT] as List<String>
|
||||
: <String>[];
|
||||
|
||||
// Read in any per-SDK overrides specified in <sdk>/config/settings.json.
|
||||
var sdkConfig = SdkConfiguration.readFromSdk();
|
||||
analysisServerOptions.configurationOverrides = sdkConfig;
|
||||
|
@ -689,6 +697,13 @@ class Driver implements ServerStarter {
|
|||
help: 'The path to the package resolution configuration file, which '
|
||||
'supplies a mapping of package names\ninto paths.',
|
||||
);
|
||||
parser.addMultiOption(
|
||||
ENABLE_EXPERIMENT,
|
||||
valueHelp: 'experiment',
|
||||
help: 'Enable one or more experimental features '
|
||||
'(see dart.dev/go/experiments).',
|
||||
hide: true,
|
||||
);
|
||||
|
||||
parser.addOption(
|
||||
SERVER_PROTOCOL,
|
||||
|
@ -784,8 +799,6 @@ class Driver implements ServerStarter {
|
|||
parser.addFlag('dartpad', hide: true);
|
||||
// Removed 11/15/2020.
|
||||
parser.addFlag('enable-completion-model', hide: true);
|
||||
// Removed 10/30/2020.
|
||||
parser.addMultiOption('enable-experiment', hide: true);
|
||||
// Removed 9/23/2020.
|
||||
parser.addFlag('enable-instrumentation', hide: true);
|
||||
// Removed 11/12/2020.
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart'
|
|||
as macro;
|
||||
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/context_locator.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';
|
||||
|
@ -16,6 +17,7 @@ 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/performance_logger.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';
|
||||
|
@ -53,7 +55,15 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
|
|||
String? sdkSummaryPath,
|
||||
AnalysisDriverScheduler? scheduler,
|
||||
FileContentCache? fileContentCache,
|
||||
void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
|
||||
@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,
|
||||
}) : resourceProvider =
|
||||
resourceProvider ?? PhysicalResourceProvider.INSTANCE {
|
||||
sdkPath ??= getSdkPath();
|
||||
|
@ -61,6 +71,12 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
|
|||
_throwIfAnyNotAbsoluteNormalizedPath(includedPaths);
|
||||
_throwIfNotAbsoluteNormalizedPath(sdkPath);
|
||||
|
||||
if (updateAnalysisOptions != null && updateAnalysisOptions2 != null) {
|
||||
throw ArgumentError(
|
||||
'Either updateAnalysisOptions or updateAnalysisOptions2 must be '
|
||||
'given, but not both.');
|
||||
}
|
||||
|
||||
var contextLocator = ContextLocator(
|
||||
resourceProvider: this.resourceProvider,
|
||||
);
|
||||
|
@ -86,7 +102,9 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
|
|||
sdkPath: sdkPath,
|
||||
sdkSummaryPath: sdkSummaryPath,
|
||||
scheduler: scheduler,
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
updateAnalysisOptions: updateAnalysisOptions,
|
||||
updateAnalysisOptions2: updateAnalysisOptions2,
|
||||
fileContentCache: fileContentCache,
|
||||
macroKernelBuilder: macroKernelBuilder,
|
||||
macroExecutor: macroExecutor,
|
||||
|
|
|
@ -59,7 +59,14 @@ class ContextBuilderImpl implements ContextBuilder {
|
|||
AnalysisDriverScheduler? scheduler,
|
||||
String? sdkPath,
|
||||
String? sdkSummaryPath,
|
||||
void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
|
||||
@Deprecated('Use updateAnalysisOptions2')
|
||||
void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
|
||||
void Function({
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk,
|
||||
})?
|
||||
updateAnalysisOptions2,
|
||||
FileContentCache? fileContentCache,
|
||||
MacroKernelBuilder? macroKernelBuilder,
|
||||
macro.MultiMacroExecutor? macroExecutor,
|
||||
|
@ -67,6 +74,11 @@ class ContextBuilderImpl implements ContextBuilder {
|
|||
// 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(StringBuffer());
|
||||
|
@ -104,6 +116,12 @@ class ContextBuilderImpl implements ContextBuilder {
|
|||
var options = _getAnalysisOptions(contextRoot, sourceFactory);
|
||||
if (updateAnalysisOptions != null) {
|
||||
updateAnalysisOptions(options);
|
||||
} else if (updateAnalysisOptions2 != null) {
|
||||
updateAnalysisOptions2(
|
||||
analysisOptions: options,
|
||||
contextRoot: contextRoot,
|
||||
sdk: sdk,
|
||||
);
|
||||
}
|
||||
|
||||
final analysisContext =
|
||||
|
|
|
@ -116,7 +116,11 @@ class LintDriver {
|
|||
sdkPath: options.dartSdkPath,
|
||||
includedPaths:
|
||||
files.map((file) => _absoluteNormalizedPath(file.path)).toList(),
|
||||
updateAnalysisOptions: (analysisOptions) {
|
||||
updateAnalysisOptions2: ({
|
||||
required analysisOptions,
|
||||
required contextRoot,
|
||||
required sdk,
|
||||
}) {
|
||||
_updateAnalyzerOptions(analysisOptions, options);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'package:analyzer/dart/analysis/analysis_context.dart';
|
||||
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
|
||||
|
@ -12,6 +13,7 @@ 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/experiments.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/test_utilities/mock_packages.dart';
|
||||
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
|
||||
|
@ -234,7 +236,11 @@ abstract class ContextResolutionTest
|
|||
|
||||
/// Override this method to update [analysisOptions] for every context root,
|
||||
/// the default or already updated with `analysis_options.yaml` file.
|
||||
void updateAnalysisOptions(AnalysisOptionsImpl analysisOptions) {}
|
||||
void updateAnalysisOptions({
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk,
|
||||
}) {}
|
||||
|
||||
/// Call this method if the test needs to use the empty byte store, without
|
||||
/// any information cached.
|
||||
|
@ -267,7 +273,7 @@ abstract class ContextResolutionTest
|
|||
sdkPath: sdkRoot.path,
|
||||
sdkSummaryPath: sdkSummaryFile?.path,
|
||||
librarySummaryPaths: librarySummaryFiles?.map((e) => e.path).toList(),
|
||||
updateAnalysisOptions: updateAnalysisOptions,
|
||||
updateAnalysisOptions2: updateAnalysisOptions,
|
||||
);
|
||||
|
||||
verifyCreatedCollection();
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
// 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/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
import 'package:pub_semver/src/version_constraint.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
|
@ -72,7 +74,11 @@ void f() {}
|
|||
}
|
||||
|
||||
@override
|
||||
void updateAnalysisOptions(AnalysisOptionsImpl analysisOptions) {
|
||||
void updateAnalysisOptions({
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk,
|
||||
}) {
|
||||
analysisOptions.sourceLanguageConstraint =
|
||||
VersionConstraint.parse('>= 2.12.0');
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/sdk/build_sdk_summary.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/error/listener.dart';
|
||||
|
@ -17,6 +18,7 @@ import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
|
|||
import 'package:analyzer/src/dart/analysis/file_state.dart';
|
||||
import 'package:analyzer/src/dart/analysis/results.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/lint/linter.dart';
|
||||
import 'package:analyzer/src/lint/pub.dart';
|
||||
|
@ -553,7 +555,7 @@ class _AnalysisContextProvider {
|
|||
packagesFile: _commandLineOptions!.defaultPackagesPath,
|
||||
resourceProvider: _resourceProvider,
|
||||
sdkPath: _commandLineOptions!.dartSdkPath,
|
||||
updateAnalysisOptions: _updateAnalysisOptions,
|
||||
updateAnalysisOptions2: _updateAnalysisOptions,
|
||||
fileContentCache: _fileContentCache,
|
||||
);
|
||||
|
||||
|
@ -578,7 +580,11 @@ class _AnalysisContextProvider {
|
|||
_analysisContext = _collection!.contextFor(path);
|
||||
}
|
||||
|
||||
void _updateAnalysisOptions(AnalysisOptionsImpl analysisOptions) {
|
||||
void _updateAnalysisOptions({
|
||||
required AnalysisOptionsImpl analysisOptions,
|
||||
required ContextRoot contextRoot,
|
||||
required DartSdk sdk,
|
||||
}) {
|
||||
_commandLineOptions!.updateAnalysisOptions(analysisOptions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:args/args.dart';
|
|||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'core.dart';
|
||||
import 'experiments.dart';
|
||||
import 'sdk.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
|
@ -33,6 +34,7 @@ class AnalysisServer {
|
|||
this.cacheDirectoryPath,
|
||||
required this.commandName,
|
||||
required this.argResults,
|
||||
this.enabledExperiments = const [],
|
||||
});
|
||||
|
||||
final String? cacheDirectoryPath;
|
||||
|
@ -41,6 +43,7 @@ class AnalysisServer {
|
|||
final List<FileSystemEntity> analysisRoots;
|
||||
final String commandName;
|
||||
final ArgResults? argResults;
|
||||
final List<String> enabledExperiments;
|
||||
|
||||
Process? _process;
|
||||
|
||||
|
@ -103,6 +106,8 @@ class AnalysisServer {
|
|||
sdkPath.path,
|
||||
if (cacheDirectoryPath != null) '--cache=$cacheDirectoryPath',
|
||||
if (packagesFile != null) '--packages=${packagesFile!.path}',
|
||||
if (enabledExperiments.isNotEmpty)
|
||||
'--$experimentFlagName=${enabledExperiments.join(',')}'
|
||||
];
|
||||
|
||||
final process = await startDartProcess(sdk, command);
|
||||
|
|
|
@ -6,12 +6,14 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
||||
import 'package:cli_util/cli_logging.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../analysis_server.dart';
|
||||
import '../core.dart';
|
||||
import '../experiments.dart';
|
||||
import '../sdk.dart';
|
||||
import '../utils.dart';
|
||||
|
||||
|
@ -80,7 +82,8 @@ class AnalyzeCommand extends DartdevCommand {
|
|||
valueHelp: 'path',
|
||||
help: 'The path to the Dart SDK.',
|
||||
hide: !verbose,
|
||||
);
|
||||
)
|
||||
..addExperimentalFlags();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -110,12 +113,6 @@ class AnalyzeCommand extends DartdevCommand {
|
|||
final machineFormat = args['format'] == 'machine';
|
||||
final jsonFormat = args['format'] == 'json';
|
||||
|
||||
final targetsNames =
|
||||
targets.map((entity) => path.basename(entity.path)).join(', ');
|
||||
|
||||
var progress =
|
||||
machineFormat ? null : log.progress('Analyzing $targetsNames');
|
||||
|
||||
io.Directory sdkPath;
|
||||
if (args.wasParsed('sdk-path')) {
|
||||
sdkPath = io.Directory(args['sdk-path'] as String);
|
||||
|
@ -137,6 +134,26 @@ class AnalyzeCommand extends DartdevCommand {
|
|||
sdkPath = io.Directory(sdk.sdkPath);
|
||||
}
|
||||
|
||||
final experimentNames = {
|
||||
for (var experiment in args.enabledExperiments)
|
||||
if (experiment.startsWith('no-'))
|
||||
experiment.substring(3)
|
||||
else
|
||||
experiment
|
||||
};
|
||||
final unknownExperiments =
|
||||
experimentNames.difference(ExperimentStatus.knownFeatures.keys.toSet());
|
||||
if (unknownExperiments.isNotEmpty) {
|
||||
final unknownExperimentsText =
|
||||
unknownExperiments.map((e) => "'$e'").join(', ');
|
||||
usageException('Unknown experiment(s): $unknownExperimentsText');
|
||||
}
|
||||
|
||||
final targetsNames =
|
||||
targets.map((entity) => path.basename(entity.path)).join(', ');
|
||||
final progress =
|
||||
machineFormat ? null : log.progress('Analyzing $targetsNames');
|
||||
|
||||
final AnalysisServer server = AnalysisServer(
|
||||
_packagesFile(),
|
||||
sdkPath,
|
||||
|
@ -144,6 +161,7 @@ class AnalyzeCommand extends DartdevCommand {
|
|||
cacheDirectoryPath: args['cache'],
|
||||
commandName: 'analyze',
|
||||
argResults: args,
|
||||
enabledExperiments: args.enabledExperiments,
|
||||
);
|
||||
|
||||
server.onErrors.listen((FileAnalysisErrors fileErrors) {
|
||||
|
|
|
@ -123,8 +123,8 @@ class CompileSnapshotCommand extends CompileSubcommandCommand {
|
|||
help: defineOption.help,
|
||||
abbr: defineOption.abbr,
|
||||
valueHelp: defineOption.valueHelp,
|
||||
);
|
||||
addExperimentalFlags(argParser, verbose);
|
||||
)
|
||||
..addExperimentalFlags(verbose: verbose);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -255,9 +255,8 @@ Remove debugging information from the output and save it separately to the speci
|
|||
help: 'Pass additional options to gen_snapshot.',
|
||||
hide: true,
|
||||
valueHelp: 'opt1,opt2,...',
|
||||
);
|
||||
|
||||
addExperimentalFlags(argParser, verbose);
|
||||
)
|
||||
..addExperimentalFlags(verbose: verbose);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -179,15 +179,15 @@ class RunCommand extends DartdevCommand {
|
|||
hide: !verbose,
|
||||
help:
|
||||
'Use the Dart Development Service (DDS) for enhanced debugging '
|
||||
'functionality. Note: Disabling DDS may break some functionality '
|
||||
'in IDEs and other tooling.',
|
||||
'functionality. Note: Disabling DDS may break some '
|
||||
'functionality in IDEs and other tooling.',
|
||||
defaultsTo: true)
|
||||
..addFlag(
|
||||
'debug-dds',
|
||||
hide: true,
|
||||
);
|
||||
}
|
||||
addExperimentalFlags(argParser, verbose);
|
||||
argParser.addExperimentalFlags(verbose: verbose);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -9,53 +9,53 @@ import 'package:collection/collection.dart' show IterableExtension;
|
|||
const experimentFlagName = 'enable-experiment';
|
||||
|
||||
/// Return a list of all the non-expired Dart experiments.
|
||||
List<ExperimentalFeature> get experimentalFeatures {
|
||||
List<ExperimentalFeature> features = ExperimentStatus.knownFeatures.values
|
||||
.where((feature) => !feature.isExpired)
|
||||
.toList();
|
||||
features.sort((a, b) => a.enableString.compareTo(b.enableString));
|
||||
return features;
|
||||
}
|
||||
List<ExperimentalFeature> get experimentalFeatures =>
|
||||
ExperimentStatus.knownFeatures.values
|
||||
.where((feature) => !feature.isExpired)
|
||||
.toList()
|
||||
..sort((a, b) => a.enableString.compareTo(b.enableString));
|
||||
|
||||
void addExperimentalFlags(ArgParser argParser, bool verbose) {
|
||||
List<ExperimentalFeature> features = experimentalFeatures;
|
||||
extension ArgParserExtensions on ArgParser {
|
||||
void addExperimentalFlags({bool verbose = false}) {
|
||||
List<ExperimentalFeature> features = experimentalFeatures;
|
||||
|
||||
Map<String, String> allowedHelp = {};
|
||||
for (ExperimentalFeature feature in features) {
|
||||
String suffix =
|
||||
feature.isEnabledByDefault ? ' (no-op - enabled by default)' : '';
|
||||
allowedHelp[feature.enableString] = '${feature.documentation}$suffix';
|
||||
Map<String, String> allowedHelp = {};
|
||||
for (ExperimentalFeature feature in features) {
|
||||
String suffix =
|
||||
feature.isEnabledByDefault ? ' (no-op - enabled by default)' : '';
|
||||
allowedHelp[feature.enableString] = '${feature.documentation}$suffix';
|
||||
}
|
||||
|
||||
addMultiOption(
|
||||
experimentFlagName,
|
||||
valueHelp: 'experiment',
|
||||
allowedHelp: verbose ? allowedHelp : null,
|
||||
help: 'Enable one or more experimental features '
|
||||
'(see dart.dev/go/experiments).',
|
||||
hide: !verbose,
|
||||
);
|
||||
}
|
||||
|
||||
argParser.addMultiOption(
|
||||
experimentFlagName,
|
||||
valueHelp: 'experiment',
|
||||
allowedHelp: verbose ? allowedHelp : null,
|
||||
help: 'Enable one or more experimental features '
|
||||
'(see dart.dev/go/experiments).',
|
||||
hide: !verbose,
|
||||
);
|
||||
}
|
||||
|
||||
extension EnabledExperimentsArg on ArgResults {
|
||||
extension ArgResultsExtensions on ArgResults {
|
||||
List<String> get enabledExperiments {
|
||||
List<String> enabledExperiments = [];
|
||||
// Check to see if the ArgParser which generated this result accepts
|
||||
// --enable-experiment as an option. If so, return the result if it was
|
||||
// `--enable-experiment` as an option. If so, return the result if it was
|
||||
// provided.
|
||||
if (options.contains(experimentFlagName)) {
|
||||
if (wasParsed(experimentFlagName)) {
|
||||
enabledExperiments = this[experimentFlagName];
|
||||
enabledExperiments = this[experimentFlagName] as List<String>;
|
||||
}
|
||||
} else {
|
||||
// In the case where a command uses ArgParser.allowAnything() as its
|
||||
// parser the valid set of options for the command isn't specified and
|
||||
// In the case where a command uses `ArgParser.allowAnything()` as its
|
||||
// parser, the valid set of options for the command isn't specified and
|
||||
// isn't enforced. Instead, we have to manually parse the arguments to
|
||||
// look for --enable-experiment=. Currently, this path is only taken for
|
||||
// the pub and test commands, as well as when we are trying to send
|
||||
// look for `--enable-experiment=`. Currently, this path is only taken for
|
||||
// the `pub` and `test` commands, as well as when we are trying to send
|
||||
// analytics.
|
||||
final String? experiments = arguments.firstWhereOrNull(
|
||||
(e) => e.startsWith('--enable-experiment='),
|
||||
final experiments = arguments.firstWhereOrNull(
|
||||
(e) => e.startsWith('--$experimentFlagName='),
|
||||
);
|
||||
if (experiments == null) {
|
||||
return [];
|
||||
|
@ -63,7 +63,7 @@ extension EnabledExperimentsArg on ArgResults {
|
|||
enabledExperiments = experiments.split('=')[1].split(',');
|
||||
}
|
||||
|
||||
for (ExperimentalFeature feature in experimentalFeatures) {
|
||||
for (final feature in experimentalFeatures) {
|
||||
// We allow default true flags, but complain when they are passed in.
|
||||
if (feature.isEnabledByDefault &&
|
||||
enabledExperiments.contains(feature.enableString)) {
|
||||
|
|
|
@ -421,6 +421,26 @@ void defineAnalyze() {
|
|||
expect(result.stderr, isEmpty);
|
||||
});
|
||||
|
||||
test('--enable-experiment', () async {
|
||||
p = project(mainSrc: 'final x = List.filled(growable: true, 7, "");');
|
||||
var result = await p
|
||||
.run(['analyze', '--enable-experiment=no-named-arguments-anywhere']);
|
||||
|
||||
expect(result.exitCode, 3);
|
||||
expect(result.stdout,
|
||||
contains('Positional arguments must occur before named arguments.'));
|
||||
expect(result.stderr, isEmpty);
|
||||
});
|
||||
|
||||
test('--enable-experiment with a bad experiment', () async {
|
||||
p = project();
|
||||
var result = await p.run(['analyze', '--enable-experiment=bad']);
|
||||
|
||||
expect(result.exitCode, 64);
|
||||
expect(result.stdout, isEmpty);
|
||||
expect(result.stderr, contains("Unknown experiment(s): 'bad'"));
|
||||
});
|
||||
|
||||
test('--verbose', () async {
|
||||
p = project(mainSrc: '''
|
||||
int f() {
|
||||
|
|
Loading…
Reference in a new issue