diff options
author | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2017-05-09 19:45:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-09 19:45:34 +0200 |
commit | c63563d1955934b5d4593c6d057351fc2dd008de (patch) | |
tree | cf568377a095ab149642ed2b30d111eb08a1214f | |
parent | c24df15ef7c3cd0d65c1e61768b54294f18cf857 (diff) | |
download | jacoco-c63563d1955934b5d4593c6d057351fc2dd008de.tar.gz |
Add filter for private empty constructors that do not have arguments (#529)
10 files changed, 267 insertions, 8 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java new file mode 100644 index 00000000..90262081 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +import static org.junit.Assert.assertEquals; + +public class PrivateEmptyNoArgConstructorFilterTest implements IFilterOutput { + + private final IFilter filter = new PrivateEmptyNoArgConstructorFilter(); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + @Test + public void test() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_PRIVATE, "<init>", "()V", null, null); + + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", + "()V", false); + m.visitInsn(Opcodes.RETURN); + + filter.filter("Foo", "java/lang/Object", m, this); + + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java new file mode 100644 index 00000000..a74d4671 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.Constructor; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a private empty + * constructors that do not have no arguments. + */ +public class ConstructorTest extends ValidationTestBase { + + public ConstructorTest() { + super(Constructor.class); + } + + @Test + public void testCoverageResult() { + // not filtered because not private: + assertLine("packageLocal", ICounter.FULLY_COVERED); + + // not filtered because has argument: + assertLine("arg", ICounter.FULLY_COVERED); + + // not filtered because not empty - prepares arguments for super + // constructor: + assertLine("super", ICounter.FULLY_COVERED); + + // not filtered because contains initialization of a field to hold + // reference to an instance of outer class that is passed as an + // argument: + assertLine("inner", ICounter.FULLY_COVERED); + + // not filtered because not empty - contains initialization of + // a field: + assertLine("innerStatic", ICounter.FULLY_COVERED); + + // not filtered because default constructor for not private inner + // classes is not private: + assertLine("publicDefault", ICounter.FULLY_COVERED); + assertLine("packageLocalDefault", ICounter.FULLY_COVERED); + + assertLine("privateDefault", ICounter.EMPTY); + + assertLine("privateNonEmptyNoArg", ICounter.FULLY_COVERED); + + assertLine("privateEmptyNoArg", ICounter.EMPTY); + assertLine("return", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java index a0b54e0b..8f8d2538 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java @@ -27,7 +27,7 @@ public class SyntheticTest extends ValidationTestBase { @Test public void testCoverageResult() { - assertMethodCount(6); + assertMethodCount(5); assertLine("classdef", ICounter.EMPTY); assertLine("field", ICounter.EMPTY); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java new file mode 100644 index 00000000..8623d2dd --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a constructors. + */ +public class Constructor { + + Constructor() { // $line-packageLocal$ + } + + private Constructor(Object arg) { // $line-arg$ + } + + private static class Super extends Constructor { + private Super() { + super(null); // $line-super$ + } + } + + private class Inner { + private Inner() { // $line-inner$ + } + } + + private static class InnerStatic { + private Object field = this; + + private InnerStatic() { // $line-innerStatic$ + } + } + + public static class PublicDefault { // $line-publicDefault$ + } + + static class PackageLocalDefault { // $line-packageLocalDefault$ + } + + private static class PrivateDefault { // $line-privateDefault$ + } + + private static class PrivateNonEmptyNoArg { + private PrivateNonEmptyNoArg() { + nop(); // $line-privateNonEmptyNoArg$ + } + } + + private static class PrivateEmptyNoArg { + private PrivateEmptyNoArg() { // $line-privateEmptyNoArg$ + } // $line-return$ + } + + public static void main(String[] args) { + new Super(); + new Constructor().new Inner(); + new InnerStatic(); + new PublicDefault(); + new PackageLocalDefault(); + new PrivateDefault(); + new PrivateNonEmptyNoArg(); + new PrivateEmptyNoArg(); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java index 783495d9..43826a8b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java @@ -18,6 +18,12 @@ public class Synthetic { // $line-classdef$ private static int counter; // $line-field$ + /** + * {@link org.jacoco.core.test.validation.targets.Target06 Default + * constructor will refer to a line of class definition}, so that we define + * constructor explicitly in order to verify that we filter all other + * constructions here that might refer to line of class definition. + */ private Synthetic() { } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java index 410f1df2..ac9b9271 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java @@ -30,8 +30,8 @@ public class PrivateEmptyDefaultConstructorTest extends ValidationTestBase { public void testCoverageResult() { assertLine("classdef", ICounter.EMPTY); - assertLine("super", ICounter.NOT_COVERED); - assertLine("constructor", ICounter.NOT_COVERED); + assertLine("super", ICounter.EMPTY); + assertLine("constructor", ICounter.EMPTY); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java index ee051436..8e07e56f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java @@ -23,6 +23,7 @@ import org.jacoco.core.internal.analysis.filter.EnumFilter; import org.jacoco.core.internal.analysis.filter.IFilter; import org.jacoco.core.internal.analysis.filter.IFilterOutput; import org.jacoco.core.internal.analysis.filter.LombokGeneratedFilter; +import org.jacoco.core.internal.analysis.filter.PrivateEmptyNoArgConstructorFilter; import org.jacoco.core.internal.analysis.filter.SynchronizedFilter; import org.jacoco.core.internal.analysis.filter.SyntheticFilter; import org.jacoco.core.internal.analysis.filter.TryWithResourcesEcjFilter; @@ -48,7 +49,7 @@ public class MethodAnalyzer extends MethodProbesVisitor private static final IFilter[] FILTERS = new IFilter[] { new EnumFilter(), new SyntheticFilter(), new SynchronizedFilter(), new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), - new LombokGeneratedFilter() }; + new PrivateEmptyNoArgConstructorFilter(), new LombokGeneratedFilter() }; private final String className; 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 e4958bdb..50a295de 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 @@ -73,11 +73,16 @@ abstract class AbstractMatcher { if (cursor == null) { return; } - do { - cursor = cursor.getNext(); - } while (cursor != null && (cursor.getType() == AbstractInsnNode.FRAME + cursor = cursor.getNext(); + skipNonOpcodes(); + } + + final void skipNonOpcodes() { + while (cursor != null && (cursor.getType() == AbstractInsnNode.FRAME || cursor.getType() == AbstractInsnNode.LABEL - || cursor.getType() == AbstractInsnNode.LINE)); + || cursor.getType() == AbstractInsnNode.LINE)) { + cursor = cursor.getNext(); + } } } 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 new file mode 100644 index 00000000..9e1bd43c --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 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: + * 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; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Filters private empty constructors that do not have arguments. + */ +public final class PrivateEmptyNoArgConstructorFilter implements IFilter { + + public void filter(final String className, final String superClassName, + final MethodNode methodNode, final IFilterOutput output) { + if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0 + && "<init>".equals(methodNode.name) + && "()V".equals(methodNode.desc) + && new Matcher().match(methodNode, superClassName)) { + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + } + + private static class Matcher extends AbstractMatcher { + private boolean match(final MethodNode methodNode, + final String superClassName) { + cursor = methodNode.instructions.getFirst(); + skipNonOpcodes(); + if (cursor.getOpcode() != Opcodes.ALOAD + || ((VarInsnNode) cursor).var != 0) { + return false; + } + nextIs(Opcodes.INVOKESPECIAL); + MethodInsnNode m = (MethodInsnNode) cursor; + if (m != null && superClassName.equals(m.owner) + && "<init>".equals(m.name) && ("()V").equals(m.desc)) { + nextIs(Opcodes.RETURN); + return cursor != null; + } + return false; + } + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 742d745f..8d2e4f8c 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -34,6 +34,8 @@ <li>Exclude from a report methods which are annotated with <code>@lombok.Generated</code>. Initial analysis and contribution by RĂ¼diger zu Dohna. (GitHub <a href="https://github.com/jacoco/jacoco/issues/513">#513</a>).</li> + <li>Exclude from a report private empty constructors that do not have arguments + (GitHub <a href="https://github.com/jacoco/jacoco/issues/529">#529</a>).</li> <li>Maven aggregated reports will now also include modules of runtime dependencies (GitHub <a href="https://github.com/jacoco/jacoco/issues/498">#498</a>).</li> </ul> |