diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java
index 7c96cd7de1e8..a84bfe67f691 100644
--- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java
+++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java
@@ -137,7 +137,6 @@ public class CoverageDataManagerImpl extends CoverageDataManager {
@Override
public void readExternal(Element element) throws InvalidDataException {
- //noinspection unchecked
for (Element suiteElement : element.getChildren(SUITE)) {
final CoverageRunner coverageRunner = BaseCoverageSuite.readRunnerAttribute(suiteElement);
// skip unknown runners
diff --git a/plugins/coverage/src/META-INF/plugin.xml b/plugins/coverage/src/META-INF/plugin.xml
index 6b9f5961d53e..97c83b556bf5 100644
--- a/plugins/coverage/src/META-INF/plugin.xml
+++ b/plugins/coverage/src/META-INF/plugin.xml
@@ -26,6 +26,8 @@
+
+
diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java
index 49be86c13f47..b36f7847dc83 100644
--- a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java
+++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java
@@ -654,8 +654,11 @@ public class JavaCoverageEngine extends CoverageEngine {
@Override
public boolean isGeneratedCode(Project project, String qualifiedName, Object lineData) {
- PsiClass psiClass = ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName));
- return PackageAnnotator.isGeneratedDefaultConstructor(psiClass, ((LineData)lineData).getMethodSignature());
+ if (JavaCoverageOptionsProvider.getInstance(project).ignoreEmptyPrivateConstructors()) {
+ PsiClass psiClass = ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName));
+ return PackageAnnotator.isGeneratedDefaultConstructor(psiClass, ((LineData)lineData).getMethodSignature());
+ }
+ return super.isGeneratedCode(project, qualifiedName, lineData);
}
@Override
diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptions.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptions.java
new file mode 100644
index 000000000000..2af4314e3c82
--- /dev/null
+++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptions.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.coverage;
+
+import com.intellij.ui.IdeBorderFactory;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class JavaCoverageOptions extends CoverageOptions {
+
+ private final JavaCoverageOptionsProvider myCoverageOptionsProvider;
+ private JavaCoverageOptionsEditor myEditor;
+
+ public JavaCoverageOptions(JavaCoverageOptionsProvider coverageOptionsProvider) {
+ myCoverageOptionsProvider = coverageOptionsProvider;
+ }
+
+ @Override
+ public JComponent getComponent() {
+ myEditor = new JavaCoverageOptionsEditor();
+ return myEditor.getComponent();
+ }
+
+ @Override
+ public boolean isModified() {
+ return myEditor.isModified(myCoverageOptionsProvider);
+ }
+
+ @Override
+ public void apply() {
+ myEditor.apply(myCoverageOptionsProvider);
+ }
+
+ @Override
+ public void reset() {
+ myEditor.reset(myCoverageOptionsProvider);
+ }
+
+ @Override
+ public void disposeUIResources() {
+ myEditor = null;
+ }
+
+ private static class JavaCoverageOptionsEditor {
+
+ private JPanel myPanel = new JPanel(new BorderLayout(0, 10));
+ private JCheckBox myCheckBox = new JCheckBox("Ignore empty private and implicit constructors", true);
+
+ public JavaCoverageOptionsEditor() {
+ myPanel.setBorder(IdeBorderFactory.createTitledBorder("Java coverage"));
+ myPanel.add(myCheckBox, BorderLayout.NORTH);
+ }
+
+ public JPanel getComponent() {
+ return myPanel;
+ }
+
+ public boolean isModified(JavaCoverageOptionsProvider provider) {
+ return myCheckBox.isSelected() != provider.ignoreEmptyPrivateConstructors();
+ }
+
+ public void apply(JavaCoverageOptionsProvider provider) {
+ provider.setIgnoreEmptyPrivateConstructors(myCheckBox.isSelected());
+ }
+
+ public void reset(JavaCoverageOptionsProvider provider) {
+ myCheckBox.setSelected(provider.ignoreEmptyPrivateConstructors());
+ }
+ }
+}
diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptionsProvider.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptionsProvider.java
new file mode 100644
index 000000000000..22fb29900059
--- /dev/null
+++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptionsProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.coverage;
+
+import com.intellij.openapi.components.*;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.Nullable;
+
+@State(
+ name = "JavaCoverageOptionsProvider",
+ storages = {
+ @Storage(StoragePathMacros.WORKSPACE_FILE)
+ }
+)
+public class JavaCoverageOptionsProvider implements PersistentStateComponent {
+ private State myState = new State();
+
+ public static JavaCoverageOptionsProvider getInstance(Project project) {
+ return ServiceManager.getService(project, JavaCoverageOptionsProvider.class);
+ }
+
+
+ public void setIgnoreEmptyPrivateConstructors(boolean state) {
+ myState.myIgnoreEmptyPrivateConstructors = state;
+ }
+
+ public boolean ignoreEmptyPrivateConstructors() {
+ return myState.myIgnoreEmptyPrivateConstructors;
+ }
+
+ @Nullable
+ @Override
+ public JavaCoverageOptionsProvider.State getState() {
+ return myState;
+ }
+
+ @Override
+ public void loadState(JavaCoverageOptionsProvider.State state) {
+ myState.myIgnoreEmptyPrivateConstructors = state.myIgnoreEmptyPrivateConstructors;
+ }
+
+
+ public static class State {
+ public boolean myIgnoreEmptyPrivateConstructors = true;
+ }
+
+}
diff --git a/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java b/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java
index 2f90f21a4db0..4f450db59e0d 100644
--- a/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java
+++ b/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java
@@ -23,6 +23,7 @@ import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -37,6 +38,7 @@ import com.intellij.rt.coverage.data.LineData;
import com.intellij.rt.coverage.data.ProjectData;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.SmartHashSet;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
import org.jetbrains.jps.model.java.JavaSourceRootType;
@@ -57,12 +59,14 @@ public class PackageAnnotator {
private final Project myProject;
private final PsiManager myManager;
private final CoverageDataManager myCoverageManager;
+ private final boolean myIgnoreEmptyPrivateConstructors;
public PackageAnnotator(final PsiPackage aPackage) {
myPackage = aPackage;
myProject = myPackage.getProject();
myManager = PsiManager.getInstance(myProject);
myCoverageManager = CoverageDataManager.getInstance(myProject);
+ myIgnoreEmptyPrivateConstructors = JavaCoverageOptionsProvider.getInstance(myProject).ignoreEmptyPrivateConstructors();
}
public interface Annotator {
@@ -455,7 +459,7 @@ public class PackageAnnotator {
touchedClass = true;
}
- if (isGeneratedDefaultConstructor(psiClass, (String)nameAndSig)) {
+ if (myIgnoreEmptyPrivateConstructors && isGeneratedDefaultConstructor(psiClass, (String)nameAndSig)) {
continue;
}
@@ -505,16 +509,16 @@ public class PackageAnnotator {
* in the bytecode, so we need to look at the PSI to see if the class defines such a constructor.
*/
public static boolean isGeneratedDefaultConstructor(@Nullable final PsiClass aClass, String nameAndSig) {
+ if (aClass == null) {
+ return false;
+ }
if (DEFAULT_CONSTRUCTOR_NAME_SIGNATURE.equals(nameAndSig)) {
return hasGeneratedOrEmptyPrivateConstructor(aClass);
}
return false;
}
- private static boolean hasGeneratedOrEmptyPrivateConstructor(@Nullable final PsiClass aClass) {
- if (aClass == null) {
- return false;
- }
+ private static boolean hasGeneratedOrEmptyPrivateConstructor(@NotNull final PsiClass aClass) {
return ReadAction.compute(() -> {
PsiMethod[] constructors = aClass.getConstructors();
if (constructors.length == 1 && constructors[0].hasModifierProperty(PsiModifier.PRIVATE)) {
@@ -563,6 +567,6 @@ public class PackageAnnotator {
if (coverageSuite == null) return false;
return SourceLineCounterUtil
.collectNonCoveredClassInfo(classCoverageInfo, packageCoverageInfo, content, coverageSuite.isTracingEnabled(),
- psiClass);
+ myIgnoreEmptyPrivateConstructors ? description -> !isGeneratedDefaultConstructor(psiClass, description) : Condition.TRUE);
}
}
diff --git a/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java b/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java
index e5e8851fbae7..b3be240bcdaf 100644
--- a/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java
+++ b/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java
@@ -17,6 +17,7 @@ package com.intellij.coverage;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.ClassUtil;
@@ -29,11 +30,10 @@ import java.util.List;
import java.util.Set;
public class SourceLineCounterUtil {
- public static boolean collectNonCoveredClassInfo(final PackageAnnotator.ClassCoverageInfo classCoverageInfo,
- final PackageAnnotator.PackageCoverageInfo packageCoverageInfo,
- byte[] content,
+ public static boolean collectNonCoveredClassInfo(final PackageAnnotator.ClassCoverageInfo classCoverageInfo,
+ final PackageAnnotator.PackageCoverageInfo packageCoverageInfo, byte[] content,
final boolean excludeLines,
- final PsiClass psiClass) {
+ final Condition includeDescriptionCondition) {
if (content == null) return false;
ClassReader reader = new ClassReader(content, 0, content.length);
@@ -42,13 +42,13 @@ public class SourceLineCounterUtil {
Set