coverage: setting to ignore trivial constructors

This commit is contained in:
Anna Kozlova
2017-09-13 16:49:27 +03:00
parent 13615c5b3d
commit 224bf4f33b
7 changed files with 180 additions and 22 deletions
@@ -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
+2
View File
@@ -26,6 +26,8 @@
<coverageRunner implementation="com.intellij.coverage.JaCoCoCoverageRunner"/>
<coverageEngine implementation="com.intellij.coverage.JavaCoverageEngine" order = "last"/>
<projectViewNodeDecorator implementation="com.intellij.coverage.CoverageProjectViewClassNodeDecorator"/>
<projectService serviceImplementation="com.intellij.coverage.JavaCoverageOptionsProvider"/>
<coverageOptions implementation="com.intellij.coverage.JavaCoverageOptions"/>
<projectService serviceInterface="com.intellij.coverage.JavaCoverageAnnotator"
serviceImplementation="com.intellij.coverage.JavaCoverageAnnotator"/>
@@ -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
@@ -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());
}
}
}
@@ -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<JavaCoverageOptionsProvider.State> {
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;
}
}
@@ -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);
}
}
@@ -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<String> includeDescriptionCondition) {
if (content == null) return false;
ClassReader reader = new ClassReader(content, 0, content.length);
@@ -42,13 +42,13 @@ public class SourceLineCounterUtil {
Set<Object> descriptions = new HashSet<>();
TIntObjectHashMap<?> lines = counter.getSourceLines();
lines.forEachEntry((line, description) -> {
if (!PackageAnnotator.isGeneratedDefaultConstructor(psiClass, (String)description)) {
classCoverageInfo.totalLineCount ++;
packageCoverageInfo.totalLineCount ++;
descriptions.add(description);
}
return true;
});
if (includeDescriptionCondition.value((String)description)) {
classCoverageInfo.totalLineCount++;
packageCoverageInfo.totalLineCount++;
descriptions.add(description);
}
return true;
});
classCoverageInfo.totalMethodCount += descriptions.size();
packageCoverageInfo.totalMethodCount += descriptions.size();
@@ -68,10 +68,16 @@ public class SourceLineCounterUtil {
reader.accept(collector, 0);
String qualifiedName = reader.getClassName();
PsiClass psiClass = ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName));
boolean ignoreEmptyPrivateConstructors = JavaCoverageOptionsProvider.getInstance(project).ignoreEmptyPrivateConstructors();
PsiClass psiClass = ignoreEmptyPrivateConstructors
? ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName))
: null;
Condition<String> includeDescriptionCondition = ignoreEmptyPrivateConstructors
? description -> !PackageAnnotator.isGeneratedDefaultConstructor(psiClass, description)
: Condition.TRUE;
TIntObjectHashMap<?> lines = collector.getSourceLines();
lines.forEachEntry((line, description) -> {
if (!PackageAnnotator.isGeneratedDefaultConstructor(psiClass, (String)description)) {
if (includeDescriptionCondition.value((String)description)) {
line--;
uncoveredLines.add(line);
}