blob: 2f5d02264b9a2f7523158b4a54e22c2eb8e24e5c [file] [log] [blame]
/*
* 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.
* 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.FileModificationService;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author ven
*/
public class WrapExpressionFix implements IntentionAction {
private final PsiExpression myExpression;
private final PsiClassType myExpectedType;
private final boolean myPrimitiveExpected;
public WrapExpressionFix(@NotNull PsiType expectedType, @NotNull PsiExpression expression) {
myExpression = expression;
myExpectedType = getClassType(expectedType, expression);
myPrimitiveExpected = expectedType instanceof PsiPrimitiveType;
}
@Nullable
private static PsiClassType getClassType(PsiType type, PsiElement place) {
if (type instanceof PsiClassType) {
return (PsiClassType)type;
}
else if (type instanceof PsiPrimitiveType) {
return ((PsiPrimitiveType)type).getBoxedType(place.getManager(), GlobalSearchScope.allScope(place.getProject()));
}
return null;
}
@Override
@NotNull
public String getText() {
final PsiMethod wrapper = myExpression.isValid() && myExpectedType != null ? findWrapper(myExpression.getType(), myExpectedType, myPrimitiveExpected) : null;
final String methodPresentation = wrapper != null ? wrapper.getContainingClass().getName() + "." + wrapper.getName() : "";
return QuickFixBundle.message("wrap.expression.using.static.accessor.text", methodPresentation);
}
@Nullable
private static PsiMethod findWrapper(PsiType type, @NotNull PsiClassType expectedType, boolean primitiveExpected) {
PsiClass aClass = expectedType.resolve();
if (aClass != null) {
PsiType expectedReturnType = expectedType;
if (primitiveExpected) {
expectedReturnType = PsiPrimitiveType.getUnboxedType(expectedType);
}
if (expectedReturnType == null) return null;
PsiMethod[] methods = aClass.getMethods();
final Set<PsiMethod> wrapperMethods = new LinkedHashSet<PsiMethod>();
for (PsiMethod method : methods) {
if (method.hasModifierProperty(PsiModifier.STATIC)
&& method.getParameterList().getParametersCount() == 1
&& method.getParameterList().getParameters()[0].getType().isAssignableFrom(type)
&& method.getReturnType() != null
&& expectedReturnType.equals(method.getReturnType())) {
final String methodName = method.getName();
if (methodName.startsWith("parse") || methodName.equals("valueOf")) {
return method;
}
wrapperMethods.add(method);
}
}
if (!wrapperMethods.isEmpty()) return wrapperMethods.iterator().next();
}
return null;
}
@Override
@NotNull
public String getFamilyName() {
return QuickFixBundle.message("wrap.expression.using.static.accessor.family");
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return myExpression.isValid()
&& myExpression.getManager().isInProject(myExpression)
&& myExpectedType != null
&& myExpectedType.isValid()
&& myExpression.getType() != null
&& findWrapper(myExpression.getType(), myExpectedType, myPrimitiveExpected) != null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
PsiMethod wrapper = findWrapper(myExpression.getType(), myExpectedType, myPrimitiveExpected);
assert wrapper != null;
PsiElementFactory factory = JavaPsiFacade.getInstance(file.getProject()).getElementFactory();
@NonNls String methodCallText = "Foo." + wrapper.getName() + "()";
PsiMethodCallExpression call = (PsiMethodCallExpression)factory.createExpressionFromText(methodCallText,
null);
call.getArgumentList().add(myExpression);
((PsiReferenceExpression)call.getMethodExpression().getQualifierExpression()).bindToElement(
wrapper.getContainingClass());
myExpression.replace(call);
}
@Override
public boolean startInWriteAction() {
return true;
}
public static void registerWrapAction(JavaResolveResult[] candidates, PsiExpression[] expressions, HighlightInfo highlightInfo) {
PsiType expectedType = null;
PsiExpression expr = null;
nextMethod:
for (int i = 0; i < candidates.length && expectedType == null; i++) {
final JavaResolveResult candidate = candidates[i];
final PsiSubstitutor substitutor = candidate.getSubstitutor();
final PsiElement element = candidate.getElement();
assert element != null;
final PsiMethod method = (PsiMethod)element;
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (!method.isVarArgs() && parameters.length != expressions.length) continue;
for (int j = 0; j < expressions.length; j++) {
PsiExpression expression = expressions[j];
final PsiType exprType = expression.getType();
if (exprType != null) {
PsiType paramType = parameters[Math.min(j, parameters.length - 1)].getType();
if (paramType instanceof PsiEllipsisType) {
paramType = ((PsiEllipsisType)paramType).getComponentType();
}
paramType = substitutor != null ? substitutor.substitute(paramType) : paramType;
if (paramType.isAssignableFrom(exprType)) continue;
final PsiClassType classType = getClassType(paramType, expression);
if (expectedType == null && classType != null && findWrapper(exprType, classType, paramType instanceof PsiPrimitiveType) != null) {
expectedType = paramType;
expr = expression;
}
else {
expectedType = null;
expr = null;
continue nextMethod;
}
}
}
}
if (expectedType != null) {
QuickFixAction.registerQuickFixAction(highlightInfo, expr.getTextRange(), new WrapExpressionFix(expectedType, expr));
}
}
}