blob: 841ccab4fb918e3c0e7e3a5ae472bf5ec1c28863 [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.siyeh.ipp.junit;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInsight.template.TemplateBuilder;
import com.intellij.codeInsight.template.TemplateBuilderFactory;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
/**
* @author Dmitry Batkovich
*/
public class DataPointHolderConversionIntention extends PsiElementBaseIntentionAction {
private static final String THEORIES_PACKAGE = "org.junit.experimental.theories";
private static final String DATA_POINT_FQN = THEORIES_PACKAGE + ".DataPoint";
private static final String DATA_POINTS_FQN = THEORIES_PACKAGE + ".DataPoints";
private static final String REPLACE_BY_TEMPLATE = "Replace by @%s %s";
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element)
throws IncorrectOperationException {
final PsiElement holder = element.getParent();
PsiModifierListOwner createdElement =
holder instanceof PsiField ? convertToMethod((PsiField)holder) : convertToField((PsiMethod)holder);
final PsiModifierListOwner oldElement = (PsiModifierListOwner)holder;
final PsiAnnotation psiAnnotation = AnnotationUtil.findAnnotation(oldElement, DATA_POINT_FQN, DATA_POINTS_FQN);
assert psiAnnotation != null;
final String annotation = psiAnnotation.getQualifiedName();
assert annotation != null;
final PsiModifierList modifierList = createdElement.getModifierList();
assert modifierList != null;
modifierList.addAnnotation(annotation);
modifierList.setModifierProperty(PsiModifier.STATIC, true);
modifierList.setModifierProperty(PsiModifier.PUBLIC, true);
createdElement = (PsiModifierListOwner)oldElement.replace(createdElement);
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
final TemplateBuilder templateBuilder = TemplateBuilderFactory.getInstance().createTemplateBuilder(createdElement);
final PsiNameIdentifierOwner asNameIdOwner = (PsiNameIdentifierOwner)createdElement;
templateBuilder.replaceElement(asNameIdOwner.getNameIdentifier(), asNameIdOwner.getName());
templateBuilder.run(editor, false);
}
private static PsiField convertToField(final PsiMethod method) {
final Project project = method.getProject();
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final String fieldName = codeStyleManager.propertyNameToVariableName(method.getName(), VariableKind.STATIC_FIELD);
final PsiType returnType = method.getReturnType();
assert returnType != null;
final PsiField field = elementFactory.createField(fieldName, returnType);
final PsiStatement returnStatement = PsiTreeUtil.findChildOfType(method, PsiStatement.class);
if (returnStatement != null) {
field.setInitializer(((PsiReturnStatement) returnStatement).getReturnValue());
}
return field;
}
private static PsiMethod convertToMethod(final PsiField field) {
final Project project = field.getProject();
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final PsiExpression fieldInitializer = field.getInitializer();
final PsiMethod method =
elementFactory.createMethod(codeStyleManager.variableNameToPropertyName(field.getName(), VariableKind.STATIC_FIELD), field.getType());
PsiCodeBlock body = method.getBody();
assert body != null;
final PsiStatement methodCode = elementFactory.createStatementFromText(PsiKeyword.RETURN + " " + fieldInitializer.getText() + ";", null);
body.add(methodCode);
return method;
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) {
final Pair<PsiMember, PsiAnnotation> dataPointsHolder = extractDataPointsHolder(element);
if (dataPointsHolder != null && isConvertible(dataPointsHolder.getFirst())) {
final String replaceType = dataPointsHolder.getFirst() instanceof PsiMethod ? "field" : "method";
final String annotation = StringUtil.getShortName(dataPointsHolder.getSecond().getQualifiedName());
setText(String.format(REPLACE_BY_TEMPLATE, annotation, replaceType));
return true;
}
return false;
}
private static Pair<PsiMember, PsiAnnotation> extractDataPointsHolder(@NotNull final PsiElement element) {
if (!(element instanceof PsiIdentifier)) {
return null;
}
final PsiElement maybeHolder = element.getParent();
if (maybeHolder == null || !(maybeHolder instanceof PsiMethod || maybeHolder instanceof PsiField)) {
return null;
}
final PsiMember holder = (PsiMember)maybeHolder;
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(holder, DATA_POINT_FQN, DATA_POINTS_FQN);
return annotation == null ? null : Pair.create(holder, annotation);
}
private static boolean isConvertible(@NotNull final PsiMember member) {
if (!(member instanceof PsiMethod)) {
return ((PsiField)member).getInitializer() != null;
}
final PsiMethod method = (PsiMethod)member;
final PsiType returnType = method.getReturnType();
if (returnType == null || returnType.equals(PsiType.VOID) || method.getParameterList().getParametersCount() != 0) {
return false;
}
final PsiCodeBlock body = method.getBody();
if (body == null) {
return false;
}
final PsiStatement[] methodStatements = body.getStatements();
switch (methodStatements.length) {
case 1:
final PsiStatement methodStatement = methodStatements[0];
return methodStatement instanceof PsiReturnStatement;
case 0:
return true;
default:
return false;
}
}
@NotNull
@Override
public String getFamilyName() {
return "Convert @DataPoint(s) annotation holder";
}
}