Skip to content
Draft
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
@@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2009, 2025 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
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Evgeny Mandrikov - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.test.validation.kotlin;

import org.jacoco.core.test.validation.ValidationTestBase;
import org.jacoco.core.test.validation.kotlin.targets.KotlinInlineReferenceTarget;

/**
* Test of code coverage in {@link KotlinInlineReferenceTarget}.
*/
public class KotlinInlineReferenceTest extends ValidationTestBase {

public KotlinInlineReferenceTest() {
super(KotlinInlineReferenceTarget.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2009, 2025 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
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Evgeny Mandrikov - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.test.validation.kotlin.targets

import org.jacoco.core.test.validation.targets.Stubs.nop
import org.jacoco.core.test.validation.targets.Stubs.t

/**
* Test target with `inline` function invoked via callable reference.
*/
object KotlinInlineReferenceTarget {

private inline fun example() { // assertEmpty()
nop() // assertFullyCovered()
} // assertFullyCovered()

private fun run(f: () -> Unit) {
f()
}

@JvmStatic
fun main(args: Array<String>) {
run(::example)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void should_ignore_module_info() throws Exception {
}

@Test
public void should_ignore_synthetic_classes() throws Exception {
public void should_not_ignore_synthetic_classes() throws Exception {
final ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_5, Opcodes.ACC_SYNTHETIC, "Foo", null,
"java/lang/Object", null);
Expand All @@ -105,7 +105,7 @@ public void should_ignore_synthetic_classes() throws Exception {

analyzer.analyzeClass(bytes, "");

assertTrue(classes.isEmpty());
assertClasses("Foo");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class FilterContextMock implements IFilterContext {

public String className = "Foo";
public String superClassName = "java/lang/Object";
public int classAccess;
public Set<String> classAnnotations = new HashSet<String>();
public Set<String> classAttributes = new HashSet<String>();
public String sourceFileName = "Foo.java";
Expand All @@ -43,6 +44,10 @@ public Set<String> getClassAttributes() {
return classAttributes;
}

public int getClassAccess() {
return classAccess;
}

public String getSourceFileName() {
return sourceFileName;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*******************************************************************************
* Copyright (c) 2009, 2025 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
* http://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.junit.Test;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.MethodNode;

/**
* Unit tests for {@link SyntheticClassFilter}.
*/
public class SyntheticClassFilterTest extends FilterTestBase {

private final SyntheticClassFilter filter = new SyntheticClassFilter();

@Test
public void should_filter() {
context.classAccess = Opcodes.ACC_SYNTHETIC;
final MethodNode m = new MethodNode();
m.visitInsn(Opcodes.NOP);

filter.filter(m, context, output);

assertMethodIgnored(m);
}

@Test
public void should_not_filter() {
final MethodNode m = new MethodNode();
m.visitInsn(Opcodes.NOP);

filter.filter(m, context, output);

assertIgnored(m);
}

}
3 changes: 0 additions & 3 deletions org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ private void analyzeClass(final byte[] source) {
if ((reader.getAccess() & Opcodes.ACC_MODULE) != 0) {
return;
}
if ((reader.getAccess() & Opcodes.ACC_SYNTHETIC) != 0) {
return;
}
final ClassVisitor visitor = createAnalyzingVisitor(classId,
reader.getClassName());
reader.accept(visitor, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class ClassAnalyzer extends ClassProbesVisitor

private final Set<String> classAttributes = new HashSet<String>();

private int classAccess;
private String sourceDebugExtension;
private KotlinSMAP smap;
private final HashMap<String, SourceNodeImpl> fragments = new HashMap<String, SourceNodeImpl>();
Expand Down Expand Up @@ -74,6 +75,7 @@ public ClassAnalyzer(final ClassCoverageImpl coverage,
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
this.classAccess = access;
coverage.setSignature(stringPool.get(signature));
coverage.setSuperName(stringPool.get(superName));
coverage.setInterfaces(stringPool.get(interfaces));
Expand Down Expand Up @@ -213,6 +215,10 @@ public Set<String> getClassAttributes() {
return classAttributes;
}

public int getClassAccess() {
return classAccess;
}

public String getSourceFileName() {
return coverage.getSourceFileName();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void filter(final MethodNode methodNode,

private static IFilter allCommonFilters() {
return new FilterSet( //
new SyntheticClassFilter(), //
new EnumFilter(), //
new BridgeFilter(), //
new SynchronizedFilter(), //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public interface IFilterContext {
*/
Set<String> getClassAttributes();

/**
* @return class access flags
*/
int getClassAccess();

/**
* @return file name of the corresponding source file or <code>null</code>
* if not available
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2009, 2025 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
* http://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.MethodNode;

/**
* Filters synthetic classes.
*/
final class SyntheticClassFilter implements IFilter {

public void filter(final MethodNode methodNode,
final IFilterContext context, final IFilterOutput output) {
if ((context.getClassAccess() & Opcodes.ACC_SYNTHETIC) == 0) {
return;
}
output.ignore(methodNode.instructions.getFirst(),
methodNode.instructions.getLast());
}

}