Package org.spongepowered.asm.mixin.injection

## Annotation Type ModifyConstant

-     @Documented
      @Retention(RUNTIME)
      public @interface ModifyConstant

  The `ModifyConstant` annotation allows to apply a function on a single constant after pushing the constant onto the operand stack. More specifically, the mixin implementation will call the constant modifier handler with the original constant value. The handler will then return the modified value which replaces the original value on the operand stack.

  ### Chaining

  While the original value can be constant, it is not guaranteed to be so. Micromixin-transformer and the spongeian mixin implementation allow `ModifyConstant` to "chain", that is multiple constant modifier handlers can target the same constant and the result of one constant modifier handler will be used as the input of the other. Or, in laymen's terms, the resulting code would look something like follows:

  > `modifyConstant0(modifyConstant1(CONSTANT))`

  In this case, modifyConstant0 has a lower `priority` than modifyConstant1 or applied before modifyConstant1 due to other (usually implementation-specific) reasons. If the ordering of constant modifiers is important, then it is necessary to set the mixin priority as necessary as otherwise the ordering is not guaranteed to stay constant, potentially causing intermittent hard-to-reproduce bugs.

  ### Signature and visibility modifiers

  The `ModifyConstant` handler (also known as the "constant modifier") MUST declare the same return type (subtypes are not supported) as its argument type (supertypes are not supported). If the targeted method is `static`, the handler MUST be `static` and `private`. For non-`static` targets the access modifiers are not of relevance, except for constructors where the handler must be `static` when not injecting immediately before the final return via `TAIL`.

  The value that is modified must be the first argument of the constant value modifier handler method. All other arguments are there for argument capture.

  ### Argument and local capture

  At this point in time, local capture is not supported.

  Argument capture behaves the same way as `ModifyReturnValue`. The arguments that can be captured are the arguments with whom the target method was called with (do note that it is permissible for the values to be reassigned - so while it guarantees the argument was captured, the value of the argument may have been altered) - or more plainly, argument capture means that the arguments of the target method are captured and passed to the return value modifier handler method.

  Captured arguments must be defined in the same order as the target method. It is not permissible to "skip" arguments, but it is permissible to not capture trailing arguments - leading arguments need to be captured however under the premise of the "no skipping" requirement.

  Reassigning captured arguments in the constant value modifier method has no effect on the target method. As such, the behaviour is quite similar to the argument and local variable capture behaviour of `Inject`.

  ### Example use and produced bytecode

  Assume the following target method:

  >      public static void main() {
  >        System.out.println("Test!");
  >      }

  The above target method can be modified with following handler to instead produce "Hello World.":

  >      @ModifyConstant(target = @Desc("main"), constant = @Constant(stringValue = "Test!"))
  >      private static String modifyConstant(String originalValue) {
  >          return "Hello World.";
  >      }

  This produces following bytecode:

  >      GETSTATIC java/lang/System.out Ljava/io/PrintStream;
  >      LDC "Test!"
  >      + INVOKESTATIC TargetClass.modifyConstant(Ljava/lang/String;)Ljava/lang/String;
  >      INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V

  which is equivalent to following code:

  >      public static void main() {
  >        System.out.println(modifyConstant("Test!"));
  >      }

- - ### Optional Element Summary

    Optional Elements
    Modifier and Type | Optional Element | Description
    --- | --- | ---
    `int` | `allow` | The maximum amount of injection points that should be allowed.
    `Constant[]` | `constant` | The list of constants the constant modifier should target.
    `int` | `expect` | The expected amount of injection points.
    `java.lang.String[]` | `method` | The targeted method selectors.
    `int` | `require` | The minimum amount of injection points.
    `Slice[]` | `slice` | The available slices used for bisecting the available injection points declared by `constant()`.
    `Desc[]` | `target` | The targeted methods.Only one method is picked from the list of provided methods.

- - ### Element Detail

    - #### allow

          int allow

      The maximum amount of injection points that should be allowed. If the value of this element is below 1 or if the value is below the `minimum amount` of allowable injection points then the limit is not being enforced. However, `expect()` has no influence on `allow()`.

      Furthermore this limit is only valid per target class. That is, if multiple target classes are defined as per `Mixin.value()` or `Mixin.targets()` then this limit is only applicable for all the injection points in the targeted class. This limitation is caused due to the fact that the targeted classes are not known until they are loaded in by the classloader, at which point all the injection logic occurs.

      This limit is shared across all methods (as defined by `method()` or `target()`) targeted by the handler within a class.

      Returns:
        The maximum amount targeted of injection points within the target class.
      Default:
        -1

  - - #### constant

          Constant[] constant

      The list of constants the constant modifier should target.

      If multiple constants are provided or if the constant occurs multiple times within the respective `slice`, then all occurrences of all constants are matched.

      If the list is empty or undefined, then a special injection point selector is used that matches any constant that matches the modifier method's accepted type (be weary when using this feature with null values - this behaviour isn't guaranteed to be stable for null values).

      This list behaves quite similarly to `Inject.at()` and micromixin-transformer's internal representation of this field is mostly identical to `Inject.at()`. While doing so greatly reduces expenses in required coding time, it has the unfortunate side effect that micromixin-transformer cannot validate the passed `constants`. In other words: It trusts you (the API consumer) to specify valid constants and will fail in unexpected ways if this assumption doesn't hold true. HOWEVER, this behaviour is subject to change and shouldn't be relied upon.

      Returns:
        A list of constants to target
      Default:
        {}

  - - #### expect

          int expect

      The expected amount of injection points. This behaves similar to `require()`, however while `require()` will cause a class file transformation failure, `expect()` is a weaker form of it. Under the spongeian implementation, this attribute behaves like `require()` if and only if the appropriate debug flags are activated. The micromixin transformer will meanwhile "just" unconditionally write a warning to the logger.

      This attribute should be used to identify potentially outdated injectors.

      Returns:
        The expected amount of injection points
      Default:
        -1

  - - #### method

          java.lang.String[] method

      The targeted method selectors. The amounts of methods that may match and are selected is not bound to any hard value and as such it should be limited by setting attributes such as `require()` or `expect()` as otherwise the injector might accidentally not match anything with no way of knowing what exactly went wrong.

      The following are all valid formats of explicit target selectors:

      - `targetMethod`
      - `targetMethod(Lcom/example/Argument;)V`
      - `(Lcom/example/Argument;)V`
      - `targetMethod(I)Lcom/example/ReturnValue;`
      - `targetMethod()Z`
      - `Lcom/example/Target;targetMethod(Lcom/example/Argument;)V`
      - `Lcom/example/Target;(Lcom/example/Argument;)V`
      - `Lcom/example/Target;targetMethod(Lcom/example/Argument;) V`
      - `Lcom/example/Target;target Method(Lcom/example/Argument;)V`
      - `Lcom/example/Target;targetMethod(Lcom/exam ple/Argument;)V`

      The parts of the explicit target selector (owner, name, descriptor) must always have the same order, but the individual parts must not necessarily be present.

      While permissible, it is strongly discouraged to make use of whitespace in explicit target selectors. When they are used, the spongeian mixin implementation (and also micromixin) will discard all whitespace characters (tabs included). This is documented behaviour (in both micromixin and sponge's mixin) and is unlikely to change in the future. This discouragement exists as this feature may cause target selectors to be illegible.

      It is generally recommended to not be lazy when it comes to explicit selectors, the more information is provided the better. Information that is not supplied is comparable to a wildcard - the first matching method will be targeted, even if nonsense. It is especially not recommended to discard the method name, even if that is theoretically valid.

      The spongeian implementation also supports schemes other than the explicit selectors. However the Micromixin implementation only supports explicit selectors as documented above. Where as the spongeian implementation supports quantifiers in explicit selectors, Micromixin does not support them (yet). As such, quantifiers are not included in the documentation.

      It is rather advisable to use `target()` over `method()`, especially for beginners, since latter provides behaviour that can more easily be anticipated.

      Returns:
        The target selectors that define the target method of the handler.
      Default:
        {}

  - - #### require

          int require

      The minimum amount of injection points. If less injection points are found (as per `constant()`). an exception is thrown during transformation. The default amount of required injection points can be set by mixin configuration file, but by default that is no minimum amount of required injection points.
      Returns:
        The minimum amount of injection points
      Default:
        -1

  - - #### slice

          Slice[] slice

      The available slices used for bisecting the available injection points declared by `constant()`.
      Returns:
        An array of declared slices.
      Default:
        {}

  - - #### target

          Desc[] target

      The targeted methods.Only one method is picked from the list of provided methods. As such the list should generally only be used to mark method aliases among others.
      Returns:
        The target selectors that define the target method of the handler.
      Default:
        {}