| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library options; | |
| 6 | |
| 7 import 'dart:io'; | |
| 8 | |
| 9 import 'package:args/args.dart'; | |
| 10 | |
| 11 const _BINARY_NAME = 'dartanalyzer'; | |
| 12 | |
| 13 /** | |
| 14 * Analyzer commandline configuration options. | |
| 15 */ | |
| 16 class CommandLineOptions { | |
| 17 /** The path to the dart SDK */ | |
| 18 final String dartSdkPath; | |
| 19 | |
| 20 /** A table mapping the names of defined variables to their values. */ | |
| 21 final Map<String, String> definedVariables; | |
| 22 | |
| 23 /** Whether to report hints */ | |
| 24 final bool disableHints; | |
| 25 | |
| 26 /** Whether to display version information */ | |
| 27 final bool displayVersion; | |
| 28 | |
| 29 /** | |
| 30 * Whether to enable null-aware operators (DEP 9). | |
| 31 */ | |
| 32 final bool enableNullAwareOperators; | |
| 33 | |
| 34 /** | |
| 35 * Whether to strictly follow the specification when generating warnings on | |
| 36 * "call" methods (fixes dartbug.com/21938). | |
| 37 */ | |
| 38 final bool enableStrictCallChecks; | |
| 39 | |
| 40 /** | |
| 41 * Whether to treat type mismatches found during constant evaluation as | |
| 42 * errors. | |
| 43 */ | |
| 44 final bool enableTypeChecks; | |
| 45 | |
| 46 /** Whether to ignore unrecognized flags */ | |
| 47 final bool ignoreUnrecognizedFlags; | |
| 48 | |
| 49 /** Whether to log additional analysis messages and exceptions */ | |
| 50 final bool log; | |
| 51 | |
| 52 /** Whether to use machine format for error display */ | |
| 53 final bool machineFormat; | |
| 54 | |
| 55 /** The path to the package root */ | |
| 56 final String packageRootPath; | |
| 57 | |
| 58 /** Whether to show performance statistics */ | |
| 59 final bool perf; | |
| 60 | |
| 61 /** Batch mode (for unit testing) */ | |
| 62 final bool shouldBatch; | |
| 63 | |
| 64 /** Whether to show package: warnings */ | |
| 65 final bool showPackageWarnings; | |
| 66 | |
| 67 /** Whether to show SDK warnings */ | |
| 68 final bool showSdkWarnings; | |
| 69 | |
| 70 /** The source files to analyze */ | |
| 71 final List<String> sourceFiles; | |
| 72 | |
| 73 /** Whether to show both cold and hot performance statistics */ | |
| 74 final bool warmPerf; | |
| 75 | |
| 76 /** Whether to treat warnings as fatal */ | |
| 77 final bool warningsAreFatal; | |
| 78 | |
| 79 /** A table mapping library URIs to the file system path where the library | |
| 80 * source is located. | |
| 81 */ | |
| 82 final Map<String, String> customUrlMappings; | |
| 83 | |
| 84 /** | |
| 85 * Initialize options from the given parsed [args]. | |
| 86 */ | |
| 87 CommandLineOptions._fromArgs(ArgResults args, | |
| 88 Map<String, String> definedVariables, | |
| 89 Map<String, String> customUrlMappings) | |
| 90 : dartSdkPath = args['dart-sdk'], | |
| 91 this.definedVariables = definedVariables, | |
| 92 disableHints = args['no-hints'], | |
| 93 displayVersion = args['version'], | |
| 94 enableNullAwareOperators = args['enable-null-aware-operators'], | |
| 95 enableStrictCallChecks = args['enable-strict-call-checks'], | |
| 96 enableTypeChecks = args['enable_type_checks'], | |
| 97 ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'], | |
| 98 log = args['log'], | |
| 99 machineFormat = args['machine'] || args['format'] == 'machine', | |
| 100 packageRootPath = args['package-root'], | |
| 101 perf = args['perf'], | |
| 102 shouldBatch = args['batch'], | |
| 103 showPackageWarnings = args['show-package-warnings'] || | |
| 104 args['package-warnings'], | |
| 105 showSdkWarnings = args['show-sdk-warnings'] || args['warnings'], | |
| 106 sourceFiles = args.rest, | |
| 107 warmPerf = args['warm-perf'], | |
| 108 warningsAreFatal = args['fatal-warnings'], | |
| 109 this.customUrlMappings = customUrlMappings; | |
| 110 | |
| 111 /** | |
| 112 * Parse [args] into [CommandLineOptions] describing the specified | |
| 113 * analyzer options. In case of a format error, prints error and exists. | |
| 114 */ | |
| 115 static CommandLineOptions parse(List<String> args) { | |
| 116 CommandLineOptions options = _parse(args); | |
| 117 // check SDK | |
| 118 { | |
| 119 var sdkPath = options.dartSdkPath; | |
| 120 // check that SDK is specified | |
| 121 if (sdkPath == null) { | |
| 122 print('Usage: $_BINARY_NAME: no Dart SDK found.'); | |
| 123 exit(15); | |
| 124 } | |
| 125 // check that SDK is existing directory | |
| 126 if (!(new Directory(sdkPath)).existsSync()) { | |
| 127 print('Usage: $_BINARY_NAME: invalid Dart SDK path: $sdkPath'); | |
| 128 exit(15); | |
| 129 } | |
| 130 } | |
| 131 // OK | |
| 132 return options; | |
| 133 } | |
| 134 | |
| 135 static String _getVersion() { | |
| 136 try { | |
| 137 // This is relative to bin/snapshot, so ../.. | |
| 138 String versionPath = | |
| 139 Platform.script.resolve('../../version').toFilePath(); | |
| 140 File versionFile = new File(versionPath); | |
| 141 return versionFile.readAsStringSync().trim(); | |
| 142 } catch (_) { | |
| 143 // This happens when the script is not running in the context of an SDK. | |
| 144 return "<unknown>"; | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 static CommandLineOptions _parse(List<String> args) { | |
| 149 args = args.expand((String arg) => arg.split('=')).toList(); | |
| 150 var parser = new CommandLineParser() | |
| 151 ..addFlag('batch', | |
| 152 abbr: 'b', | |
| 153 help: 'Run in batch mode', | |
| 154 defaultsTo: false, | |
| 155 negatable: false) | |
| 156 ..addOption('dart-sdk', help: 'The path to the Dart SDK') | |
| 157 ..addOption('package-root', | |
| 158 abbr: 'p', | |
| 159 help: 'The path to the package root. The flag package-root is deprecat
ed. Remove to use package information computed by pub.') | |
| 160 ..addOption('format', | |
| 161 help: 'Specifies the format in which errors are displayed') | |
| 162 ..addFlag('machine', | |
| 163 help: 'Print errors in a format suitable for parsing (deprecated)', | |
| 164 defaultsTo: false, | |
| 165 negatable: false) | |
| 166 ..addFlag('version', | |
| 167 help: 'Print the analyzer version', | |
| 168 defaultsTo: false, | |
| 169 negatable: false) | |
| 170 ..addFlag('no-hints', | |
| 171 help: 'Do not show hint results', defaultsTo: false, negatable: false) | |
| 172 ..addFlag('ignore-unrecognized-flags', | |
| 173 help: 'Ignore unrecognized command line flags', | |
| 174 defaultsTo: false, | |
| 175 negatable: false) | |
| 176 ..addFlag('fatal-warnings', | |
| 177 help: 'Treat non-type warnings as fatal', | |
| 178 defaultsTo: false, | |
| 179 negatable: false) | |
| 180 ..addFlag('package-warnings', | |
| 181 help: 'Show warnings from package: imports', | |
| 182 defaultsTo: false, | |
| 183 negatable: false) | |
| 184 ..addFlag('show-package-warnings', | |
| 185 help: 'Show warnings from package: imports (deprecated)', | |
| 186 defaultsTo: false, | |
| 187 negatable: false) | |
| 188 ..addFlag('perf', | |
| 189 help: 'Show performance statistics', | |
| 190 defaultsTo: false, | |
| 191 negatable: false) | |
| 192 ..addFlag('warnings', | |
| 193 help: 'Show warnings from SDK imports', | |
| 194 defaultsTo: false, | |
| 195 negatable: false) | |
| 196 ..addFlag('show-sdk-warnings', | |
| 197 help: 'Show warnings from SDK imports (deprecated)', | |
| 198 defaultsTo: false, | |
| 199 negatable: false) | |
| 200 ..addFlag('help', | |
| 201 abbr: 'h', | |
| 202 help: 'Display this help message', | |
| 203 defaultsTo: false, | |
| 204 negatable: false) | |
| 205 ..addOption('url-mapping', | |
| 206 help: '--url-mapping=libraryUri,/path/to/library.dart directs the ' | |
| 207 'analyzer to use "library.dart" as the source for an import ' 'of "lib
raryUri"', | |
| 208 allowMultiple: true) | |
| 209 // | |
| 210 // Hidden flags. | |
| 211 // | |
| 212 ..addFlag('enable-async', | |
| 213 help: 'Enable support for the proposed async feature', | |
| 214 defaultsTo: false, | |
| 215 negatable: false, | |
| 216 hide: true) | |
| 217 ..addFlag('enable-enum', | |
| 218 help: 'Enable support for the proposed enum feature', | |
| 219 defaultsTo: false, | |
| 220 negatable: false, | |
| 221 hide: true) | |
| 222 ..addFlag('enable-null-aware-operators', | |
| 223 help: 'Enable support for null-aware operators (DEP 9)', | |
| 224 defaultsTo: false, | |
| 225 negatable: false, | |
| 226 hide: true) | |
| 227 ..addFlag('enable-strict-call-checks', | |
| 228 help: 'Fix issue 21938', | |
| 229 defaultsTo: false, | |
| 230 negatable: false, | |
| 231 hide: true) | |
| 232 ..addFlag('log', | |
| 233 help: 'Log additional messages and exceptions', | |
| 234 defaultsTo: false, | |
| 235 negatable: false, | |
| 236 hide: true) | |
| 237 ..addFlag('warm-perf', | |
| 238 help: 'Show both cold and warm performance statistics', | |
| 239 defaultsTo: false, | |
| 240 negatable: false, | |
| 241 hide: true) | |
| 242 ..addFlag('enable_type_checks', | |
| 243 help: 'Check types in constant evaluation', | |
| 244 defaultsTo: false, | |
| 245 negatable: false, | |
| 246 hide: true); | |
| 247 | |
| 248 try { | |
| 249 // TODO(scheglov) https://code.google.com/p/dart/issues/detail?id=11061 | |
| 250 args = | |
| 251 args.map((String arg) => arg == '-batch' ? '--batch' : arg).toList(); | |
| 252 Map<String, String> definedVariables = <String, String>{}; | |
| 253 var results = parser.parse(args, definedVariables); | |
| 254 // help requests | |
| 255 if (results['help']) { | |
| 256 _showUsage(parser); | |
| 257 exit(0); | |
| 258 } | |
| 259 // batch mode and input files | |
| 260 if (results['batch']) { | |
| 261 if (results.rest.isNotEmpty) { | |
| 262 print('No source files expected in the batch mode.'); | |
| 263 _showUsage(parser); | |
| 264 exit(15); | |
| 265 } | |
| 266 } else if (results['version']) { | |
| 267 print('$_BINARY_NAME version ${_getVersion()}'); | |
| 268 exit(0); | |
| 269 } else { | |
| 270 if (results.rest.isEmpty) { | |
| 271 _showUsage(parser); | |
| 272 exit(15); | |
| 273 } | |
| 274 } | |
| 275 Map<String, String> customUrlMappings = <String, String>{}; | |
| 276 for (String mapping in results['url-mapping']) { | |
| 277 List<String> splitMapping = mapping.split(','); | |
| 278 if (splitMapping.length != 2) { | |
| 279 _showUsage(parser); | |
| 280 exit(15); | |
| 281 } | |
| 282 customUrlMappings[splitMapping[0]] = splitMapping[1]; | |
| 283 } | |
| 284 return new CommandLineOptions._fromArgs( | |
| 285 results, definedVariables, customUrlMappings); | |
| 286 } on FormatException catch (e) { | |
| 287 print(e.message); | |
| 288 _showUsage(parser); | |
| 289 exit(15); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 static _showUsage(parser) { | |
| 294 print('Usage: $_BINARY_NAME [options...] <libraries to analyze...>'); | |
| 295 print(parser.getUsage()); | |
| 296 print(''); | |
| 297 print('For more information, see http://www.dartlang.org/tools/analyzer.'); | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 /** | |
| 302 * Commandline argument parser. | |
| 303 * | |
| 304 * TODO(pquitslund): when the args package supports ignoring unrecognized | |
| 305 * options/flags, this class can be replaced with a simple [ArgParser] instance. | |
| 306 */ | |
| 307 class CommandLineParser { | |
| 308 final List<String> _knownFlags; | |
| 309 final bool _alwaysIgnoreUnrecognized; | |
| 310 final ArgParser _parser; | |
| 311 | |
| 312 /** Creates a new command line parser */ | |
| 313 CommandLineParser({bool alwaysIgnoreUnrecognized: false}) | |
| 314 : _knownFlags = <String>[], | |
| 315 _alwaysIgnoreUnrecognized = alwaysIgnoreUnrecognized, | |
| 316 _parser = new ArgParser(allowTrailingOptions: true); | |
| 317 | |
| 318 ArgParser get parser => _parser; | |
| 319 | |
| 320 /** | |
| 321 * Defines a flag. | |
| 322 * | |
| 323 * See [ArgParser.addFlag()]. | |
| 324 */ | |
| 325 void addFlag(String name, {String abbr, String help, bool defaultsTo: false, | |
| 326 bool negatable: true, void callback(bool value), bool hide: false}) { | |
| 327 _knownFlags.add(name); | |
| 328 _parser.addFlag(name, | |
| 329 abbr: abbr, | |
| 330 help: help, | |
| 331 defaultsTo: defaultsTo, | |
| 332 negatable: negatable, | |
| 333 callback: callback, | |
| 334 hide: hide); | |
| 335 } | |
| 336 | |
| 337 /** | |
| 338 * Defines a value-taking option. | |
| 339 * | |
| 340 * See [ArgParser.addOption()]. | |
| 341 */ | |
| 342 void addOption(String name, {String abbr, String help, List<String> allowed, | |
| 343 Map<String, String> allowedHelp, String defaultsTo, void callback(value), | |
| 344 bool allowMultiple: false}) { | |
| 345 _knownFlags.add(name); | |
| 346 _parser.addOption(name, | |
| 347 abbr: abbr, | |
| 348 help: help, | |
| 349 allowed: allowed, | |
| 350 allowedHelp: allowedHelp, | |
| 351 defaultsTo: defaultsTo, | |
| 352 callback: callback, | |
| 353 allowMultiple: allowMultiple); | |
| 354 } | |
| 355 | |
| 356 /** | |
| 357 * Generates a string displaying usage information for the defined options. | |
| 358 * | |
| 359 * See [ArgParser.usage]. | |
| 360 */ | |
| 361 String getUsage() => _parser.usage; | |
| 362 | |
| 363 /** | |
| 364 * Parses [args], a list of command-line arguments, matches them against the | |
| 365 * flags and options defined by this parser, and returns the result. The | |
| 366 * values of any defined variables are captured in the given map. | |
| 367 * | |
| 368 * See [ArgParser]. | |
| 369 */ | |
| 370 ArgResults parse( | |
| 371 List<String> args, Map<String, String> definedVariables) => _parser | |
| 372 .parse(_filterUnknowns(parseDefinedVariables(args, definedVariables))); | |
| 373 | |
| 374 List<String> parseDefinedVariables( | |
| 375 List<String> args, Map<String, String> definedVariables) { | |
| 376 int count = args.length; | |
| 377 List<String> remainingArgs = <String>[]; | |
| 378 for (int i = 0; i < count; i++) { | |
| 379 String arg = args[i]; | |
| 380 if (arg == '--') { | |
| 381 while (i < count) { | |
| 382 remainingArgs.add(args[i++]); | |
| 383 } | |
| 384 } else if (arg.startsWith("-D")) { | |
| 385 definedVariables[arg.substring(2)] = args[++i]; | |
| 386 } else { | |
| 387 remainingArgs.add(arg); | |
| 388 } | |
| 389 } | |
| 390 return remainingArgs; | |
| 391 } | |
| 392 | |
| 393 List<String> _filterUnknowns(List<String> args) { | |
| 394 | |
| 395 // Only filter args if the ignore flag is specified, or if | |
| 396 // _alwaysIgnoreUnrecognized was set to true | |
| 397 if (_alwaysIgnoreUnrecognized || | |
| 398 args.contains('--ignore-unrecognized-flags')) { | |
| 399 | |
| 400 //TODO(pquitslund): replace w/ the following once library skew issues are | |
| 401 // sorted out | |
| 402 //return args.where((arg) => !arg.startsWith('--') || | |
| 403 // _knownFlags.contains(arg.substring(2))); | |
| 404 | |
| 405 // Filter all unrecognized flags and options. | |
| 406 List<String> filtered = <String>[]; | |
| 407 for (int i = 0; i < args.length; ++i) { | |
| 408 String arg = args[i]; | |
| 409 if (arg.startsWith('--') && arg.length > 2) { | |
| 410 String option = arg.substring(2); | |
| 411 // strip the last '=value' | |
| 412 int equalsOffset = option.lastIndexOf('='); | |
| 413 if (equalsOffset != -1) { | |
| 414 option = option.substring(0, equalsOffset); | |
| 415 } | |
| 416 // check the option | |
| 417 if (!_knownFlags.contains(option)) { | |
| 418 //print('remove: $arg'); | |
| 419 //"eat" params by advancing to the next flag/option | |
| 420 i = _getNextFlagIndex(args, i); | |
| 421 } else { | |
| 422 filtered.add(arg); | |
| 423 } | |
| 424 } else { | |
| 425 filtered.add(arg); | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 return filtered; | |
| 430 } else { | |
| 431 return args; | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 _getNextFlagIndex(args, i) { | |
| 436 for (; i < args.length; ++i) { | |
| 437 if (args[i].startsWith('--')) { | |
| 438 return i; | |
| 439 } | |
| 440 } | |
| 441 return i; | |
| 442 } | |
| 443 } | |
| OLD | NEW |