This commit is contained in:
Alexey Kudravtsev
2013-10-09 13:51:27 +04:00
parent 2e0029d703
commit 836e381afc
7 changed files with 97 additions and 60 deletions
@@ -61,13 +61,13 @@ public class AbstractBaseJavaLocalInspectionTool extends LocalInspectionTool {
}
/**
* Override this to report problems at file level.
*
* @param file to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at file level.
*/
* Override this to report problems at file level.
*
* @param file to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at file level.
*/
@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
@@ -78,21 +78,26 @@ public class AbstractBaseJavaLocalInspectionTool extends LocalInspectionTool {
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitMethod(PsiMethod method) {
@Override
public void visitMethod(PsiMethod method) {
addDescriptors(checkMethod(method, holder.getManager(), isOnTheFly));
}
@Override public void visitClass(PsiClass aClass) {
@Override
public void visitClass(PsiClass aClass) {
addDescriptors(checkClass(aClass, holder.getManager(), isOnTheFly));
}
@Override public void visitField(PsiField field) {
@Override
public void visitField(PsiField field) {
addDescriptors(checkField(field, holder.getManager(), isOnTheFly));
}
@Override public void visitFile(PsiFile file) {
@Override
public void visitFile(PsiFile file) {
addDescriptors(checkFile(file, holder.getManager(), isOnTheFly));
}
private void addDescriptors(final ProblemDescriptor[] descriptors) {
if (descriptors != null) {
for (ProblemDescriptor descriptor : descriptors) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -18,7 +18,9 @@ package com.intellij.codeInspection.miscGenerics;
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,6 +36,17 @@ public abstract class GenericsInspectionToolBase extends BaseJavaBatchLocalInspe
public boolean isEnabledByDefault() {
return true;
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
PsiFile file = holder.getFile();
if (!PsiUtil.isLanguageLevel5OrHigher(file)) return new PsiElementVisitor() {
};
return super.buildVisitor(holder, isOnTheFly);
}
@Override
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
final PsiClassInitializer[] initializers = aClass.getInitializers();
@@ -71,5 +84,5 @@ public abstract class GenericsInspectionToolBase extends BaseJavaBatchLocalInspe
}
@Nullable
public abstract ProblemDescriptor[] getDescriptions(PsiElement place, InspectionManager manager, boolean isOnTheFly);
public abstract ProblemDescriptor[] getDescriptions(@NotNull PsiElement place, @NotNull InspectionManager manager, boolean isOnTheFly);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -70,7 +70,7 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase {
}
@Override
public ProblemDescriptor[] getDescriptions(PsiElement place, final InspectionManager inspectionManager, boolean isOnTheFly) {
public ProblemDescriptor[] getDescriptions(@NotNull PsiElement place, @NotNull final InspectionManager inspectionManager, boolean isOnTheFly) {
final List<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
place.accept(new JavaRecursiveElementWalkingVisitor() {
@Override public void visitMethodCallExpression(PsiMethodCallExpression expression) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -56,7 +56,7 @@ public class RedundantCastInspection extends GenericsInspectionToolBase {
@Override
@Nullable
public ProblemDescriptor[] getDescriptions(PsiElement where, InspectionManager manager, boolean isOnTheFly) {
public ProblemDescriptor[] getDescriptions(@NotNull PsiElement where, @NotNull InspectionManager manager, boolean isOnTheFly) {
List<PsiTypeCastExpression> redundantCasts = RedundantCastUtil.getRedundantCastsInside(where);
if (redundantCasts.isEmpty()) return null;
List<ProblemDescriptor> descriptions = new ArrayList<ProblemDescriptor>(redundantCasts.size());
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -21,6 +21,7 @@ import com.intellij.psi.impl.source.resolve.CompletionParameterTypeInferencePoli
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -137,7 +138,7 @@ public class ExpectedTypeUtil {
public static class ExpectedClassesFromSetProvider implements ExpectedTypesProvider.ExpectedClassProvider {
private final Set<PsiClass> myOccurrenceClasses;
public ExpectedClassesFromSetProvider(Set<PsiClass> occurrenceClasses) {
public ExpectedClassesFromSetProvider(@NotNull Set<PsiClass> occurrenceClasses) {
myOccurrenceClasses = occurrenceClasses;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -23,7 +23,6 @@ import com.intellij.codeInspection.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.InlineUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
@@ -38,12 +37,12 @@ import java.util.List;
*/
public class RedundantArrayForVarargsCallInspection extends GenericsInspectionToolBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.miscGenerics.RedundantArrayForVarargsCallInspection");
private final LocalQuickFix myQuickFixAction = new MyQuickFix();
private static final LocalQuickFix myQuickFixAction = new MyQuickFix();
private static class MyQuickFix implements LocalQuickFix {
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiNewExpression arrayCreation = (PsiNewExpression) descriptor.getPsiElement();
PsiNewExpression arrayCreation = (PsiNewExpression)descriptor.getPsiElement();
if (arrayCreation == null || !arrayCreation.isValid()) return;
if (!FileModificationService.getInstance().prepareFileForWrite(arrayCreation.getContainingFile())) return;
InlineUtil.inlineArrayCreationForVarargs(arrayCreation);
@@ -63,21 +62,25 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo
}
@Override
public ProblemDescriptor[] getDescriptions(PsiElement place, final InspectionManager manager, final boolean isOnTheFly) {
if (!PsiUtil.isLanguageLevel5OrHigher(place)) return null;
public ProblemDescriptor[] getDescriptions(@NotNull PsiElement place,
@NotNull final InspectionManager manager,
final boolean isOnTheFly) {
final List<ProblemDescriptor> problems = new ArrayList<ProblemDescriptor>();
place.accept(new JavaRecursiveElementWalkingVisitor() {
@Override public void visitCallExpression(PsiCallExpression expression) {
@Override
public void visitCallExpression(PsiCallExpression expression) {
super.visitCallExpression(expression);
checkCall(expression);
}
@Override public void visitEnumConstant(PsiEnumConstant enumConstant) {
@Override
public void visitEnumConstant(PsiEnumConstant enumConstant) {
super.visitEnumConstant(enumConstant);
checkCall(enumConstant);
}
@Override public void visitClass(PsiClass aClass) {
@Override
public void visitClass(PsiClass aClass) {
//do not go inside to prevent multiple signals of the same problem
}
@@ -85,38 +88,44 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo
final JavaResolveResult resolveResult = expression.resolveMethodGenerics();
PsiElement element = resolveResult.getElement();
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (element instanceof PsiMethod && ((PsiMethod)element).isVarArgs()) {
PsiMethod method = (PsiMethod)element;
PsiParameter[] parameters = method.getParameterList().getParameters();
PsiExpressionList argumentList = expression.getArgumentList();
if (argumentList != null) {
PsiExpression[] args = argumentList.getExpressions();
if (parameters.length == args.length) {
PsiExpression lastArg = args[args.length - 1];
PsiParameter lastParameter = parameters[args.length - 1];
PsiType lastParamType = lastParameter.getType();
LOG.assertTrue(lastParamType instanceof PsiEllipsisType);
if (lastArg instanceof PsiNewExpression &&
substitutor.substitute(((PsiEllipsisType) lastParamType).toArrayType()).equals(lastArg.getType())) {
PsiExpression[] initializers = getInitializers((PsiNewExpression)lastArg);
if (initializers != null) {
if (isSafeToFlatten(expression, method, initializers)) {
final ProblemDescriptor descriptor = manager.createProblemDescriptor(lastArg,
InspectionsBundle.message("inspection.redundant.array.creation.for.varargs.call.descriptor"),
myQuickFixAction,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
isOnTheFly);
problems.add(descriptor);
}
}
}
}
}
if (!(element instanceof PsiMethod)) {
return;
}
PsiMethod method = (PsiMethod)element;
if (!method.isVarArgs()) {
return;
}
PsiParameter[] parameters = method.getParameterList().getParameters();
PsiExpressionList argumentList = expression.getArgumentList();
if (argumentList == null) {
return;
}
PsiExpression[] args = argumentList.getExpressions();
if (parameters.length != args.length) {
return;
}
PsiExpression lastArg = args[args.length - 1];
PsiParameter lastParameter = parameters[args.length - 1];
PsiType lastParamType = lastParameter.getType();
LOG.assertTrue(lastParamType instanceof PsiEllipsisType);
if (!(lastArg instanceof PsiNewExpression) ||
!substitutor.substitute(((PsiEllipsisType)lastParamType).toArrayType()).equals(lastArg.getType())) {
return;
}
PsiExpression[] initializers = getInitializers((PsiNewExpression)lastArg);
if (initializers == null) {
return;
}
if (!isSafeToFlatten(expression, method, initializers)) {
return;
}
String message = InspectionsBundle.message("inspection.redundant.array.creation.for.varargs.call.descriptor");
ProblemDescriptor descriptor = manager.createProblemDescriptor(lastArg, message, myQuickFixAction,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly);
problems.add(descriptor);
}
private boolean isSafeToFlatten(PsiCall callExpression, PsiMethod oldRefMethod, PsiExpression[] arrayElements) {
private boolean isSafeToFlatten(@NotNull PsiCall callExpression, @NotNull PsiMethod oldRefMethod, @NotNull PsiExpression[] arrayElements) {
if (arrayElements.length == 1) {
PsiType type = arrayElements[0].getType();
// change foo(new Object[]{array}) to foo(array) is not safe
@@ -140,12 +149,13 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo
final PsiClassType classType = facade.getElementFactory().createType(containingClass);
resolveResult = facade.getResolveHelper().resolveConstructor(classType, copyArgumentList, enumConstant);
return resolveResult.isValidResult() && resolveResult.getElement() == oldRefMethod;
} else {
}
else {
resolveResult = copy.resolveMethodGenerics();
if (!resolveResult.isValidResult() || resolveResult.getElement() != oldRefMethod) {
return false;
}
final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes((PsiCallExpression) callExpression, false);
final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes((PsiCallExpression)callExpression, false);
final PsiType expressionType = ((PsiCallExpression)copy).getType();
for (ExpectedTypeInfo expectedType : expectedTypes) {
if (!expectedType.getType().isAssignableFrom(expressionType)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -165,10 +165,12 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(myMainOccurrence, false, myOccurrenceClassProvider, false);
final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() {
@Override
public void visitType(PsiType aType) {
checkIfAllowed(aType);
}
@Override
public void visitClass(PsiClass aClass) {
checkIfAllowed(myFactory.createType(aClass));
}
@@ -204,10 +206,12 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
RefactoringHierarchyUtil.processSuperTypes(getDefaultType(), new RefactoringHierarchyUtil.SuperTypeVisitor() {
@Override
public void visitType(PsiType aType) {
checkIfAllowed(aType);
}
@Override
public void visitClass(PsiClass aClass) {
checkIfAllowed(myFactory.createType(aClass));
}
@@ -270,6 +274,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
return result;
}
@Override
public void setAllOccurrences(boolean allOccurrences) {
if (myIsOneSuggestion) return;
setTypesAndPreselect(allOccurrences ? myTypesForAll : myTypesForMain);
@@ -292,6 +297,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
}
}
@Override
public boolean isSuggestedType(final String fqName) {
for(PsiType type: myTypesForAll) {
if (type.getCanonicalText().equals(fqName)) {
@@ -308,6 +314,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
return false;
}
@Override
public void typeSelected(@NotNull PsiType type) {
typeSelected(type, getDefaultType());
}
@@ -329,6 +336,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager {
return TypeConversionUtil.erasure(type).getCanonicalText();
}
@Override
public TypeSelector getTypeSelector() {
return myTypeSelector;
}