mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
redundant lambda param types: inspection->intention
This commit is contained in:
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
* 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.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntentionAction {
|
||||
public static final Logger LOG = Logger.getInstance("#" + RedundantLambdaParameterTypeIntention.class.getName());
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Remove redundant types";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
final PsiParameterList parameterList = PsiTreeUtil.getParentOfType(element, PsiParameterList.class);
|
||||
if (parameterList == null) return false;
|
||||
final PsiElement parent = parameterList.getParent();
|
||||
if (!(parent instanceof PsiLambdaExpression)) return false;
|
||||
final PsiLambdaExpression expression = (PsiLambdaExpression)parent;
|
||||
final PsiParameter[] parameters = parameterList.getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (parameter.getTypeElement() == null) return false;
|
||||
}
|
||||
if (parameters.length == 0) return false;
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false);
|
||||
if (functionalInterfaceType != null) {
|
||||
final PsiElement lambdaParent = expression.getParent();
|
||||
if (lambdaParent instanceof PsiExpressionList) {
|
||||
final PsiElement gParent = lambdaParent.getParent();
|
||||
if (gParent instanceof PsiCallExpression && ((PsiCallExpression)gParent).getTypeArguments().length == 0) {
|
||||
final PsiMethod method = ((PsiCallExpression)gParent).resolveMethod();
|
||||
if (method == null) return false;
|
||||
final int idx = LambdaUtil.getLambdaIdx((PsiExpressionList)lambdaParent, expression);
|
||||
if (idx < 0) return false;
|
||||
|
||||
final PsiTypeParameter[] typeParameters = method.getTypeParameters();
|
||||
final PsiExpression[] arguments = ((PsiExpressionList)lambdaParent).getExpressions();
|
||||
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
|
||||
arguments[idx] = javaPsiFacade.getElementFactory().createExpressionFromText(
|
||||
"(" + StringUtil.join(expression.getParameterList().getParameters(), new Function<PsiParameter, String>() {
|
||||
@Override
|
||||
public String fun(PsiParameter parameter) {
|
||||
return parameter.getName();
|
||||
}
|
||||
}, ", ") + ") -> {}", expression);
|
||||
final PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper()
|
||||
.inferTypeArguments(typeParameters, method.getParameterList().getParameters(), arguments, PsiSubstitutor.EMPTY,
|
||||
gParent, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
final PsiType psiType = substitutor.substitute(parameter);
|
||||
if (psiType == null || LambdaUtil.dependsOnTypeParams(psiType, expression, parameter)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!LambdaUtil.isLambdaFullyInferred(expression, functionalInterfaceType)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
|
||||
removeTypes(lambdaExpression);
|
||||
}
|
||||
|
||||
private static void removeTypes(PsiLambdaExpression lambdaExpression) {
|
||||
if (lambdaExpression != null) {
|
||||
final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters();
|
||||
final String text;
|
||||
if (parameters.length == 1) {
|
||||
text = parameters[0].getName();
|
||||
}
|
||||
else {
|
||||
text = "(" + StringUtil.join(parameters, new Function<PsiParameter, String>() {
|
||||
@Override
|
||||
public String fun(PsiParameter parameter) {
|
||||
return parameter.getName();
|
||||
}
|
||||
}, ", ") + ")";
|
||||
}
|
||||
final PsiLambdaExpression expression = (PsiLambdaExpression)JavaPsiFacade.getElementFactory(lambdaExpression.getProject())
|
||||
.createExpressionFromText(text + "->{}", lambdaExpression);
|
||||
lambdaExpression.getParameterList().replace(expression.getParameterList());
|
||||
}
|
||||
}
|
||||
}
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.
|
||||
* 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.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Function;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
public class RedundantLambdaParameterTypeInspection extends BaseJavaLocalInspectionTool {
|
||||
public static final Logger LOG = Logger.getInstance("#" + RedundantLambdaParameterTypeInspection.class.getName());
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getGroupDisplayName() {
|
||||
return GroupNames.LANGUAGE_LEVEL_SPECIFIC_GROUP_NAME;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Redundant lambda parameter type";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "RedundantLambdaParameterType";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
super.visitLambdaExpression(expression);
|
||||
final PsiParameter[] parameters = expression.getParameterList().getParameters();
|
||||
for (PsiParameter parameter : parameters) {
|
||||
if (parameter.getTypeElement() == null) return;
|
||||
}
|
||||
if (parameters.length == 0) return;
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false);
|
||||
if (functionalInterfaceType != null) {
|
||||
final PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
final PsiElement gParent = parent.getParent();
|
||||
if (gParent instanceof PsiCallExpression && ((PsiCallExpression)gParent).getTypeArguments().length == 0) {
|
||||
final PsiMethod method = ((PsiCallExpression)gParent).resolveMethod();
|
||||
if (method == null) return;
|
||||
final int idx = LambdaUtil.getLambdaIdx((PsiExpressionList)parent, expression);
|
||||
if (idx < 0) return;
|
||||
|
||||
final PsiTypeParameter[] typeParameters = method.getTypeParameters();
|
||||
final PsiExpression[] arguments = ((PsiExpressionList)parent).getExpressions();
|
||||
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(holder.getProject());
|
||||
arguments[idx] = javaPsiFacade.getElementFactory().createExpressionFromText("(" + StringUtil.join(expression.getParameterList().getParameters(), new Function<PsiParameter, String>() {
|
||||
@Override
|
||||
public String fun(PsiParameter parameter) {
|
||||
return parameter.getName();
|
||||
}
|
||||
}, ", ") + ") -> {}", expression);
|
||||
final PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper()
|
||||
.inferTypeArguments(typeParameters, method.getParameterList().getParameters(), arguments, PsiSubstitutor.EMPTY,
|
||||
gParent, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
final PsiType psiType = substitutor.substitute(parameter);
|
||||
if (psiType == null || LambdaUtil.dependsOnTypeParams(psiType, expression, parameter)) return;
|
||||
}
|
||||
}
|
||||
} else if (!LambdaUtil.isLambdaFullyInferred(expression, functionalInterfaceType)) {
|
||||
return;
|
||||
}
|
||||
holder.registerProblem(expression.getParameterList(), "Redundant parameter type declarations",
|
||||
ProblemHighlightType.LIKE_UNUSED_SYMBOL, new RemoveTypeDeclarationsFix());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class RemoveTypeDeclarationsFix implements LocalQuickFix, HighPriorityAction {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Remove redundant types";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (element != null) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
|
||||
removeTypes(lambdaExpression);
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeTypes(PsiLambdaExpression lambdaExpression) {
|
||||
if (lambdaExpression != null) {
|
||||
final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters();
|
||||
final String text;
|
||||
if (parameters.length == 1) {
|
||||
text = parameters[0].getName();
|
||||
}
|
||||
else {
|
||||
text = "(" + StringUtil.join(parameters, new Function<PsiParameter, String>() {
|
||||
@Override
|
||||
public String fun(PsiParameter parameter) {
|
||||
return parameter.getName();
|
||||
}
|
||||
}, ", ") + ")";
|
||||
}
|
||||
final PsiLambdaExpression expression = (PsiLambdaExpression)JavaPsiFacade.getElementFactory(lambdaExpression.getProject())
|
||||
.createExpressionFromText(text + "->{}", lambdaExpression);
|
||||
lambdaExpression.getParameterList().replace(expression.getParameterList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-12
@@ -15,18 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.RedundantLambdaParameterTypeInspection;
|
||||
|
||||
|
||||
public class RedundantLambdaParameterTypeInspectionTest extends LightQuickFixTestCase {
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{
|
||||
new RedundantLambdaParameterTypeInspection(),
|
||||
};
|
||||
}
|
||||
|
||||
public class RedundantLambdaParameterTypeIntentionTest extends LightQuickFixTestCase {
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@Override
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports lambda expressions with formal parameter types which can be inferred from context and thus are redundant.
|
||||
</body>
|
||||
</html>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class X {
|
||||
{
|
||||
Comparable<String> c = o -> 0;
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class X {
|
||||
{
|
||||
Comparable<String> c = <spot>(String o)</spot> -> 0;
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention removes lambda formal parameter types when they can be inferred from context.
|
||||
</body>
|
||||
</html>
|
||||
@@ -539,9 +539,6 @@
|
||||
<localInspection language="JAVA" shortName="CodeBlock2Expr" displayName="Lambda code block can be replaced with expression"
|
||||
groupName="Java language level migration aids" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.RedundantLambdaCodeBlockInspection" />
|
||||
<localInspection language="JAVA" shortName="RedundantLambdaParameterType" displayName="Redundant lambda parameter type"
|
||||
groupName="Java language level migration aids" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.RedundantLambdaParameterTypeInspection" />
|
||||
<localInspection language="JAVA" suppressId="unchecked" shortName="SafeVarargsDetector"
|
||||
displayName="Possible heap pollution from parameterized vararg type" groupName="Java language level migration aids"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
@@ -554,6 +551,10 @@
|
||||
implementationClass="com.intellij.codeInspection.magicConstant.MagicConstantInspection" />
|
||||
|
||||
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.daemon.quickFix.RedundantLambdaParameterTypeIntention</className>
|
||||
<category>Declaration</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInsight.intention.impl.SplitIfAction</className>
|
||||
<category>Control Flow</category>
|
||||
|
||||
Reference in New Issue
Block a user