diff options
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core/internal/analysis/filter')
29 files changed, 573 insertions, 255 deletions
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index 38860a83..837278e9 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -34,7 +35,7 @@ abstract class AbstractMatcher { final void firstIsALoad0(final MethodNode methodNode) { cursor = methodNode.instructions.getFirst(); skipNonOpcodes(); - if (cursor.getOpcode() == Opcodes.ALOAD + if (cursor != null && cursor.getOpcode() == Opcodes.ALOAD && ((VarInsnNode) cursor).var == 0) { return; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java index d78444c0..1653fa27 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/BridgeFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/BridgeFilter.java new file mode 100644 index 00000000..bc23941b --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/BridgeFilter.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2009, 2021 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 bridge methods. + */ +final class BridgeFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if ((methodNode.access & Opcodes.ACC_BRIDGE) == 0) { + return; + } + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java index 4a39d1e8..ae23c641 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java index 0c2eef58..faab0ad4 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 7a1053b5..484ccc00 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -27,24 +28,25 @@ public final class Filters implements IFilter { /** * Creates filter that combines all other filters. - * + * * @return filter that combines all other filters */ public static IFilter all() { return new Filters(new EnumFilter(), new SyntheticFilter(), - new SynchronizedFilter(), new TryWithResourcesJavac11Filter(), + new BridgeFilter(), new SynchronizedFilter(), + new TryWithResourcesJavac11Filter(), new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), - new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), - new EnumEmptyConstructorFilter(), + new StringSwitchJavacFilter(), new StringSwitchFilter(), + new EnumEmptyConstructorFilter(), new RecordsFilter(), new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), new KotlinLateinitFilter(), new KotlinWhenFilter(), new KotlinWhenStringFilter(), new KotlinUnsafeCastOperatorFilter(), new KotlinNotNullOperatorFilter(), new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter(), - new KotlinCoroutineFilter()); + new KotlinCoroutineFilter(), new KotlinDefaultMethodsFilter()); } private Filters(final IFilter... filters) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java index b2e0b145..284d4322 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -26,7 +27,7 @@ import org.objectweb.asm.tree.VarInsnNode; * Filters duplicates of finally blocks that compiler generates. * * To understand algorithm of filtering, consider following example: - * + * * <pre> * try { * if (x) { @@ -44,7 +45,7 @@ import org.objectweb.asm.tree.VarInsnNode; * There are 4 <b>distinct</b> points of exit out of these "try/catch/finally" * blocks - three without exception, and one with Throwable if it is thrown * prior to reaching first three points of exit. - * + * * "finally" block must be executed just before these points, so there must be 4 * copies of its bytecode instructions. * diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java index b662ba4f..9f0a7589 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java index 8b97654d..992e3e8d 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java @@ -1,48 +1,54 @@ -/*******************************************************************************
- * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis.filter;
-
-import java.util.Set;
-
-/**
- * Context information provided to filters.
- */
-public interface IFilterContext {
-
- /**
- * @return vm name of the enclosing class
- */
- String getClassName();
-
- /**
- * @return vm name of the super class of the enclosing class
- */
- String getSuperClassName();
-
- /**
- * @return vm names of the class annotations of the enclosing class
- */
- Set<String> getClassAnnotations();
-
- /**
- * @return file name of the corresponding source file or <code>null</code>
- * if not available
- */
- String getSourceFileName();
-
- /**
- * @return value of SourceDebugExtension attribute or <code>null</code> if
- * not available
- */
- String getSourceDebugExtension();
-
-}
+/******************************************************************************* + * Copyright (c) 2009, 2021 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: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.Set; + +/** + * Context information provided to filters. + */ +public interface IFilterContext { + + /** + * @return vm name of the enclosing class + */ + String getClassName(); + + /** + * @return vm name of the super class of the enclosing class + */ + String getSuperClassName(); + + /** + * @return vm names of the class annotations of the enclosing class + */ + Set<String> getClassAnnotations(); + + /** + * @return names of the class attributes + */ + Set<String> getClassAttributes(); + + /** + * @return file name of the corresponding source file or <code>null</code> + * if not available + */ + String getSourceFileName(); + + /** + * @return value of SourceDebugExtension attribute or <code>null</code> if + * not available + */ + String getSourceDebugExtension(); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java index 0f022201..93ad2eeb 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -35,7 +36,7 @@ public interface IFilterOutput { /** * Marks two instructions that should be merged during computation of * coverage. - * + * * @param i1 * first instruction * @param i2 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index 66d450a3..4b850f33 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -19,6 +20,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; @@ -27,7 +29,11 @@ import org.objectweb.asm.tree.TableSwitchInsnNode; */ public final class KotlinCoroutineFilter implements IFilter { - static boolean isLastArgumentContinuation(final MethodNode methodNode) { + static boolean isImplementationOfSuspendFunction( + final MethodNode methodNode) { + if (methodNode.name.startsWith("access$")) { + return false; + } final Type methodType = Type.getMethodType(methodNode.desc); final int lastArgument = methodType.getArgumentTypes().length - 1; return lastArgument >= 0 && "kotlin.coroutines.Continuation".equals( @@ -42,16 +48,41 @@ public final class KotlinCoroutineFilter implements IFilter { } new Matcher().match(methodNode, output); - + new Matcher().matchOptimizedTailCall(methodNode, output); } private static class Matcher extends AbstractMatcher { + + private void matchOptimizedTailCall(final MethodNode methodNode, + final IFilterOutput output) { + for (final AbstractInsnNode i : methodNode.instructions) { + cursor = i; + nextIs(Opcodes.DUP); + nextIsInvoke(Opcodes.INVOKESTATIC, + "kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;"); + nextIs(Opcodes.IF_ACMPNE); + nextIs(Opcodes.ARETURN); + nextIs(Opcodes.POP); + if (cursor != null) { + output.ignore(i.getNext(), cursor); + } + } + } + private void match(final MethodNode methodNode, final IFilterOutput output) { - cursor = methodNode.instructions.getFirst(); - nextIsInvoke(Opcodes.INVOKESTATIC, - "kotlin/coroutines/intrinsics/IntrinsicsKt", - "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;"); + cursor = skipNonOpcodes(methodNode.instructions.getFirst()); + if (cursor == null || cursor.getOpcode() != Opcodes.INVOKESTATIC) { + cursor = null; + } else { + final MethodInsnNode m = (MethodInsnNode) cursor; + if (!"kotlin/coroutines/intrinsics/IntrinsicsKt".equals(m.owner) + || !"getCOROUTINE_SUSPENDED".equals(m.name) + || !"()Ljava/lang/Object;".equals(m.desc)) { + cursor = null; + } + } if (cursor == null) { cursor = skipNonOpcodes(methodNode.instructions.getFirst()); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java index ef198447..b734d234 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -18,15 +19,16 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; /** * Filters branches that Kotlin compiler generates for default arguments. - * + * * For each default argument Kotlin compiler generates following bytecode to * determine if it should be used or not: - * + * * <pre> * ILOAD maskVar * ICONST_x, BIPUSH, SIPUSH, LDC or LDC_W @@ -35,16 +37,30 @@ import org.objectweb.asm.tree.VarInsnNode; * default argument * label: * </pre> - * + * * Where <code>maskVar</code> is penultimate argument of synthetic method with - * suffix "$default". And its value can't be zero - invocation with all - * arguments uses original non synthetic method, thus <code>IFEQ</code> - * instructions should be ignored. + * suffix "$default" or of synthetic constructor with last argument + * "kotlin.jvm.internal.DefaultConstructorMarker". And its value can't be zero - + * invocation with all arguments uses original non synthetic method, thus + * <code>IFEQ</code> instructions should be ignored. */ public final class KotlinDefaultArgumentsFilter implements IFilter { - static boolean isDefaultArgumentsMethodName(final String methodName) { - return methodName.endsWith("$default"); + static boolean isDefaultArgumentsMethod(final MethodNode methodNode) { + return methodNode.name.endsWith("$default"); + } + + static boolean isDefaultArgumentsConstructor(final MethodNode methodNode) { + if (!"<init>".equals(methodNode.name)) { + return false; + } + final Type[] argumentTypes = Type.getMethodType(methodNode.desc) + .getArgumentTypes(); + if (argumentTypes.length < 2) { + return false; + } + return "kotlin.jvm.internal.DefaultConstructorMarker" + .equals(argumentTypes[argumentTypes.length - 1].getClassName()); } public void filter(final MethodNode methodNode, @@ -52,24 +68,45 @@ public final class KotlinDefaultArgumentsFilter implements IFilter { if ((methodNode.access & Opcodes.ACC_SYNTHETIC) == 0) { return; } - if (!isDefaultArgumentsMethodName(methodNode.name)) { - return; - } if (!KotlinGeneratedFilter.isKotlinClass(context)) { return; } - new Matcher().match(methodNode, output); + if (isDefaultArgumentsMethod(methodNode)) { + new Matcher().match(methodNode, output, false); + } else if (isDefaultArgumentsConstructor(methodNode)) { + new Matcher().match(methodNode, output, true); + } } private static class Matcher extends AbstractMatcher { public void match(final MethodNode methodNode, - final IFilterOutput output) { - cursor = methodNode.instructions.getFirst(); + final IFilterOutput output, final boolean constructor) { + cursor = skipNonOpcodes(methodNode.instructions.getFirst()); + + nextIs(Opcodes.IFNULL); + nextIsType(Opcodes.NEW, "java/lang/UnsupportedOperationException"); + nextIs(Opcodes.DUP); + nextIs(Opcodes.LDC); + if (cursor == null + || !(((LdcInsnNode) cursor).cst instanceof String) + || !(((String) ((LdcInsnNode) cursor).cst).startsWith( + "Super calls with default arguments not supported in this target"))) { + cursor = null; + } + nextIsInvoke(Opcodes.INVOKESPECIAL, + "java/lang/UnsupportedOperationException", "<init>", + "(Ljava/lang/String;)V"); + nextIs(Opcodes.ATHROW); + if (cursor != null) { + output.ignore(methodNode.instructions.getFirst(), cursor); + next(); + } else { + cursor = skipNonOpcodes(methodNode.instructions.getFirst()); + } final Set<AbstractInsnNode> ignore = new HashSet<AbstractInsnNode>(); - final int maskVar = Type.getMethodType(methodNode.desc) - .getArgumentTypes().length - 2; + final int maskVar = maskVar(methodNode.desc, constructor); while (true) { if (cursor.getOpcode() != Opcodes.ILOAD) { break; @@ -92,6 +129,22 @@ public final class KotlinDefaultArgumentsFilter implements IFilter { output.ignore(i, i); } } + + private static int maskVar(final String desc, + final boolean constructor) { + int slot = 0; + if (constructor) { + // one slot for reference to current object + slot++; + } + final Type[] argumentTypes = Type.getMethodType(desc) + .getArgumentTypes(); + final int penultimateArgument = argumentTypes.length - 2; + for (int i = 0; i < penultimateArgument; i++) { + slot += argumentTypes[i].getSize(); + } + return slot; + } } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultMethodsFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultMethodsFilter.java new file mode 100644 index 00000000..50d6280e --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultMethodsFilter.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2009, 2021 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.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters methods that Kotlin compiler generates for non-overridden + * non-abstract methods of interfaces. + */ +final class KotlinDefaultMethodsFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if (!KotlinGeneratedFilter.isKotlinClass(context)) { + return; + } + new Matcher().match(methodNode, output); + } + + private static class Matcher extends AbstractMatcher { + private void match(final MethodNode methodNode, + final IFilterOutput output) { + firstIsALoad0(methodNode); + nextIs(Opcodes.INVOKESTATIC); + if (cursor != null && ((MethodInsnNode) cursor).owner + .endsWith("$DefaultImpls")) { + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java index 129580a9..4ebc3707 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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: * Nikolay Krasko - initial API and implementation @@ -49,8 +50,7 @@ public class KotlinGeneratedFilter implements IFilter { } private boolean hasLineNumber(final MethodNode methodNode) { - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + for (final AbstractInsnNode i : methodNode.instructions) { if (AbstractInsnNode.LINE == i.getType()) { return true; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java index 5666de2d..f3e7d6b9 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -46,8 +47,7 @@ public final class KotlinInlineFilter implements IFilter { } int line = 0; - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + for (final AbstractInsnNode i : methodNode.instructions) { if (AbstractInsnNode.LINE == i.getType()) { line = ((LineNumberNode) i).line; } @@ -92,7 +92,11 @@ public final class KotlinInlineFilter implements IFilter { } // LineSection int min = Integer.MAX_VALUE; - while (!"*E".equals(line = br.readLine())) { + while (true) { + line = br.readLine(); + if (line.equals("*E") || line.equals("*S KotlinDebug")) { + break; + } final Matcher m = LINE_INFO_PATTERN.matcher(line); if (!m.matches()) { throw new IllegalStateException( diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java index 12fe926c..a5e20265 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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: * Fabian Mastenbroek - initial API and implementation @@ -13,6 +14,7 @@ package org.jacoco.core.internal.analysis.filter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.MethodNode; /** @@ -24,9 +26,8 @@ public class KotlinLateinitFilter implements IFilter { public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { final Matcher matcher = new Matcher(); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { - matcher.match(i, output); + for (final AbstractInsnNode node : methodNode.instructions) { + matcher.match(node, output); } } @@ -44,6 +45,13 @@ public class KotlinLateinitFilter implements IFilter { "throwUninitializedPropertyAccessException", "(Ljava/lang/String;)V"); + if (cursor != null + && skipNonOpcodes(cursor.getNext()) != skipNonOpcodes( + ((JumpInsnNode) start).label)) { + nextIs(Opcodes.ACONST_NULL); + nextIs(Opcodes.ATHROW); + } + if (cursor != null) { output.ignore(start, cursor); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java index 4dd223a3..dda54210 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -24,8 +25,7 @@ public final class KotlinNotNullOperatorFilter implements IFilter { public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { final Matcher matcher = new Matcher(); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + for (final AbstractInsnNode i : methodNode.instructions) { matcher.match(i, output); } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java index c298e945..82522a8a 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -23,27 +24,29 @@ import org.objectweb.asm.tree.MethodNode; */ public final class KotlinUnsafeCastOperatorFilter implements IFilter { - private static final String KOTLIN_TYPE_CAST_EXCEPTION = "kotlin/TypeCastException"; - public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { + if (!KotlinGeneratedFilter.isKotlinClass(context)) { + return; + } final Matcher matcher = new Matcher(); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { - matcher.match(i, output); + for (final AbstractInsnNode i : methodNode.instructions) { + matcher.match("kotlin/TypeCastException", i, output); + // Since Kotlin 1.4.0: + matcher.match("java/lang/NullPointerException", i, output); } } private static class Matcher extends AbstractMatcher { - public void match(final AbstractInsnNode start, - final IFilterOutput output) { + public void match(final String exceptionType, + final AbstractInsnNode start, final IFilterOutput output) { if (Opcodes.IFNONNULL != start.getOpcode()) { return; } cursor = start; - - nextIsType(Opcodes.NEW, KOTLIN_TYPE_CAST_EXCEPTION); + final JumpInsnNode jumpInsnNode = (JumpInsnNode) cursor; + nextIsType(Opcodes.NEW, exceptionType); nextIs(Opcodes.DUP); nextIs(Opcodes.LDC); if (cursor == null) { @@ -54,13 +57,13 @@ public final class KotlinUnsafeCastOperatorFilter implements IFilter { .startsWith("null cannot be cast to non-null type"))) { return; } - nextIsInvoke(Opcodes.INVOKESPECIAL, KOTLIN_TYPE_CAST_EXCEPTION, - "<init>", "(Ljava/lang/String;)V"); + nextIsInvoke(Opcodes.INVOKESPECIAL, exceptionType, "<init>", + "(Ljava/lang/String;)V"); nextIs(Opcodes.ATHROW); if (cursor == null) { return; } - if (cursor.getNext() != ((JumpInsnNode) start).label) { + if (cursor.getNext() != jumpInsnNode.label) { return; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java index a229aa04..ba2fb95c 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -17,7 +18,6 @@ import java.util.Set; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; @@ -37,15 +37,14 @@ public final class KotlinWhenFilter implements IFilter { public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { final Matcher matcher = new Matcher(); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + for (final AbstractInsnNode i : methodNode.instructions) { matcher.match(i, output); } } private static class Matcher extends AbstractMatcher { void match(final AbstractInsnNode start, final IFilterOutput output) { - if (start.getType() != InsnNode.LABEL) { + if (start.getType() != AbstractInsnNode.LABEL) { return; } cursor = start; @@ -92,7 +91,7 @@ public final class KotlinWhenFilter implements IFilter { labels = ((TableSwitchInsnNode) switchNode).labels; } final Set<AbstractInsnNode> newTargets = new HashSet<AbstractInsnNode>(); - for (LabelNode label : labels) { + for (final LabelNode label : labels) { newTargets.add(AbstractMatcher.skipNonOpcodes(label)); } output.replaceBranches(switchNode, newTargets); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java index fcccb550..5fd20874 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -32,8 +33,7 @@ public final class KotlinWhenStringFilter implements IFilter { public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { final Matcher matcher = new Matcher(); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + for (final AbstractInsnNode i : methodNode.instructions) { matcher.match(i, output); } } @@ -67,10 +67,14 @@ public final class KotlinWhenStringFilter implements IFilter { hashCodes = tableSwitch.labels.size(); } + if (hashCodes == 0) { + return; + } + final Set<AbstractInsnNode> replacements = new HashSet<AbstractInsnNode>(); replacements.add(skipNonOpcodes(defaultLabel)); - for (int i = 0; i < hashCodes; i++) { + for (int i = 1; i <= hashCodes; i++) { while (true) { nextIsVar(Opcodes.ALOAD, "s"); nextIs(Opcodes.LDC); @@ -79,18 +83,24 @@ public final class KotlinWhenStringFilter implements IFilter { // jump to next comparison or default case nextIs(Opcodes.IFEQ); final JumpInsnNode jump = (JumpInsnNode) cursor; - // jump to case - nextIs(Opcodes.GOTO); + next(); if (cursor == null) { return; - } - - replacements - .add(skipNonOpcodes(((JumpInsnNode) cursor).label)); - - if (jump.label == defaultLabel) { - // end of comparisons for same hashCode + } else if (cursor.getOpcode() == Opcodes.GOTO) { + // jump to case body + replacements.add( + skipNonOpcodes(((JumpInsnNode) cursor).label)); + if (jump.label == defaultLabel) { + // end of comparisons for same hashCode + break; + } + } else if (i == hashCodes && jump.label == defaultLabel) { + // case body + replacements.add(cursor); + cursor = jump; break; + } else { + return; } } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java index 236ef712..4b22dc29 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/RecordsFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/RecordsFilter.java new file mode 100644 index 00000000..745848ba --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/RecordsFilter.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2009, 2021 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.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters methods <code>toString</code>, <code>hashCode</code> and + * <code>equals</code> that compiler generates for records. + */ +public final class RecordsFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if (!"java/lang/Record".equals(context.getSuperClassName())) { + return; + } + final Matcher matcher = new Matcher(); + if (matcher.isEquals(methodNode) || matcher.isHashCode(methodNode) + || matcher.isToString(methodNode)) { + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + } + + private static class Matcher extends AbstractMatcher { + boolean isToString(final MethodNode m) { + if (!"toString".equals(m.name) + || !"()Ljava/lang/String;".equals(m.desc)) { + return false; + } + firstIsALoad0(m); + nextIsInvokeDynamic("toString"); + nextIs(Opcodes.ARETURN); + return cursor != null; + } + + boolean isHashCode(final MethodNode m) { + if (!"hashCode".equals(m.name) || !"()I".equals(m.desc)) { + return false; + } + firstIsALoad0(m); + nextIsInvokeDynamic("hashCode"); + nextIs(Opcodes.IRETURN); + return cursor != null; + } + + boolean isEquals(final MethodNode m) { + if (!"equals".equals(m.name) + || !"(Ljava/lang/Object;)Z".equals(m.desc)) { + return false; + } + firstIsALoad0(m); + nextIs(Opcodes.ALOAD); + nextIsInvokeDynamic("equals"); + nextIs(Opcodes.IRETURN); + return cursor != null; + } + + private void nextIsInvokeDynamic(final String name) { + nextIs(Opcodes.INVOKEDYNAMIC); + if (cursor == null) { + return; + } + final InvokeDynamicInsnNode i = (InvokeDynamicInsnNode) cursor; + final Handle bsm = i.bsm; + if (name.equals(i.name) + && "java/lang/runtime/ObjectMethods".equals(bsm.getOwner()) + && "bootstrap".equals(bsm.getName())) { + return; + } + cursor = null; + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchFilter.java index e0aba35d..a78e253e 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -25,15 +26,15 @@ import org.objectweb.asm.tree.VarInsnNode; /** * Filters code that is generated by ECJ for a <code>switch</code> statement - * with a <code>String</code>. + * with a <code>String</code> and by Kotlin compiler 1.5 and above for a + * <code>when</code> expression with a <code>String</code>. */ -public final class StringSwitchEcjFilter implements IFilter { +public final class StringSwitchFilter implements IFilter { public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { final Matcher matcher = new Matcher(); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + for (final AbstractInsnNode i : methodNode.instructions) { matcher.match(i, output); } } @@ -42,7 +43,8 @@ public final class StringSwitchEcjFilter implements IFilter { public void match(final AbstractInsnNode start, final IFilterOutput output) { - if (Opcodes.ASTORE != start.getOpcode()) { + if (start.getOpcode() != /* ECJ */ Opcodes.ASTORE + && start.getOpcode() != /* Kotlin */ Opcodes.ALOAD) { return; } cursor = start; @@ -67,6 +69,10 @@ public final class StringSwitchEcjFilter implements IFilter { hashCodes = tableSwitch.labels.size(); } + if (hashCodes == 0) { + return; + } + final Set<AbstractInsnNode> replacements = new HashSet<AbstractInsnNode>(); replacements.add(skipNonOpcodes(defaultLabel)); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java index 3033d9bc..a5baf34c 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -26,10 +27,8 @@ public final class StringSwitchJavacFilter implements IFilter { public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { - AbstractInsnNode i = methodNode.instructions.getFirst(); - while (i != null) { + for (final AbstractInsnNode i : methodNode.instructions) { filter(i, output); - i = i.getNext(); } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java index 6341328f..abc9e45b 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java index 69c4092a..127f7b03 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -19,6 +20,11 @@ import org.objectweb.asm.tree.MethodNode; */ public final class SyntheticFilter implements IFilter { + private static boolean isScalaClass(final IFilterContext context) { + return context.getClassAttributes().contains("ScalaSig") + || context.getClassAttributes().contains("Scala"); + } + public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { if ((methodNode.access & Opcodes.ACC_SYNTHETIC) == 0) { @@ -29,13 +35,25 @@ public final class SyntheticFilter implements IFilter { return; } + if (isScalaClass(context)) { + if (methodNode.name.startsWith("$anonfun$")) { + return; + } + } + if (KotlinGeneratedFilter.isKotlinClass(context)) { if (KotlinDefaultArgumentsFilter - .isDefaultArgumentsMethodName(methodNode.name)) { + .isDefaultArgumentsMethod(methodNode)) { + return; + } + + if (KotlinDefaultArgumentsFilter + .isDefaultArgumentsConstructor(methodNode)) { return; } - if (KotlinCoroutineFilter.isLastArgumentContinuation(methodNode)) { + if (KotlinCoroutineFilter + .isImplementationOfSuspendFunction(methodNode)) { return; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java index 94dea561..714ab223 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java index 7a20f74f..0b451750 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -55,7 +56,7 @@ public final class TryWithResourcesJavac11Filter implements IFilter { * throw primaryExc; * } * </pre> - * + * * <code>null</code> check for resource is omitted when it is initialized * using <code>new</code> */ diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java index 23ecb0e6..c3a0fa32 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java @@ -1,9 +1,10 @@ /******************************************************************************* - * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2009, 2021 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 @@ -47,7 +48,7 @@ public final class TryWithResourcesJavacFilter implements IFilter { * compilation of source code that is described in <a href= * "http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3.1">JLS * 14.20.3. try-with-resources</a>: - * + * * <pre> * Resource r = ...; * Throwable primaryExc = null; |