OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, 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 analyzer.src.command_line.arguments; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/file_system/file_system.dart'; |
| 10 import 'package:analyzer/src/context/builder.dart'; |
| 11 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart'; |
| 13 import 'package:analyzer/src/generated/sdk.dart'; |
| 14 import 'package:args/args.dart'; |
| 15 import 'package:path/path.dart'; |
| 16 |
| 17 const String analysisOptionsFileOption = 'options'; |
| 18 const String defineVariableOption = 'D'; |
| 19 const String enableInitializingFormalAccessFlag = 'initializing-formal-access'; |
| 20 const String enableStrictCallChecksFlag = 'enable-strict-call-checks'; |
| 21 const String enableSuperInMixinFlag = 'supermixin'; |
| 22 const String ignoreUnrecognizedFlagsFlag = 'ignore_unrecognized_flags'; |
| 23 const String noImplicitCastsFlag = 'no-implicit-casts'; |
| 24 const String noImplicitDynamicFlag = 'no-implicit-dynamic'; |
| 25 const String packageRootOption = 'package-root'; |
| 26 const String packagesOption = 'packages'; |
| 27 const String sdkPathOption = 'dart-sdk'; |
| 28 const String sdkSummaryPathOption = 'dart-sdk-summary'; |
| 29 const String strongModeFlag = 'strong'; |
| 30 |
| 31 /** |
| 32 * Use the given [resourceProvider], [contentCache] and command-line [args] to |
| 33 * create a context builder. |
| 34 */ |
| 35 ContextBuilderOptions createContextBuilderOptions(ArgResults args) { |
| 36 ContextBuilderOptions builderOptions = new ContextBuilderOptions(); |
| 37 // |
| 38 // File locations. |
| 39 // |
| 40 builderOptions.dartSdkSummaryPath = args[sdkSummaryPathOption]; |
| 41 builderOptions.defaultAnalysisOptionsFilePath = |
| 42 args[analysisOptionsFileOption]; |
| 43 builderOptions.defaultPackageFilePath = args[packagesOption]; |
| 44 builderOptions.defaultPackagesDirectoryPath = args[packageRootOption]; |
| 45 // |
| 46 // Analysis options. |
| 47 // |
| 48 AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl(); |
| 49 defaultOptions.enableInitializingFormalAccess = |
| 50 args[enableInitializingFormalAccessFlag]; |
| 51 defaultOptions.enableStrictCallChecks = args[enableStrictCallChecksFlag]; |
| 52 defaultOptions.enableSuperMixins = args[enableSuperInMixinFlag]; |
| 53 defaultOptions.implicitCasts = !args[noImplicitCastsFlag]; |
| 54 defaultOptions.implicitDynamic = !args[noImplicitDynamicFlag]; |
| 55 defaultOptions.strongMode = args[strongModeFlag]; |
| 56 builderOptions.defaultOptions = defaultOptions; |
| 57 // |
| 58 // Declared variables. |
| 59 // |
| 60 Map<String, String> declaredVariables = <String, String>{}; |
| 61 List<String> variables = args[defineVariableOption] as List<String>; |
| 62 for (String variable in variables) { |
| 63 int index = variable.indexOf('='); |
| 64 if (index < 0) { |
| 65 // TODO (brianwilkerson) Decide the semantics we want in this case. |
| 66 // The VM prints "No value given to -D option", then tries to load '-Dfoo' |
| 67 // as a file and dies. Unless there was nothing after the '-D', in which |
| 68 // case it prints the warning and ignores the option. |
| 69 } else { |
| 70 String name = variable.substring(0, index); |
| 71 if (name.isNotEmpty) { |
| 72 // TODO (brianwilkerson) Decide the semantics we want in the case where |
| 73 // there is no name. If there is no name, the VM tries to load a file |
| 74 // named '-D' and dies. |
| 75 declaredVariables[name] = variable.substring(index + 1); |
| 76 } |
| 77 } |
| 78 } |
| 79 builderOptions.declaredVariables = declaredVariables; |
| 80 |
| 81 return builderOptions; |
| 82 } |
| 83 |
| 84 /** |
| 85 * Use the given [resourceProvider] and command-line [args] to create a Dart SDK |
| 86 * manager. The manager will use summary information if [useSummaries] is `true` |
| 87 * and if the summary information exists. |
| 88 */ |
| 89 DartSdkManager createDartSdkManager( |
| 90 ResourceProvider resourceProvider, bool useSummaries, ArgResults args) { |
| 91 String sdkPath = args[sdkPathOption]; |
| 92 |
| 93 bool canUseSummaries = useSummaries && |
| 94 args.rest.every((String sourcePath) { |
| 95 sourcePath = context.absolute(sourcePath); |
| 96 sourcePath = context.normalize(sourcePath); |
| 97 return !context.isWithin(sdkPath, sourcePath); |
| 98 }); |
| 99 return new DartSdkManager( |
| 100 sdkPath ?? FolderBasedDartSdk.defaultSdkDirectory(resourceProvider), |
| 101 canUseSummaries); |
| 102 } |
| 103 |
| 104 /** |
| 105 * Add the standard flags and options to the given [parser]. The standard flags |
| 106 * are those that are typically used to control the way in which the code is |
| 107 * analyzed. |
| 108 */ |
| 109 void defineAnalysisArguments(ArgParser parser) { |
| 110 parser.addOption(defineVariableOption, |
| 111 abbr: 'D', |
| 112 allowMultiple: true, |
| 113 help: 'Define environment variables. For example, "-Dfoo=bar" defines an ' |
| 114 'environment variable named "foo" whose value is "bar".'); |
| 115 parser.addOption(sdkPathOption, help: 'The path to the Dart SDK.'); |
| 116 parser.addOption(sdkSummaryPathOption, |
| 117 help: 'The path to the Dart SDK summary file.', hide: true); |
| 118 parser.addOption(analysisOptionsFileOption, |
| 119 help: 'Path to an analysis options file.'); |
| 120 parser.addOption(packagesOption, |
| 121 help: 'The path to the package resolution configuration file, which ' |
| 122 'supplies a mapping of package names to paths. This option cannot be ' |
| 123 'used with --package-root.'); |
| 124 parser.addOption(packageRootOption, |
| 125 abbr: 'p', |
| 126 help: 'The path to a package root directory (deprecated). This option ' |
| 127 'cannot be used with --packages.'); |
| 128 |
| 129 parser.addFlag(strongModeFlag, |
| 130 help: 'Enable strong static checks (https://goo.gl/DqcBsw)'); |
| 131 parser.addFlag(noImplicitCastsFlag, |
| 132 negatable: false, |
| 133 help: 'Disable implicit casts in strong mode (https://goo.gl/cTLz40)'); |
| 134 parser.addFlag(noImplicitDynamicFlag, |
| 135 negatable: false, |
| 136 help: 'Disable implicit dynamic (https://goo.gl/m0UgXD)'); |
| 137 // |
| 138 // Hidden flags and options. |
| 139 // |
| 140 // parser.addFlag(enableNullAwareOperatorsFlag, // 'enable-null-aware-operators
' |
| 141 // help: 'Enable support for null-aware operators (DEP 9).', |
| 142 // defaultsTo: false, |
| 143 // negatable: false, |
| 144 // hide: true); |
| 145 parser.addFlag(enableStrictCallChecksFlag, |
| 146 help: 'Fix issue 21938.', |
| 147 defaultsTo: false, |
| 148 negatable: false, |
| 149 hide: true); |
| 150 parser.addFlag(enableInitializingFormalAccessFlag, |
| 151 help: |
| 152 'Enable support for allowing access to field formal parameters in a ' |
| 153 'constructor\'s initializer list', |
| 154 defaultsTo: false, |
| 155 negatable: false, |
| 156 hide: true); |
| 157 parser.addFlag(enableSuperInMixinFlag, |
| 158 help: 'Relax restrictions on mixins (DEP 34).', |
| 159 defaultsTo: false, |
| 160 negatable: false, |
| 161 hide: true); |
| 162 // parser.addFlag('enable_type_checks', |
| 163 // help: 'Check types in constant evaluation.', |
| 164 // defaultsTo: false, |
| 165 // negatable: false, |
| 166 // hide: true); |
| 167 } |
| 168 |
| 169 /** |
| 170 * Return a list of command-line arguments containing all of the given [args] |
| 171 * that are defined by the given [parser]. An argument is considered to be |
| 172 * defined by the parser if |
| 173 * - it starts with '--' and the rest of the argument (minus any value |
| 174 * introduced by '=') is the name of a known option, |
| 175 * - it starts with '-' and the rest of the argument (minus any value |
| 176 * introduced by '=') is the name of a known abbreviation, or |
| 177 * - it starts with something other than '--' or '-'. |
| 178 * |
| 179 * This function allows command-line tools to implement the |
| 180 * '--ignore_unrecognized_flags' option. |
| 181 */ |
| 182 List<String> filterUnknownArguments(List<String> args, ArgParser parser) { |
| 183 Set<String> knownOptions = new HashSet<String>(); |
| 184 Set<String> knownAbbreviations = new HashSet<String>(); |
| 185 parser.options.forEach((String name, Option option) { |
| 186 knownOptions.add(name); |
| 187 String abbreviation = option.abbreviation; |
| 188 if (abbreviation != null) { |
| 189 knownAbbreviations.add(abbreviation); |
| 190 } |
| 191 }); |
| 192 String optionName(int prefixLength, String argument) { |
| 193 int equalsOffset = argument.lastIndexOf('='); |
| 194 if (equalsOffset < 0) { |
| 195 return argument.substring(prefixLength); |
| 196 } |
| 197 return argument.substring(prefixLength, equalsOffset); |
| 198 } |
| 199 |
| 200 List<String> filtered = <String>[]; |
| 201 for (int i = 0; i < args.length; i++) { |
| 202 String argument = args[i]; |
| 203 if (argument.startsWith('--') && argument.length > 2) { |
| 204 if (knownOptions.contains(optionName(2, argument))) { |
| 205 filtered.add(argument); |
| 206 } |
| 207 } else if (argument.startsWith('-') && argument.length > 1) { |
| 208 if (knownAbbreviations.contains(optionName(1, argument))) { |
| 209 filtered.add(argument); |
| 210 } |
| 211 } else { |
| 212 filtered.add(argument); |
| 213 } |
| 214 } |
| 215 return filtered; |
| 216 } |
| 217 |
| 218 /** |
| 219 * Use the given [parser] to parse the given command-line [args], and return the |
| 220 * result. |
| 221 */ |
| 222 ArgResults parse( |
| 223 ResourceProvider provider, ArgParser parser, List<String> args) { |
| 224 args = preprocessArgs(provider, args); |
| 225 if (args.contains('--$ignoreUnrecognizedFlagsFlag')) { |
| 226 args = filterUnknownArguments(args, parser); |
| 227 } |
| 228 return parser.parse(args); |
| 229 } |
| 230 |
| 231 /** |
| 232 * Preprocess the given list of command line [args] by checking whether the real |
| 233 * arguments are in a file (Bazel worker mode). |
| 234 */ |
| 235 List<String> preprocessArgs(ResourceProvider provider, List<String> args) { |
| 236 if (args.isEmpty) { |
| 237 return args; |
| 238 } |
| 239 String lastArg = args.last; |
| 240 if (lastArg.startsWith('@')) { |
| 241 File argsFile = provider.getFile(lastArg.substring(1)); |
| 242 try { |
| 243 List<String> newArgs = args.sublist(0, args.length - 1).toList(); |
| 244 newArgs.addAll(argsFile |
| 245 .readAsStringSync() |
| 246 .replaceAll('\r\n', '\n') |
| 247 .replaceAll('\r', '\n') |
| 248 .split('\n') |
| 249 .where((String line) => line.isNotEmpty)); |
| 250 return newArgs; |
| 251 } on FileSystemException { |
| 252 // Don't modify args if the file does not exist or cannot be read. |
| 253 } |
| 254 } |
| 255 return args; |
| 256 } |
OLD | NEW |