IDEA-79715 Groovy: Inspection "There is no default constructor available in class *" must have a quickfix

This commit is contained in:
Maxim.Medvedev
2012-04-25 18:00:55 +04:00
parent e856e8f135
commit ed0afd2ce7
17 changed files with 408 additions and 66 deletions
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.generation.ConstructorBodyGenerator;
import com.intellij.codeInsight.generation.GenerateMembersUtil;
import com.intellij.codeInsight.generation.PsiMethodMember;
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
@@ -27,6 +28,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
@@ -34,7 +36,6 @@ import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -101,7 +102,7 @@ public class CreateConstructorMatchingSuperFix extends BaseIntentionAction {
MemberChooser<PsiMethodMember> chooser = new MemberChooser<PsiMethodMember>(constructors, false, true, project);
chooser.setTitle(QuickFixBundle.message("super.class.constructors.chooser.title"));
chooser.show();
if (chooser.getExitCode() != MemberChooser.OK_EXIT_CODE) return;
if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
constructors = chooser.getSelectedElements(new PsiMethodMember[0]);
isCopyJavadoc = chooser.isCopyJavadoc();
}
@@ -117,12 +118,12 @@ public class CreateConstructorMatchingSuperFix extends BaseIntentionAction {
PsiClass psiClass = JavaPsiFacade.getInstance(targetClass.getProject()).getElementFactory().createClass("X");
targetClass.addRangeAfter(psiClass.getLBrace(), psiClass.getRBrace(), targetClass.getLastChild());
}
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
CodeStyleManager reformatter = CodeStyleManager.getInstance(project);
JVMElementFactory factory = JVMElementFactories.getFactory(targetClass.getLanguage(), project);
CodeStyleManager formatter = CodeStyleManager.getInstance(project);
PsiMethod derived = null;
for (PsiMethodMember candidate : constructors1) {
PsiMethod base = candidate.getElement();
derived = GenerateMembersUtil.substituteGenericMethod(base, candidate.getSubstitutor());
derived = GenerateMembersUtil.substituteGenericMethod(base, candidate.getSubstitutor(), targetClass);
if (!isCopyJavadoc1) {
final PsiDocComment docComment = derived.getDocComment();
@@ -131,23 +132,18 @@ public class CreateConstructorMatchingSuperFix extends BaseIntentionAction {
}
}
final PsiIdentifier identifier = targetClass.getNameIdentifier();
LOG.assertTrue(identifier != null, targetClass);
derived.getNameIdentifier().replace(identifier);
@NonNls StringBuffer buffer = new StringBuffer();
buffer.append("void foo () {\nsuper(");
derived.setName(targetClass.getName());
PsiParameter[] params = derived.getParameterList().getParameters();
for (int j = 0; j < params.length; j++) {
PsiParameter param = params[j];
buffer.append(param.getName());
if (j < params.length - 1) buffer.append(",");
ConstructorBodyGenerator generator = ConstructorBodyGenerator.INSTANCE.forLanguage(derived.getLanguage());
if (generator != null) {
StringBuilder buffer = new StringBuilder();
generator.start(buffer, derived.getName(), PsiParameter.EMPTY_ARRAY);
generator.generateSuperCallIfNeeded(buffer, derived.getParameterList().getParameters());
generator.finish(buffer);
PsiMethod stub = factory.createMethodFromText(buffer.toString(), targetClass);
derived.getBody().replace(stub.getBody());
}
buffer.append(");\n}");
PsiMethod stub = factory.createMethodFromText(buffer.toString(), targetClass);
derived.getBody().replace(stub.getBody());
derived = (PsiMethod)reformatter.reformat(derived);
derived = (PsiMethod)formatter.reformat(derived);
derived = (PsiMethod)JavaCodeStyleManager.getInstance(project).shortenClassReferences(derived);
derived = (PsiMethod)GenerateMembersUtil.insert(targetClass, derived, null, true);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2012 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.generation;
import com.intellij.lang.LanguageExtension;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiParameter;
import org.jetbrains.annotations.NotNull;
/**
* @author Max Medvedev
*/
public interface ConstructorBodyGenerator {
LanguageExtension<ConstructorBodyGenerator> INSTANCE = new LanguageExtension<ConstructorBodyGenerator>("com.intellij.constructorBodyGenerator");
void generateFieldInitialization(@NotNull StringBuilder buffer, @NotNull PsiField[] fields, @NotNull PsiParameter[] parameters);
void generateSuperCallIfNeeded(@NotNull StringBuilder buffer, @NotNull PsiParameter[] parameters);
StringBuilder start(StringBuilder buffer, @NotNull String name, @NotNull PsiParameter[] parameters);
void finish(StringBuilder builder);
}
@@ -211,7 +211,7 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase {
public static PsiMethod generateConstructorPrototype(PsiClass aClass, PsiMethod baseConstructor, boolean copyJavaDoc, PsiField[] fields) throws IncorrectOperationException {
PsiManager manager = aClass.getManager();
PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
JVMElementFactory factory = JVMElementFactories.getFactory(aClass.getLanguage(), aClass.getProject());
CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject());
PsiMethod constructor = factory.createConstructor();
@@ -235,37 +235,28 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase {
}
}
@NonNls StringBuilder body = new StringBuilder();
body.append("{\n");
boolean isNotEnum = false;
if (baseConstructor != null){
PsiClass superClass = aClass.getSuperClass();
LOG.assertTrue(superClass != null);
if (!CommonClassNames.JAVA_LANG_ENUM.equals(superClass.getQualifiedName())) {
isNotEnum = true;
if (baseConstructor instanceof PsiCompiledElement){ // to get some parameter names
PsiClass dummyClass = factory.createClass("Dummy");
PsiClass dummyClass = JVMElementFactories.getFactory(baseConstructor.getLanguage(), baseConstructor.getProject()).createClass("Dummy");
baseConstructor = (PsiMethod)dummyClass.add(baseConstructor);
}
PsiParameter[] parms = baseConstructor.getParameterList().getParameters();
for (PsiParameter parm : parms) {
constructor.getParameterList().add(parm);
}
if (parms.length > 0){
body.append("super(");
for(int j = 0; j < parms.length; j++) {
PsiParameter parm = parms[j];
if (j > 0){
body.append(",");
}
body.append(parm.getName());
}
body.append(");\n");
PsiParameter newParam = factory.createParameter(parm.getName(), parm.getType());
copyModifierList(factory, parm, newParam);
constructor.getParameterList().add(newParam);
}
}
}
JavaCodeStyleManager javaStyle = JavaCodeStyleManager.getInstance(aClass.getProject());
List<PsiParameter> fieldParams = new ArrayList<PsiParameter>();
for (PsiField field : fields) {
String fieldName = field.getName();
String name = javaStyle.variableNameToPropertyName(fieldName, VariableKind.FIELD);
@@ -280,22 +271,39 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase {
}
constructor.getParameterList().add(parm);
if (fieldName.equals(parmName)) {
body.append("this.");
fieldParams.add(parm);
}
ConstructorBodyGenerator generator = ConstructorBodyGenerator.INSTANCE.forLanguage(aClass.getLanguage());
if (generator != null) {
@NonNls StringBuilder buffer = new StringBuilder();
generator.start(buffer, constructor.getName(), PsiParameter.EMPTY_ARRAY);
if (isNotEnum) {
generator.generateSuperCallIfNeeded(buffer, baseConstructor.getParameterList().getParameters());
}
body.append(fieldName);
body.append("=");
body.append(parmName);
body.append(";\n");
generator.generateFieldInitialization(buffer, fields, fieldParams.toArray(new PsiParameter[fieldParams.size()]));
generator.finish(buffer);
PsiMethod stub = factory.createMethodFromText(buffer.toString(), aClass);
constructor.getBody().replace(stub.getBody());
}
body.append("}");
PsiCodeBlock bodyBlock = factory.createCodeBlockFromText(body.toString(), null);
constructor.getBody().replace(bodyBlock);
constructor = (PsiMethod)codeStyleManager.reformat(constructor);
return constructor;
}
static void copyModifierList(JVMElementFactory factory, PsiParameter parm, PsiParameter newParam) {
PsiModifierList modifierList = parm.getModifierList();
PsiModifierList newMList = newParam.getModifierList();
if (modifierList != null && newMList != null) {
for (PsiAnnotation annotation : modifierList.getAnnotations()) {
newMList.add(factory.createAnnotationFromText(annotation.getText(), newParam));
}
for (@PsiModifier.ModifierConstant String m : PsiModifier.MODIFIERS) {
newMList.setModifierProperty(m, parm.hasModifierProperty(m));
}
}
}
@PsiModifier.ModifierConstant
public static String getConstructorModifier(final PsiClass aClass) {
String modifier = PsiModifier.PUBLIC;
@@ -172,7 +172,7 @@ public class GenerateMembersUtil {
editor.getSelectionModel().removeSelection();
}
public static PsiElement insert(PsiClass aClass, PsiMember member, PsiElement anchor, boolean before) throws IncorrectOperationException {
public static PsiElement insert(@NotNull PsiClass aClass, @NotNull PsiMember member, @Nullable PsiElement anchor, boolean before) throws IncorrectOperationException {
if (member instanceof PsiMethod) {
if (!aClass.isInterface()) {
final PsiParameter[] parameters = ((PsiMethod)member).getParameterList().getParameters();
@@ -228,9 +228,15 @@ public class GenerateMembersUtil {
public static PsiMethod substituteGenericMethod(PsiMethod method,
final PsiSubstitutor substitutor,
final PsiElement target) {
@Nullable final PsiElement target) {
Project project = method.getProject();
final PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
final JVMElementFactory factory;
if (target != null) {
factory = JVMElementFactories.getFactory(target.getLanguage(), method.getProject());
}
else {
factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
}
try {
PsiType returnType = method.getReturnType();
@@ -238,7 +244,7 @@ public class GenerateMembersUtil {
PsiMethod newMethod;
if (method.isConstructor()) {
newMethod = factory.createConstructor();
newMethod.getNameIdentifier().replace(factory.createIdentifier(method.getName()));
newMethod.setName(method.getName());
}
else {
final PsiType substitutedReturnType = substituteType(substitutor, returnType);
@@ -292,10 +298,15 @@ public class GenerateMembersUtil {
if (paramName == null) paramName = "p" + i;
PsiParameter newParameter = factory.createParameter(paramName, substituted);
if (parameter.getLanguage() == JavaLanguage.INSTANCE) {
if (parameter.getLanguage() == newParameter.getLanguage()) {
PsiModifierList modifierList = newParameter.getModifierList();
modifierList = (PsiModifierList)modifierList.replace(parameter.getModifierList());
processAnnotations(project, modifierList, moduleScope);
if (parameter.getLanguage() == JavaLanguage.INSTANCE) {
processAnnotations(project, modifierList, moduleScope);
}
}
else {
GenerateConstructorHandler.copyModifierList(factory, parameter, newParameter);
}
newMethod.getParameterList().add(newParameter);
}
@@ -0,0 +1,73 @@
/*
* Copyright 2000-2012 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.generation;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiParameter;
import org.jetbrains.annotations.NotNull;
/**
* @author Max Medvedev
*/
public class JavaConstructorBodyWithSuperCallGenerator implements ConstructorBodyGenerator {
@Override
public void generateFieldInitialization(@NotNull StringBuilder buffer,
@NotNull PsiField[] fields,
@NotNull PsiParameter[] parameters) {
for (int i = 0, length = fields.length; i < length; i++) {
String fieldName = fields[i].getName();
String paramName = parameters[i].getName();
if (fieldName.equals(paramName)) {
buffer.append("this.");
}
buffer.append(fieldName);
buffer.append("=");
buffer.append(paramName);
buffer.append(";\n");
}
}
@Override
public void generateSuperCallIfNeeded(@NotNull StringBuilder buffer, @NotNull PsiParameter[] parameters) {
if (parameters.length > 0) {
buffer.append("super(");
for (int j = 0; j < parameters.length; j++) {
PsiParameter param = parameters[j];
buffer.append(param.getName());
if (j < parameters.length - 1) buffer.append(",");
}
buffer.append(");\n");
}
}
@Override
public StringBuilder start(StringBuilder buffer, @NotNull String name, @NotNull PsiParameter[] parameters) {
buffer.append("public ").append(name).append("(");
for (PsiParameter parameter : parameters) {
buffer.append(parameter.getType().getPresentableText()).append(' ').append(parameter.getName()).append(',');
}
if (parameters.length > 0) {
buffer.delete(buffer.length() - 1, buffer.length());
}
buffer.append("){\n");
return buffer;
}
@Override
public void finish(StringBuilder buffer) {
buffer.append('}');
}
}