| /* |
| * User: anna |
| * Date: 27-Aug-2009 |
| */ |
| package com.intellij.execution.coverage; |
| |
| import com.intellij.coverage.*; |
| import com.intellij.coverage.listeners.CoverageListener; |
| import com.intellij.execution.CommonJavaRunConfigurationParameters; |
| import com.intellij.execution.Location; |
| import com.intellij.execution.RunConfigurationExtension; |
| import com.intellij.execution.configurations.*; |
| import com.intellij.execution.configurations.coverage.CoverageConfigurable; |
| import com.intellij.execution.configurations.coverage.CoverageEnabledConfiguration; |
| import com.intellij.execution.configurations.coverage.JavaCoverageEnabledConfiguration; |
| import com.intellij.execution.junit.RefactoringListeners; |
| import com.intellij.execution.process.ProcessHandler; |
| import com.intellij.notification.Notification; |
| import com.intellij.notification.NotificationType; |
| import com.intellij.notification.Notifications; |
| import com.intellij.openapi.options.SettingsEditor; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.projectRoots.JavaSdk; |
| import com.intellij.openapi.projectRoots.JavaSdkVersion; |
| import com.intellij.openapi.projectRoots.Sdk; |
| import com.intellij.openapi.util.InvalidDataException; |
| import com.intellij.openapi.util.WriteExternalException; |
| import com.intellij.psi.*; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.refactoring.listeners.RefactoringElementListener; |
| import com.intellij.refactoring.listeners.RefactoringElementListenerComposite; |
| import com.intellij.ui.classFilter.ClassFilter; |
| import com.intellij.util.ArrayUtil; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Registers "Coverage" tab in Java run configurations |
| */ |
| public class CoverageJavaRunConfigurationExtension extends RunConfigurationExtension { |
| public void attachToProcess(@NotNull final RunConfigurationBase configuration, @NotNull ProcessHandler handler, RunnerSettings runnerSettings) { |
| CoverageDataManager.getInstance(configuration.getProject()).attachToProcess(handler, configuration, runnerSettings); |
| } |
| |
| @Nullable |
| public SettingsEditor createEditor(@NotNull RunConfigurationBase configuration) { |
| return new CoverageConfigurable(configuration); |
| } |
| |
| public String getEditorTitle() { |
| return CoverageEngine.getEditorTitle(); |
| } |
| |
| @NotNull |
| @Override |
| public String getSerializationId() { |
| return "coverage"; |
| } |
| |
| public void updateJavaParameters(RunConfigurationBase configuration, JavaParameters params, RunnerSettings runnerSettings) { |
| if (!isApplicableFor(configuration)) { |
| return; |
| } |
| |
| final JavaCoverageEnabledConfiguration coverageConfig = JavaCoverageEnabledConfiguration.getFrom(configuration); |
| //noinspection ConstantConditions |
| coverageConfig.setCurrentCoverageSuite(null); |
| final CoverageRunner coverageRunner = coverageConfig.getCoverageRunner(); |
| if (runnerSettings instanceof CoverageRunnerData && coverageRunner != null) { |
| final CoverageDataManager coverageDataManager = CoverageDataManager.getInstance(configuration.getProject()); |
| coverageConfig.setCurrentCoverageSuite(coverageDataManager.addCoverageSuite(coverageConfig)); |
| coverageConfig.appendCoverageArgument(params); |
| |
| final Sdk jdk = params.getJdk(); |
| if (jdk != null && JavaSdk.getInstance().isOfVersionOrHigher(jdk, JavaSdkVersion.JDK_1_7) && coverageRunner instanceof JavaCoverageRunner && !((JavaCoverageRunner)coverageRunner).isJdk7Compatible()) { |
| Notifications.Bus.notify(new Notification("Coverage", "Coverage instrumentation is not fully compatible with JDK 7", |
| coverageRunner.getPresentableName() + |
| " coverage instrumentation can lead to java.lang.VerifyError errors with JDK 7. If so, please try IDEA coverage runner.", |
| NotificationType.WARNING)); |
| } |
| } |
| } |
| |
| @Override |
| public void readExternal(@NotNull final RunConfigurationBase runConfiguration, @NotNull Element element) throws InvalidDataException { |
| if (!isApplicableFor(runConfiguration)) { |
| return; |
| } |
| |
| //noinspection ConstantConditions |
| JavaCoverageEnabledConfiguration.getFrom(runConfiguration).readExternal(element); |
| } |
| |
| @Override |
| public void writeExternal(@NotNull RunConfigurationBase runConfiguration, @NotNull Element element) throws WriteExternalException { |
| if (!isApplicableFor(runConfiguration)) { |
| return; |
| } |
| //noinspection ConstantConditions |
| JavaCoverageEnabledConfiguration.getFrom(runConfiguration).writeExternal(element); |
| } |
| |
| @Override |
| public void extendCreatedConfiguration(@NotNull RunConfigurationBase runJavaConfiguration, @NotNull Location location) { |
| final JavaCoverageEnabledConfiguration coverageEnabledConfiguration = JavaCoverageEnabledConfiguration.getFrom(runJavaConfiguration); |
| assert coverageEnabledConfiguration != null; |
| if (runJavaConfiguration instanceof CommonJavaRunConfigurationParameters) { |
| coverageEnabledConfiguration.setUpCoverageFilters(((CommonJavaRunConfigurationParameters)runJavaConfiguration).getRunClass(), |
| ((CommonJavaRunConfigurationParameters)runJavaConfiguration).getPackage()); |
| } |
| } |
| |
| @Override |
| public void cleanUserData(RunConfigurationBase runConfiguration) { |
| runConfiguration.putCopyableUserData(CoverageEnabledConfiguration.COVERAGE_KEY, null); |
| } |
| |
| @Override |
| public void validateConfiguration(@NotNull RunConfigurationBase runJavaConfiguration, boolean isExecution) |
| throws RuntimeConfigurationException { |
| } |
| |
| @Override |
| public RefactoringElementListener wrapElementListener(PsiElement element, |
| RunConfigurationBase configuration, |
| RefactoringElementListener listener) { |
| if (!isApplicableFor(configuration)) { |
| return listener; |
| } |
| final JavaCoverageEnabledConfiguration coverageEnabledConfiguration = JavaCoverageEnabledConfiguration.getFrom(configuration); |
| if (coverageEnabledConfiguration != null) { |
| final Project project = configuration.getProject(); |
| final ClassFilter[] patterns = coverageEnabledConfiguration.getCoveragePatterns(); |
| final String[] filters = getFilters(coverageEnabledConfiguration); |
| if (patterns != null) { |
| assert filters != null; |
| if (element instanceof PsiClass) { |
| final int idx = ArrayUtil.find(filters, ((PsiClass)element).getQualifiedName()); |
| if (idx > -1) { |
| final RefactoringListeners.Accessor<PsiClass> accessor = new MyClassAccessor(project, patterns, idx, filters); |
| final RefactoringElementListener classListener = RefactoringListeners.getClassOrPackageListener(element, accessor); |
| if (classListener != null) { |
| listener = appendListener(listener, classListener); |
| } |
| } |
| } else if (element instanceof PsiPackage) { |
| final String qualifiedName = ((PsiPackage)element).getQualifiedName(); |
| for (int i = 0, filtersLength = filters.length; i < filtersLength; i++) { |
| if (filters[i].startsWith(qualifiedName + ".")) { |
| final RefactoringElementListener packageListener; |
| if (filters[i].endsWith("*")) { |
| packageListener = RefactoringListeners.getListener((PsiPackage)element, |
| new MyPackageAccessor(project, patterns, i, filters)); |
| } else { |
| packageListener = RefactoringListeners.getClassOrPackageListener(element, |
| new MyClassAccessor(project, patterns, i, filters)); |
| } |
| if (packageListener != null) { |
| listener = appendListener(listener, packageListener); |
| } |
| } |
| } |
| } |
| } |
| } |
| return listener; |
| } |
| |
| @Nullable |
| private static String[] getFilters(JavaCoverageEnabledConfiguration coverageEnabledConfiguration) { |
| final ClassFilter[] patterns = coverageEnabledConfiguration.getCoveragePatterns(); |
| if (patterns != null) { |
| final List<String> filters = new ArrayList<String>(); |
| for (ClassFilter classFilter : patterns) { |
| filters.add(classFilter.getPattern()); |
| } |
| return ArrayUtil.toStringArray(filters); |
| } |
| return null; |
| } |
| |
| private static RefactoringElementListener appendListener(RefactoringElementListener listener, |
| final RefactoringElementListener classOrPackageListener) { |
| if (listener == null) { |
| listener = new RefactoringElementListenerComposite(); |
| } else if (!(listener instanceof RefactoringElementListenerComposite)) { |
| final RefactoringElementListenerComposite composite = new RefactoringElementListenerComposite(); |
| composite.addListener(listener); |
| listener = composite; |
| } |
| ((RefactoringElementListenerComposite)listener).addListener(classOrPackageListener); |
| return listener; |
| } |
| |
| @Override |
| public boolean isListenerDisabled(RunConfigurationBase configuration, Object listener, RunnerSettings runnerSettings) { |
| if (listener instanceof CoverageListener) { |
| if (!(runnerSettings instanceof CoverageRunnerData)) return true; |
| final CoverageEnabledConfiguration coverageEnabledConfiguration = CoverageEnabledConfiguration.getOrCreate(configuration); |
| return !(coverageEnabledConfiguration.getCoverageRunner() instanceof IDEACoverageRunner) || |
| !(coverageEnabledConfiguration.isTrackPerTestCoverage() && !coverageEnabledConfiguration.isSampling()); |
| } |
| return false; |
| } |
| |
| protected boolean isApplicableFor(@NotNull final RunConfigurationBase configuration) { |
| return CoverageEnabledConfiguration.isApplicableTo(configuration); |
| } |
| |
| private static class MyPackageAccessor extends MyAccessor implements RefactoringListeners.Accessor<PsiPackage> { |
| |
| |
| private MyPackageAccessor(Project project, ClassFilter[] patterns, int idx, String[] filters) { |
| super(project, patterns, idx, filters); |
| } |
| |
| public void setName(String qualifiedName) { |
| super.setName(qualifiedName + ".*"); |
| } |
| |
| public PsiPackage getPsiElement() { |
| final String name = getName(); |
| return JavaPsiFacade.getInstance(getProject()).findPackage(name.substring(0, name.length() - ".*".length())); |
| } |
| |
| public void setPsiElement(PsiPackage psiElement) { |
| setName(psiElement.getQualifiedName()); |
| } |
| } |
| |
| private static class MyClassAccessor extends MyAccessor implements RefactoringListeners.Accessor<PsiClass> { |
| |
| private MyClassAccessor(Project project, ClassFilter[] patterns, int idx, String[] filters) { |
| super(project, patterns, idx, filters); |
| } |
| |
| public PsiClass getPsiElement() { |
| return JavaPsiFacade.getInstance(getProject()).findClass(getName(), GlobalSearchScope.allScope(getProject())); |
| } |
| |
| public void setPsiElement(PsiClass psiElement) { |
| setName(psiElement.getQualifiedName()); |
| } |
| } |
| |
| private static class MyAccessor { |
| private final Project myProject; |
| private final ClassFilter[] myPatterns; |
| private final int myIdx; |
| private final String[] myFilters; |
| |
| private MyAccessor(Project project, ClassFilter[] patterns, int idx, String[] filters) { |
| myProject = project; |
| myPatterns = patterns; |
| myIdx = idx; |
| myFilters = filters; |
| } |
| |
| public void setName(String qName) { |
| myPatterns[myIdx] = new ClassFilter(qName); |
| } |
| |
| public String getName() { |
| return myFilters[myIdx]; |
| } |
| |
| public Project getProject() { |
| return myProject; |
| } |
| } |
| } |