Package org.spongepowered.asm.mixin.injection

## Annotation Type ModifyVariable

    @Target(METHOD)
    @Retention(RUNTIME)
    public @interface ModifyVariable

Specifies that this mixin method should inject a variable modifier callback to itself in the target method(s) identified by `method()`. The variable modifier can modify a single local variable in the target method frame.

If the variable being modified is a method argument, specifying the ``argsOnly=true`` reduces the overhead of calculating the local variable table for the method.

`ModifyVariable` callbacks should always take one argument of the type to capture and return the same type. For example a `ModifyVariable` for a local of type `String` should have the signature:

> `private String myHandlerMethod(String variable) {
> ...`

The callback receives the current value of the local variable, and should return the new value.

The injector has two operating modes, explicit and implicit , and can operate either on the entire LVT or on the `method arguments only`.

#### Explicit mode

In explicit mode, the variable to capture can be specified by specifying values for the discriminator arguments `ordinal()`, `index()` and `name()`. The injector uses the discriminators in order to attempt to locate the variable to capture. If no local variable matches any discriminators, the capture fails.

#### Implicit mode

If no values for the capture discrimiators are specified, the injector operates in implicit mode. If exactly one variable of the capture type exists in the target LVT, then capture will succeed. However, if more than one variable of the required type is encountered in the LVT then an `InvalidInjectionException` is thrown.

#### Context-sensitive injection points

Normally the `injection points` specified by `at()` are independent of the injector being used. With `ModifyVariable` there are two special injection points which consume the discriminator from the annotation:

- `LOAD` - matches `xLOAD` insns for the variable matched by the discriminator in the target method.
- `STORE` - matches `xSTORE` insns for the variable matched by the discriminator in the target method.

See the javadoc for each injection point for details.

#### Notes

Like other injectors, the callback signature can optionally include the target method arguments by simply appending them to the handler method signature.

### Required Element Summary

Required Elements
`At` `at` An `At` annotation which describes the `InjectionPoint` in the target method.

### Optional Element Summary

Optional Elements
`int` `allow` Injection points are in general expected to match every candidate instruction in the target method or slice, except in cases where options such as `At.ordinal()` are specified which naturally limit the number of results.
`boolean` `argsOnly` Under normal circumstances the injector will consider all local variables including method arguments and all other local variables.
`java.lang.String` `constraints` Returns constraints which must be validated for this injector to succeed.
`int` `expect` Like `require()` but only enabled if the `mixin.debug.countInjections` option is set to `true` and defaults to 1.
`int` `index` Gets the absolute index of the local variable within the local variable table to capture.
`java.lang.String[]` `method` String representation of one or more `target selectors` which identify the target methods.
`java.lang.String[]` `name` Gets the name of the variable to capture.
`int` `order` By default almost all injectors for a target class apply their injections at the same time.
`int` `ordinal` Gets the local variable ordinal by type.
`boolean` `print` When creating a `ModifyVariable` callback, you may wish to first inspect the local variable table in the target method at the injection point.
`boolean` `remap` By default, the annotation processor will attempt to locate an obfuscation mapping for all `ModifyVariable` methods since it is anticipated that in general the target of a `ModifyVariable` annotation will be an obfuscated method in the target class.
`int` `require` In general, injectors are intended to "fail soft" in that a failure to locate the injection point in the target method is not considered an error condition.
`Slice` `slice` A `Slice` annotation which describes the method bisection used in the `at()` query for this injector.
`Desc[]` `target` Literal representation of one or more `@Desc` annotations which identify the target methods.

### Element Detail

#### at

    At at

An `At` annotation which describes the `InjectionPoint` in the target method.

Returns:
  `At` which identifies the location to inject inside the target method.

#### method

    java.lang.String[] method

String representation of one or more `target selectors` which identify the target methods.

Returns:
  target method(s) for this injector

Default:
  {}

#### target

    Desc[] target

Literal representation of one or more `@Desc` annotations which identify the target methods.

Returns:
  target method(s) for this injector as descriptors

Default:
  {}

#### slice

    Slice slice

A `Slice` annotation which describes the method bisection used in the `at()` query for this injector.

Returns:
  slice

Default:
  @org.spongepowered.asm.mixin.injection.Slice

#### print

    boolean print

When creating a `ModifyVariable` callback, you may wish to first inspect the local variable table in the target method at the injection point. Set this value to `true` to print the local variable table and perform no injection.

Returns:
  true to print the LVT to the console

Default:
  false

#### ordinal

    int ordinal

Gets the local variable ordinal by type. For example, if there are 3 `String` arguments in the local variable table, ordinal 0 specifies the first, 1 specifies the second, etc. Use `ordinal` when the index within the LVT is known. Takes precedence over `index()`.

Returns:
  variable ordinal

Default:
  -1

#### index

    int index

Gets the absolute index of the local variable within the local variable table to capture. The local variable at the specified index must be of the same type as the capture. Takes precedence over `name()`.

Returns:
  argument index to modify or -1 for automatic

Default:
  -1

#### name

    java.lang.String[] name

Gets the name of the variable to capture. Only used if the variable cannot be located via `ordinal()` or `index()`.

Returns:
  possible names to capture, only useful when the LVT in the target method is known to be complete.

Default:
  {}

#### argsOnly

    boolean argsOnly

Under normal circumstances the injector will consider all local variables including method arguments and all other local variables. This involves reading (and possibly generating) the local variable table for the method which can have mixed results. Set this value to `true` to only consider method arguments.

Returns:
  true if this injector should only consider method arguments and not all locals.

Default:
  false

#### remap

    boolean remap

By default, the annotation processor will attempt to locate an obfuscation mapping for all `ModifyVariable` methods since it is anticipated that in general the target of a `ModifyVariable` annotation will be an obfuscated method in the target class. However since it is possible to also apply mixins to non-obfuscated targets (or non- obfuscated methods in obfuscated targets, such as methods added by Forge) it may be necessary to suppress the compiler error which would otherwise be generated. Setting this value to false will cause the annotation processor to skip this annotation when attempting to build the obfuscation table for the mixin.

Returns:
  True to instruct the annotation processor to search for obfuscation mappings for this annotation

Default:
  true

#### require

    int require

In general, injectors are intended to "fail soft" in that a failure to locate the injection point in the target method is not considered an error condition. Another transformer may have changed the method structure or any number of reasons may cause an injection to fail. This also makes it possible to define several injections to achieve the same task given expected mutation of the target class and the injectors which fail are simply ignored.

However, this behaviour is not always desirable. For example, if your application depends on a particular injection succeeding you may wish to detect the injection failure as an error condition. This argument is thus provided to allow you to stipulate a minimum number of successful injections for this callback handler. If the number of injections specified is not achieved then an `InjectionError` is thrown at application time. Use this option with care.

Returns:
  Minimum required number of injected callbacks, default specified by the containing config

Default:
  -1

#### expect

    int expect

Like `require()` but only enabled if the `mixin.debug.countInjections` option is set to `true` and defaults to 1. Use this option during debugging to perform simple checking of your injectors. Causes the injector to throw a `InvalidInjectionException` if the expected number of injections is not realised.

Returns:
  Minimum number of expected callbacks, default 1

Default:
  1

#### allow

    int allow

Injection points are in general expected to match every candidate instruction in the target method or slice, except in cases where options such as `At.ordinal()` are specified which naturally limit the number of results.

This option allows for sanity-checking to be performed on the results of an injection point by specifying a maximum allowed number of matches, similar to that afforded by `Group.max()`. For example if your injection is expected to match 4 invocations of a target method, but instead matches 5, this can become a detectable tamper condition by setting this value to `4`.

Setting any value 1 or greater is allowed. Values less than 1 or less than `require()` are ignored. `require()` supercedes this argument such that if `allow` is less than `require` the value of `require` is always used.

Note that this option is not a limit on the query behaviour of this injection point. It is only a sanity check used to ensure that the number of matches is not too high

Returns:
  Maximum allowed number of injections for this

Default:
  -1

#### constraints

    java.lang.String constraints

Returns constraints which must be validated for this injector to succeed. See `ConstraintParser.Constraint` for details of constraint formats.

Returns:
  Constraints for this annotation

Default:
  ""

#### order

    int order

By default almost all injectors for a target class apply their injections at the same time. In other words, if multiple mixins target the same class then injectors are applied in priority order (since the mixins themselves are merged in priority order, and injectors run in the order they were merged). The exception being redirect injectors, which apply in a later pass.

The default order for injectors is `1000`, and redirect injectors use `10000`.

Specifying a value for `order` alters this default behaviour and causes the injector to inject either earlier or later than it normally would. For example specifying `900` will cause the injector to apply before others, while `1100` will apply later. Injectors with the same `order` will still apply in order of their mixin's `priority`.

Returns:
  the application order for this injector, uses DEFAULT (1000) if not specified

Default:
  1000