/* * Cobertura - http://cobertura.sourceforge.net/ * * Copyright (C) 2011 Piotr Tabor * * Note: This file is dual licensed under the GPL and the Apache * Source License (so that it can be used from both the main * Cobertura classes and the ant tasks). * * Cobertura is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * Cobertura is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cobertura; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ package net.sourceforge.cobertura.instrument.pass2; import net.sourceforge.cobertura.CoverageIgnore; import net.sourceforge.cobertura.instrument.AbstractFindTouchPointsClassInstrumenter; import net.sourceforge.cobertura.instrument.FindTouchPointsMethodAdapter; import net.sourceforge.cobertura.instrument.HistoryMethodAdapter; import net.sourceforge.cobertura.instrument.pass3.CodeProvider; import net.sourceforge.cobertura.instrument.tp.ClassMap; import org.objectweb.asm.*; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; /** * <p>Analyzes given class. Builds {@link ClassMap} that represents any touch-points and other important information * for instrumentation.</p> * <p/> * This instrumenter ({@link ClassVisitor}) does not change the bytecode of the class. It makes only analyzys and fills {@link ClassMap}. * * @author piotr.tabor@gmail.com */ public class BuildClassMapClassVisitor extends AbstractFindTouchPointsClassInstrumenter { /** * {@link ClassMap} for the currently analyzed class. */ private final ClassMap classMap = new ClassMap(); /** * Information about important 'events' (instructions) are sent into the listener that is internally * responsible for modifying the {@link #classMap} content. */ private final BuildClassMapTouchPointListener touchPointListener = new BuildClassMapTouchPointListener( classMap); /** * It's flag that signals if the class should be instrumented by cobertura. * After analyzing the class you can check the field using {@link #shouldBeInstrumented()}. */ private boolean toInstrument = true; private final Set<String> ignoredMethods; /** * @param cv - a listener for code-instrumentation events * @param ignoreRegexp - list of patters of method calls that should be ignored from line-coverage-measurement * @param duplicatedLinesMap - map of found duplicates in the class. You should use {@link DetectDuplicatedCodeClassVisitor} to find the duplicated lines. */ public BuildClassMapClassVisitor(ClassVisitor cv, Collection<Pattern> ignoreRegexes, Map<Integer, Map<Integer, Integer>> duplicatedLinesMap, Set<String> ignoredMethods) { super(cv, ignoreRegexes, duplicatedLinesMap); this.ignoredMethods = ignoredMethods; } @Override public AnnotationVisitor visitAnnotation(String name, boolean arg1) { if (Type.getDescriptor(CoverageIgnore.class).equals(name)) { toInstrument = false; } return super.visitAnnotation(name, arg1); } /** * Stores in {@link #classMap} information of className and if the class should be instrumented ({@link #shouldBeInstrumented()}) */ @Override public void visit(int version, int access, String name, String signature, String parent, String[] interfaces) { classMap.setClassName(name); if ((access & Opcodes.ACC_INTERFACE) != 0) { toInstrument = false; } super.visit(version, access, name, signature, parent, interfaces); } /** * Stores in {@link #classMap} information of source filename */ @Override public void visitSource(String file, String debug) { classMap.setSource(file); super.visitSource(file, debug); } /** * Analyzes given method and stores information about all found important places into {@link #classMap} */ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (((access & Opcodes.ACC_STATIC) != 0) && CodeProvider.COBERTURA_INIT_METHOD_NAME.equals(name)) { toInstrument = false; // The class has bean already instrumented. } MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (ignoredMethods.contains(name + desc)) { return mv; } FindTouchPointsMethodAdapter instrumenter = new FindTouchPointsMethodAdapter( new HistoryMethodAdapter(mv, 4), classMap.getClassName(), name, desc, eventIdGenerator, duplicatedLinesMap, lineIdGenerator); instrumenter.setTouchPointListener(touchPointListener); instrumenter.setIgnoreRegexp(getIgnoreRegexp()); return instrumenter; } /** * Returns classMap build for the analyzed map. The classmap is filled after running the analyzer ({@link ClassReader#accept(ClassVisitor, int)}). * * @return the classmap. */ public ClassMap getClassMap() { return classMap; } /** * It's flag that signals if the class should be instrumented by Cobertura. */ public boolean shouldBeInstrumented() { return toInstrument; } }