/* * This file is part of Mixin, licensed under the MIT License (MIT). * * Copyright (c) SpongePowered * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.spongepowered.asm.mixin.injection; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.points.*; /** * Annotation for specifying the type of {@link InjectionPoint} to use to * perform an {@link Inject} process. This annotation allows the * {@link InjectionPoint} class to be specified, as well as arguments to be * passed to the {@link InjectionPoint} instance to configure it. The data * contained in the annotation are wrapped into a * {@link org.spongepowered.asm.mixin.injection.struct.InjectionInfo * InjectionInfo} object before being passed to the {@link InjectionPoint} for * parsing. All values are optional apart from {@link #value}, which specifies * the type of {@link InjectionPoint} to use. All other parameters depend on the * InjectionPoint chosen, and the javadoc for each {@link InjectionPoint} class * should be consulted for the meaning of the argument to that particular class. * A general description of each parameter is provided below. */ @Target({ /* No targets allowed */ }) @Retention(RetentionPolicy.RUNTIME) public @interface At { /** * Shift is used to shift resulting opcodes */ public enum Shift { /** * Do not shift the returned opcodes */ NONE, /** * Shift the returned opcodes back one instruction */ BEFORE, /** * Shift the returned opcodes forward one instruction */ AFTER, /** * Shift the returned opcodes by the amount specified in {@link At#by} */ BY } /** * The identifier for this injection point, can be retrieved via the * {@link CallbackInfo#getId} accessor. If specified, the ID is appended to * the value specified in the outer annotion. Eg. specifying "foo" for this * attribute and "bar" for the Inject.{@link Inject#id} attribute * will result in a combined id of "bar:foo". Note that if no id * is specified for the outer injector, the name of the calling method is * used. * * @return the injection point id to use */ public String id() default ""; /** *

Type of {@link InjectionPoint} to use. Can be a built-in class or the * fully-qualified name of a custom class which extends * {@link InjectionPoint}.

* *

Built-in types are * {@link MethodHead HEAD}, * {@link BeforeReturn RETURN}, * {@link BeforeFinalReturn TAIL}, * {@link BeforeInvoke INVOKE}, * {@link AfterInvoke INVOKE_ASSIGN}, * {@link BeforeFieldAccess FIELD}, * {@link BeforeNew NEW}, * {@link BeforeStringInvoke INVOKE_STRING}, * {@link JumpInsnPoint JUMP} and * {@link BeforeConstant CONSTANT}. * See the javadoc for each type for more details on the scheme used by each * injection point.

* * @return Injection point specifier or fully-qualified class name */ public String value(); /** * For {@link Inject} queries, this specifies the ID of the slice to use for * this query. For other injector types it is ignored because only one slice * is supported. * *

For more details see the {@link Slice#id}

* * @return the slice identifier, or empty string to use the default slice */ public String slice() default ""; /** * Shift type for returned opcodes. For example use {@link At.Shift#AFTER * AFTER} with an INVOKE InjectionPoint to move the returned opcodes to * after the invoation. Use {@link At.Shift#BY BY} in conjunction * with the {@link #by} parameter to shift by an arbitrary number of * opcodes. * * @return Type of shift to apply */ public Shift shift() default Shift.NONE; /** * If {@link #shift} is specified as {@link At.Shift#BY BY}, specifies the * number of opcodes to shift by (negative numbers are allowed). Note that * values above 3 should be avoided and in general either replaced * with a custom injection point or with sliced injection points. The * warning/error threshold is defined by the config (with a hard limit on * value of {@link InjectionPoint#MAX_ALLOWED_SHIFT_BY}) * * @return Amount of shift to apply for the {@link At.Shift#BY BY} shift */ public int by() default 0; /** *

The named arguments list is used to expand the scope of the * annotation beyond the fixed values below in order to accommodate the * needs of custom injection point classes.

* * @return Named arguments for the injection point */ public String[] args() default { }; /** * Target identifier used by INVOKE, INVOKE_STRING, INVOKE_ASSIGN, FIELD and * NEW. This must be specified as a fully-qualified member path * including the class name and signature. Failing to fully-qualify the * target member will result in an error at obfuscation time. * * @return target reference for supported InjectionPoint types */ public String target() default ""; /** * Target descriptor used in place of string-based descriptors for * {@link #target} */ public Desc desc() default @Desc(""); /** * Ordinal offset. Many InjectionPoints will return every opcode matching * their criteria, specifying ordinal allows a particular opcode to * be identified from the returned list. The default value of -1 does not * alter the behaviour and returns all matching opcodes. Specifying a value * of 0 or higher returns only the requested opcode (if one exists: * for example specifying an ordinal of 4 when only 2 opcodes are matched by * the InjectionPoint is not going to work particularly well!) * * @return ordinal value for supported InjectionPoint types */ public int ordinal() default -1; /** * Target opcode for FIELD and JUMP InjectionPoints. See the javadoc for the * relevant injection point for more details. * * @return Bytecode opcode for supported InjectionPoints */ public int opcode() default -1; /** * By default, the annotation processor will attempt to locate an * obfuscation mapping for the {@link #target} member and any other * {@link #args} known to contain potentially obfuscated references, since * it is anticipated that in general the target of an {@link At} annotation * will be an obfuscated method or field. However since it is also possible * that the target is a non-obfuscated reference 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. * * @return True to instruct the annotation processor to search for * obfuscation mappings for this annotation */ public boolean remap() default true; /** * In general, injecting into constructors should be treated with care, * since compiled constructors - unlike regular methods - contain other * structural elements of the class, including implied (when not explicit) * superconstructor calls, explicit superconstructor or other delegated * constructor calls, field initialisers and code from initialiser blocks, * and of course the code from the original "constructor". * *

This means that unlike targetting a regular method, where it's often * possible to derive a reasonable injection point from the Java source, in * a constructor such assumptions can be dangerous. For example the HEAD * of a regular method will always mean "before the first * instruction", however in a constructor it's not possible to reasonably * ascertain what the first instruction will actually be without inspecting * the bytecode. This will certainly be prior to the delegate constructor * call, which might come as a surprise if the delegate constructor is not * explicit. Ultimately this means that for constructor code which appears * before the regular constructor body, the class can be in a * partially-initialised state (during initialisers) or in a * fully-uninitialised state (prior to the delegate constructor call).

* *

Because of this, by default certain injectors restrict usage to only * RETURN opcodes when targetting a constructor, in order to ensure * that the consumers are properly aware of the potential pitfalls. Whilst * it was previously necessary to create a custom injection point in order * to bypass this restriction, setting this option to true will * also allow other injectors to act upon constructors, though care should * be taken to ensure that the target is properly specified and attention is * paid to the structure of the target bytecode.

* * FABRIC CHANGE: true by default. * */ public boolean unsafe() default true; }