/******************************************************************************* * Copyright (c) 2006 Mountainminds GmbH & Co. KG * This software is provided under the terms of the Eclipse Public License v1.0 * See http://www.eclipse.org/legal/epl-v10.html. * * $Id: SessionAnalyzer.java 473 2008-05-28 20:51:30Z mtnminds $ ******************************************************************************/ package com.mountainminds.eclemma.internal.core.analysis; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.osgi.util.NLS; import com.mountainminds.eclemma.core.EclEmmaStatus; import com.mountainminds.eclemma.core.ICoverageSession; import com.mountainminds.eclemma.core.IInstrumentation; import com.mountainminds.eclemma.core.analysis.IJavaModelCoverage; import com.mountainminds.eclemma.internal.core.CoreMessages; import com.mountainminds.eclemma.internal.core.DebugOptions; import com.mountainminds.eclemma.internal.core.EclEmmaCorePlugin; import com.mountainminds.eclemma.internal.core.DebugOptions.ITracer; import com.mountainminds.eclemma.internal.core.analysis.TypeCoverage.UnboundMethodCoverage; import com.vladium.emma.data.ClassDescriptor; import com.vladium.emma.data.DataFactory; import com.vladium.emma.data.ICoverageData; import com.vladium.emma.data.IMergeable; import com.vladium.emma.data.IMetaData; import com.vladium.emma.data.MethodDescriptor; import com.vladium.emma.data.ICoverageData.DataHolder; /** * @author Marc R. Hoffmann * @version $Revision: 473 $ */ public class SessionAnalyzer { private static final ITracer TRACER = DebugOptions.ANALYSISTRACER; private static final ITracer PERFORMANCE = DebugOptions.PERFORMANCETRACER; private JavaModelCoverage modelcoverage; public IJavaModelCoverage processSession(ICoverageSession session, IProgressMonitor monitor) throws CoreException { PERFORMANCE.startTimer(); PERFORMANCE.startMemoryUsage(); modelcoverage = new JavaModelCoverage(); IPath[] coveragefiles = session.getCoverageDataFiles(); IInstrumentation[] instrumentations = session.getInstrumentations(); monitor.beginTask(NLS.bind(CoreMessages.AnalyzingCoverageSession_task, session.getDescription()), coveragefiles.length + instrumentations.length); ICoverageData coveragedata = null; for (int i = 0; i < coveragefiles.length && !monitor.isCanceled(); i++) { coveragedata = processCoveragedataFile(coveragedata, coveragefiles[i]); monitor.worked(1); } for (int i = 0; i < instrumentations.length && !monitor.isCanceled(); i++) { processMetadataFile(coveragedata, instrumentations[i], new SubProgressMonitor(monitor, 1)); } monitor.done(); PERFORMANCE.stopTimer("loading " + session.getDescription()); //$NON-NLS-1$ PERFORMANCE.stopMemoryUsage("loading " + session.getDescription()); //$NON-NLS-1$ return modelcoverage; } private ICoverageData processCoveragedataFile(ICoverageData coveragedata, IPath path) throws CoreException { try { File f = path.toFile(); if (f.exists()) { IMergeable data = DataFactory.load(f)[DataFactory.TYPE_COVERAGEDATA]; if (coveragedata == null) { coveragedata = (ICoverageData) data; } else { coveragedata = (ICoverageData) coveragedata.merge(data); } } return coveragedata; } catch (IOException e) { throw new CoreException(EclEmmaStatus.COVERAGEDATA_FILE_READ_ERROR .getStatus(path, e)); } } private void processMetadataFile(ICoverageData coveragedata, IInstrumentation instrumentation, IProgressMonitor monitor) throws CoreException { IPath metadatafile = instrumentation.getMetaDataFile(); File f = metadatafile.toFile(); if (f.exists()) { IMetaData metadata; try { metadata = (IMetaData) DataFactory.load(f)[DataFactory.TYPE_METADATA]; } catch (IOException e) { throw new CoreException(EclEmmaStatus.METADATA_FILE_READ_ERROR.getStatus( metadatafile, e)); } if (metadata == null) { throw new CoreException(EclEmmaStatus.FILE_CONTAINS_NO_METADATA.getStatus( metadatafile)); } IPackageFragmentRoot[] roots = instrumentation.getClassFiles().getPackageFragmentRoots(); TypeTraverser jep = new TypeTraverser(roots); jep.process(new TypeVisitor(metadata, coveragedata), monitor); } } private class TypeVisitor implements ITypeVisitor { private final ICoverageData coveragedata; private final Map descriptors; TypeVisitor(IMetaData metadata, ICoverageData coveragedata) { this.coveragedata = coveragedata; this.descriptors = new HashMap(); for (Iterator i = metadata.iterator(); i.hasNext();) { ClassDescriptor cd = (ClassDescriptor) i.next(); descriptors.put(cd.getClassVMName(), cd); } } public void visit(IType type, String vmname) { ClassDescriptor descriptor = (ClassDescriptor) descriptors.remove(vmname); if (descriptor != null) { DataHolder data = coveragedata == null ? null : coveragedata.getCoverage(descriptor); if (data != null && data.m_stamp != descriptor.getStamp()) { TRACER.trace("Invalid meta data signature for {0}.", descriptor.getClassVMName()); //$NON-NLS-1$ } else { // This call recurses up the hierarchy from the current Type up // to the package root setting up coverage objects TypeCoverage typecoverage = (TypeCoverage) getCoverage(type, descriptor.hasCompleteLineNumberInfo()); // Check whether there are any active filters boolean activeFilters = EclEmmaCorePlugin.getInstance().getJavaCoverageLoader().coverageFiltersActive(); // This adds all the child objects and sets up their associated // coverage objects IResource resource = type.getResource(); typecoverage.addType(data != null); MethodDescriptor[] methods = descriptor.getMethods(); boolean[][] covered = data == null ? null : data.m_coverage; if (!activeFilters) { // No active filters - revert to legacy lazy binding UnboundMethodCoverage[] ubcoverage = new UnboundMethodCoverage[methods.length]; for (int i = 0; i < methods.length; i++) { JavaElementCoverage coverage = new JavaElementCoverage(typecoverage, methods[i].hasLineNumberInfo(), resource); processMethodCoverage(coverage, methods[i], covered == null ? null : covered[i], resource); ubcoverage[i] = new UnboundMethodCoverage(methods[i].getName(), methods[i].getDescriptor(), coverage); } typecoverage.setUnboundMethods(ubcoverage); } else { // Check whether any filters are interested in this Type boolean typeFiltered = EclEmmaCorePlugin.getInstance().getJavaCoverageLoader().isElementFiltered(type, true); if (!typeFiltered) { try { MethodMatcher matcher = new MethodMatcher(type, covered, methods); while(matcher.methodMatched()) { // Get selected objects IJavaElement element = matcher.getMatchedElement(); MethodDescriptor mdescriptor = matcher.getMatchedDescriptor(); boolean[] mcoverage = matcher.getMatchedCoverageData(); boolean methodFiltered = EclEmmaCorePlugin.getInstance().getJavaCoverageLoader().isElementFiltered(element, false); if (!methodFiltered) { // Setup coverage data JavaElementCoverage elementCoverage = getCoverage(element, mdescriptor.hasLineNumberInfo()); processMethodCoverage(elementCoverage, mdescriptor, mcoverage, resource); } } } catch (JavaModelException e) { IStatus status = new Status(IStatus.ERROR, EclEmmaCorePlugin.ID, IStatus.ERROR, "Exception examining methods within type: " + type,e); //$NON-NLS-1$ EclEmmaCorePlugin.getInstance().getLog().log(status); } } } } } } public void done() { // dump what's left for (Iterator i = descriptors.keySet().iterator(); i.hasNext();) { TRACER.trace("Instrumented type {0} has not been processed.", i.next()); //$NON-NLS-1$ } } } private boolean isMethodCovered(boolean[] blocks) { for (int i = 0; blocks != null && i < blocks.length; i++) { if (blocks[i]) return true; } return false; } private void processMethodCoverage(JavaElementCoverage coverage, MethodDescriptor descriptor, boolean[] covered, IResource resource) { coverage.addMethod(isMethodCovered(covered)); IJavaElement element = coverage.getJavaElement(coverage); int[] blocksizes = descriptor.getBlockSizes(); if (blocksizes != null) { int blockcount = blocksizes.length; int[][] blocklines = descriptor.getBlockMap(); for (int i = 0; i < blockcount; i++) { // Apply any active line filters int[] filteredLines = EclEmmaCorePlugin.getInstance().getJavaCoverageLoader().getFilteredLines(blocklines == null ? null : blocklines[i], element, false); // Load the block coverage.addBlock(blocksizes[i], filteredLines, covered == null ? false : covered[i]); } } } private JavaElementCoverage getCoverage(IJavaElement element, boolean haslines) { if (element == null) return null; JavaElementCoverage c = (JavaElementCoverage) modelcoverage.getCoverageFor(element); if (c == null) { switch (element.getElementType()) { case IJavaElement.JAVA_MODEL: c = modelcoverage; break; case IJavaElement.JAVA_PROJECT: case IJavaElement.PACKAGE_FRAGMENT_ROOT: case IJavaElement.PACKAGE_FRAGMENT: c = new JavaElementCoverage(getCoverage(element.getParent(), false), false, element.getResource()); break; case IJavaElement.TYPE: c = new TypeCoverage(getCoverage(element.getParent(), haslines), haslines, element.getResource()); break; default: c = new JavaElementCoverage(getCoverage(element.getParent(), haslines), haslines, element.getResource()); break; } modelcoverage.put(element, c); } return c; } }