blob: 82f73ee15a8d4c4c1e21a012556f6ebb1e260103 [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.intentions.style;
import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
import org.jetbrains.plugins.groovy.intentions.base.Intention;
import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.refactoring.DefaultGroovyVariableNameValidator;
import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil;
import java.util.*;
/**
* @author Maxim.Medvedev
*/
public class ReplaceAbstractClassInstanceByMapIntention extends Intention {
@NotNull
@Override
protected PsiElementPredicate getElementPredicate() {
return new MyPredicate();
}
@Override
protected void processIntention(@NotNull PsiElement psiElement, Project project, Editor editor) throws IncorrectOperationException {
PsiDocumentManager.getInstance(project).commitAllDocuments();
GrCodeReferenceElement ref = (GrCodeReferenceElement)psiElement;
final GrAnonymousClassDefinition anonymous = (GrAnonymousClassDefinition)ref.getParent();
final GrNewExpression newExpr = (GrNewExpression)anonymous.getParent();
final PsiElement resolved = ref.resolve();
assert resolved instanceof PsiClass;// && ((PsiClass)resolved).isInterface();
GrTypeDefinitionBody body = anonymous.getBody();
assert body != null;
List<Pair<PsiMethod, GrOpenBlock>> methods = new ArrayList<Pair<PsiMethod, GrOpenBlock>>();
for (GrMethod method : body.getMethods()) {
methods.add(new Pair<PsiMethod, GrOpenBlock>(method, method.getBlock()));
}
final PsiClass iface = (PsiClass)resolved;
final Collection<CandidateInfo> collection = OverrideImplementExploreUtil.getMethodsToOverrideImplement(anonymous, true);
for (CandidateInfo info : collection) {
methods.add(new Pair<PsiMethod, GrOpenBlock>((PsiMethod)info.getElement(), null));
}
StringBuilder buffer = new StringBuilder();
if (methods.size() == 1) {
final Pair<PsiMethod, GrOpenBlock> pair = methods.get(0);
appendClosureTextByMethod(pair.getFirst(), buffer, pair.getSecond(), newExpr);
if (!GroovyConfigUtils.getInstance().isVersionAtLeast(psiElement, GroovyConfigUtils.GROOVY2_2)) {
buffer.append(" as ").append(iface.getQualifiedName());
}
}
else {
buffer.append("[");
buffer.append("\n");
for (Pair<PsiMethod, GrOpenBlock> pair : methods) {
final PsiMethod method = pair.getFirst();
final GrOpenBlock block = pair.getSecond();
buffer.append(method.getName()).append(": ");
appendClosureTextByMethod(method, buffer, block, newExpr);
buffer.append(",\n");
}
if (!methods.isEmpty()) {
buffer.delete(buffer.length() - 2, buffer.length());
buffer.append('\n');
}
buffer.append("]");
buffer.append(" as ").append(iface.getQualifiedName());
}
createAndAdjustNewExpression(project, newExpr, buffer);
}
private static void createAndAdjustNewExpression(final Project project,
final GrNewExpression newExpression,
final StringBuilder buffer) throws IncorrectOperationException {
final GrExpression expr = GroovyPsiElementFactory.getInstance(project).createExpressionFromText(buffer.toString());
final GrExpression safeTypeExpr = newExpression.replaceWithExpression(expr, false);
JavaCodeStyleManager.getInstance(project).shortenClassReferences(safeTypeExpr);
}
private static void appendClosureTextByMethod(final PsiMethod method,
final StringBuilder buffer,
@Nullable GrOpenBlock block,
GroovyPsiElement context) {
final PsiParameterList list = method.getParameterList();
buffer.append("{ ");
final PsiParameter[] parameters = list.getParameters();
Set<String> generatedNames = new HashSet<String>();
if (parameters.length > 0) {
final PsiParameter first = parameters[0];
final PsiType type = first.getType();
buffer.append(type.getCanonicalText()).append(" ");
buffer.append(createName(generatedNames, first, type, context));
}
for (int i = 1; i < parameters.length; i++) {
buffer.append(", ");
final PsiParameter param = parameters[i];
final PsiType type = param.getType();
buffer.append(type.getCanonicalText()).append(" ");
String name = createName(generatedNames, param, type, context);
buffer.append(name);
}
if (parameters.length > 0) {
buffer.append(" ->");
}
if (block != null) {
final PsiElement lBrace = block.getLBrace();
final PsiElement rBrace = block.getRBrace();
for (PsiElement child = lBrace != null ? lBrace.getNextSibling() : block.getFirstChild();
child != null && child != rBrace;
child = child.getNextSibling()) {
buffer.append(child.getText());
}
}
buffer.append(" }");
}
private static String createName(final Set<String> generatedNames, final PsiParameter param, final PsiType type, GroovyPsiElement context) {
String name = param.getName();
if (name == null) {
name = GroovyNameSuggestionUtil.suggestVariableNameByType(type, new DefaultGroovyVariableNameValidator(context, generatedNames))[0];
assert name != null;
}
generatedNames.add(name);
return name;
}
static class MyPredicate implements PsiElementPredicate {
@Override
public boolean satisfiedBy(PsiElement element) {
if (element instanceof GrCodeReferenceElement && element.getParent() instanceof GrAnonymousClassDefinition) {
final GrAnonymousClassDefinition anonymous = ((GrAnonymousClassDefinition)element.getParent());
GrNewExpression newExpression = (GrNewExpression)anonymous.getParent();
if (newExpression.getQualifier() == null && anonymous.getFields().length == 0) {
return true;
}
}
return false;
}
}
}