blob: 881e823285c979681032d979a4a3057f0bd248ed [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 org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.generation.PsiGenerationInfo;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.GroovyLanguage;
import org.jetbrains.plugins.groovy.intentions.base.IntentionUtils;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStaticChecker;
import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.template.expressions.ChooseTypeExpression;
/**
* @author ven
*/
public class CreateMethodFromUsageFix extends GrCreateFromUsageBaseFix implements IntentionAction {
public CreateMethodFromUsageFix(@NotNull GrReferenceExpression refExpression) {
super(refExpression);
}
@Override
@NotNull
public String getText() {
return GroovyBundle.message("create.method.from.usage", getMethodName());
}
@Override
protected void invokeImpl(Project project, @NotNull PsiClass targetClass) {
final JVMElementFactory factory = JVMElementFactories.getFactory(targetClass.getLanguage(), targetClass.getProject());
assert factory != null;
PsiMethod method = factory.createMethod(getMethodName(), PsiType.VOID);
final GrReferenceExpression ref = getRefExpr();
if (GrStaticChecker.isInStaticContext(ref, targetClass)) {
method.getModifierList().setModifierProperty(PsiModifier.STATIC, true);
}
PsiType[] argTypes = getArgumentTypes();
assert argTypes != null;
ChooseTypeExpression[] paramTypesExpressions = setupParams(method, argTypes, factory);
TypeConstraint[] constraints = getReturnTypeConstraints();
final PsiGenerationInfo<PsiMethod> info = OverrideImplementUtil.createGenerationInfo(method);
info.insert(targetClass, findInsertionAnchor(info, targetClass), false);
method = info.getPsiMember();
if (shouldBeAbstract(targetClass)) {
method.getBody().delete();
if (!targetClass.isInterface()) {
method.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, true);
}
}
final PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiClass.class, PsiMethod.class, PsiFile.class);
IntentionUtils.createTemplateForMethod(argTypes, paramTypesExpressions, method, targetClass, constraints, false, context);
}
@NotNull
protected TypeConstraint[] getReturnTypeConstraints() {
return GroovyExpectedTypesProvider.calculateTypeConstraints((GrExpression)getRefExpr().getParent());
}
protected PsiType[] getArgumentTypes() {
return PsiUtil.getArgumentTypes(getRefExpr(), false);
}
@NotNull
protected String getMethodName() {
return getRefExpr().getReferenceName();
}
protected boolean shouldBeAbstract(PsiClass aClass) {
return aClass.isInterface() && !GrTraitUtil.isTrait(aClass);
}
@Nullable
private PsiElement findInsertionAnchor(PsiGenerationInfo<PsiMethod> info,
PsiClass targetClass) {
PsiElement parent = targetClass instanceof GroovyScriptClass ? ((GroovyScriptClass)targetClass).getContainingFile() : targetClass;
if (PsiTreeUtil.isAncestor(parent, getRefExpr(), false)) {
return info.findInsertionAnchor(targetClass, getRefExpr());
}
else {
return null;
}
}
@NotNull
private ChooseTypeExpression[] setupParams(@NotNull PsiMethod method, @NotNull PsiType[] argTypes, @NotNull JVMElementFactory factory) {
final PsiParameterList parameterList = method.getParameterList();
ChooseTypeExpression[] paramTypesExpressions = new ChooseTypeExpression[argTypes.length];
for (int i = 0; i < argTypes.length; i++) {
PsiType argType = TypesUtil.unboxPrimitiveTypeWrapper(argTypes[i]);
if (argType == null || argType == PsiType.NULL) argType = TypesUtil.getJavaLangObject(getRefExpr());
final PsiParameter p = factory.createParameter("o", argType);
parameterList.add(p);
TypeConstraint[] constraints = {SupertypeConstraint.create(argType)};
boolean isGroovy = method.getLanguage() == GroovyLanguage.INSTANCE;
paramTypesExpressions[i] = new ChooseTypeExpression(constraints, method.getManager(), method.getResolveScope(), isGroovy);
}
return paramTypesExpressions;
}
}