Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ public class InvokeDynamicConstant extends Constant {
*/
public Clazz[] referencedClasses;

/**
* An extra field pointing to the Clazz that contains the method referenced. This field is
* populated by the <code>{@link proguard.classfile.util.LambdaReferenceInitializer}</code>.
*/
public Clazz referencedClass;

/**
* An extra field pointing to the Member referenced by this InvokeDynamic. This field is populated
* by the <code>{@link proguard.classfile.util.LambdaReferenceInitializer}</code>.
*/
public Member referencedMember;

/** Creates an uninitialized InvokeDynamicConstant. */
public InvokeDynamicConstant() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,28 @@ public void visitInterfaceMethodrefConstant(
}
}

@Override
public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) {
// Do we know the referenced member?
if (invokeDynamicConstant.referencedMember != null) {
Clazz referencedClass = invokeDynamicConstant.referencedClass;
Member referencedMember = invokeDynamicConstant.referencedMember;

// Does it have a new name?
String newName = referencedMember.getName(referencedClass);
String currentName = invokeDynamicConstant.getName(clazz);

if (!currentName.equals(newName)) {
String currentDescriptor = invokeDynamicConstant.getType(clazz);

// Update the name and type index.
invokeDynamicConstant.u2nameAndTypeIndex =
new ConstantPoolEditor((ProgramClass) clazz)
.addNameAndTypeConstant(newName, currentDescriptor);
}
}
}

public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) {
// Do we know the referenced method?
Method referencedMethod = methodrefConstant.referencedMethod;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* ProGuardCORE -- library to process Java bytecode.
*
* Copyright (c) 2002-2025 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.classfile.util;

import proguard.classfile.ClassPool;
import proguard.classfile.Clazz;
import proguard.classfile.Member;
import proguard.classfile.ProgramClass;
import proguard.classfile.constant.Constant;
import proguard.classfile.constant.InvokeDynamicConstant;
import proguard.classfile.constant.visitor.ConstantVisitor;
import proguard.classfile.visitor.ClassVisitor;

/**
* This {@link ClassVisitor} initializes the references of {@link InvokeDynamicConstant}s that
* represent lambda expressions. More specifically, it links the constants to the actual functional
* interface methods they target in the program class pool or in the library class pool.
*
* <p>The class hierarchy must be initialized before using this visitor.
*
* @author ShortyDev
*/
public class LambdaReferenceInitializer implements ClassVisitor, ConstantVisitor {
private final ClassPool programClassPool;
private final ClassPool libraryClassPool;

public LambdaReferenceInitializer(ClassPool programClassPool, ClassPool libraryClassPool) {
this.programClassPool = programClassPool;
this.libraryClassPool = libraryClassPool;
}

// Implementations for ClassVisitor.
@Override
public void visitAnyClass(Clazz clazz) {}

@Override
public void visitProgramClass(ProgramClass programClass) {
programClass.constantPoolEntriesAccept(this);
}

// Implementations for ConstantVisitor.
@Override
public void visitAnyConstant(Clazz clazz, Constant constant) {}

@Override
public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) {
// Get the descriptor to find the return type.
String descriptor = invokeDynamicConstant.getType(clazz);
String returnType = ClassUtil.internalMethodReturnType(descriptor);

// Check if the return type is a class type.
if (ClassUtil.isInternalClassType(returnType)) {
String interfaceClassName = ClassUtil.internalClassNameFromClassType(returnType);

// Find the interface class.
Clazz interfaceClass = programClassPool.getClass(interfaceClassName);

if (interfaceClass == null) {
interfaceClass = libraryClassPool.getClass(interfaceClassName);
}

if (interfaceClass != null) {
String methodName = invokeDynamicConstant.getName(clazz);

// Find the method in the interface.
Member referencedMember = interfaceClass.findMethod(methodName, null);

if (referencedMember != null) {
invokeDynamicConstant.referencedClass = interfaceClass;
invokeDynamicConstant.referencedMember = referencedMember;
}
}
}
}
}