ddc7523958
Bug: https://github.com/dart-lang/sdk/issues/45267 Change-Id: Iac7dd7502b6936bab91279ac5db7cdafaa90c580 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212271 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
645 lines
22 KiB
Dart
645 lines
22 KiB
Dart
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:analyzer/dart/analysis/features.dart';
|
|
import 'package:analyzer/file_system/file_system.dart';
|
|
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
|
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
|
|
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
|
import 'package:analyzer/src/util/sdk.dart';
|
|
import 'package:analyzer_cli/src/ansi.dart' as ansi;
|
|
import 'package:analyzer_cli/src/driver.dart';
|
|
import 'package:args/args.dart';
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
|
|
const _analysisOptionsFileOption = 'options';
|
|
const _binaryName = 'dartanalyzer';
|
|
const _defaultLanguageVersionOption = 'default-language-version';
|
|
const _defineVariableOption = 'D';
|
|
const _enableExperimentOption = 'enable-experiment';
|
|
const _enableInitializingFormalAccessFlag = 'initializing-formal-access';
|
|
const _ignoreUnrecognizedFlagsFlag = 'ignore-unrecognized-flags';
|
|
const _implicitCastsFlag = 'implicit-casts';
|
|
const _lintsFlag = 'lints';
|
|
const _noImplicitDynamicFlag = 'no-implicit-dynamic';
|
|
const _packagesOption = 'packages';
|
|
const _sdkPathOption = 'dart-sdk';
|
|
|
|
/// Shared exit handler.
|
|
///
|
|
/// *Visible for testing.*
|
|
ExitHandler exitHandler = io.exit;
|
|
|
|
T cast<T>(dynamic value) => value as T;
|
|
|
|
/// Print the given [message] to stderr and exit with the given [exitCode].
|
|
void printAndFail(String message, {int exitCode = 15}) {
|
|
errorSink.writeln(message);
|
|
exitHandler(exitCode);
|
|
}
|
|
|
|
/// Exit handler.
|
|
///
|
|
/// *Visible for testing.*
|
|
typedef ExitHandler = void Function(int code);
|
|
|
|
/// Analyzer commandline configuration options.
|
|
class CommandLineOptions {
|
|
final ArgResults _argResults;
|
|
|
|
/// The file path of the analysis options file that should be used in place of
|
|
/// any file in the root directory or a parent of the root directory,
|
|
/// or `null` if the normal lookup mechanism should be used.
|
|
String defaultAnalysisOptionsPath;
|
|
|
|
/// The file path of the .packages file that should be used in place of any
|
|
/// file found using the normal (Package Specification DEP) lookup mechanism,
|
|
/// or `null` if the normal lookup mechanism should be used.
|
|
String defaultPackagesPath;
|
|
|
|
/// A table mapping variable names to values for the declared variables.
|
|
final Map<String, String> declaredVariables = {};
|
|
|
|
/// The path to the dart SDK.
|
|
String dartSdkPath;
|
|
|
|
/// Whether to disable cache flushing. This option can improve analysis
|
|
/// speed at the expense of memory usage. It may also be useful for working
|
|
/// around bugs.
|
|
final bool disableCacheFlushing;
|
|
|
|
/// Whether to report hints
|
|
final bool disableHints;
|
|
|
|
/// Whether to display version information
|
|
final bool displayVersion;
|
|
|
|
/// Whether to ignore unrecognized flags
|
|
final bool ignoreUnrecognizedFlags;
|
|
|
|
/// Whether to log additional analysis messages and exceptions
|
|
final bool log;
|
|
|
|
/// Whether to use 'json' format for error display
|
|
final bool jsonFormat;
|
|
|
|
/// Whether to use 'machine' format for error display
|
|
final bool machineFormat;
|
|
|
|
/// The path to a file to write a performance log.
|
|
/// (Or null if not enabled.)
|
|
final String perfReport;
|
|
|
|
/// Batch mode (for unit testing)
|
|
final bool batchMode;
|
|
|
|
/// Whether to show package: warnings
|
|
final bool showPackageWarnings;
|
|
|
|
/// If not null, show package: warnings only for matching packages.
|
|
final String showPackageWarningsPrefix;
|
|
|
|
/// Whether to show SDK warnings
|
|
final bool showSdkWarnings;
|
|
|
|
/// The source files to analyze
|
|
final List<String> sourceFiles;
|
|
|
|
/// Whether to treat warnings as fatal
|
|
final bool warningsAreFatal;
|
|
|
|
/// Whether to treat info level items as fatal
|
|
final bool infosAreFatal;
|
|
|
|
/// Whether to treat lints as fatal
|
|
// TODO(devoncarew): Deprecate and remove this flag.
|
|
final bool lintsAreFatal;
|
|
|
|
/// Emit output in a verbose mode.
|
|
final bool verbose;
|
|
|
|
/// Use ANSI color codes for output.
|
|
final bool color;
|
|
|
|
/// Whether we should analyze the given source for the purposes of training a
|
|
/// Dart analyzer snapshot.
|
|
final bool trainSnapshot;
|
|
|
|
/// Initialize options from the given parsed [args].
|
|
CommandLineOptions._fromArgs(
|
|
ResourceProvider resourceProvider,
|
|
ArgResults args,
|
|
) : _argResults = args,
|
|
dartSdkPath = cast(args[_sdkPathOption]),
|
|
disableCacheFlushing = cast(args['disable-cache-flushing']),
|
|
disableHints = cast(args['no-hints']),
|
|
displayVersion = cast(args['version']),
|
|
ignoreUnrecognizedFlags = cast(args[_ignoreUnrecognizedFlagsFlag]),
|
|
log = cast(args['log']),
|
|
jsonFormat = args['format'] == 'json',
|
|
machineFormat = args['format'] == 'machine',
|
|
perfReport = cast(args['x-perf-report']),
|
|
batchMode = cast(args['batch']),
|
|
showPackageWarnings = cast(args['show-package-warnings']) ||
|
|
cast(args['package-warnings']) ||
|
|
args['x-package-warnings-prefix'] != null,
|
|
showPackageWarningsPrefix = cast(args['x-package-warnings-prefix']),
|
|
showSdkWarnings = cast(args['sdk-warnings']),
|
|
sourceFiles = args.rest,
|
|
infosAreFatal = cast(args['fatal-infos']) || cast(args['fatal-hints']),
|
|
warningsAreFatal = cast(args['fatal-warnings']),
|
|
lintsAreFatal = cast(args['fatal-lints']),
|
|
trainSnapshot = cast(args['train-snapshot']),
|
|
verbose = cast(args['verbose']),
|
|
color = cast(args['color']) {
|
|
//
|
|
// File locations.
|
|
//
|
|
defaultAnalysisOptionsPath = _absoluteNormalizedPath(
|
|
resourceProvider,
|
|
cast(args[_analysisOptionsFileOption]),
|
|
);
|
|
defaultPackagesPath = _absoluteNormalizedPath(
|
|
resourceProvider,
|
|
cast(args[_packagesOption]),
|
|
);
|
|
|
|
//
|
|
// Declared variables.
|
|
//
|
|
var variables = (args[_defineVariableOption] as List).cast<String>();
|
|
for (var variable in variables) {
|
|
var index = variable.indexOf('=');
|
|
if (index < 0) {
|
|
// TODO (brianwilkerson) Decide the semantics we want in this case.
|
|
// The VM prints "No value given to -D option", then tries to load '-Dfoo'
|
|
// as a file and dies. Unless there was nothing after the '-D', in which
|
|
// case it prints the warning and ignores the option.
|
|
} else {
|
|
var name = variable.substring(0, index);
|
|
if (name.isNotEmpty) {
|
|
// TODO (brianwilkerson) Decide the semantics we want in the case where
|
|
// there is no name. If there is no name, the VM tries to load a file
|
|
// named '-D' and dies.
|
|
declaredVariables[name] = variable.substring(index + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The default language version for files that are not in a package.
|
|
/// (Or null if no default language version to force.)
|
|
String get defaultLanguageVersion {
|
|
return cast(_argResults[_defaultLanguageVersionOption]);
|
|
}
|
|
|
|
/// A list of the names of the experiments that are to be enabled.
|
|
List<String> get enabledExperiments {
|
|
return cast(_argResults[_enableExperimentOption]);
|
|
}
|
|
|
|
bool get implicitCasts => _argResults[_implicitCastsFlag] as bool;
|
|
|
|
bool get lints => _argResults[_lintsFlag] as bool;
|
|
|
|
bool get noImplicitDynamic => _argResults[_noImplicitDynamicFlag] as bool;
|
|
|
|
/// Update the [analysisOptions] with flags that the user specified
|
|
/// explicitly. The [analysisOptions] are usually loaded from one of
|
|
/// `analysis_options.yaml` files, possibly with includes. We consider
|
|
/// flags that the user specified as command line options more important,
|
|
/// so override the corresponding options.
|
|
void updateAnalysisOptions(AnalysisOptionsImpl analysisOptions) {
|
|
var defaultLanguageVersion = this.defaultLanguageVersion;
|
|
if (defaultLanguageVersion != null) {
|
|
var nonPackageLanguageVersion =
|
|
Version.parse('$defaultLanguageVersion.0');
|
|
analysisOptions.nonPackageLanguageVersion = nonPackageLanguageVersion;
|
|
analysisOptions.nonPackageFeatureSet = FeatureSet.latestLanguageVersion()
|
|
.restrictToVersion(nonPackageLanguageVersion);
|
|
}
|
|
|
|
var enabledExperiments = this.enabledExperiments;
|
|
if (enabledExperiments.isNotEmpty) {
|
|
analysisOptions.contextFeatures = FeatureSet.fromEnableFlags2(
|
|
sdkLanguageVersion: ExperimentStatus.currentVersion,
|
|
flags: enabledExperiments,
|
|
);
|
|
}
|
|
|
|
var implicitCasts = this.implicitCasts;
|
|
if (implicitCasts != null) {
|
|
analysisOptions.implicitCasts = implicitCasts;
|
|
}
|
|
|
|
var lints = this.lints;
|
|
if (lints != null) {
|
|
analysisOptions.lint = lints;
|
|
}
|
|
|
|
var noImplicitDynamic = this.noImplicitDynamic;
|
|
if (noImplicitDynamic != null) {
|
|
analysisOptions.implicitDynamic = !noImplicitDynamic;
|
|
}
|
|
}
|
|
|
|
/// Return a list of command-line arguments containing all of the given [args]
|
|
/// that are defined by the given [parser]. An argument is considered to be
|
|
/// defined by the parser if
|
|
/// - it starts with '--' and the rest of the argument (minus any value
|
|
/// introduced by '=') is the name of a known option,
|
|
/// - it starts with '-' and the rest of the argument (minus any value
|
|
/// introduced by '=') is the name of a known abbreviation, or
|
|
/// - it starts with something other than '--' or '-'.
|
|
///
|
|
/// This function allows command-line tools to implement the
|
|
/// '--ignore-unrecognized-flags' option.
|
|
static List<String> filterUnknownArguments(
|
|
List<String> args, ArgParser parser) {
|
|
var knownOptions = <String>{};
|
|
var knownAbbreviations = <String>{};
|
|
parser.options.forEach((String name, Option option) {
|
|
knownOptions.add(name);
|
|
var abbreviation = option.abbr;
|
|
if (abbreviation != null) {
|
|
knownAbbreviations.add(abbreviation);
|
|
}
|
|
if (option.negatable ?? false) {
|
|
knownOptions.add('no-$name');
|
|
}
|
|
});
|
|
String optionName(int prefixLength, String argument) {
|
|
var equalsOffset = argument.lastIndexOf('=');
|
|
if (equalsOffset < 0) {
|
|
return argument.substring(prefixLength);
|
|
}
|
|
return argument.substring(prefixLength, equalsOffset);
|
|
}
|
|
|
|
var filtered = <String>[];
|
|
for (var i = 0; i < args.length; i++) {
|
|
var argument = args[i];
|
|
if (argument.startsWith('--') && argument.length > 2) {
|
|
if (knownOptions.contains(optionName(2, argument))) {
|
|
filtered.add(argument);
|
|
}
|
|
} else if (argument.startsWith('-D') && argument.indexOf('=') > 0) {
|
|
filtered.add(argument);
|
|
}
|
|
if (argument.startsWith('-') && argument.length > 1) {
|
|
if (knownAbbreviations.contains(optionName(1, argument))) {
|
|
filtered.add(argument);
|
|
}
|
|
} else {
|
|
filtered.add(argument);
|
|
}
|
|
}
|
|
return filtered;
|
|
}
|
|
|
|
/// Parse [args] into [CommandLineOptions] describing the specified
|
|
/// analyzer options. In case of a format error, calls [printAndFail], which
|
|
/// by default prints an error message to stderr and exits.
|
|
static CommandLineOptions parse(
|
|
ResourceProvider resourceProvider, List<String> args,
|
|
{void Function(String msg) printAndFail = printAndFail}) {
|
|
var options = _parse(resourceProvider, args);
|
|
|
|
/// Only happens in testing.
|
|
if (options == null) {
|
|
return null;
|
|
}
|
|
|
|
// Check SDK.
|
|
{
|
|
var sdkPath = options.dartSdkPath;
|
|
|
|
// Check that SDK is existing directory.
|
|
if (sdkPath != null) {
|
|
if (!(io.Directory(sdkPath)).existsSync()) {
|
|
printAndFail('Invalid Dart SDK path: $sdkPath');
|
|
return null; // Only reachable in testing.
|
|
}
|
|
}
|
|
|
|
// Infer if unspecified.
|
|
sdkPath ??= getSdkPath(args);
|
|
|
|
var pathContext = resourceProvider.pathContext;
|
|
options.dartSdkPath = file_paths.absoluteNormalized(pathContext, sdkPath);
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
static String _absoluteNormalizedPath(
|
|
ResourceProvider resourceProvider,
|
|
String path,
|
|
) {
|
|
if (path == null) {
|
|
return null;
|
|
}
|
|
var pathContext = resourceProvider.pathContext;
|
|
return pathContext.normalize(
|
|
pathContext.absolute(path),
|
|
);
|
|
}
|
|
|
|
/// Add the standard flags and options to the given [parser]. The standard flags
|
|
/// are those that are typically used to control the way in which the code is
|
|
/// analyzed.
|
|
///
|
|
/// TODO(danrubel) Update DDC to support all the options defined in this method
|
|
/// then remove the [ddc] named argument from this method.
|
|
static void _defineAnalysisArguments(ArgParser parser,
|
|
{bool hide = true, bool ddc = false}) {
|
|
parser.addOption(_sdkPathOption,
|
|
help: 'The path to the Dart SDK.', hide: ddc && hide);
|
|
parser.addOption(_analysisOptionsFileOption,
|
|
help: 'Path to an analysis options file.', hide: ddc && hide);
|
|
parser.addFlag('strong',
|
|
help: 'Enable strong mode (deprecated); this option is now ignored.',
|
|
defaultsTo: true,
|
|
hide: true,
|
|
negatable: true);
|
|
parser.addFlag('declaration-casts',
|
|
negatable: true,
|
|
help:
|
|
'Disable declaration casts in strong mode (https://goo.gl/cTLz40)\n'
|
|
'This option is now ignored and will be removed in a future release.',
|
|
hide: ddc && hide);
|
|
parser.addMultiOption(_enableExperimentOption,
|
|
help: 'Enable one or more experimental features. If multiple features '
|
|
'are being added, they should be comma separated.',
|
|
splitCommas: true);
|
|
parser.addFlag(_implicitCastsFlag,
|
|
negatable: true,
|
|
help: 'Disable implicit casts in strong mode (https://goo.gl/cTLz40).',
|
|
defaultsTo: null,
|
|
hide: ddc && hide);
|
|
parser.addFlag(_noImplicitDynamicFlag,
|
|
defaultsTo: null,
|
|
negatable: false,
|
|
help: 'Disable implicit dynamic (https://goo.gl/m0UgXD).',
|
|
hide: ddc && hide);
|
|
|
|
//
|
|
// Hidden flags and options.
|
|
//
|
|
parser.addMultiOption(_defineVariableOption,
|
|
abbr: 'D',
|
|
help:
|
|
'Define an environment declaration. For example, "-Dfoo=bar" defines '
|
|
'an environment declaration named "foo" whose value is "bar".',
|
|
hide: hide);
|
|
parser.addOption(_packagesOption,
|
|
help: 'The path to the package resolution configuration file, which '
|
|
'supplies a mapping of package names\ninto paths.',
|
|
hide: ddc);
|
|
parser.addFlag(_enableInitializingFormalAccessFlag,
|
|
help:
|
|
'Enable support for allowing access to field formal parameters in a '
|
|
'constructor\'s initializer list (deprecated).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide || ddc);
|
|
if (!ddc) {
|
|
parser.addFlag(_lintsFlag,
|
|
help: 'Show lint results.', defaultsTo: null, negatable: true);
|
|
}
|
|
}
|
|
|
|
static String _getVersion() {
|
|
try {
|
|
// This is relative to bin/snapshot, so ../..
|
|
var versionPath =
|
|
io.Platform.script.resolve('../../version').toFilePath();
|
|
var versionFile = io.File(versionPath);
|
|
return versionFile.readAsStringSync().trim();
|
|
} catch (_) {
|
|
// This happens when the script is not running in the context of an SDK.
|
|
return '<unknown>';
|
|
}
|
|
}
|
|
|
|
static CommandLineOptions _parse(
|
|
ResourceProvider resourceProvider,
|
|
List<String> args,
|
|
) {
|
|
var verbose = args.contains('-v') || args.contains('--verbose');
|
|
var hide = !verbose;
|
|
|
|
var parser = ArgParser(allowTrailingOptions: true);
|
|
|
|
if (!hide) {
|
|
parser.addSeparator('General options:');
|
|
}
|
|
|
|
// TODO(devoncarew): This defines some hidden flags, which would be better
|
|
// defined with the rest of the hidden flags below (to group well with the
|
|
// other flags).
|
|
_defineAnalysisArguments(parser, hide: hide);
|
|
|
|
parser
|
|
..addOption('format',
|
|
help: 'Specifies the format in which errors are displayed; the only '
|
|
'currently recognized values are \'json\' and \'machine\'.')
|
|
..addFlag('version',
|
|
help: 'Print the analyzer version.',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag('no-hints',
|
|
help: 'Do not show hint results.',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag('fatal-infos',
|
|
help: 'Treat infos as fatal.', defaultsTo: false, negatable: false)
|
|
..addFlag('fatal-warnings',
|
|
help: 'Treat non-type warnings as fatal.',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag('help',
|
|
abbr: 'h',
|
|
help:
|
|
'Display this help message. Add --verbose to show hidden options.',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag('verbose',
|
|
abbr: 'v',
|
|
defaultsTo: false,
|
|
help: 'Verbose output.',
|
|
negatable: false);
|
|
|
|
parser.addFlag('color',
|
|
help: 'Use ansi colors when printing messages.',
|
|
defaultsTo: ansi.terminalSupportsAnsi(),
|
|
hide: hide);
|
|
|
|
// Hidden flags.
|
|
if (!hide) {
|
|
parser.addSeparator('Less frequently used flags:');
|
|
}
|
|
|
|
parser
|
|
..addFlag('batch',
|
|
help: 'Read commands from standard input (for testing).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag(_ignoreUnrecognizedFlagsFlag,
|
|
help: 'Ignore unrecognized command line flags.',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addOption(_defaultLanguageVersionOption,
|
|
help: 'The default language version when it is not specified via '
|
|
'other ways (internal, tests only).',
|
|
hide: false)
|
|
..addFlag('disable-cache-flushing', defaultsTo: false, hide: hide)
|
|
..addOption('x-perf-report',
|
|
help: 'Writes a performance report to the given file (experimental).',
|
|
hide: hide)
|
|
..addOption('x-package-warnings-prefix',
|
|
help:
|
|
'Show warnings from package: imports that match the given prefix (deprecated).',
|
|
hide: hide)
|
|
..addFlag('enable-conditional-directives',
|
|
help:
|
|
'deprecated -- Enable support for conditional directives (DEP 40).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('show-package-warnings',
|
|
help: 'Show warnings from package: imports (deprecated).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('sdk-warnings',
|
|
help: 'Show warnings from SDK imports (deprecated).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('log',
|
|
help: 'Log additional messages and exceptions.',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('enable_type_checks',
|
|
help: 'Check types in constant evaluation (deprecated).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: true)
|
|
..addFlag('use-analysis-driver-memory-byte-store',
|
|
help: 'Use memory byte store, not the file system cache.',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('fatal-hints',
|
|
help: 'Treat hints as fatal (deprecated: use --fatal-infos).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('fatal-lints',
|
|
help: 'Treat lints as fatal.',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addFlag('package-warnings',
|
|
help: 'Show warnings from package: imports (deprecated).',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: hide)
|
|
..addMultiOption('url-mapping',
|
|
help: '--url-mapping=libraryUri,/path/to/library.dart directs the '
|
|
'analyzer to use "library.dart" as the source for an import '
|
|
'of "libraryUri".',
|
|
splitCommas: false,
|
|
hide: hide)
|
|
..addFlag('train-snapshot',
|
|
help: 'Analyze the given source for the purposes of training a '
|
|
'dartanalyzer snapshot.',
|
|
hide: hide,
|
|
negatable: false);
|
|
|
|
try {
|
|
if (args.contains('--$_ignoreUnrecognizedFlagsFlag')) {
|
|
args = filterUnknownArguments(args, parser);
|
|
}
|
|
var results = parser.parse(args);
|
|
|
|
// Help requests.
|
|
if (cast(results['help'])) {
|
|
_showUsage(parser, fromHelp: true);
|
|
exitHandler(0);
|
|
return null; // Only reachable in testing.
|
|
}
|
|
|
|
// Batch mode and input files.
|
|
if (cast(results['batch'])) {
|
|
if (results.rest.isNotEmpty) {
|
|
errorSink.writeln('No source files expected in the batch mode.');
|
|
_showUsage(parser);
|
|
exitHandler(15);
|
|
return null; // Only reachable in testing.
|
|
}
|
|
} else if (cast(results['version'])) {
|
|
outSink.writeln('$_binaryName version ${_getVersion()}');
|
|
exitHandler(0);
|
|
return null; // Only reachable in testing.
|
|
} else {
|
|
if (results.rest.isEmpty) {
|
|
_showUsage(parser, fromHelp: true);
|
|
exitHandler(15);
|
|
return null; // Only reachable in testing.
|
|
}
|
|
}
|
|
|
|
if (results.wasParsed('strong')) {
|
|
errorSink.writeln(
|
|
'Note: the --strong flag is deprecated and will be removed in an '
|
|
'future release.\n');
|
|
}
|
|
if (results.wasParsed(_enableExperimentOption)) {
|
|
var names =
|
|
(results[_enableExperimentOption] as List).cast<String>().toList();
|
|
var errorFound = false;
|
|
for (var validationResult in validateFlags(names)) {
|
|
if (validationResult.isError) {
|
|
errorFound = true;
|
|
}
|
|
var kind = validationResult.isError ? 'ERROR' : 'WARNING';
|
|
errorSink.writeln('$kind: ${validationResult.message}');
|
|
}
|
|
if (errorFound) {
|
|
_showUsage(parser);
|
|
exitHandler(15);
|
|
return null; // Only reachable in testing.
|
|
}
|
|
}
|
|
|
|
return CommandLineOptions._fromArgs(resourceProvider, results);
|
|
} on FormatException catch (e) {
|
|
errorSink.writeln(e.message);
|
|
_showUsage(parser);
|
|
exitHandler(15);
|
|
return null; // Only reachable in testing.
|
|
}
|
|
}
|
|
|
|
static void _showUsage(ArgParser parser, {bool fromHelp = false}) {
|
|
errorSink.writeln(
|
|
'Usage: $_binaryName [options...] <directory or list of files>');
|
|
|
|
errorSink.writeln('');
|
|
errorSink.writeln(parser.usage);
|
|
|
|
errorSink.writeln('');
|
|
errorSink.writeln('''
|
|
Run "dartanalyzer -h -v" for verbose help output, including less commonly used options.
|
|
For more information, see https://dart.dev/tools/dartanalyzer.\n''');
|
|
}
|
|
}
|