1 /* 2 * Copyright (C) 2019 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen.compileroption; 18 19 import static com.google.common.base.CaseFormat.LOWER_CAMEL; 20 import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE; 21 import static com.google.common.base.Preconditions.checkArgument; 22 import static com.google.common.collect.Sets.immutableEnumSet; 23 import static dagger.internal.codegen.compileroption.FeatureStatus.DISABLED; 24 import static dagger.internal.codegen.compileroption.FeatureStatus.ENABLED; 25 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS; 26 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_ANDROID_MODE; 27 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_DAGGER_ERROR_MESSAGES; 28 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FAST_INIT; 29 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FLOATING_BINDS_METHODS; 30 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE; 31 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.GENERATED_CLASS_EXTENDS_COMPONENT; 32 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT; 33 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PROVISION_KEY_WILDCARDS; 34 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES; 35 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS; 36 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION; 37 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_SUPERFICIAL_VALIDATION; 38 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES; 39 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM; 40 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WRITE_PRODUCER_NAME_IN_TOKEN; 41 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.KeyOnlyOption.HEADER_COMPILATION; 42 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.KeyOnlyOption.USE_GRADLE_INCREMENTAL_PROCESSING; 43 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.DISABLE_INTER_COMPONENT_SCOPE_VALIDATION; 44 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.EXPLICIT_BINDING_CONFLICTS_WITH_INJECT; 45 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.FULL_BINDING_GRAPH_VALIDATION; 46 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.MODULE_HAS_DIFFERENT_SCOPES_VALIDATION; 47 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.NULLABLE_VALIDATION; 48 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.PRIVATE_MEMBER_VALIDATION; 49 import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.STATIC_MEMBER_VALIDATION; 50 import static dagger.internal.codegen.compileroption.ValidationType.ERROR; 51 import static dagger.internal.codegen.compileroption.ValidationType.NONE; 52 import static dagger.internal.codegen.compileroption.ValidationType.WARNING; 53 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 54 import static java.util.stream.Collectors.joining; 55 import static java.util.stream.Stream.concat; 56 57 import androidx.room.compiler.processing.XMessager; 58 import androidx.room.compiler.processing.XProcessingEnv; 59 import androidx.room.compiler.processing.XTypeElement; 60 import com.google.common.base.Ascii; 61 import com.google.common.collect.ImmutableList; 62 import com.google.common.collect.ImmutableMap; 63 import com.google.common.collect.ImmutableSet; 64 import dagger.internal.codegen.javapoet.TypeNames; 65 import java.util.Arrays; 66 import java.util.EnumSet; 67 import java.util.HashMap; 68 import java.util.Map; 69 import java.util.Optional; 70 import java.util.Set; 71 import java.util.stream.Stream; 72 import javax.inject.Inject; 73 import javax.tools.Diagnostic; 74 75 /** {@link CompilerOptions} for the given processor. */ 76 public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions { 77 // EnumOption<T> doesn't support integer inputs so just doing this as a 1-off for now. 78 private static final String KEYS_PER_COMPONENT_SHARD = "dagger.keysPerComponentShard"; 79 80 private final XProcessingEnv processingEnv; 81 private final XMessager messager; 82 private final Map<String, String> options; 83 private final Map<EnumOption<?>, Object> enumOptions = new HashMap<>(); 84 private final Map<EnumOption<?>, ImmutableMap<String, ? extends Enum<?>>> allCommandLineOptions = 85 new HashMap<>(); 86 87 @Inject ProcessingEnvironmentCompilerOptions( XProcessingEnv processingEnv, XMessager messager, @ProcessingOptions Map<String, String> options)88 ProcessingEnvironmentCompilerOptions( 89 XProcessingEnv processingEnv, 90 XMessager messager, 91 @ProcessingOptions Map<String, String> options) { 92 this.processingEnv = processingEnv; 93 this.messager = messager; 94 this.options = options; 95 checkValid(); 96 } 97 98 @Override usesProducers()99 public boolean usesProducers() { 100 return processingEnv.findTypeElement(TypeNames.PRODUCES) != null; 101 } 102 103 @Override headerCompilation()104 public boolean headerCompilation() { 105 return isEnabled(HEADER_COMPILATION); 106 } 107 108 @Override fastInit(XTypeElement component)109 public boolean fastInit(XTypeElement component) { 110 return fastInitInternal(component); 111 } 112 fastInitInternal(XTypeElement component)113 private boolean fastInitInternal(XTypeElement component) { 114 return isEnabled(FAST_INIT); 115 } 116 117 @Override formatGeneratedSource()118 public boolean formatGeneratedSource() { 119 return isEnabled(FORMAT_GENERATED_SOURCE); 120 } 121 122 @Override writeProducerNameInToken()123 public boolean writeProducerNameInToken() { 124 return isEnabled(WRITE_PRODUCER_NAME_IN_TOKEN); 125 } 126 127 @Override nullableValidationKind()128 public Diagnostic.Kind nullableValidationKind() { 129 return diagnosticKind(NULLABLE_VALIDATION); 130 } 131 132 @Override privateMemberValidationKind()133 public Diagnostic.Kind privateMemberValidationKind() { 134 return diagnosticKind(PRIVATE_MEMBER_VALIDATION); 135 } 136 137 @Override staticMemberValidationKind()138 public Diagnostic.Kind staticMemberValidationKind() { 139 return diagnosticKind(STATIC_MEMBER_VALIDATION); 140 } 141 142 @Override includeStacktraceWithDeferredErrorMessages()143 public boolean includeStacktraceWithDeferredErrorMessages() { 144 return isEnabled(INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES); 145 } 146 147 @Override ignorePrivateAndStaticInjectionForComponent()148 public boolean ignorePrivateAndStaticInjectionForComponent() { 149 return isEnabled(IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT); 150 } 151 152 @Override scopeCycleValidationType()153 public ValidationType scopeCycleValidationType() { 154 return parseOption(DISABLE_INTER_COMPONENT_SCOPE_VALIDATION); 155 } 156 157 @Override validateTransitiveComponentDependencies()158 public boolean validateTransitiveComponentDependencies() { 159 return isEnabled(VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES); 160 } 161 162 @Override warnIfInjectionFactoryNotGeneratedUpstream()163 public boolean warnIfInjectionFactoryNotGeneratedUpstream() { 164 return isEnabled(WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM); 165 } 166 167 @Override fullBindingGraphValidationType()168 public ValidationType fullBindingGraphValidationType() { 169 return parseOption(FULL_BINDING_GRAPH_VALIDATION); 170 } 171 172 @Override pluginsVisitFullBindingGraphs(XTypeElement component)173 public boolean pluginsVisitFullBindingGraphs(XTypeElement component) { 174 return isEnabled(PLUGINS_VISIT_FULL_BINDING_GRAPHS); 175 } 176 177 @Override moduleHasDifferentScopesDiagnosticKind()178 public Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind() { 179 return diagnosticKind(MODULE_HAS_DIFFERENT_SCOPES_VALIDATION); 180 } 181 182 @Override explicitBindingConflictsWithInjectValidationType()183 public ValidationType explicitBindingConflictsWithInjectValidationType() { 184 return parseOption(EXPLICIT_BINDING_CONFLICTS_WITH_INJECT); 185 } 186 187 @Override experimentalDaggerErrorMessages()188 public boolean experimentalDaggerErrorMessages() { 189 return isEnabled(EXPERIMENTAL_DAGGER_ERROR_MESSAGES); 190 } 191 192 @Override ignoreProvisionKeyWildcards()193 public boolean ignoreProvisionKeyWildcards() { 194 return isEnabled(IGNORE_PROVISION_KEY_WILDCARDS); 195 } 196 197 @Override strictMultibindingValidation()198 public boolean strictMultibindingValidation() { 199 return isEnabled(STRICT_MULTIBINDING_VALIDATION); 200 } 201 202 @Override strictSuperficialValidation()203 public boolean strictSuperficialValidation() { 204 return isEnabled(STRICT_SUPERFICIAL_VALIDATION); 205 } 206 207 @Override generatedClassExtendsComponent()208 public boolean generatedClassExtendsComponent() { 209 return isEnabled(GENERATED_CLASS_EXTENDS_COMPONENT); 210 } 211 212 @Override keysPerComponentShard(XTypeElement component)213 public int keysPerComponentShard(XTypeElement component) { 214 if (options.containsKey(KEYS_PER_COMPONENT_SHARD)) { 215 checkArgument( 216 component.getClassName().packageName().startsWith("dagger."), 217 "Cannot set %s. It is only meant for internal testing.", KEYS_PER_COMPONENT_SHARD); 218 return Integer.parseInt(options.get(KEYS_PER_COMPONENT_SHARD)); 219 } 220 return super.keysPerComponentShard(component); 221 } 222 isEnabled(KeyOnlyOption keyOnlyOption)223 private boolean isEnabled(KeyOnlyOption keyOnlyOption) { 224 return options.containsKey(keyOnlyOption.toString()); 225 } 226 isEnabled(Feature feature)227 private boolean isEnabled(Feature feature) { 228 return parseOption(feature).equals(ENABLED); 229 } 230 diagnosticKind(Validation validation)231 private Diagnostic.Kind diagnosticKind(Validation validation) { 232 return parseOption(validation).diagnosticKind().get(); 233 } 234 235 @SuppressWarnings("CheckReturnValue") checkValid()236 private ProcessingEnvironmentCompilerOptions checkValid() { 237 for (Feature feature : Feature.values()) { 238 parseOption(feature); 239 } 240 for (Validation validation : Validation.values()) { 241 parseOption(validation); 242 } 243 noLongerRecognized(EXPERIMENTAL_ANDROID_MODE); 244 noLongerRecognized(FLOATING_BINDS_METHODS); 245 noLongerRecognized(EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS); 246 noLongerRecognized(USE_GRADLE_INCREMENTAL_PROCESSING); 247 if (!isEnabled(IGNORE_PROVISION_KEY_WILDCARDS)) { 248 if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP) { 249 processingEnv.getMessager().printMessage( 250 Diagnostic.Kind.ERROR, 251 String.format( 252 "When using KSP, you must also enable the '%s' compiler option (see %s).", 253 "dagger.ignoreProvisionKeyWildcards", 254 "https://dagger.dev/dev-guide/compiler-options#ignore-provision-key-wildcards")); 255 } 256 } 257 return this; 258 } 259 noLongerRecognized(CommandLineOption commandLineOption)260 private void noLongerRecognized(CommandLineOption commandLineOption) { 261 if (options.containsKey(commandLineOption.toString())) { 262 messager.printMessage( 263 Diagnostic.Kind.WARNING, commandLineOption + " is no longer recognized by Dagger"); 264 } 265 } 266 267 private interface CommandLineOption { 268 /** The key of the option (appears after "-A"). */ 269 @Override toString()270 String toString(); 271 272 /** 273 * Returns all aliases besides {@link #toString()}, such as old names for an option, in order of 274 * precedence. 275 */ aliases()276 default ImmutableList<String> aliases() { 277 return ImmutableList.of(); 278 } 279 280 /** All the command-line names for this option, in order of precedence. */ allNames()281 default Stream<String> allNames() { 282 return concat(Stream.of(toString()), aliases().stream()); 283 } 284 } 285 286 /** An option that can be set on the command line. */ 287 private interface EnumOption<E extends Enum<E>> extends CommandLineOption { 288 /** The default value for this option. */ defaultValue()289 E defaultValue(); 290 291 /** The valid values for this option. */ validValues()292 Set<E> validValues(); 293 } 294 295 enum KeyOnlyOption implements CommandLineOption { 296 HEADER_COMPILATION { 297 @Override toString()298 public String toString() { 299 return "experimental_turbine_hjar"; 300 } 301 }, 302 303 USE_GRADLE_INCREMENTAL_PROCESSING { 304 @Override toString()305 public String toString() { 306 return "dagger.gradle.incremental"; 307 } 308 }, 309 } 310 311 /** 312 * A feature that can be enabled or disabled on the command line by setting {@code -Akey=ENABLED} 313 * or {@code -Akey=DISABLED}. 314 */ 315 enum Feature implements EnumOption<FeatureStatus> { 316 FAST_INIT, 317 318 EXPERIMENTAL_ANDROID_MODE, 319 320 FORMAT_GENERATED_SOURCE, 321 322 WRITE_PRODUCER_NAME_IN_TOKEN, 323 324 WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM, 325 326 INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES, 327 328 IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT, 329 330 EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS, 331 332 FORCE_USE_SERIALIZED_COMPONENT_IMPLEMENTATIONS, 333 334 EMIT_MODIFIABLE_METADATA_ANNOTATIONS(ENABLED), 335 336 PLUGINS_VISIT_FULL_BINDING_GRAPHS, 337 338 FLOATING_BINDS_METHODS, 339 340 EXPERIMENTAL_DAGGER_ERROR_MESSAGES, 341 342 STRICT_MULTIBINDING_VALIDATION, 343 344 STRICT_SUPERFICIAL_VALIDATION(ENABLED), 345 346 GENERATED_CLASS_EXTENDS_COMPONENT, 347 348 IGNORE_PROVISION_KEY_WILDCARDS(ENABLED), 349 350 VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED) 351 ; 352 353 final FeatureStatus defaultValue; 354 Feature()355 Feature() { 356 this(DISABLED); 357 } 358 Feature(FeatureStatus defaultValue)359 Feature(FeatureStatus defaultValue) { 360 this.defaultValue = defaultValue; 361 } 362 363 @Override defaultValue()364 public FeatureStatus defaultValue() { 365 return defaultValue; 366 } 367 368 @Override validValues()369 public Set<FeatureStatus> validValues() { 370 return EnumSet.allOf(FeatureStatus.class); 371 } 372 373 @Override toString()374 public String toString() { 375 return optionName(this); 376 } 377 } 378 379 /** The diagnostic kind or validation type for a kind of validation. */ 380 enum Validation implements EnumOption<ValidationType> { 381 DISABLE_INTER_COMPONENT_SCOPE_VALIDATION(), 382 383 NULLABLE_VALIDATION(ERROR, WARNING), 384 385 PRIVATE_MEMBER_VALIDATION(ERROR, WARNING), 386 387 STATIC_MEMBER_VALIDATION(ERROR, WARNING), 388 389 /** Whether to validate full binding graphs for components, subcomponents, and modules. */ FULL_BINDING_GRAPH_VALIDATION(NONE, ERROR, WARNING)390 FULL_BINDING_GRAPH_VALIDATION(NONE, ERROR, WARNING) { 391 @Override 392 public ImmutableList<String> aliases() { 393 return ImmutableList.of("dagger.moduleBindingValidation"); 394 } 395 }, 396 397 /** 398 * How to report conflicting scoped bindings when validating partial binding graphs associated 399 * with modules. 400 */ 401 MODULE_HAS_DIFFERENT_SCOPES_VALIDATION(ERROR, WARNING), 402 403 /** 404 * How to report that an explicit binding in a subcomponent conflicts with an {@code @Inject} 405 * constructor used in an ancestor component. 406 */ 407 EXPLICIT_BINDING_CONFLICTS_WITH_INJECT(ERROR, WARNING, NONE), 408 ; 409 410 final ValidationType defaultType; 411 final ImmutableSet<ValidationType> validTypes; 412 Validation()413 Validation() { 414 this(ERROR, WARNING, NONE); 415 } 416 Validation(ValidationType defaultType, ValidationType... moreValidTypes)417 Validation(ValidationType defaultType, ValidationType... moreValidTypes) { 418 this.defaultType = defaultType; 419 this.validTypes = immutableEnumSet(defaultType, moreValidTypes); 420 } 421 422 @Override defaultValue()423 public ValidationType defaultValue() { 424 return defaultType; 425 } 426 427 @Override validValues()428 public Set<ValidationType> validValues() { 429 return validTypes; 430 } 431 432 @Override toString()433 public String toString() { 434 return optionName(this); 435 } 436 } 437 optionName(Enum<? extends EnumOption<?>> option)438 private static String optionName(Enum<? extends EnumOption<?>> option) { 439 return "dagger." + UPPER_UNDERSCORE.to(LOWER_CAMEL, option.name()); 440 } 441 442 /** The supported command-line options. */ supportedOptions()443 public static ImmutableSet<String> supportedOptions() { 444 // need explicit type parameter to avoid a runtime stream error 445 return ImmutableSet.<String>builder() 446 .addAll( 447 Stream.<CommandLineOption[]>of( 448 KeyOnlyOption.values(), Feature.values(), Validation.values()) 449 .flatMap(Arrays::stream) 450 .flatMap(CommandLineOption::allNames) 451 .collect(toImmutableSet())) 452 .add(KEYS_PER_COMPONENT_SHARD) 453 .build(); 454 } 455 456 /** 457 * Returns the value for the option as set on the command line by any name, or the default value 458 * if not set. 459 * 460 * <p>If more than one name is used to set the value, but all names specify the same value, 461 * reports a warning and returns that value. 462 * 463 * <p>If more than one name is used to set the value, and not all names specify the same value, 464 * reports an error and returns the default value. 465 */ parseOption(EnumOption<T> option)466 private <T extends Enum<T>> T parseOption(EnumOption<T> option) { 467 @SuppressWarnings("unchecked") // we only put covariant values into the map 468 T value = (T) enumOptions.computeIfAbsent(option, this::parseOptionUncached); 469 return value; 470 } 471 isSetOnCommandLine(Feature feature)472 private boolean isSetOnCommandLine(Feature feature) { 473 return getUsedNames(feature).count() > 0; 474 } 475 parseOptionUncached(EnumOption<T> option)476 private <T extends Enum<T>> T parseOptionUncached(EnumOption<T> option) { 477 ImmutableMap<String, T> values = parseOptionWithAllNames(option); 478 479 // If no value is specified, return the default value. 480 if (values.isEmpty()) { 481 return option.defaultValue(); 482 } 483 484 // If all names have the same value, return that. 485 if (values.asMultimap().inverse().keySet().size() == 1) { 486 // Warn if an option was set with more than one name. That would be an error if the values 487 // differed. 488 if (values.size() > 1) { 489 reportUseOfDifferentNamesForOption(Diagnostic.Kind.WARNING, option, values.keySet()); 490 } 491 return values.values().asList().get(0); 492 } 493 494 // If different names have different values, report an error and return the default 495 // value. 496 reportUseOfDifferentNamesForOption(Diagnostic.Kind.ERROR, option, values.keySet()); 497 return option.defaultValue(); 498 } 499 reportUseOfDifferentNamesForOption( Diagnostic.Kind diagnosticKind, EnumOption<?> option, ImmutableSet<String> usedNames)500 private void reportUseOfDifferentNamesForOption( 501 Diagnostic.Kind diagnosticKind, EnumOption<?> option, ImmutableSet<String> usedNames) { 502 messager.printMessage( 503 diagnosticKind, 504 String.format( 505 "Only one of the equivalent options (%s) should be used; prefer -A%s", 506 usedNames.stream().map(name -> "-A" + name).collect(joining(", ")), option)); 507 } 508 parseOptionWithAllNames( EnumOption<T> option)509 private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNames( 510 EnumOption<T> option) { 511 @SuppressWarnings("unchecked") // map is covariant 512 ImmutableMap<String, T> aliasValues = 513 (ImmutableMap<String, T>) 514 allCommandLineOptions.computeIfAbsent(option, this::parseOptionWithAllNamesUncached); 515 return aliasValues; 516 } 517 parseOptionWithAllNamesUncached( EnumOption<T> option)518 private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNamesUncached( 519 EnumOption<T> option) { 520 ImmutableMap.Builder<String, T> values = ImmutableMap.builder(); 521 getUsedNames(option) 522 .forEach( 523 name -> parseOptionWithName(option, name).ifPresent(value -> values.put(name, value))); 524 return values.build(); 525 } 526 parseOptionWithName(EnumOption<T> option, String key)527 private <T extends Enum<T>> Optional<T> parseOptionWithName(EnumOption<T> option, String key) { 528 checkArgument(options.containsKey(key), "key %s not found", key); 529 String stringValue = options.get(key); 530 if (stringValue == null) { 531 messager.printMessage(Diagnostic.Kind.ERROR, "Processor option -A" + key + " needs a value"); 532 } else { 533 try { 534 T value = 535 Enum.valueOf(option.defaultValue().getDeclaringClass(), Ascii.toUpperCase(stringValue)); 536 if (option.validValues().contains(value)) { 537 return Optional.of(value); 538 } 539 } catch (IllegalArgumentException e) { 540 // handled below 541 } 542 messager.printMessage( 543 Diagnostic.Kind.ERROR, 544 String.format( 545 "Processor option -A%s may only have the values %s (case insensitive), found: %s", 546 key, option.validValues(), stringValue)); 547 } 548 return Optional.empty(); 549 } 550 getUsedNames(CommandLineOption option)551 private Stream<String> getUsedNames(CommandLineOption option) { 552 return option.allNames().filter(options::containsKey); 553 } 554 } 555