CoverageTransformer.java revision c572b099c3b59e6e03d9bdaa2ba5e27d4845dcdf
1e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/******************************************************************************* 2e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Copyright (c) 2009, 2012 Mountainminds GmbH & Co. KG and Contributors 3e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * All rights reserved. This program and the accompanying materials 4e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * are made available under the terms of the Eclipse Public License v1.0 5e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * which accompanies this distribution, and is available at 6e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * http://www.eclipse.org/legal/epl-v10.html 7e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 8e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Contributors: 9e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Marc R. Hoffmann - initial API and implementation 10e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 11e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov *******************************************************************************/ 12e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpackage org.jacoco.agent.rt; 13e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 14e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport static java.lang.String.format; 15e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 16e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.lang.instrument.ClassFileTransformer; 17e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.lang.instrument.IllegalClassFormatException; 18e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport java.security.ProtectionDomain; 19e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 20e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.instr.Instrumenter; 21e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.runtime.AgentOptions; 22e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.runtime.IRuntime; 23e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovimport org.jacoco.core.runtime.WildcardMatcher; 24e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 25e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov/** 26e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Class file transformer to instrument classes for code coverage analysis. 27e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 28e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikovpublic class CoverageTransformer implements ClassFileTransformer { 29e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 30e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private static final String AGENT_PREFIX; 31e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 32e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov static { 33e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final String name = CoverageTransformer.class.getName(); 34e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov AGENT_PREFIX = toVMName(name.substring(0, name.lastIndexOf('.'))); 35e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 36e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 37e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final IRuntime runtime; 38e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 39e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final Instrumenter instrumenter; 40e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 41e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final IExceptionLogger logger; 42e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 43e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final WildcardMatcher includes; 44e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 45e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final WildcardMatcher excludes; 46e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 47e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final WildcardMatcher exclClassloader; 48e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 49e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private final ClassFileDumper classFileDumper; 50e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 51e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 52e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * New transformer with the given delegates. 53e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 54e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param runtime 55e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * coverage runtime 56e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param options 57e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * configuration options for the generator 58e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param logger 59e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * logger for exceptions during instrumentation 60e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 61e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public CoverageTransformer(final IRuntime runtime, 62e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final AgentOptions options, final IExceptionLogger logger) { 63e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.runtime = runtime; 64e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.instrumenter = new Instrumenter(runtime); 65e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov this.logger = logger; 66e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // Class names will be reported in VM notation: 67e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov includes = new WildcardMatcher( 68e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov toWildcard(toVMName(options.getIncludes()))); 69e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov excludes = new WildcardMatcher( 70e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov toWildcard(toVMName(options.getExcludes()))); 71e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov exclClassloader = new WildcardMatcher( 72e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov toWildcard(options.getExclClassloader())); 73e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov classFileDumper = new ClassFileDumper(options.getClassDumpDir()); 74e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 75e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 76e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov public byte[] transform(final ClassLoader loader, final String classname, 77e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final Class<?> classBeingRedefined, 78e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final ProtectionDomain protectionDomain, 79e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final byte[] classfileBuffer) throws IllegalClassFormatException { 80e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 81e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov if (!filter(loader, classname)) { 82e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return null; 83e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 84e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 85e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov try { 86e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov classFileDumper.dump(classname, classfileBuffer); 87e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov if (classBeingRedefined != null) { 88e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // For redefined classes we must clear the execution data 89e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // reference as probes might have changed. 90e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov runtime.disconnect(classBeingRedefined); 91e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 92e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return instrumenter.instrument(classfileBuffer); 93e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } catch (final Exception ex) { 94e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final IllegalClassFormatException wrapper = new IllegalClassFormatException( 95e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov format("Error while instrumenting class %s.", classname)); 96c572b099c3b59e6e03d9bdaa2ba5e27d4845dcdfMarc R. Hoffmann wrapper.initCause(ex); 97e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // Report this, as the exception is ignored by the JVM: 98e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov logger.logExeption(wrapper); 99c572b099c3b59e6e03d9bdaa2ba5e27d4845dcdfMarc R. Hoffmann throw wrapper; 100e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 101e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 102e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 103e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov /** 104e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * Checks whether this class should be instrumented. 105e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * 106e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param loader 107e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * loader for the class 108e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @param classname 109e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * VM name of the class to check 110e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov * @return <code>true</code> if the class should be instrumented 111e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov */ 112e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov protected boolean filter(final ClassLoader loader, final String classname) { 113e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov // Don't instrument classes of the bootstrap loader: 114e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return loader != null && 115e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 116e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov !classname.startsWith(AGENT_PREFIX) && 117e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 118e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov !exclClassloader.matches(loader.getClass().getName()) && 119e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 120e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov includes.matches(classname) && 121e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 122e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov !excludes.matches(classname); 123e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 124e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 125e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private String toWildcard(final String src) { 126e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov if (src.indexOf('|') != -1) { 127e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov final IllegalArgumentException ex = new IllegalArgumentException( 128e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov "Usage of '|' as a list separator for JaCoCo agent options is deprecated and will not work in future versions - use ':' instead."); 129e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov logger.logExeption(ex); 130e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return src.replace('|', ':'); 131e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 132e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return src; 133e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 134e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 135e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov private static String toVMName(final String srcName) { 136e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov return srcName.replace('.', '/'); 137e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov } 138e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov 139e69ba4dbb015949c5d84ba7bbb0b53efac28bb23Evgeny Mandrikov} 140