IDEA-91960 (Type parameter extends final class inspection warns on cases when can not be removed)

This commit is contained in:
Bas Leijdekkers
2013-09-10 16:13:45 +02:00
parent f0e77a8c94
commit 70a172a9bd
3 changed files with 71 additions and 16 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2012 Bas Leijdekkers
* Copyright 2006-2013 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,11 +15,13 @@
*/
package com.siyeh.ig.inheritance;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.siyeh.InspectionGadgetsBundle;
@@ -127,10 +129,7 @@ public class TypeParameterExtendsFinalClassInspection extends BaseInspection {
}
final PsiClassType extendsType = extendsListTypes[0];
final PsiClass aClass = extendsType.resolve();
if (aClass == null) {
return;
}
if (!aClass.hasModifierProperty(PsiModifier.FINAL)) {
if (aClass == null || !aClass.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
final PsiIdentifier nameIdentifier = classParameter.getNameIdentifier();
@@ -156,22 +155,63 @@ public class TypeParameterExtendsFinalClassInspection extends BaseInspection {
if (aClass == null || !aClass.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
if (isPartOfOverriddenMethod(typeElement)) {
if (!shouldReport(typeElement)) {
return;
}
registerError(typeElement.getFirstChild(), aClass, Integer.valueOf(2));
}
private static boolean isPartOfOverriddenMethod(PsiTypeElement typeElement) {
final PsiMethod method = PsiTreeUtil.getParentOfType(typeElement, PsiMethod.class);
if (method == null) {
return false;
private static boolean shouldReport(PsiTypeElement typeElement) {
final PsiElement ancestor = PsiTreeUtil.skipParentsOfType(
typeElement, PsiTypeElement.class, PsiJavaCodeReferenceElement.class, PsiReferenceParameterList.class);
if (ancestor instanceof PsiParameter) {
final PsiParameter parameter = (PsiParameter)ancestor;
final PsiElement scope = parameter.getDeclarationScope();
if (scope instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)scope;
if (MethodUtils.hasSuper(method)) {
return false;
}
}
else if (scope instanceof PsiForeachStatement) {
final PsiForeachStatement foreachStatement = (PsiForeachStatement)scope;
final PsiParameter iterationParameter = foreachStatement.getIterationParameter();
final PsiType iterationType = iterationParameter.getType();
final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
if (iteratedValue == null) {
return false; // incomplete code
}
final PsiType type = JavaGenericsUtil.getCollectionItemType(iteratedValue);
if (type == null || !TypeConversionUtil.isAssignable(iterationType, type)) { // sanity check
return false;
}
if (type.equals(iterationType)) {
return false;
}
if (!(type instanceof PsiCapturedWildcardType)) {
return true;
}
final PsiCapturedWildcardType capturedWildcardType = (PsiCapturedWildcardType)type;
final PsiType upperBound = capturedWildcardType.getUpperBound();
if (iterationType.equals(upperBound)) {
return false;
}
}
}
final PsiCodeBlock body = method.getBody();
if (PsiTreeUtil.isAncestor(body, typeElement, true)) {
return false;
else if (ancestor instanceof PsiLocalVariable) {
final PsiLocalVariable localVariable = (PsiLocalVariable)ancestor;
final PsiExpression initializer = localVariable.getInitializer();
if (initializer == null) {
return true;
}
final PsiType type = initializer.getType();
final PsiType expectedType = GenericsUtil.getVariableTypeByExpressionType(type);
final PsiType variableType = localVariable.getType();
if (variableType.equals(expectedType)) {
return false;
}
}
return MethodUtils.hasSuper(method);
return true;
}
}
}
@@ -1,7 +1,7 @@
package com.siyeh.igtest.inheritance.type_parameter_extends_final_class;
import java.util.Collection;
import java.util.List;
import java.util.*;
public class TypeParameterExtendsFinalClass<T extends String> {}
final class Usee {}
@@ -15,4 +15,12 @@ abstract class MyList implements List<Integer> {
public boolean addAll(Collection<? extends Integer> c) {
return false;
}
}
abstract class SampleMap<T extends String> implements Map<String, Object> {
public void putAll(final Map<? extends String, ?> m) {
final Set<? extends Entry<? extends String,?>> entries = m.entrySet();
for (Entry<? extends String, ?> entry : entries) {
}
}
}
@@ -13,4 +13,11 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Type parameter extends final class</problem_class>
<description>Wildcard type argument &lt;code&gt;?&lt;/code&gt; extends final class 'Usee' #loc</description>
</problem>
<problem>
<file>TypeParameterExtendsFinalClass.java</file>
<line>19</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Type parameter extends final class</problem_class>
<description>Type parameter &lt;code&gt;T&lt;/code&gt; extends 'final' class 'String' #loc</description>
</problem>
</problems>