proguard.backport.LambdaExpression Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proguard-core Show documentation
Show all versions of proguard-core Show documentation
ProGuardCORE is a free library to read, analyze, modify, and write Java class files.
/*
* ProGuardCORE -- library to process Java bytecode.
*
* Copyright (c) 2002-2021 Guardsquare NV
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package proguard.backport;
import proguard.classfile.*;
import proguard.classfile.attribute.BootstrapMethodInfo;
import proguard.classfile.constant.MethodHandleConstant;
import proguard.classfile.util.*;
/**
* A small helper class that captures useful information
* about a lambda expression as encountered in a class file.
*
* @author Thomas Neidhart
*/
public class LambdaExpression
{
// The referenced class of the lambda expression.
public ProgramClass referencedClass;
// The referenced bootstrap method index.
public int bootstrapMethodIndex;
// The referenced bootstrap method info.
public BootstrapMethodInfo bootstrapMethodInfo;
// The lambda factory method type.
public String factoryMethodDescriptor;
// The implemented interfaces of the Lambda expression.
public String[] interfaces;
// The additional bridge method descriptors to be added.
public String[] bridgeMethodDescriptors;
// The name and descriptor of the implemented interface method.
public String interfaceMethod;
public String interfaceMethodDescriptor;
// Information regarding the invoked method.
public int invokedReferenceKind;
public String invokedClassName;
public String invokedMethodName;
public String invokedMethodDesc;
public Clazz referencedInvokedClass;
public Method referencedInvokedMethod;
// The created lambda class.
public ProgramClass lambdaClass;
//The index of the lambda expression, used for naming purposes.
private final int lambdaExpressionIndex;
/**
* Creates a new initialized LambdaExpression (except for the lambdaClass).
*/
public LambdaExpression(ProgramClass referencedClass,
int bootstrapMethodIndex,
BootstrapMethodInfo bootstrapMethodInfo,
String factoryMethodDescriptor,
String[] interfaces,
String[] bridgeMethodDescriptors,
String interfaceMethod,
String interfaceMethodDescriptor,
int invokedReferenceKind,
String invokedClassName,
String invokedMethodName,
String invokedMethodDesc,
Clazz referencedInvokedClass,
Method referencedInvokedMethod,
int lambdaExpressionIndex)
{
this.referencedClass = referencedClass;
this.bootstrapMethodIndex = bootstrapMethodIndex;
this.bootstrapMethodInfo = bootstrapMethodInfo;
this.factoryMethodDescriptor = factoryMethodDescriptor;
this.interfaces = interfaces;
this.bridgeMethodDescriptors = bridgeMethodDescriptors;
this.interfaceMethod = interfaceMethod;
this.interfaceMethodDescriptor = interfaceMethodDescriptor;
this.invokedReferenceKind = invokedReferenceKind;
this.invokedClassName = invokedClassName;
this.invokedMethodName = invokedMethodName;
this.invokedMethodDesc = invokedMethodDesc;
this.referencedInvokedClass = referencedInvokedClass;
this.referencedInvokedMethod = referencedInvokedMethod;
this.lambdaExpressionIndex = lambdaExpressionIndex;
}
/**
* Returns the class name of the converted anonymous class.
*/
public String getLambdaClassName()
{
return String.format("%s$$Lambda$%d",
referencedClass.getName(),
lambdaExpressionIndex);
}
public String getConstructorDescriptor()
{
if (isStateless())
{
return ClassConstants.METHOD_TYPE_INIT;
}
else
{
int endIndex = factoryMethodDescriptor.indexOf(TypeConstants.METHOD_ARGUMENTS_CLOSE);
return factoryMethodDescriptor.substring(0, endIndex + 1) + TypeConstants.VOID;
}
}
/**
* Returns whether the lambda expression is serializable.
*/
public boolean isSerializable()
{
for (String interfaceName : interfaces)
{
if (ClassConstants.NAME_JAVA_IO_SERIALIZABLE.equals(interfaceName))
{
return true;
}
}
return false;
}
/**
* Returns whether the lambda expression is actually a method reference.
*/
public boolean isMethodReference()
{
return !isLambdaMethod(invokedMethodName);
}
/**
* Returns whether the lambda expression is stateless.
*/
public boolean isStateless()
{
// The lambda expression is stateless if the factory method does
// not have arguments.
return
ClassUtil.internalMethodParameterCount(factoryMethodDescriptor) == 0;
}
/**
* Returns whether the invoked method is a static interface method.
*/
public boolean invokesStaticInterfaceMethod()
{
// We assume unknown classes are not interfaces.
return invokedReferenceKind == MethodHandleConstant.REF_INVOKE_STATIC &&
referencedInvokedClass != null &&
(referencedInvokedClass.getAccessFlags() & AccessConstants.INTERFACE) != 0;
}
/**
* Returns whether the invoked method is a non-static, private synthetic
* method in an interface.
*/
boolean referencesPrivateSyntheticInterfaceMethod()
{
// We assume unknown classes are not interfaces.
return (referencedInvokedClass != null) &&
(referencedInvokedClass .getAccessFlags() & AccessConstants.INTERFACE) != 0 &&
(referencedInvokedMethod.getAccessFlags() & (AccessConstants.PRIVATE |
AccessConstants.SYNTHETIC)) != 0 ;
}
/**
* Returns whether an accessor method is needed to access
* the invoked method from the lambda class.
*/
public boolean needsAccessorMethod()
{
// We assume unknown classes don't need an accessor method.
return referencedInvokedClass != null &&
new MemberFinder().findMethod(lambdaClass,
referencedInvokedClass,
invokedMethodName,
invokedMethodDesc) == null;
}
/**
* Returns whether the lambda expression is a method reference
* to a private constructor.
*/
public boolean referencesPrivateConstructor()
{
return invokedReferenceKind == MethodHandleConstant.REF_NEW_INVOKE_SPECIAL &&
ClassConstants.METHOD_NAME_INIT.equals(invokedMethodName) &&
(referencedInvokedMethod.getAccessFlags() & AccessConstants.PRIVATE) != 0;
}
// Small Utility methods.
private static final String LAMBDA_METHOD_PREFIX = "lambda$";
private static boolean isLambdaMethod(String methodName)
{
return methodName.startsWith(LAMBDA_METHOD_PREFIX);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy