mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-24588 (Inspection: symbol in production code is only referenced from test code)
This commit is contained in:
@@ -1904,3 +1904,7 @@ unnecessary.explicit.numeric.cast.quickfix=Remove cast
|
||||
null.thrown.display.name='null' thrown
|
||||
null.thrown.problem.descriptor=<code>#ref</code> thrown
|
||||
null.thrown.quickfix=Replace with 'new NullPointerException()'
|
||||
element.only.used.from.test.code.display.name=Symbol only used from test code
|
||||
class.only.used.from.test.code.problem.descriptor=class <code>#ref</code> only used from test code #loc
|
||||
method.only.used.from.test.code.problem.descriptor=method <code>#ref</code> only called from test code #loc
|
||||
field.only.used.from.test.code.problem.descriptor=field <code>#ref</code> only accessed from test code #loc
|
||||
|
||||
@@ -74,6 +74,7 @@ import com.siyeh.ig.numeric.*;
|
||||
import com.siyeh.ig.packaging.*;
|
||||
import com.siyeh.ig.performance.*;
|
||||
import com.siyeh.ig.portability.*;
|
||||
import com.siyeh.ig.redundancy.ElementOnlyUsedFromTestCodeInspection;
|
||||
import com.siyeh.ig.redundancy.UnusedLabelInspection;
|
||||
import com.siyeh.ig.resources.*;
|
||||
import com.siyeh.ig.security.*;
|
||||
@@ -985,6 +986,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent,
|
||||
}
|
||||
|
||||
private void registerRedundancyInspections() {
|
||||
m_inspectionClasses.add(ElementOnlyUsedFromTestCodeInspection.class);
|
||||
m_inspectionClasses.add(UnusedLabelInspection.class);
|
||||
}
|
||||
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2011 Bas Leijdekkers
|
||||
*
|
||||
* 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.siyeh.ig.redundancy;
|
||||
|
||||
import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.codeInsight.TestUtil;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.reference.*;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseGlobalInspection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ElementOnlyUsedFromTestCodeInspection
|
||||
extends BaseGlobalInspection {
|
||||
|
||||
private static final Key<Boolean> ONLY_USED_FROM_TEST_CODE =
|
||||
Key.create("ONLY_USED_FROM_TEST_CODE");
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"element.only.used.from.test.code.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RefGraphAnnotator getAnnotator(RefManager refManager) {
|
||||
return new ElementOnlyUsedFromTestCodeAnnotator();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CommonProblemDescriptor[] checkElement(
|
||||
RefEntity refEntity, AnalysisScope scope, InspectionManager manager,
|
||||
GlobalInspectionContext globalContext,
|
||||
ProblemDescriptionsProcessor processor) {
|
||||
if (!isOnlyUsedFromTestCode(refEntity)) {
|
||||
return null;
|
||||
}
|
||||
if (!(refEntity instanceof RefJavaElement)) {
|
||||
return null;
|
||||
}
|
||||
final RefJavaElement javaElement = (RefJavaElement) refEntity;
|
||||
if (!javaElement.isReferenced()) {
|
||||
return null;
|
||||
}
|
||||
final PsiElement element = javaElement.getElement();
|
||||
if (element instanceof PsiClass) {
|
||||
final PsiClass aClass = (PsiClass) element;
|
||||
final PsiIdentifier identifier = aClass.getNameIdentifier();
|
||||
if (identifier == null) {
|
||||
return null;
|
||||
}
|
||||
return new CommonProblemDescriptor[]{
|
||||
manager.createProblemDescriptor(identifier,
|
||||
InspectionGadgetsBundle.message(
|
||||
"class.only.used.from.test.code.problem.descriptor"),
|
||||
true, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)
|
||||
};
|
||||
} else if (element instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod) element;
|
||||
final PsiIdentifier identifier = method.getNameIdentifier();
|
||||
if (identifier == null) {
|
||||
return null;
|
||||
}
|
||||
return new CommonProblemDescriptor[]{
|
||||
manager.createProblemDescriptor(identifier,
|
||||
InspectionGadgetsBundle.message(
|
||||
"method.only.used.from.test.code.problem.descriptor"),
|
||||
true, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)
|
||||
};
|
||||
} else if (element instanceof PsiField) {
|
||||
final PsiField field = (PsiField) element;
|
||||
final PsiIdentifier identifier = field.getNameIdentifier();
|
||||
return new CommonProblemDescriptor[]{
|
||||
manager.createProblemDescriptor(identifier,
|
||||
InspectionGadgetsBundle.message(
|
||||
"field.only.used.from.test.code.problem.descriptor"),
|
||||
true, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isInsideTestClass(@NotNull PsiElement e) {
|
||||
final PsiClass aClass = getTopLevelParentClass(e);
|
||||
return aClass != null && TestUtil.isTestClass(aClass);
|
||||
}
|
||||
|
||||
private static boolean isUnderTestSources(PsiElement e) {
|
||||
final ProjectRootManager rootManager =
|
||||
ProjectRootManager.getInstance(e.getProject());
|
||||
final VirtualFile file = e.getContainingFile().getVirtualFile();
|
||||
return file != null &&
|
||||
rootManager.getFileIndex().isInTestSourceContent(file);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClass getTopLevelParentClass(PsiElement e) {
|
||||
PsiClass result = null;
|
||||
PsiElement parent = e.getParent();
|
||||
while (parent != null && !(parent instanceof PsiFile)) {
|
||||
if (parent instanceof PsiClass) {
|
||||
result = (PsiClass)parent;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isOnlyUsedFromTestCode(RefEntity refElement) {
|
||||
final Boolean usedFromTestCode =
|
||||
refElement.getUserData(ONLY_USED_FROM_TEST_CODE);
|
||||
return usedFromTestCode != null && usedFromTestCode.booleanValue();
|
||||
}
|
||||
|
||||
private static class ElementOnlyUsedFromTestCodeAnnotator
|
||||
extends RefGraphAnnotator {
|
||||
|
||||
@Override
|
||||
public void onMarkReferenced(RefElement refWhat, RefElement refFrom,
|
||||
boolean referencedFromClassInitializer) {
|
||||
if (!(refWhat instanceof RefMethod) &&
|
||||
!(refWhat instanceof RefField) &&
|
||||
!(refWhat instanceof RefClass)) {
|
||||
return;
|
||||
}
|
||||
if (referencedFromClassInitializer ||
|
||||
refFrom instanceof RefImplicitConstructor) {
|
||||
return;
|
||||
}
|
||||
final PsiElement whatElement = refWhat.getElement();
|
||||
if (isInsideTestClass(whatElement) ||
|
||||
isUnderTestSources(whatElement)) {
|
||||
// test code itself is allowed to only be used from test code
|
||||
return;
|
||||
}
|
||||
if (refFrom instanceof RefMethod && refWhat instanceof RefClass) {
|
||||
final RefMethod method = (RefMethod) refFrom;
|
||||
if (method.isConstructor() &&
|
||||
method.getOwnerClass() == refWhat) {
|
||||
// don't count references to class from its own constructor
|
||||
return;
|
||||
}
|
||||
}
|
||||
final Boolean onlyUsedFromTestCode =
|
||||
refWhat.getUserData(ONLY_USED_FROM_TEST_CODE);
|
||||
if (onlyUsedFromTestCode == null) {
|
||||
refWhat.putUserData(ONLY_USED_FROM_TEST_CODE, Boolean.TRUE);
|
||||
} else if (!onlyUsedFromTestCode.booleanValue()) {
|
||||
return;
|
||||
}
|
||||
final PsiElement fromElement = refFrom.getElement();
|
||||
if (isInsideTestClass(fromElement) ||
|
||||
isUnderTestSources(fromElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (refWhat instanceof RefMethod) {
|
||||
final RefMethod what = (RefMethod) refWhat;
|
||||
if (what.isConstructor()) {
|
||||
final RefClass ownerClass = what.getOwnerClass();
|
||||
ownerClass.putUserData(ONLY_USED_FROM_TEST_CODE,
|
||||
Boolean.FALSE);
|
||||
// do count references to class from its own constructor
|
||||
// when that constructor is used outside of test code.
|
||||
}
|
||||
}
|
||||
refWhat.putUserData(ONLY_USED_FROM_TEST_CODE, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
This global inspection reports classes, methods or fields which are only used from test code.
|
||||
Since this inspection requires global code analysis, it is only available in batch inspection mode.
|
||||
<p>
|
||||
<small>New in 11, Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user