Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add filter for methods annotated with @groovy.transform.Generated (#610)
  • Loading branch information
datoma authored and Godin committed Oct 17, 2017
1 parent 88d7b01 commit ec6287a
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 20 deletions.
@@ -0,0 +1,86 @@
/*******************************************************************************
* 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:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;

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;

public class GroovyGeneratedFilterTest implements IFilterOutput {

private final IFilter filter = new GroovyGeneratedFilter();

private AbstractInsnNode fromInclusive;
private AbstractInsnNode toInclusive;

@Test
public void testNoAnnotations() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"hashCode", "()I", null, null);

m.visitInsn(Opcodes.ICONST_0);
m.visitInsn(Opcodes.IRETURN);

filter.filter("Foo", "java/lang/Object", m, this);

assertNull(fromInclusive);
assertNull(toInclusive);
}

@Test
public void testOtherAnnotation() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"hashCode", "()I", null, null);
m.visitAnnotation("Lother/Annotation;", true);

m.visitInsn(Opcodes.ICONST_0);
m.visitInsn(Opcodes.IRETURN);

filter.filter("Foo", "java/lang/Object", m, this);

assertNull(fromInclusive);
assertNull(toInclusive);
}

@Test
public void testGroovyGeneratedAnnotation() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"hashCode", "()I", null, null);
m.visitAnnotation("Lgroovy/transform/Generated;", true);

m.visitInsn(Opcodes.ICONST_0);
m.visitInsn(Opcodes.IRETURN);

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) {
assertNull(this.fromInclusive);
this.fromInclusive = fromInclusive;
this.toInclusive = toInclusive;
}

public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
fail();
}

}
@@ -0,0 +1,66 @@
/*******************************************************************************
* 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:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;

import java.util.List;

import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.MethodNode;

/**
* Filters annotated methods.
*/
abstract class AbstractAnnotatedMethodFilter implements IFilter {
private final String descType;

/**
* Configures a new filter instance.
*
* @param annotationType
* VM type of the annotation
*/
protected AbstractAnnotatedMethodFilter(final String annotationType) {
this.descType = "L" + annotationType + ";";
}

public void filter(final String className, final String superClassName,
final MethodNode methodNode, final IFilterOutput output) {
if (hasAnnotation(methodNode)) {
output.ignore(methodNode.instructions.getFirst(),
methodNode.instructions.getLast());
}
}

private boolean hasAnnotation(final MethodNode methodNode) {
final List<AnnotationNode> annotations = getAnnotations(methodNode);
if (annotations != null) {
for (final AnnotationNode annotation : annotations) {
if (descType.equals(annotation.desc)) {
return true;
}
}
}
return false;
}

/**
* Retrieves the annotations to search from a method. Depending on the
* retention of the annotation this is either
* <code>visibleAnnotations</code> or <code>invisibleAnnotations</code>.
*
* @param methodNode
* method to retrieve annotations from
* @return list of annotations
*/
abstract List<AnnotationNode> getAnnotations(final MethodNode methodNode);

}
Expand Up @@ -30,11 +30,12 @@ public final class Filters implements IFilter {
new SyntheticFilter(), new SynchronizedFilter(),
new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(),
new PrivateEmptyNoArgConstructorFilter(),
new StringSwitchJavacFilter(), new LombokGeneratedFilter());
new StringSwitchJavacFilter(), new LombokGeneratedFilter(),
new GroovyGeneratedFilter());

private final IFilter[] filters;

private Filters(IFilter... filters) {
private Filters(final IFilter... filters) {
this.filters = filters;
}

Expand Down
@@ -0,0 +1,36 @@
/*******************************************************************************
* 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:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;

import java.util.List;

import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.MethodNode;

/**
* Filters methods annotated with <code>@groovy.transform.Generated</code>.
*/
public final class GroovyGeneratedFilter extends AbstractAnnotatedMethodFilter {

/**
* New filter.
*/
public GroovyGeneratedFilter() {
super("groovy/transform/Generated");
}

@Override
List<AnnotationNode> getAnnotations(final MethodNode methodNode) {
return methodNode.visibleAnnotations;
}

}
Expand Up @@ -19,26 +19,18 @@
/**
* Filters methods annotated with <code>@lombok.Generated</code>.
*/
public final class LombokGeneratedFilter implements IFilter {
public final class LombokGeneratedFilter extends AbstractAnnotatedMethodFilter {

public void filter(final String className, final String superClassName,
final MethodNode methodNode, final IFilterOutput output) {
if (hasLombokGeneratedAnnotation(methodNode)) {
output.ignore(methodNode.instructions.getFirst(),
methodNode.instructions.getLast());
}
/**
* New filter.
*/
public LombokGeneratedFilter() {
super("lombok/Generated");
}

private boolean hasLombokGeneratedAnnotation(final MethodNode methodNode) {
final List<AnnotationNode> runtimeInvisibleAnnotations = methodNode.invisibleAnnotations;
if (runtimeInvisibleAnnotations != null) {
for (final AnnotationNode annotation : runtimeInvisibleAnnotations) {
if ("Llombok/Generated;".equals(annotation.desc)) {
return true;
}
}
}
return false;
@Override
List<AnnotationNode> getAnnotations(final MethodNode methodNode) {
return methodNode.invisibleAnnotations;
}

}
6 changes: 5 additions & 1 deletion org.jacoco.doc/docroot/doc/changes.html
Expand Up @@ -35,8 +35,12 @@ <h3>New Features</h3>
try-with-resources statement
(GitHub <a href="https://github.com/jacoco/jacoco/issues/500">#500</a>).</li>
<li>Exclude from a report methods which are annotated with <code>@lombok.Generated</code>.
Initial analysis and contribution by Rüdiger zu Dohna.
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 methods which are annotated with
<code>@groovy.transform.Generated</code> to better integrate with Groovy
>= 2.5.0. Thanks to Andres Almiray for adding the annotation to Groovy
(GitHub <a href="https://github.com/jacoco/jacoco/issues/610">#610</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>Exclude from a report a part of bytecode that javac generates for a
Expand Down

0 comments on commit ec6287a

Please sign in to comment.