Index: pkg/analyzer_cli/lib/src/options.dart |
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ee683e2d084e7eb1a190f6aa8a6ff833fa297fc3 |
--- /dev/null |
+++ b/pkg/analyzer_cli/lib/src/options.dart |
@@ -0,0 +1,485 @@ |
+// 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. |
+ |
+library analyzer_cli.src.options; |
+ |
+import 'dart:io'; |
+ |
+import 'package:analyzer_cli/src/driver.dart'; |
+import 'package:args/args.dart'; |
+import 'package:cli_util/cli_util.dart' show getSdkDir; |
+ |
+const _binaryName = 'dartanalyzer'; |
+ |
+/// Shared exit handler. |
+/// |
+/// *Visible for testing.* |
+ExitHandler exitHandler = exit; |
+ |
+/// 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 void ExitHandler(int code); |
+ |
+/// Analyzer commandline configuration options. |
+class CommandLineOptions { |
+ /// The path to an analysis options file |
+ final String analysisOptionsFile; |
+ |
+ /// The path to the dart SDK |
+ String dartSdkPath; |
+ |
+ /// A table mapping the names of defined variables to their values. |
+ final Map<String, String> definedVariables; |
+ |
+ /// Whether to report hints |
+ final bool disableHints; |
+ |
+ /// Whether to display version information |
+ final bool displayVersion; |
+ |
+ /// Whether to enable null-aware operators (DEP 9). |
+ final bool enableNullAwareOperators; |
+ |
+ /// Whether to strictly follow the specification when generating warnings on |
+ /// "call" methods (fixes dartbug.com/21938). |
+ final bool enableStrictCallChecks; |
+ |
+ /// Whether to relax restrictions on mixins (DEP 34). |
+ final bool enableSuperMixins; |
+ |
+ /// Whether to treat type mismatches found during constant evaluation as |
+ /// errors. |
+ final bool enableTypeChecks; |
+ |
+ /// Whether to treat hints as fatal |
+ final bool hintsAreFatal; |
+ |
+ /// Whether to ignore unrecognized flags |
+ final bool ignoreUnrecognizedFlags; |
+ |
+ /// Whether to report lints |
+ final bool lints; |
+ |
+ /// Whether to log additional analysis messages and exceptions |
+ final bool log; |
+ |
+ /// Whether to use machine format for error display |
+ final bool machineFormat; |
+ |
+ /// The path to the package root |
+ final String packageRootPath; |
+ |
+ /// The path to a `.packages` configuration file |
+ final String packageConfigPath; |
+ |
+ /// Batch mode (for unit testing) |
+ final bool shouldBatch; |
+ |
+ /// Whether to show package: warnings |
+ final bool showPackageWarnings; |
+ |
+ /// 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 use strong static checking. |
+ final bool strongMode; |
+ |
+ /// Initialize options from the given parsed [args]. |
+ CommandLineOptions._fromArgs( |
+ ArgResults args, Map<String, String> definedVariables) |
+ : dartSdkPath = args['dart-sdk'], |
+ this.definedVariables = definedVariables, |
+ analysisOptionsFile = args['options'], |
+ disableHints = args['no-hints'], |
+ displayVersion = args['version'], |
+ enableNullAwareOperators = args['enable-null-aware-operators'], |
+ enableStrictCallChecks = args['enable-strict-call-checks'], |
+ enableSuperMixins = args['supermixin'], |
+ enableTypeChecks = args['enable_type_checks'], |
+ hintsAreFatal = args['fatal-hints'], |
+ ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'], |
+ lints = args['lints'], |
+ log = args['log'], |
+ machineFormat = args['machine'] || args['format'] == 'machine', |
+ packageConfigPath = args['packages'], |
+ packageRootPath = args['package-root'], |
+ shouldBatch = args['batch'], |
+ showPackageWarnings = |
+ args['show-package-warnings'] || args['package-warnings'], |
+ showSdkWarnings = args['show-sdk-warnings'] || args['warnings'], |
+ sourceFiles = args.rest, |
+ warningsAreFatal = args['fatal-warnings'], |
+ strongMode = args['strong']; |
+ |
+ /// 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(List<String> args, |
+ [printAndFail = printAndFail]) { |
+ CommandLineOptions options = _parse(args); |
+ // Check SDK. |
+ { |
+ // Infer if unspecified. |
+ if (options.dartSdkPath == null) { |
+ Directory sdkDir = getSdkDir(args); |
+ if (sdkDir != null) { |
+ options.dartSdkPath = sdkDir.path; |
+ } |
+ } |
+ |
+ var sdkPath = options.dartSdkPath; |
+ |
+ // Check that SDK is specified. |
+ if (sdkPath == null) { |
+ printAndFail('No Dart SDK found.'); |
+ } |
+ // Check that SDK is existing directory. |
+ if (!(new Directory(sdkPath)).existsSync()) { |
+ printAndFail('Invalid Dart SDK path: $sdkPath'); |
+ } |
+ } |
+ |
+ // Check package config. |
+ { |
+ if (options.packageRootPath != null && |
+ options.packageConfigPath != null) { |
+ printAndFail("Cannot specify both '--package-root' and '--packages."); |
+ } |
+ } |
+ |
+ // OK. Report deprecated options. |
+ if (options.enableNullAwareOperators) { |
+ stderr.writeln( |
+ "Info: Option '--enable-null-aware-operators' is no longer needed. Null aware operators are supported by default."); |
+ } |
+ |
+ return options; |
+ } |
+ |
+ static String _getVersion() { |
+ try { |
+ // This is relative to bin/snapshot, so ../.. |
+ String versionPath = |
+ Platform.script.resolve('../../version').toFilePath(); |
+ File versionFile = new 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(List<String> args) { |
+ args = args.expand((String arg) => arg.split('=')).toList(); |
+ var parser = new CommandLineParser() |
+ ..addFlag('batch', |
+ abbr: 'b', |
+ help: 'Read commands from standard input (for testing).', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addOption('dart-sdk', help: 'The path to the Dart SDK.') |
+ ..addOption('packages', |
+ help: |
+ 'Path to the package resolution configuration file, which supplies a mapping of package names to paths. This option cannot be used with --package-root.') |
+ ..addOption('package-root', |
+ abbr: 'p', |
+ help: |
+ 'Path to a package root directory (deprecated). This option cannot be used with --packages.') |
+ ..addOption('options', help: 'Path to an analysis options file.') |
+ ..addOption('format', |
+ help: 'Specifies the format in which errors are displayed.') |
+ ..addFlag('machine', |
+ help: 'Print errors in a format suitable for parsing (deprecated).', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('version', |
+ help: 'Print the analyzer version.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('lints', |
+ help: 'Show lint results.', defaultsTo: false, negatable: false) |
+ ..addFlag('no-hints', |
+ help: 'Do not show hint results.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('ignore-unrecognized-flags', |
+ help: 'Ignore unrecognized command line flags.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('fatal-hints', |
+ help: 'Treat hints as fatal.', defaultsTo: false, negatable: false) |
+ ..addFlag('fatal-warnings', |
+ help: 'Treat non-type warnings as fatal.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('package-warnings', |
+ help: 'Show warnings from package: imports.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('show-package-warnings', |
+ help: 'Show warnings from package: imports (deprecated).', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('warnings', |
+ help: 'Show warnings from SDK imports.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('show-sdk-warnings', |
+ help: 'Show warnings from SDK imports (deprecated).', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addFlag('help', |
+ abbr: 'h', |
+ help: 'Display this help message.', |
+ defaultsTo: false, |
+ negatable: false) |
+ ..addOption('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".', |
+ allowMultiple: true, |
+ splitCommas: false) |
+ // |
+ // Hidden flags. |
+ // |
+ ..addFlag('enable-async', |
+ help: 'Enable support for the proposed async feature.', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('enable-enum', |
+ help: 'Enable support for the proposed enum feature.', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('enable-null-aware-operators', |
+ help: 'Enable support for null-aware operators (DEP 9).', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('enable-strict-call-checks', |
+ help: 'Fix issue 21938.', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('enable-new-task-model', |
+ help: 'Ennable new task model.', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('supermixin', |
+ help: 'Relax restrictions on mixins (DEP 34).', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('log', |
+ help: 'Log additional messages and exceptions.', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('enable_type_checks', |
+ help: 'Check types in constant evaluation.', |
+ defaultsTo: false, |
+ negatable: false, |
+ hide: true) |
+ ..addFlag('strong', |
+ help: 'Enable strong static checks (https://goo.gl/DqcBsw)'); |
+ |
+ try { |
+ // TODO(scheglov) https://code.google.com/p/dart/issues/detail?id=11061 |
+ args = |
+ args.map((String arg) => arg == '-batch' ? '--batch' : arg).toList(); |
+ Map<String, String> definedVariables = <String, String>{}; |
+ var results = parser.parse(args, definedVariables); |
+ // Help requests. |
+ if (results['help']) { |
+ _showUsage(parser); |
+ exit(0); |
+ } |
+ // Batch mode and input files. |
+ if (results['batch']) { |
+ if (results.rest.isNotEmpty) { |
+ stderr.writeln('No source files expected in the batch mode.'); |
+ _showUsage(parser); |
+ exit(15); |
+ } |
+ } else if (results['version']) { |
+ print('$_binaryName version ${_getVersion()}'); |
+ exit(0); |
+ } else { |
+ if (results.rest.isEmpty) { |
+ _showUsage(parser); |
+ exit(15); |
+ } |
+ } |
+ return new CommandLineOptions._fromArgs(results, definedVariables); |
+ } on FormatException catch (e) { |
+ stderr.writeln(e.message); |
+ _showUsage(parser); |
+ exit(15); |
+ } |
+ } |
+ |
+ static _showUsage(parser) { |
+ stderr |
+ .writeln('Usage: $_binaryName [options...] <libraries to analyze...>'); |
+ stderr.writeln(parser.getUsage()); |
+ stderr.writeln(''); |
+ stderr.writeln( |
+ 'For more information, see http://www.dartlang.org/tools/analyzer.'); |
+ } |
+} |
+ |
+/// Commandline argument parser. |
+/// |
+/// TODO(pquitslund): when the args package supports ignoring unrecognized |
+/// options/flags, this class can be replaced with a simple [ArgParser] |
+/// instance. |
+class CommandLineParser { |
+ final List<String> _knownFlags; |
+ final bool _alwaysIgnoreUnrecognized; |
+ final ArgParser _parser; |
+ |
+ /// Creates a new command line parser. |
+ CommandLineParser({bool alwaysIgnoreUnrecognized: false}) |
+ : _knownFlags = <String>[], |
+ _alwaysIgnoreUnrecognized = alwaysIgnoreUnrecognized, |
+ _parser = new ArgParser(allowTrailingOptions: true); |
+ |
+ ArgParser get parser => _parser; |
+ |
+ /// Defines a flag. |
+ /// See [ArgParser.addFlag()]. |
+ void addFlag(String name, |
+ {String abbr, |
+ String help, |
+ bool defaultsTo: false, |
+ bool negatable: true, |
+ void callback(bool value), |
+ bool hide: false}) { |
+ _knownFlags.add(name); |
+ _parser.addFlag(name, |
+ abbr: abbr, |
+ help: help, |
+ defaultsTo: defaultsTo, |
+ negatable: negatable, |
+ callback: callback, |
+ hide: hide); |
+ } |
+ |
+ /// Defines a value-taking option. |
+ /// See [ArgParser.addOption()]. |
+ void addOption(String name, |
+ {String abbr, |
+ String help, |
+ List<String> allowed, |
+ Map<String, String> allowedHelp, |
+ String defaultsTo, |
+ void callback(value), |
+ bool allowMultiple: false, |
+ bool splitCommas}) { |
+ _knownFlags.add(name); |
+ _parser.addOption(name, |
+ abbr: abbr, |
+ help: help, |
+ allowed: allowed, |
+ allowedHelp: allowedHelp, |
+ defaultsTo: defaultsTo, |
+ callback: callback, |
+ allowMultiple: allowMultiple, |
+ splitCommas: splitCommas); |
+ } |
+ |
+ /// Generates a string displaying usage information for the defined options. |
+ /// See [ArgParser.usage]. |
+ String getUsage() => _parser.usage; |
+ |
+ /// Parses [args], a list of command-line arguments, matches them against the |
+ /// flags and options defined by this parser, and returns the result. The |
+ /// values of any defined variables are captured in the given map. |
+ /// See [ArgParser]. |
+ ArgResults parse(List<String> args, Map<String, String> definedVariables) => |
+ _parser.parse( |
+ _filterUnknowns(parseDefinedVariables(args, definedVariables))); |
+ |
+ List<String> parseDefinedVariables( |
+ List<String> args, Map<String, String> definedVariables) { |
+ int count = args.length; |
+ List<String> remainingArgs = <String>[]; |
+ for (int i = 0; i < count; i++) { |
+ String arg = args[i]; |
+ if (arg == '--') { |
+ while (i < count) { |
+ remainingArgs.add(args[i++]); |
+ } |
+ } else if (arg.startsWith("-D")) { |
+ definedVariables[arg.substring(2)] = args[++i]; |
+ } else { |
+ remainingArgs.add(arg); |
+ } |
+ } |
+ return remainingArgs; |
+ } |
+ |
+ List<String> _filterUnknowns(List<String> args) { |
+ // Only filter args if the ignore flag is specified, or if |
+ // _alwaysIgnoreUnrecognized was set to true. |
+ if (_alwaysIgnoreUnrecognized || |
+ args.contains('--ignore-unrecognized-flags')) { |
+ //TODO(pquitslund): replace w/ the following once library skew issues are |
+ // sorted out |
+ //return args.where((arg) => !arg.startsWith('--') || |
+ // _knownFlags.contains(arg.substring(2))); |
+ |
+ // Filter all unrecognized flags and options. |
+ List<String> filtered = <String>[]; |
+ for (int i = 0; i < args.length; ++i) { |
+ String arg = args[i]; |
+ if (arg.startsWith('--') && arg.length > 2) { |
+ String option = arg.substring(2); |
+ // strip the last '=value' |
+ int equalsOffset = option.lastIndexOf('='); |
+ if (equalsOffset != -1) { |
+ option = option.substring(0, equalsOffset); |
+ } |
+ // Check the option |
+ if (!_knownFlags.contains(option)) { |
+ //"eat" params by advancing to the next flag/option |
+ i = _getNextFlagIndex(args, i); |
+ } else { |
+ filtered.add(arg); |
+ } |
+ } else { |
+ filtered.add(arg); |
+ } |
+ } |
+ |
+ return filtered; |
+ } else { |
+ return args; |
+ } |
+ } |
+ |
+ int _getNextFlagIndex(args, i) { |
+ for (; i < args.length; ++i) { |
+ if (args[i].startsWith('--')) { |
+ return i; |
+ } |
+ } |
+ return i; |
+ } |
+} |