diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index 70a4c19f644f..3c1bf42c0840 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -279,6 +279,8 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, inspectionClasses.add(EmptyStatementBodyInspection.class); inspectionClasses.add(EmptyInitializerInspection.class); inspectionClasses.add(EqualsBetweenInconvertibleTypesInspection.class); + inspectionClasses.add(CastToIncompatibleInterfaceInspection.class); + inspectionClasses.add(InstanceofIncompatibleInterfaceInspection.class); inspectionClasses.add(BigDecimalEqualsInspection.class); inspectionClasses.add(CovariantCompareToInspection.class); inspectionClasses.add(CovariantEqualsInspection.class); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CastToIncompatibleInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CastToIncompatibleInterfaceInspection.java new file mode 100644 index 000000000000..a36bf437e16c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CastToIncompatibleInterfaceInspection.java @@ -0,0 +1,102 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.SearchScope; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class CastToIncompatibleInterfaceInspection extends ExpressionInspection{ + public String getDisplayName(){ + return "Casting to incompatible interface"; + } + + public String getGroupDisplayName(){ + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location){ + return "Cast to incompatible interface #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, + boolean onTheFly){ + return new CastToIncompatibleInterfaceVisitor(this, + inspectionManager, + onTheFly); + } + + private static class CastToIncompatibleInterfaceVisitor + extends BaseInspectionVisitor{ + private CastToIncompatibleInterfaceVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly){ + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTypeCastExpression(PsiTypeCastExpression expression){ + super.visitTypeCastExpression(expression); + + final PsiTypeElement castTypeElement = expression.getCastType(); + if(castTypeElement == null){ + return; + } + final PsiType castType = castTypeElement.getType(); + if(castType == null){ + return; + } + if(!(castType instanceof PsiClassType)){ + return; + } + final PsiClass castClass = ((PsiClassType) castType).resolve(); + if(castClass == null){ + return; + } + if(!castClass.isInterface()){ + return; + } + final PsiExpression operand = expression.getOperand(); + if(operand == null){ + return; + } + final PsiType operandType = operand.getType(); + if(operandType == null){ + return; + } + if(!(operandType instanceof PsiClassType)){ + return; + } + final PsiClass operandClass = + ((PsiClassType) operandType).resolve(); + if(operandClass == null){ + return; + } + if(existsImplementingSubClass(operandClass, castClass)){ + return; + } + registerError(castTypeElement); + } + } + + private static boolean existsImplementingSubClass(PsiClass aClass, + PsiClass anInterface){ + if(aClass.isInheritor(anInterface, true)){ + return true; + } + final PsiManager psiManager = aClass.getManager(); + final PsiSearchHelper searchHelper = psiManager.getSearchHelper(); + final SearchScope searchScope = aClass.getUseScope(); + final PsiClass[] inheritors = + searchHelper.findInheritors(aClass, searchScope, false); + for(int i = 0; i < inheritors.length; i++){ + final PsiClass inheritor = inheritors[i]; + if(inheritor.isInheritor(anInterface, true)){ + return true; + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InstanceofIncompatibleInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InstanceofIncompatibleInterfaceInspection.java new file mode 100644 index 000000000000..600d84098299 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InstanceofIncompatibleInterfaceInspection.java @@ -0,0 +1,103 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.SearchScope; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class InstanceofIncompatibleInterfaceInspection extends ExpressionInspection{ + public String getDisplayName(){ + return "'instanceof' with incompatible interface"; + } + + public String getGroupDisplayName(){ + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location){ + return "'instanceof' incompatible interface #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, + boolean onTheFly){ + return new InstanceofIncompatibleInterfaceVisitor(this, + inspectionManager, + onTheFly); + } + + private static class InstanceofIncompatibleInterfaceVisitor + extends BaseInspectionVisitor{ + private InstanceofIncompatibleInterfaceVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly){ + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitInstanceOfExpression(PsiInstanceOfExpression expression){ + super.visitInstanceOfExpression(expression); + + final PsiTypeElement castTypeElement = expression.getCheckType(); + if(castTypeElement == null){ + return; + } + final PsiType castType = castTypeElement.getType(); + if(castType == null){ + return; + } + if(!(castType instanceof PsiClassType)){ + return; + } + final PsiClass castClass = ((PsiClassType) castType).resolve(); + if(castClass == null){ + return; + } + if(!castClass.isInterface()){ + return; + } + final PsiExpression operand = expression.getOperand(); + if(operand == null){ + return; + } + final PsiType operandType = operand.getType(); + if(operandType == null){ + return; + } + if(!(operandType instanceof PsiClassType)){ + return; + } + final PsiClass operandClass = + ((PsiClassType) operandType).resolve(); + if(operandClass == null){ + return; + } + if(existsImplementingSubClass(operandClass, castClass)){ + return; + } + registerError(castTypeElement); + } + + } + + private static boolean existsImplementingSubClass(PsiClass aClass, + PsiClass anInterface){ + if(aClass.isInheritor(anInterface, true)){ + return true; + } + final PsiManager psiManager = aClass.getManager(); + final PsiSearchHelper searchHelper = psiManager.getSearchHelper(); + final SearchScope searchScope = aClass.getUseScope(); + final PsiClass[] inheritors = + searchHelper.findInheritors(aClass, searchScope, false); + for(int i = 0; i < inheritors.length; i++){ + final PsiClass inheritor = inheritors[i]; + if(inheritor.isInheritor(anInterface, true)){ + return true; + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CastToIncompatibleInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CastToIncompatibleInterface.html new file mode 100644 index 000000000000..7e42f99859e6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CastToIncompatibleInterface.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports type cast expressions where +the cast type is an interface, and the cast expression has a class type which neither +implements the cast interface, nor has any visible subclasses which implement the cast interface. +While it is possible that this was intended, such a construct is most likely an error, and will +result in a java.lang.ClassCastException at runtime. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofIncompatibleInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofIncompatibleInterface.html new file mode 100644 index 000000000000..7789465c30d1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofIncompatibleInterface.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instanceof expressions where +the compared type is an interface, and the compared expression has a class type which neither +implements the compared interface, nor has any visible subclasses which implement the compared interface. +While it is possible that this was intended, such a construct is most likely an error, where +the resulting instanceof expression always evaluates to +false +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CastToIncompatibleInterfaceInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CastToIncompatibleInterfaceInspection.java new file mode 100644 index 000000000000..077dfa924457 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CastToIncompatibleInterfaceInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.bugs; + +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + +public class CastToIncompatibleInterfaceInspection { + public void foo() + { + List list = (List) new HashMap(); + List list2 = (List) new ArrayList(); + if(new HashMap() instanceof List) + { + + } + } +}