/*******************************************************************************
* Copyright (c) 2006, 2016 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 com.mountainminds.eclemma.internal.core.analysis;
import java.util.HashMap;
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.jdt.core.IPackageFragmentRoot;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.data.ExecutionDataStore;
import com.mountainminds.eclemma.core.EclEmmaStatus;
import com.mountainminds.eclemma.internal.core.DebugOptions;
import com.mountainminds.eclemma.internal.core.DebugOptions.ITracer;
/**
* Analyzes the class files that belong to given package fragment roots. This
* analyzer implements an cache to remember the class files that have been
* analyzed before.
*/
final class PackageFragementRootAnalyzer {
private static final ITracer TRACER = DebugOptions.ANALYSISTRACER;
private final ExecutionDataStore executiondata;
private final Map<Object, AnalyzedNodes> cache;
PackageFragementRootAnalyzer(final ExecutionDataStore executiondata) {
this.executiondata = executiondata;
this.cache = new HashMap<Object, AnalyzedNodes>();
}
AnalyzedNodes analyze(final IPackageFragmentRoot root) throws CoreException {
if (root.isExternal()) {
return analyzeExternal(root);
} else {
return analyzeInternal(root);
}
}
private AnalyzedNodes analyzeInternal(final IPackageFragmentRoot root)
throws CoreException {
IResource location = null;
try {
location = getClassfilesLocation(root);
if (location == null) {
TRACER.trace("No class files found for package fragment root {0}", //$NON-NLS-1$
root.getPath());
return AnalyzedNodes.EMPTY;
}
AnalyzedNodes nodes = cache.get(location);
if (nodes != null) {
return nodes;
}
final CoverageBuilder builder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executiondata, builder);
new ResourceTreeWalker(analyzer).walk(location);
nodes = new AnalyzedNodes(builder.getClasses(), builder.getSourceFiles());
cache.put(location, nodes);
return nodes;
} catch (Exception e) {
throw new CoreException(EclEmmaStatus.BUNDLE_ANALYSIS_ERROR.getStatus(
root.getElementName(), location, e));
}
}
private AnalyzedNodes analyzeExternal(final IPackageFragmentRoot root)
throws CoreException {
IPath location = null;
try {
location = root.getPath();
AnalyzedNodes nodes = cache.get(location);
if (nodes != null) {
return nodes;
}
final CoverageBuilder builder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executiondata, builder);
new ResourceTreeWalker(analyzer).walk(location);
nodes = new AnalyzedNodes(builder.getClasses(), builder.getSourceFiles());
cache.put(location, nodes);
return nodes;
} catch (Exception e) {
throw new CoreException(EclEmmaStatus.BUNDLE_ANALYSIS_ERROR.getStatus(
root.getElementName(), location, e));
}
}
private IResource getClassfilesLocation(IPackageFragmentRoot root)
throws CoreException {
// For binary roots the underlying resource directly points to class files:
if (root.getKind() == IPackageFragmentRoot.K_BINARY) {
return root.getResource();
}
// For source roots we need to find the corresponding output folder:
IPath path = root.getRawClasspathEntry().getOutputLocation();
if (path == null) {
path = root.getJavaProject().getOutputLocation();
}
return root.getResource().getWorkspace().getRoot().findMember(path);
}
}