Package com.llamalad7.mixinextras.injector

## Annotation Type ModifyReturnValue

-     @Documented
      @Retention(RUNTIME)
      @Target(METHOD)
      public @interface ModifyReturnValue

  The `ModifyReturnValue` annotation allows to apply a function on the return value of a method. More specifically, the mixin implementation will call the modify return value handler with the original return value and return the actual return value.

  ### Availability

  This annotation is not available as-is on the spongeian mixin implementation and is part of Llamalad7's MixinExtras. Please refer to your launcher documentation for more details. Recent release of SLL's launcher-sponge variant should come with MixinExtras already bundled by default. However, as MixinExtras is widely used in the minecraft scene it is very likely that your loader supports it, provided you are either using SLL or a loader written for minecraft (such as neoforge or fabric).

  ### ModifyReturnValue versus Inject

  Usage of `ModifyReturnValue` should be preferred over other annotations such as `Inject` for it's supposed capability of being easily and safely chained. In truth we do not see if that is really the case under the micromixin-transformer implementation. Usage of

  >      @Inject(...)
  >      private void handleCallback(CallbackInfoReturnable<T> cir) {
  >           cir.setReturnValue(apply(cir.getReturnValue()));
  >      }

  can and should be replaced with

  >      @ModifyReturnValue(...)
  >      private T handleCallback(T original) {
  >           return apply(original);
  >      }

  Aside from the aforementioned improvements this annotations does not (as seen above) allocate a `CallbackInfoReturnable` and is as such more performant. It should as such be used in hot code whenever appropriate. While the assumption that the CallbackInfoReturnable allocation will get inlined or otherwise optimized in the JVM may be true, some JVMs might not follow this and will show a notable performance gain when using this annotation over `Inject`.

  ### Signature and visibility modifiers

  The `ModifyReturnValue` handler (also known as the "return value modifier") MUST declare the same return type (subtypes are not supported) as the return type of the targeted method. 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 handler should furthermore also have the original return type (supertypes are not supported) as it's argument.

  The value that is modified must be the first argument of the return 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 `ModifyConstant`. 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 return 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`.

- - ### Required Element Summary

    Required Elements
    Modifier and Type | Required Element | Description
    --- | --- | ---
    `At[]` | `at` | The injection points where the injection should occur.
    `java.lang.String[]` | `method` | The targeted method selectors.

  - ### Optional Element Summary

    Optional Elements
    Modifier and Type | Optional Element | Description
    --- | --- | ---
    `int` | `allow` | The maximum amount of injection points that should be allowed.
    `int` | `expect` | The expected amount of injection points.
    `int` | `require` | The minimum amount of amount of injection points.
    `Slice[]` | `slice` | The available slices used for bisecting the available injection points declared by `at()`.

- - ### Element Detail

    - #### at

          At[] at

      The injection points where the injection should occur. If none of the injection points apply no exception is thrown by default (this default can be changed through `require()`), however transformation does not occur (Micromixin still copies the handler into the target class anyways).

      For `ModifyReturnValue` the injection points MUST target return instructions. If that is not the case, the class will fail to transform.

      Returns:
        The injection points.

  - - #### 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.

      MixinExtra does not support target matching via `Desc`. It is likely that this feature will never be implemented by MixinExtra as the developer finds that feature superfluous. While the micromixin-transformer does implement that feature regardless, making use of the feature would require a custom annotation library for as long as Mixin implementations based on the spongeian mixin implementation remain viable in the galimulator modding space and the strict interoperability between the implementations is needed.

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

  - - #### 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()`) targeted by the handler within a class.

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

  - - #### 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

  - - #### require

          int require

      The minimum amount of amount of injection points. If less injection points are found (as per `at()`). 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 `at()`.
      Returns:
        An array of declared slices.
      Default:
        {}