KotlinJvmStaticFilter.java

/*******************************************************************************
 * Copyright (c) 2009, 2026 Mountainminds GmbH & Co. KG and Contributors
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which is available at
 * https://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Evgeny Mandrikov - initial API and implementation
 *
 *******************************************************************************/
package org.jacoco.core.internal.analysis.filter;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.MethodNode;

/**
 * Filters methods that Kotlin compiler generates for functions annotated with
 * <a href=
 * "https://kotlinlang.org/docs/java-to-kotlin-interop.html#static-methods">
 * {@code JvmStatic}</a>.
 */
final class KotlinJvmStaticFilter implements IFilter {

	public void filter(final MethodNode methodNode,
			final IFilterContext context, final IFilterOutput output) {
		if ((methodNode.access & Opcodes.ACC_STATIC) == 0) {
			return;
		}
		if (!isJvmStatic(methodNode)) {
			return;
		}
		if (!isGetStaticCompanion(methodNode.instructions.getFirst(),
				context.getClassName())) {
			return;
		}
		output.ignore(methodNode.instructions.getFirst(),
				methodNode.instructions.getLast());
	}

	private static boolean isGetStaticCompanion(final AbstractInsnNode i,
			final String owner) {
		if (i == null || i.getOpcode() != Opcodes.GETSTATIC) {
			return false;
		}
		final FieldInsnNode f = (FieldInsnNode) i;
		return f.owner.equals(owner) && f.name.equals("Companion");
	}

	private boolean isJvmStatic(final MethodNode methodNode) {
		if (methodNode.visibleAnnotations != null) {
			for (AnnotationNode annotation : methodNode.visibleAnnotations) {
				if ("Lkotlin/jvm/JvmStatic;".equals(annotation.desc)) {
					return true;
				}
			}
		}
		return false;
	}

}