mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-91011 (Cast to concrete class shall have an option to ignore equals() method)
This commit is contained in:
@@ -1932,6 +1932,7 @@ simplifiable.equals.expression.display.name=Unnecessary 'null' check before 'equ
|
||||
simplifiable.equals.expression.problem.descriptor=Unnecessary ''null'' check before ''{0}()'' call #loc
|
||||
simplifiable.equals.expression.quickfix=Flip ''.{0}()'' and remove unnecessary ''null'' check
|
||||
cast.to.concrete.class.option=Ignore casts to an abstract class type
|
||||
cast.to.concrete.class.ignore.equals.option=Ignore in equals()
|
||||
instanceof.interfaces.option=Ignore instanceof abstract class
|
||||
instance.variable.of.concrete.class.option=Ignore instance fields whose type is an abstract class
|
||||
local.variable.of.concrete.class.option=Ignore local variables whose type is an abstract class
|
||||
|
||||
+55
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,43 +15,45 @@
|
||||
*/
|
||||
package com.siyeh.ig.abstraction;
|
||||
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.*;
|
||||
|
||||
public class CastToConcreteClassInspection extends BaseInspection {
|
||||
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreAbstractClasses = false;
|
||||
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreInEquals = true;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"cast.to.concrete.class.display.name");
|
||||
return InspectionGadgetsBundle.message("cast.to.concrete.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
final PsiElement typeElement = (PsiElement)infos[0];
|
||||
return InspectionGadgetsBundle.message(
|
||||
"cast.to.concrete.class.problem.descriptor",
|
||||
typeElement.getText());
|
||||
final PsiType type= (PsiType)infos[0];
|
||||
return InspectionGadgetsBundle.message("cast.to.concrete.class.problem.descriptor", type.getPresentableText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(
|
||||
InspectionGadgetsBundle.message(
|
||||
"cast.to.concrete.class.option"),
|
||||
this, "ignoreAbstractClasses");
|
||||
final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
|
||||
panel.addCheckbox(InspectionGadgetsBundle.message("cast.to.concrete.class.option"), "ignoreAbstractClasses");
|
||||
panel.addCheckbox(InspectionGadgetsBundle.message("cast.to.concrete.class.ignore.equals.option"), "ignoreInEquals");
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,49 +61,68 @@ public class CastToConcreteClassInspection extends BaseInspection {
|
||||
return new CastToConcreteClassVisitor();
|
||||
}
|
||||
|
||||
private class CastToConcreteClassVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
private class CastToConcreteClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitTypeCastExpression(
|
||||
@NotNull PsiTypeCastExpression expression) {
|
||||
public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) {
|
||||
super.visitTypeCastExpression(expression);
|
||||
final PsiTypeElement typeElement = expression.getCastType();
|
||||
if (typeElement == null) {
|
||||
return;
|
||||
}
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(typeElement,
|
||||
ignoreAbstractClasses)) {
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(typeElement, ignoreAbstractClasses)) {
|
||||
return;
|
||||
}
|
||||
registerError(typeElement, typeElement);
|
||||
if (ignoreInEquals) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class);
|
||||
if (MethodUtils.isEquals(method)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerError(typeElement, typeElement.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(
|
||||
PsiMethodCallExpression expression) {
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression =
|
||||
expression.getMethodExpression();
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
@NonNls
|
||||
final String referenceName = methodExpression.getReferenceName();
|
||||
if (!"cast".equals(referenceName)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression qualifier =
|
||||
methodExpression.getQualifierExpression();
|
||||
if (!(qualifier instanceof PsiClassObjectAccessExpression)) {
|
||||
final PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
if (qualifier == null) {
|
||||
return;
|
||||
}
|
||||
final PsiClassObjectAccessExpression classObjectAccessExpression =
|
||||
(PsiClassObjectAccessExpression)qualifier;
|
||||
final PsiTypeElement operand =
|
||||
classObjectAccessExpression.getOperand();
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(operand,
|
||||
ignoreAbstractClasses)) {
|
||||
final PsiType type = qualifier.getType();
|
||||
if (!(type instanceof PsiClassType)) {
|
||||
return;
|
||||
}
|
||||
registerMethodCallError(expression, operand);
|
||||
final PsiClassType classType = (PsiClassType)type;
|
||||
final PsiClass aClass = classType.resolve();
|
||||
if (aClass == null) {
|
||||
return;
|
||||
}
|
||||
final String className = aClass.getQualifiedName();
|
||||
if (!CommonClassNames.JAVA_LANG_CLASS.equals(className)) {
|
||||
return;
|
||||
}
|
||||
final PsiType[] parameters = classType.getParameters();
|
||||
if (parameters.length != 1) {
|
||||
return;
|
||||
}
|
||||
final PsiType parameter = parameters[0];
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(parameter, ignoreAbstractClasses)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreInEquals) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class);
|
||||
if (MethodUtils.isEquals(method)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerMethodCallError(expression, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,30 +21,33 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class ConcreteClassUtil {
|
||||
|
||||
private ConcreteClassUtil() {
|
||||
}
|
||||
private ConcreteClassUtil() {}
|
||||
|
||||
public static boolean typeIsConcreteClass(
|
||||
@Nullable PsiTypeElement typeElement,
|
||||
boolean ignoreCastToAbstractClass) {
|
||||
public static boolean typeIsConcreteClass(@Nullable PsiTypeElement typeElement, boolean ignoreCastToAbstractClass) {
|
||||
if (typeElement == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiType type = typeElement.getType();
|
||||
return typeIsConcreteClass(type, ignoreCastToAbstractClass);
|
||||
}
|
||||
|
||||
public static boolean typeIsConcreteClass(@Nullable PsiType type, boolean ignoreCastToAbstractClass) {
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiType baseType = type.getDeepComponentType();
|
||||
if (!(baseType instanceof PsiClassType)) {
|
||||
return false;
|
||||
}
|
||||
final PsiClass aClass = ((PsiClassType)baseType).resolve();
|
||||
final PsiClassType classType = (PsiClassType)baseType;
|
||||
final PsiClass aClass = classType.resolve();
|
||||
if (aClass == null) {
|
||||
return false;
|
||||
}
|
||||
if (ignoreCastToAbstractClass &&
|
||||
aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
if (ignoreCastToAbstractClass && aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return false;
|
||||
}
|
||||
if (aClass.isInterface() || aClass.isEnum() ||
|
||||
aClass.isAnnotationType()) {
|
||||
if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) {
|
||||
return false;
|
||||
}
|
||||
if (aClass instanceof PsiTypeParameter) {
|
||||
|
||||
@@ -5,7 +5,9 @@ Such declarations may represent a failure of abstraction, and may make testing m
|
||||
Declarations whose classes come from system or third-party libraries will not be reported by this inspection.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
Use the checkbox below to have this inspection ignore casts to abstract classes.
|
||||
Use the first checkbox below to have this inspection ignore casts to abstract classes.
|
||||
<p>
|
||||
Use the second checkbox below to have this inspection ignore casts inside <code>equals()</code> methods.
|
||||
<p>
|
||||
<small>Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.siyeh.igtest.abstraction.cast_to_concrete_class;
|
||||
|
||||
class CastToConcreteClass {
|
||||
|
||||
private String field;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
try {
|
||||
CastToConcreteClass c = (CastToConcreteClass)obj;
|
||||
return c.field.equals(field);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void foo(Object o) {
|
||||
CastToConcreteClass c = (CastToConcreteClass)o;
|
||||
CastToConcreteClass c2 = CastToConcreteClass.class.cast(o);
|
||||
final Class<CastToConcreteClass> aClass = CastToConcreteClass.class;
|
||||
final CastToConcreteClass c3 = aClass.cast(o);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>CastToConcreteClass.java</file>
|
||||
<line>18</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cast to a concrete class</problem_class>
|
||||
<description>Cast to concrete class <code>CastToConcreteClass</code> #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>CastToConcreteClass.java</file>
|
||||
<line>19</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cast to a concrete class</problem_class>
|
||||
<description>Cast to concrete class <code>CastToConcreteClass</code> #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>CastToConcreteClass.java</file>
|
||||
<line>21</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cast to a concrete class</problem_class>
|
||||
<description>Cast to concrete class <code>CastToConcreteClass</code> #loc</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.siyeh.ig.abstraction;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
|
||||
public class CastToConcreteClassInspectionTest extends IGInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
final CastToConcreteClassInspection tool = new CastToConcreteClassInspection();
|
||||
tool.ignoreInEquals = true;
|
||||
doTest("com/siyeh/igtest/abstraction/cast_to_concrete_class", tool);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user