WrapWithAdapterMethodCallFix replaces individual cases

WrapArrayToArraysAsListFix, WrapLongWithMathToIntExactFix, WrapStringWithFileFix are united into WrapWithAdapterMethodCallFix. Also Paths.get(), Collections.singleton(), Collections.singletonList(), Arrays.stream() wrappers added

Fixes IDEA-175129 Suggest to wrap a value with `Collections.singleton*()`
This commit is contained in:
Tagir Valeev
2017-08-25 14:29:33 +07:00
parent 0024a3aeb3
commit 661388f0c2
33 changed files with 330 additions and 402 deletions

View File

@@ -282,9 +282,6 @@ public abstract class QuickFixFactory {
@NotNull
public abstract IntentionAction addMethodQualifierFix(@NotNull PsiMethodCallExpression methodCall);
@NotNull
public abstract IntentionAction createWrapLongWithMathToIntExactFix(@Nullable PsiType type, @NotNull PsiExpression expression);
@NotNull
public abstract IntentionAction createWrapWithOptionalFix(@Nullable PsiType type, @NotNull PsiExpression expression);
@@ -304,5 +301,5 @@ public abstract class QuickFixFactory {
public abstract LocalQuickFixAndIntentionActionOnPsiElement createAccessStaticViaInstanceFix(PsiReferenceExpression methodRef, JavaResolveResult result);
@NotNull
public abstract IntentionAction createWrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression);
public abstract IntentionAction createWrapWithAdapterFix(@Nullable PsiType type, @NotNull PsiExpression expression);
}

View File

@@ -710,10 +710,8 @@ public class HighlightMethodUtil {
TextRange fixRange = getFixRange(elementToHighlight);
CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapWithAdapterMethodCallFix.registerCastActions(candidates, methodCall, info, fixRange);
PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange);
WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info);
registerChangeParameterClassFix(methodCall, list, info);
@@ -790,10 +788,8 @@ public class HighlightMethodUtil {
TextRange fixRange = getFixRange(elementToHighlight);
CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapStringWithFileFix.REGISTAR.registerCastActions(candidates, methodCall, info, fixRange);
WrapWithAdapterMethodCallFix.registerCastActions(candidates, methodCall, info, fixRange);
PermuteArgumentsFix.registerFix(info, methodCall, candidates, fixRange);
WrapExpressionFix.registerWrapAction(candidates, list.getExpressions(), info);
registerChangeParameterClassFix(methodCall, list, info);
@@ -858,10 +854,8 @@ public class HighlightMethodUtil {
CastMethodArgumentFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
PermuteArgumentsFix.registerFix(highlightInfo, methodCall, methodCandidates, fixRange);
AddTypeArgumentsFix.REGISTRAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
WrapStringWithFileFix.REGISTAR.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
WrapWithAdapterMethodCallFix.registerCastActions(methodCandidates, methodCall, highlightInfo, fixRange);
registerMethodAccessLevelIntentions(methodCandidates, methodCall, list, highlightInfo);
registerChangeMethodSignatureFromUsageIntentions(methodCandidates, list, highlightInfo, fixRange);
RemoveRedundantArgumentsFix.registerIntentions(methodCandidates, list, highlightInfo, fixRange);

View File

@@ -576,10 +576,9 @@ public class HighlightUtil extends HighlightUtilBase {
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createAddTypeCastFix(lType, expression));
}
if (expression != null) {
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createWrapLongWithMathToIntExactFix(lType, expression));
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createWrapWithOptionalFix(lType, expression));
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createWrapExpressionFix(lType, expression));
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createWrapStringWithFileFix(lType, expression));
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createWrapWithAdapterFix(lType, expression));
AddTypeArgumentsConditionalFix.register(highlightInfo, expression, lType);
registerCollectionToArrayFixAction(highlightInfo, rType, lType, expression);
}
@@ -1462,7 +1461,7 @@ public class HighlightUtil extends HighlightUtilBase {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createConvertSwitchToIfIntention(statement));
if (PsiType.LONG.equals(type) || PsiType.FLOAT.equals(type) || PsiType.DOUBLE.equals(type)) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createAddTypeCastFix(PsiType.INT, expression));
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createWrapLongWithMathToIntExactFix(PsiType.INT, expression));
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createWrapWithAdapterFix(PsiType.INT, expression));
}
if (requiredLevel != null) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createIncreaseLanguageLevelFix(requiredLevel));

View File

@@ -43,9 +43,7 @@ public class ConstructorParametersFixer {
}
CastMethodArgumentFix.REGISTRAR.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
AddTypeArgumentsFix.REGISTRAR.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
WrapArrayToArraysAsListFix.REGISTAR.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
WrapLongWithMathToIntExactFix.REGISTAR.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
WrapObjectWithOptionalOfNullableFix.REGISTAR.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
WrapStringWithFileFix.REGISTAR.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
WrapWithAdapterMethodCallFix.registerCastActions(candidates, constructorCall, highlightInfo, fixRange);
}
}

View File

@@ -31,7 +31,7 @@ public abstract class MethodArgumentFix implements IntentionAction {
protected final PsiExpressionList myArgList;
protected final int myIndex;
private final ArgumentFixerActionFactory myArgumentFixerActionFactory;
protected final ArgumentFixerActionFactory myArgumentFixerActionFactory;
protected final PsiType myToType;
protected MethodArgumentFix(@NotNull PsiExpressionList list, int i, @NotNull PsiType toType, @NotNull ArgumentFixerActionFactory fixerActionFactory) {

View File

@@ -1,94 +0,0 @@
/*
* Copyright 2000-2014 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.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Batkovich
*/
public class WrapArrayToArraysAsListFix extends MethodArgumentFix {
public static final ArgumentFixerActionFactory REGISTAR = new MyFixerActionFactory();
protected WrapArrayToArraysAsListFix(final @NotNull PsiExpressionList list,
final int i,
final @NotNull PsiType toType,
final @NotNull ArgumentFixerActionFactory fixerActionFactory) {
super(list, i, toType, fixerActionFactory);
}
@NotNull
@Override
public String getText() {
if (myArgList.getExpressions().length == 1) {
return QuickFixBundle.message("wrap.array.to.arrays.as.list.single.parameter.text");
} else {
return QuickFixBundle.message("wrap.array.to.arrays.as.list.parameter.text", myIndex + 1);
}
}
public static class MyFixerActionFactory extends ArgumentFixerActionFactory {
@Nullable
@Override
protected PsiExpression getModifiedArgument(final PsiExpression expression, final PsiType toType) throws IncorrectOperationException {
final PsiType exprType = expression.getType();
if (!(exprType instanceof PsiArrayType && toType instanceof PsiClassType)) {
return null;
}
final PsiClass resolvedToType = ((PsiClassType)toType).resolve();
if (resolvedToType == null) {
return null;
}
final PsiClass javaUtilList = getJavaUtilList(expression);
if (javaUtilList == null || !InheritanceUtil.isInheritorOrSelf(javaUtilList, resolvedToType, true)) {
return null;
}
final PsiType[] parameters = ((PsiClassType)toType).getParameters();
final PsiType arrayComponentType = ((PsiArrayType)exprType).getComponentType();
if (!(parameters.length == 1 && parameters[0].equals(arrayComponentType))) {
return null;
}
final String rawNewExpression = String.format("java.util.Arrays.asList(%s)", expression.getText());
final Project project = expression.getProject();
final PsiExpression newExpression = JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(rawNewExpression, null);
return (PsiExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(newExpression);
}
@Nullable
private static PsiClass getJavaUtilList(final PsiElement context) {
return JavaPsiFacade.getInstance(context.getProject()).findClass(CommonClassNames.JAVA_UTIL_LIST, context.getResolveScope());
}
@Override
public boolean areTypesConvertible(@NotNull final PsiType exprType, @NotNull final PsiType parameterType, @NotNull final PsiElement context) {
return true;
}
@Override
public MethodArgumentFix createFix(final PsiExpressionList list, final int i, final PsiType toType) {
return new WrapArrayToArraysAsListFix(list, i, toType, this);
}
}
}

View File

@@ -1,128 +0,0 @@
/*
* Copyright 2000-2016 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.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Batkovich
*/
public class WrapLongWithMathToIntExactFix extends LocalQuickFixAndIntentionActionOnPsiElement implements HighPriorityAction {
public final static MyMethodArgumentFixerFactory REGISTAR = new MyMethodArgumentFixerFactory();
private final PsiType myType;
public WrapLongWithMathToIntExactFix(final PsiType type, final @NotNull PsiExpression expression) {
super(expression);
myType = type;
}
@NotNull
@Override
public String getText() {
return getFamilyName();
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable("is null when called from inspection") Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
startElement.replace(getModifiedExpression(startElement));
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return startElement.isValid() &&
startElement.getManager().isInProject(startElement) &&
PsiUtil.isLanguageLevel8OrHigher(startElement) &&
areSameTypes(myType, PsiType.INT) &&
areSameTypes(((PsiExpression) startElement).getType(), PsiType.LONG);
}
private static boolean areSameTypes(@Nullable PsiType type, @NotNull PsiPrimitiveType expected) {
return !(type == null ||
!type.isValid() ||
(!type.equals(expected) && !expected.getBoxedTypeName().equals(type.getCanonicalText(false))));
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return QuickFixBundle.message("wrap.long.with.math.to.int.text");
}
private static PsiElement getModifiedExpression(PsiElement expression) {
return JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText("java.lang.Math.toIntExact(" + expression.getText() + ")", expression);
}
private static class MyMethodArgumentFix extends MethodArgumentFix implements HighPriorityAction {
protected MyMethodArgumentFix(@NotNull PsiExpressionList list,
int i,
@NotNull PsiType toType,
@NotNull ArgumentFixerActionFactory fixerActionFactory) {
super(list, i, toType, fixerActionFactory);
}
@Nls
@NotNull
@Override
public String getText() {
return myArgList.getExpressions().length == 1
? QuickFixBundle.message("wrap.long.with.math.to.int.parameter.single.text")
: QuickFixBundle.message("wrap.long.with.math.to.int.parameter.multiple.text", myIndex + 1);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return PsiUtil.isLanguageLevel8OrHigher(file) && super.isAvailable(project, editor, file);
}
}
public static class MyMethodArgumentFixerFactory extends ArgumentFixerActionFactory {
@Nullable
@Override
protected PsiExpression getModifiedArgument(final PsiExpression expression, final PsiType toType) throws IncorrectOperationException {
return areSameTypes(expression.getType(), PsiType.LONG) && areSameTypes(toType, PsiType.INT) ? (PsiExpression)getModifiedExpression(expression) : null;
}
@Override
public boolean areTypesConvertible(@NotNull final PsiType exprType, @NotNull final PsiType parameterType, @NotNull final PsiElement context) {
return parameterType.isConvertibleFrom(exprType) || (areSameTypes(parameterType, PsiType.INT) && areSameTypes(exprType, PsiType.LONG));
}
@Override
public MethodArgumentFix createFix(final PsiExpressionList list, final int i, final PsiType toType) {
return new MyMethodArgumentFix(list, i, toType, this);
}
}
}

View File

@@ -1,129 +0,0 @@
/*
* Copyright 2000-2017 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.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class WrapStringWithFileFix extends LocalQuickFixAndIntentionActionOnPsiElement implements HighPriorityAction {
public final static MyMethodArgumentFixerFactory REGISTAR = new MyMethodArgumentFixerFactory();
@Nullable private final PsiType myType;
public WrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
super(expression);
myType = type;
}
@Nls
@NotNull
@Override
public String getText() {
return getFamilyName();
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return QuickFixBundle.message("wrap.with.java.io.file.text");
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return myType != null &&
myType.isValid() &&
myType.equalsToText(CommonClassNames.JAVA_IO_FILE) &&
startElement.isValid() &&
startElement.getManager().isInProject(startElement) &&
isStringType(startElement);
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
startElement.replace(getModifiedExpression(startElement));
}
private static boolean isStringType(@NotNull PsiElement expression) {
if (!(expression instanceof PsiExpression)) return false;
final PsiType type = ((PsiExpression) expression).getType();
if (type == null) return false;
return type.equalsToText(CommonClassNames.JAVA_LANG_STRING);
}
private static PsiElement getModifiedExpression(@NotNull PsiElement expression) {
return JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(PsiKeyword.NEW + " " + CommonClassNames.JAVA_IO_FILE + "(" + expression.getText() + ")", expression);
}
private static class MyMethodArgumentFix extends MethodArgumentFix implements HighPriorityAction {
protected MyMethodArgumentFix(@NotNull PsiExpressionList list,
int i,
@NotNull PsiType toType,
@NotNull ArgumentFixerActionFactory fixerActionFactory) {
super(list, i, toType, fixerActionFactory);
}
@Nls
@NotNull
@Override
public String getText() {
return myArgList.getExpressions().length == 1
? QuickFixBundle.message("wrap.with.java.io.file.parameter.single.text")
: QuickFixBundle.message("wrap.with.java.io.file.parameter.multiple.text", myIndex + 1);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return PsiUtil.isLanguageLevel8OrHigher(file) && super.isAvailable(project, editor, file);
}
}
public static class MyMethodArgumentFixerFactory extends ArgumentFixerActionFactory {
@Nullable
@Override
protected PsiExpression getModifiedArgument(final PsiExpression expression, final PsiType toType) throws IncorrectOperationException {
return isStringType(expression) && toType.equalsToText(CommonClassNames.JAVA_IO_FILE) ? (PsiExpression)getModifiedExpression(expression) : null;
}
@Override
public boolean areTypesConvertible(@NotNull final PsiType exprType, @NotNull final PsiType parameterType, @NotNull final PsiElement context) {
return parameterType.isConvertibleFrom(exprType) || (parameterType.equalsToText(CommonClassNames.JAVA_IO_FILE) && exprType.equalsToText(CommonClassNames.JAVA_LANG_STRING));
}
@Override
public MethodArgumentFix createFix(final PsiExpressionList list, final int i, final PsiType toType) {
return new MyMethodArgumentFix(list, i, toType, this);
}
}
}

View File

@@ -0,0 +1,203 @@
/*
* Copyright 2000-2017 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.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.util.IncorrectOperationException;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
public class WrapWithAdapterMethodCallFix extends LocalQuickFixAndIntentionActionOnPsiElement implements HighPriorityAction {
static class Wrapper extends ArgumentFixerActionFactory {
final Predicate<PsiType> myInTypeFilter;
final Predicate<PsiType> myOutTypeFilter;
final String myTemplate;
/**
* @param template template for replacement (original expression is referenced as {@code {0}})
* @param inTypeFilter filter for input type (must return true if supplied type is acceptable as input type for this wrapper)
* @param outTypeFilter quick filter for output type (must return true if supplied output type is acceptable for this wrapper).
* It's allowed to check imprecisely (return true even if output type is not acceptable) as more
* expensive type check will be performed automatically.
*/
Wrapper(String template, Predicate<PsiType> inTypeFilter, Predicate<PsiType> outTypeFilter) {
myInTypeFilter = inTypeFilter;
myOutTypeFilter = outTypeFilter;
myTemplate = template;
}
boolean isApplicable(PsiElement context, PsiType inType, PsiType outType) {
if (inType == null ||
outType == null ||
inType.equals(PsiType.NULL) ||
!myInTypeFilter.test(inType) ||
!myOutTypeFilter.test(outType)) {
return false;
}
PsiType resultType = createReplacement(context, "((" + inType.getCanonicalText() + ")null)").getType();
return resultType != null && outType.isAssignableFrom(resultType);
}
@NotNull
private PsiExpression createReplacement(PsiElement context, String replacement) {
return JavaPsiFacade.getElementFactory(context.getProject()).createExpressionFromText(
myTemplate.replace("{0}", replacement), context);
}
@Nullable
@Override
protected PsiExpression getModifiedArgument(final PsiExpression expression, final PsiType toType) throws IncorrectOperationException {
if (isApplicable(expression, expression.getType(), toType)) {
return (PsiExpression)JavaCodeStyleManager.getInstance(expression.getProject())
.shortenClassReferences(createReplacement(expression, expression.getText()));
}
return null;
}
@Override
public boolean areTypesConvertible(@NotNull final PsiType exprType,
@NotNull final PsiType parameterType,
@NotNull final PsiElement context) {
return parameterType.isConvertibleFrom(exprType) || isApplicable(context, exprType, parameterType);
}
@Override
public MethodArgumentFix createFix(final PsiExpressionList list, final int i, final PsiType toType) {
return new MyMethodArgumentFix(list, i, toType, this);
}
public String toString() {
return myTemplate.replace("{0}", "").replaceAll("\\b[a-z.]+\\.", "");
}
}
private static final Wrapper[] WRAPPERS = {
new Wrapper("new java.io.File({0})",
inType -> inType.equalsToText(CommonClassNames.JAVA_LANG_STRING),
outType -> outType.equalsToText(CommonClassNames.JAVA_IO_FILE)),
new Wrapper("java.nio.file.Paths.get({0})",
inType -> inType.equalsToText(CommonClassNames.JAVA_LANG_STRING),
outType -> outType.equalsToText("java.nio.file.Path")),
new Wrapper("java.util.Arrays.asList({0})",
inType -> inType instanceof PsiArrayType && ((PsiArrayType)inType).getComponentType() instanceof PsiClassType,
outType -> InheritanceUtil.isInheritor(outType, CommonClassNames.JAVA_LANG_ITERABLE)),
new Wrapper("java.lang.Math.toIntExact({0})",
inType -> PsiType.LONG.equals(inType) || inType.equalsToText(CommonClassNames.JAVA_LANG_LONG),
outType -> PsiType.INT.equals(outType) || outType.equalsToText(CommonClassNames.JAVA_LANG_INTEGER)),
new Wrapper("java.util.Collections.singleton({0})",
inType -> true,
outType -> InheritanceUtil.isInheritor(outType, CommonClassNames.JAVA_LANG_ITERABLE)),
new Wrapper("java.util.Collections.singletonList({0})",
inType -> true,
outType -> outType instanceof PsiClassType &&
((PsiClassType)outType).rawType().equalsToText(CommonClassNames.JAVA_UTIL_LIST)),
new Wrapper("java.util.Arrays.stream({0})",
inType -> inType instanceof PsiArrayType,
outType -> InheritanceUtil.isInheritor(outType, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM))
};
@Nullable private final PsiType myType;
@Nullable private final Wrapper myWrapper;
public WrapWithAdapterMethodCallFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
super(expression);
myType = type;
myWrapper = StreamEx.of(WRAPPERS).findFirst(w -> w.isApplicable(expression, expression.getType(), type)).orElse(null);
}
@Nls
@NotNull
@Override
public String getText() {
return QuickFixBundle.message("wrap.with.adapter.text", myWrapper);
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return QuickFixBundle.message("wrap.with.adapter.call.family.name");
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return myType != null &&
myWrapper != null &&
myType.isValid() &&
startElement.isValid() &&
startElement.getManager().isInProject(startElement);
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
JavaCodeStyleManager.getInstance(project).shortenClassReferences(startElement.replace(getModifiedExpression(startElement)));
}
private PsiExpression getModifiedExpression(@NotNull PsiElement expression) {
assert myWrapper != null;
return myWrapper.createReplacement(expression, expression.getText());
}
private static class MyMethodArgumentFix extends MethodArgumentFix implements HighPriorityAction {
protected MyMethodArgumentFix(@NotNull PsiExpressionList list,
int i,
@NotNull PsiType toType,
@NotNull Wrapper fixerActionFactory) {
super(list, i, toType, fixerActionFactory);
}
@Nls
@NotNull
@Override
public String getText() {
return myArgList.getExpressions().length == 1
? QuickFixBundle.message("wrap.with.adapter.parameter.single.text", myArgumentFixerActionFactory)
: QuickFixBundle.message("wrap.with.adapter.parameter.multiple.text", myIndex + 1, myArgumentFixerActionFactory);
}
}
public static void registerCastActions(@NotNull CandidateInfo[] candidates,
@NotNull PsiCall call,
HighlightInfo highlightInfo,
final TextRange fixRange) {
for (Wrapper wrapper : WRAPPERS) {
wrapper.registerCastActions(candidates, call, highlightInfo, fixRange);
}
}
}

View File

@@ -657,12 +657,6 @@ public class EmptyQuickFixFactory extends QuickFixFactory {
return QuickFixes.EMPTY_FIX;
}
@NotNull
@Override
public IntentionAction createWrapLongWithMathToIntExactFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
return QuickFixes.EMPTY_FIX;
}
@NotNull
@Override
public IntentionAction createWrapWithOptionalFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
@@ -702,7 +696,7 @@ public class EmptyQuickFixFactory extends QuickFixFactory {
@NotNull
@Override
public IntentionAction createWrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
public IntentionAction createWrapWithAdapterFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
return QuickFixes.EMPTY_FIX;
}

View File

@@ -803,12 +803,6 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
return new AddMethodQualifierFix(methodCall);
}
@NotNull
@Override
public IntentionAction createWrapLongWithMathToIntExactFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
return new WrapLongWithMathToIntExactFix(type, expression);
}
@NotNull
@Override
public IntentionAction createWrapWithOptionalFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
@@ -885,8 +879,8 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
@NotNull
@Override
public IntentionAction createWrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
return new WrapStringWithFileFix(type, expression);
public IntentionAction createWrapWithAdapterFix(@Nullable PsiType type, @NotNull PsiExpression expression) {
return new WrapWithAdapterMethodCallFix(type, expression);
}
@NotNull

View File

@@ -0,0 +1,10 @@
// "Wrap using 'Collections.singletonList()'" "true"
import java.util.*;
class Test {
void m(long l) {
List<Long> list = Collections.singletonList(l);
}
}

View File

@@ -0,0 +1,10 @@
// "Wrap using 'Paths.get()'" "true"
import java.nio.file.*;
class Test {
Path m() {
return Paths.get("/etc/passwd");
}
}

View File

@@ -0,0 +1,14 @@
// "Wrap 1st parameter using 'Collections.singleton()'" "true"
import java.util.*;
class Test {
void method(Set<Long> set, double val) {
}
void m(long l) {
method(Collections.singleton(l), l);
}
}

View File

@@ -0,0 +1,9 @@
// "Wrap using 'Arrays.stream()'" "true"
import java.util.*;
import java.util.stream.Stream;
public class Test {
Stream<String> testStream(List<String[]> list) {
return Arrays.stream(list.get(0));
}
}

View File

@@ -0,0 +1,10 @@
// "Wrap using 'Collections.singletonList()'" "true"
import java.util.*;
class Test {
void m(long l) {
List<Long> list = <caret>l;
}
}

View File

@@ -0,0 +1,10 @@
// "Wrap using 'Collections.singletonList()'" "false"
import java.util.*;
class Test {
void m(long l) {
List<Integer> list = <caret>l;
}
}

View File

@@ -0,0 +1,10 @@
// "Wrap using 'Paths.get()'" "true"
import java.nio.file.*;
class Test {
Path m() {
return "/<caret>etc/passwd";
}
}

View File

@@ -0,0 +1,14 @@
// "Wrap 1st parameter using 'Collections.singleton()'" "true"
import java.util.*;
class Test {
void method(Set<Long> set, double val) {
}
void m(long l) {
method(<caret>l, l);
}
}

View File

@@ -0,0 +1,9 @@
// "Wrap using 'Arrays.stream()'" "true"
import java.util.*;
import java.util.stream.Stream;
public class Test {
Stream<String> testStream(List<String[]> list) {
return list.<caret>get(0);
}
}

View File

@@ -1,4 +1,4 @@
// "Wrap using 'Arrays.asList()'" "true"
// "Wrap parameter using 'Arrays.asList()'" "true"
import java.util.Arrays;
import java.util.List;

View File

@@ -1,4 +1,4 @@
// "Wrap using 'Arrays.asList()'" "false"
// "Wrap parameter using 'Arrays.asList()'" "false"
import java.util.LinkedList;
public class Test {

View File

@@ -1,4 +1,4 @@
// "Wrap using 'Arrays.asList()'" "false"
// "Wrap parameter using 'Arrays.asList()'" "false"
import java.util.LinkedList;
public class Test {

View File

@@ -1,4 +1,4 @@
// "Wrap using 'Arrays.asList()'" "true"
// "Wrap parameter using 'Arrays.asList()'" "true"
import java.util.List;
public class Test {

View File

@@ -16,14 +16,24 @@
package com.intellij.java.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
public class WrapStringWithFileFixTest extends LightQuickFixParameterizedTestCase {
import static com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase.JAVA_9;
public class WrapWithAdapterMethodCallFixTest extends LightQuickFixParameterizedTestCase {
public void test() {
doAllTests();
}
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_9; // java.nio.file is mocked since Java 9 only
}
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/wrapStringWithFile";
return "/codeInsight/daemonCodeAnalyzer/quickFix/wrapAdapterCall";
}
}

View File

@@ -265,9 +265,6 @@ replace.with.list.access.text=Replace with list access
add.qualifier=Add qualifier
add.qualifier.original.class.chooser.title=Original class
wrap.array.to.arrays.as.list.parameter.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''Arrays.asList()''
wrap.array.to.arrays.as.list.single.parameter.text=Wrap using 'Arrays.asList()'
annotations.fix=Annotations
add.missing.annotation.parameters.fix=Add missing annotation parameters - {0}
add.missing.annotation.single.parameter.fix=Add missing annotation parameter ''{0}''
@@ -279,10 +276,6 @@ collection.addall.can.be.replaced.with.constructor.fix.options.title=Classes to
collection.addall.can.be.replaced.with.constructor.fix.description=''{0}()'' method can be replaced with parametrized constructor
collection.addall.can.be.replaced.with.constructor.fix.title=Replace 'addAll/putAll' method with parametrized constructor call
wrap.long.with.math.to.int.text=Wrap using 'Math.toIntExact()'
wrap.long.with.math.to.int.parameter.single.text=Wrap parameter using 'Math.toIntExact()'
wrap.long.with.math.to.int.parameter.multiple.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''Math.toIntExact()''
add.exception.from.field.initializer.to.constructor.throws.text=Add exception to class {0, choice, 0#default constructor|1#constructor|2#constructors} signature
add.exception.from.field.initializer.to.constructor.throws.family.text=Add exception to class constructors signature
java.8.map.api.inspection.fix.text=Replace with ''{0}'' method call
@@ -315,9 +308,10 @@ collection.to.array.family.name=Apply conversion '.toArray()'
insert.sam.method.call.fix.name=Insert ''.{0}'' to call functional interface method
insert.sam.method.call.fix.family.name=Insert single abstract method call
wrap.with.java.io.file.text=Wrap using 'new File()'
wrap.with.java.io.file.parameter.single.text=Wrap parameter using 'new File()'
wrap.with.java.io.file.parameter.multiple.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''new File()''
wrap.with.adapter.call.family.name=Wrap using adapter call or object
wrap.with.adapter.text=Wrap using ''{0}''
wrap.with.adapter.parameter.single.text=Wrap parameter using ''{0}''
wrap.with.adapter.parameter.multiple.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''{1}''
java.9.merge.module.statements.fix.family.name=Merge with other ''{0}'' directive
java.9.merge.module.statements.fix.name=Merge with other ''{0} {1}'' directive