package org.stianloader.remapper; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonBlocking; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * A {@link HierarchyAwareMappingDelegator} is an implementation of {@link MappingLookup} that binds mappings of class members * provided by {@link MappingSink#remapMember(MemberRef, String)} to their top level definition. The actual storage of mappings * are handled by a defined delegated {@link MappingLookup} (which also implements the {@link MappingSink} instance) of type * T. * *
The main point in using this delegator is in ensuring that disjointed method overrides do not happen, although this * {@link MappingLookup} still allows for name collisions to occur (unless the delegate prohibits it - read up on the * behaviour of delegates) * *
All implementations of {@link TopLevelMemberLookup} provided by stianloader-remapper are immutable and thus fully * thread safe, unless explicitly stated otherwise, however thread safety is not necessarily a required aspect for * implementors, although it is recommended to take advantage of it in order to reduce the required work for those that * wish to employ concurrency in their software (which could be you!). */ public interface TopLevelMemberLookup { /** * Obtain the root-level definition of a member. * *
Beware that this method may be called for fields and static methods, too. * It is imperative that the declaration of fields is also followed as it is possible for javac to emit * GETFIELD and PUTFIELD requests where the owner does not match the class where the field in question * is defined - this for example might be produced by anonymous enum members. * *
Implementors are free to handle bridge methods as they please - the only requirement is that * they do it persistently and that implementors should be aware that this would cause the bridge methods * to potentially have the same name as the method it bridges to. This interface does not mandate any * behaviour towards bridge methods and they may be ignored completely (this most likely won't have * any notable repercussions anyways unless the codebase in question uses a lot of generics - however, * generics are likely to be absent anyways in which case searching for bridge methods may be a bit * superfluous). * *
Changing the computational type of the descriptor of the member * is not permitted and will result in an exception being thrown in * {@link HierarchyAwareMappingDelegator#remapMember(MemberRef, String)}. * However, outside of that changing the descriptor of a method is permitted, as might * for example be needed for bridge methods. * *
Implementations should return the original source reference for classes or methods they do not know. * Under rare cases it is possible for methods to change their descriptor in the JRE, so this fact shouldn't be * ignored even if the implementation should handle JRE classes (this specification recommends against * handling inheritance beyond the application that needs to be remapped). * *
Returning a {@link MemberRef} in a non-source namespace is permissible, but it is highly recommended against doing * so. That being said, the input {@link MemberRef} MUST be in the source namespace. * *
lookupDelegate of type T
* and a given {@link TopLevelMemberLookup}.
*
* @param lookupDelegate The object to which all lookup and sink calls are delegated to.
* @param definitionLookup The lookup that is used to acquire the top-level definition of a class member.
*/
public HierarchyAwareMappingDelegator(@NotNull T lookupDelegate, @NotNull TopLevelMemberLookup definitionLookup) {
this.definitionLookup = definitionLookup;
this.delegate = lookupDelegate;
}
@Override
@NotNull
public String getRemappedClassName(@NotNull String srcName) {
return this.delegate.getRemappedClassName(srcName);
}
@Override
@Nullable
public String getRemappedClassNameFast(@NotNull String srcName) {
return this.delegate.getRemappedClassNameFast(srcName);
}
@Override
@NotNull
public String getRemappedFieldName(@NotNull String srcOwner, @NotNull String srcName, @NotNull String srcDesc) {
MemberRef topLevel = this.definitionLookup.getDefinition(new MemberRef(srcOwner, srcName, srcDesc));
if (srcDesc.codePointAt(0) != topLevel.getDesc().codePointAt(0)) {
throw new IllegalStateException("Definition lookup altered the type of member from " + srcDesc + " to " + topLevel.getDesc() + ", which is not permitted.");
}
return this.delegate.getRemappedFieldName(topLevel.getOwner(), topLevel.getName(), topLevel.getDesc());
}
@Override
@NotNull
public String getRemappedMethodName(@NotNull String srcOwner, @NotNull String srcName, @NotNull String srcDesc) {
MemberRef topLevel = this.definitionLookup.getDefinition(new MemberRef(srcOwner, srcName, srcDesc));
if (srcDesc.codePointAt(0) != topLevel.getDesc().codePointAt(0)) {
throw new IllegalStateException("Definition lookup altered the type of member from " + srcDesc + " to " + topLevel.getDesc() + ", which is not permitted.");
}
return this.delegate.getRemappedMethodName(topLevel.getOwner(), topLevel.getName(), topLevel.getDesc());
}
@Override
@Nullable
public String getRemappedParameterName(@NotNull String srcOwner, @NotNull String srcName, @NotNull String srcDesc, int paramIndex, boolean isStatic) {
MemberRef topLevel = this.definitionLookup.getDefinition(new MemberRef(srcOwner, srcName, srcDesc));
if (srcDesc.codePointAt(0) != topLevel.getDesc().codePointAt(0)) {
throw new IllegalStateException("Definition lookup altered the type of member from " + srcDesc + " to " + topLevel.getDesc() + ", which is not permitted.");
}
return this.delegate.getRemappedParameterName(topLevel.getOwner(), topLevel.getName(), topLevel.getDesc(), paramIndex, isStatic);
}
@Override
@NotNull
public HierarchyAwareMappingDelegator