blob: 74df48381201dfa9e3987d5eb61fde52b38b3471 [file] [log] [blame]
/*
* 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.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypeInfoImpl;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class CreateMethodFromMethodReferenceFix extends CreateFromUsageBaseFix {
private static final Logger LOG = Logger.getInstance("#" + CreateMethodFromMethodReferenceFix.class.getName());
private final SmartPsiElementPointer myMethodReferenceExpression;
public CreateMethodFromMethodReferenceFix(@NotNull PsiMethodReferenceExpression methodRef) {
myMethodReferenceExpression = SmartPointerManager.getInstance(methodRef.getProject()).createSmartPsiElementPointer(methodRef);
}
@Override
protected boolean isAvailableImpl(int offset) {
final PsiMethodReferenceExpression call = getMethodReference();
if (call == null || !call.isValid()) return false;
final PsiType functionalInterfaceType = call.getFunctionalInterfaceType();
if (functionalInterfaceType == null ||
LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) == null){
return false;
}
final String name = call.getReferenceName();
if (name == null) return false;
if (call.isConstructor() && name.equals("new") || PsiNameHelper.getInstance(call.getProject()).isIdentifier(name)) {
setText(call.isConstructor() ? QuickFixBundle.message("create.constructor.from.new.text") : QuickFixBundle.message("create.method.from.usage.text", name));
return true;
}
return false;
}
@Override
protected PsiElement getElement() {
final PsiMethodReferenceExpression call = getMethodReference();
if (call == null || !call.getManager().isInProject(call)) return null;
return call;
}
@Override
@NotNull
protected List<PsiClass> getTargetClasses(PsiElement element) {
List<PsiClass> targets = super.getTargetClasses(element);
PsiMethodReferenceExpression call = getMethodReference();
if (call == null) return Collections.emptyList();
return targets;
}
@Override
protected void invokeImpl(final PsiClass targetClass) {
if (targetClass == null) return;
PsiMethodReferenceExpression expression = getMethodReference();
if (expression == null) return;
if (isValidElement(expression)) return;
PsiClass parentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
PsiMember enclosingContext = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, PsiField.class, PsiClassInitializer.class);
String methodName = expression.getReferenceName();
LOG.assertTrue(methodName != null);
final Project project = targetClass.getProject();
JVMElementFactory elementFactory = JVMElementFactories.getFactory(targetClass.getLanguage(), project);
if (elementFactory == null) elementFactory = JavaPsiFacade.getElementFactory(project);
PsiMethod method = expression.isConstructor() ? (PsiMethod)targetClass.add(elementFactory.createConstructor())
: CreateMethodFromUsageFix.createMethod(targetClass, parentClass, enclosingContext, methodName);
if (method == null) {
return;
}
if (!expression.isConstructor()) {
setupVisibility(parentClass, targetClass, method.getModifierList());
}
expression = getMethodReference();
LOG.assertTrue(expression.isValid());
if (!expression.isConstructor() && shouldCreateStaticMember(expression, targetClass)) {
PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true);
}
final PsiElement context = PsiTreeUtil.getParentOfType(expression, PsiClass.class, PsiMethod.class);
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(classResolveResult);
LOG.assertTrue(interfaceMethod != null);
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType);
LOG.assertTrue(interfaceReturnType != null);
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, classResolveResult);
final ExpectedTypeInfo[] expectedTypes = {new ExpectedTypeInfoImpl(interfaceReturnType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, interfaceReturnType, TailType.NONE, null, ExpectedTypeInfoImpl.NULL)};
CreateMethodFromUsageFix.doCreate(targetClass, method, false,
ContainerUtil.map2List(interfaceMethod.getParameterList().getParameters(), new Function<PsiParameter, Pair<PsiExpression, PsiType>>() {
@Override
public Pair<PsiExpression, PsiType> fun(PsiParameter parameter) {
return Pair.create(null, substitutor.substitute(parameter.getType()));
}
}),
PsiSubstitutor.EMPTY,
expectedTypes, context);
}
@Override
protected boolean isValidElement(PsiElement element) {
return false;
}
@Override
@NotNull
public String getFamilyName() {
return QuickFixBundle.message("create.method.from.usage.family");
}
@Nullable
protected PsiMethodReferenceExpression getMethodReference() {
return (PsiMethodReferenceExpression)myMethodReferenceExpression.getElement();
}
}