All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.denwav.hypo.model.data.MethodData Maven / Gradle / Ivy

/*
 * Hypo, an extensible and pluggable Java bytecode analytical model.
 *
 * Copyright (C) 2023  Kyle Wood (DenWav)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Lesser GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License only.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package dev.denwav.hypo.model.data;

import dev.denwav.hypo.model.data.types.JvmType;
import dev.denwav.hypo.model.data.types.PrimitiveType;
import java.util.List;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * Java method model.
 *
 * 

{@link Object#equals(Object) equals()}, {@link Object#hashCode() hashCode()}, and * {@link Object#toString() toString()} are all written purely against the {@link #name()} of the parent class, this * method's name, and this method's descriptor. This is to prevent poor performance from using {@link MethodData} * objects directly in data structures. */ public interface MethodData extends MemberData { /** * The descriptor of this method. This does not include the method's generic signature, this is only the method's * basic type descriptor. * * @return This method's descriptor. */ @NotNull MethodDescriptor descriptor(); /** * The internal JVM text representation of this method's descriptor. * * @return The internal JVM text representation of this method's descriptor. * @see #descriptor() */ default @NotNull String descriptorText() { return this.descriptor().toInternalString(); } /** * Returns {@code true} if this method is abstract. * @return {@code true} if this method is abstract. */ boolean isAbstract(); /** * Returns {@code true} if this is a bridge method. * @return {@code true} if this is a bridge method. */ boolean isBridge(); /** * Returns {@code true} if this is a native method. * @return {@code true} if this is a native method. */ boolean isNative(); /** * Returns {@code true} if this method is a constructor. * @return {@code true} if this method is a constructor. */ default boolean isConstructor() { return false; } /** * The method parameters component of the {@link #descriptor() descriptor}. * * @return This method's list of parameters. * @see #descriptor() */ default @NotNull List<@NotNull JvmType> params() { return this.descriptor().getParams(); } /** * Get the parameter based on the position the parameter appears in the parameter list, starting from 0. The * parameter's LVT index is not considered with this method, only the positional index. For LVT index, use * {@link #paramLvt(int)}. * * @param i The positional index of the parameter to find. * @return The parameter at the position index given. * @throws IndexOutOfBoundsException If the given index is out of bounds. * @see #paramLvt(int) */ default @NotNull JvmType param(final int i) { final List<@NotNull JvmType> params = this.descriptor().getParams(); if (i < 0 || i >= params.size()) { throw new IndexOutOfBoundsException( "Index out of range: " + i + ", list has " + params.size() + " items" ); } return params.get(i); } /** * Get the parameter based on the parameter at the LVT index given. The parameter's position index is not considered * with this method, only the LVT index. For positional index, use {@link #param(int)}. * * @param i The LVT index of the parameter to find. * @return The parameter at the LVT index given, or {@code null} if no parameter could be found at the given LVT * index. * @see #param(int) */ @SuppressWarnings("EmptyCatch") default @Nullable JvmType paramLvt(final int i) { final List<@NotNull JvmType> params = this.descriptor().getParams(); // `this` int index = this.isStatic() ? 0 : 1; for (final JvmType param : params) { if (index == i) { return param; } index++; if (param == PrimitiveType.LONG || param == PrimitiveType.DOUBLE) { index++; } } return null; } /** * The return type component of the {@link #descriptor() descriptor}. * * @return This method's return type. * @see #descriptor() */ default @NotNull JvmType returnType() { return this.descriptor().getReturnType(); } /** * Returns {@code true} if this method data extends the given method data, or if this method data is the same as the * given method data. This checks method modifiers to first determine if the given method is allowed to be * overridden, and checks this and the given method data's visibility to ensure they are valid. * *

This method does not handle covariant return types, or methods which override a parent method with a more * specific return type. From the JVM's perspective only methods with identical descriptors override each other, * so information around method synthetic targets is needed to determine those situations. * * @param that The method to check if this method extends. * @return {@code true} if this method overrides the given method. */ default boolean overrides(final @NotNull MethodData that) { if (this.isStatic() || that.isStatic() || that.isFinal()) { return false; } if (!this.visibility().canOverride(that.visibility())) { return false; } if (that.visibility() == Visibility.PACKAGE) { final String thisClassName = this.parentClass().name(); final String thatClassName = that.parentClass().name(); final int thisLastIndex = thisClassName.lastIndexOf('/'); final int thatLastIndex = thatClassName.lastIndexOf('/'); if (thisLastIndex != thatLastIndex) { return false; } if (!thisClassName.regionMatches(0, thatClassName, 0, thatLastIndex)) { return false; } } if (!this.name().equals(that.name())) { return false; } if (!this.descriptor().equals(that.descriptor())) { return false; } return this.parentClass().doesExtendOrImplement(that.parentClass()); } // Hydration methods /** * Set this method's super method. The given method must satisfy the {@link #overrides(MethodData)} method such * that the following code returns {@code true}: * *

     *     someMethod.setSuperMethod(superMethod);
     *     someMethod.overrides(someMethod.superMethod())
     * 
* *

This method is intended only to be called during hydration. * * @param superMethod The method to set as this method's super method. */ void setSuperMethod(final @Nullable MethodData superMethod); /** * Returns this method's super method, if one has been set. This method will always return {@code null} unless this * method data has been hydrated. * * @return This method's super method. */ @Nullable MethodData superMethod(); /** * Returns the set of methods which override this method. This method will always return {@code null} unless this * method data has been hydrated. * * @return The set of methods which override this method. */ @NotNull Set childMethods(); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy