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

proguard.evaluation.ExecutorLookup Maven / Gradle / Ivy

Go to download

ProGuardCORE is a free library to read, analyze, modify, and write Java class files.

There is a newer version: 9.1.6
Show newest version
package proguard.evaluation;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import proguard.classfile.Clazz;
import proguard.classfile.MethodSignature;
import proguard.classfile.util.ClassUtil;
import proguard.evaluation.executor.Executor;
import proguard.evaluation.executor.MethodExecutionInfo;
import proguard.evaluation.value.TypedReferenceValue;

/**
 * Class for performing lookups of registered executors based on method signatures.
 *
 * 

Dynamic lookup is performed for instance methods by using the analyzed type, if available, * instead of the static type of the target method. * *

Executors are expected to provide exactly all the methods they expect to be able to support * via {@link Executor#getSupportedMethodSignatures()}, for example to support inheritance the * executors need to specify both the parent and child class in the returned signatures. */ final class ExecutorLookup { private static final Logger log = LogManager.getLogger(ExecutorLookup.class); private static final boolean PRINT_ERRORS = System.getProperty("proguard.value.logerrors") != null; private final Map executorFromSignature = new HashMap<>(); private final Set supportedClasses = new HashSet<>(); /** * Constructor * * @param registeredExecutors A list of executors that the lookup procedures run on. */ public ExecutorLookup(List registeredExecutors) { for (Executor executor : registeredExecutors) { for (MethodSignature signature : executor.getSupportedMethodSignatures()) { if (PRINT_ERRORS && signature.isIncomplete()) { log.warn( "Wildcard signatures are not supported by ExecutorLookup, they will get ignored"); continue; } if (executorFromSignature.putIfAbsent(signature, executor) != null) { if (PRINT_ERRORS) log.warn( "Signature {} is supported by multiple executors. {} will be ignored", signature, executor.getClass().getSimpleName()); } else { supportedClasses.add(signature.getClassName()); } } } } /** * Find and return an executor that handles the given method execution. * * @param info information about the method invocation * @return Executor, if the method can be handled. Null otherwise. */ public @Nullable Executor lookupExecutor(@NotNull MethodExecutionInfo info) { MethodSignature targetSignature; MethodSignature staticSignature = info.getSignature(); boolean isTargetDynamic = false; if (info.isInstanceMethod() && (info.getInstanceNonStatic() instanceof TypedReferenceValue) && info.getInstanceNonStatic().getType() != null) { // Try to perform a "dynamic" lookup for instance methods if additional type information is // available isTargetDynamic = true; TypedReferenceValue instance = (TypedReferenceValue) info.getInstanceNonStatic(); targetSignature = new MethodSignature( ClassUtil.internalClassNameFromClassType(instance.getType()), staticSignature.method, staticSignature.descriptor); } else { // For the remaining invocations just use the static signature targetSignature = staticSignature; } info.setResolvedTargetSignature(targetSignature); Executor targetExecutor = executorFromSignature.get(targetSignature); if (PRINT_ERRORS && isTargetDynamic && targetExecutor == null && executorFromSignature.get(staticSignature) != null) { log.warn( "Dynamic target {} is not supported by the executors but static target {} is, check if your executor should also support the child class methods", targetSignature, staticSignature); } return targetExecutor; } /** * Check, whether the given signature is supported by this executor. * *

NB: inheritance is not taken into account if not explicitly specified. i.e., if a certain * method is supported it does not necessarily mean that the same method from a child class is * supported, even if the method was not overridden. * * @param methodSignature The given method signature to check. * @return True iff the method can be executed. */ public boolean hasExecutorFor(@NotNull MethodSignature methodSignature) { return this.executorFromSignature.containsKey(methodSignature); } /** * Checks whether it makes sense to track objects of the given class, i.e. if there exists a * method on that class that we are able to execute. * *

NB: inheritance is not taken into account if not explicitly specified. i.e., if an object of * a certain type is supported it does not mean that objects of its child classes are. * * @param clazz The class to be tested * @return True if instances of that class should be tracked */ public boolean shouldTrackInstancesOf(@NotNull Clazz clazz) { return shouldTrackInstancesOf(clazz.getName()); } /** * Checks whether it makes sense to track objects of the given class, i.e. if there exists a * method on that class that we are able to execute. * *

NB: inheritance is not taken into account if not explicitly specified. i.e., if an object of * a certain type is supported it does not mean that objects of its child classes are. * * @param className The class to be tested * @return True if instances of that class should be tracked */ public boolean shouldTrackInstancesOf(@NotNull String className) { return supportedClasses.contains(className); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy