IDEA-86368 Groovy: Create From Usage: Code Completion for destination package is missing in Create Class/Interface/Enum dialog

This commit is contained in:
Maxim.Medvedev
2012-06-26 10:46:32 +04:00
parent 492f88c1be
commit e173a311dd
4 changed files with 134 additions and 74 deletions
@@ -124,6 +124,7 @@ import.class=Import Class
create.class.family.name=Create Class
create.class.text=Create Class {0}
create.interface.text=Create Interface {0}
create.annotation.text=Create Annotation {0}
static.declaration.in.inner.class=Inner classes cannot have static declarations
constructors.are.not.allowed.in.anonymous.class=Constructors are not allowed in anonymous class
no.such.property=Property ''{0}'' does not exist
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar;
import com.intellij.codeInsight.daemon.impl.quickfix.AddMethodBodyFix;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateConstructorMatchingSuperFix;
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
@@ -1981,21 +1982,29 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
}
else {
if (shouldBeInterface(refElement)) {
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.INTERFACE));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.INTERFACE));
}
else if (shouldBeClass(refElement)) {
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.CLASS));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.ENUM));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.CLASS));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.ENUM));
}
else if (shouldBeAnnotation(refElement)) {
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.ANNOTATION));
}
else {
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.CLASS));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.INTERFACE));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassActionBase.Type.ENUM));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.CLASS));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.INTERFACE));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.ENUM));
annotation.registerFix(CreateClassFix.createClassFixAction(refElement, CreateClassKind.ANNOTATION));
}
}
}
}
private static boolean shouldBeAnnotation(GrReferenceElement element) {
return element.getParent() instanceof GrAnnotation;
}
private static boolean shouldBeInterface(GrReferenceElement myRefElement) {
PsiElement parent = myRefElement.getParent();
return parent instanceof GrImplementsClause || parent instanceof GrExtendsClause && parent.getParent() instanceof GrInterfaceDefinition;
@@ -16,7 +16,9 @@
package org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.CreateClassDialog;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
@@ -24,7 +26,9 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -40,12 +44,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
* @author ilyas
*/
public abstract class CreateClassActionBase implements IntentionAction {
private Type myType;
private CreateClassKind myType;
protected final GrReferenceElement myRefElement;
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.annotator.intentions.CreateClassActionBase");
public CreateClassActionBase(Type type, GrReferenceElement refElement) {
public CreateClassActionBase(CreateClassKind type, GrReferenceElement refElement) {
myType = type;
myRefElement = refElement;
}
@@ -60,6 +64,8 @@ public abstract class CreateClassActionBase implements IntentionAction {
return GroovyBundle.message("create.class.text", referenceName);
case INTERFACE:
return GroovyBundle.message("create.interface.text", referenceName);
case ANNOTATION:
return GroovyBundle.message("create.annotation.text", referenceName);
default:
return "";
}
@@ -75,11 +81,11 @@ public abstract class CreateClassActionBase implements IntentionAction {
}
public boolean startInWriteAction() {
return true;
return false;
}
protected Type getType() {
protected CreateClassKind getType() {
return myType;
}
@@ -145,7 +151,17 @@ public abstract class CreateClassActionBase implements IntentionAction {
}
}
public static enum Type {
ENUM, CLASS, INTERFACE
@Nullable
protected PsiDirectory getTargetDirectory(Project project, String qualifier, String name, Module module, String title) {
CreateClassDialog dialog = new CreateClassDialog(project, title, name, qualifier, getType(), false, module) {
@Override
protected boolean reportBaseInSourceSelectionInTest() {
return true;
}
};
dialog.show();
if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null;
return dialog.getTargetDirectory();
}
}
@@ -16,12 +16,15 @@
package org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
@@ -34,7 +37,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
@@ -49,58 +51,91 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
public abstract class CreateClassFix {
public static IntentionAction createClassFromNewAction(final GrNewExpression expression) {
return new CreateClassActionBase(CreateClassActionBase.Type.CLASS, expression.getReferenceElement()) {
return new CreateClassActionBase(CreateClassKind.CLASS, expression.getReferenceElement()) {
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!(file instanceof GroovyFileBase)) return;
GroovyFileBase groovyFile = (GroovyFileBase) file;
final String qualifier = groovyFile instanceof GroovyFile ? groovyFile.getPackageName() : "";
GroovyFileBase groovyFile = (GroovyFileBase)file;
final PsiManager manager = myRefElement.getManager();
final String name = myRefElement.getReferenceName();
assert name != null;
final Module module = ModuleUtil.findModuleForPsiElement(file);
final String qualifier;
final String name;
final Module module;
final AccessToken accessToken = ReadAction.start();
try {
qualifier = groovyFile instanceof GroovyFile ? groovyFile.getPackageName() : "";
name = myRefElement.getReferenceName();
assert name != null;
module = ModuleUtil.findModuleForPsiElement(file);
}
finally {
accessToken.finish();
}
PsiDirectory targetDirectory = getTargetDirectory(project, qualifier, name, module, getText());
if (targetDirectory == null) return;
GrTypeDefinition targetClass = createClassByType(targetDirectory, name, manager, myRefElement, NewGroovyClassAction.GROOVY_CLASS);
if (targetClass == null) return;
GrArgumentList argList = expression.getArgumentList();
if (argList != null && argList.getNamedArguments().length + argList.getExpressionArguments().length > 0 && targetClass != null) {
PsiType[] argTypes = PsiUtil.getArgumentTypes(myRefElement, false);
assert argTypes != null;
ChooseTypeExpression[] paramTypesExpressions = new ChooseTypeExpression[argTypes.length];
String[] paramTypes = new String[argTypes.length];
String[] paramNames = new String[argTypes.length];
for (int i = 0; i < argTypes.length; i++) {
PsiType argType = argTypes[i];
if (argType == null) argType = TypesUtil.getJavaLangObject(myRefElement);
paramTypes[i] = "Object";
paramNames[i] = "o" + i;
paramTypesExpressions[i] = new ChooseTypeExpression(new TypeConstraint[]{SupertypeConstraint.create(argType)}, myRefElement.getManager());
}
GrMethod method = GroovyPsiElementFactory.getInstance(project).createConstructorFromText(name, paramTypes, paramNames, "{\n}");
method = targetClass.addMemberDeclaration(method, null);
final PsiNameIdentifierOwner context = PsiTreeUtil.getParentOfType(myRefElement, PsiMethod.class, PsiClass.class);
IntentionUtils.createTemplateForMethod(argTypes, paramTypesExpressions, method, targetClass, new TypeConstraint[0], true, context);
} else {
PsiType[] argTypes = getArgTypes(myRefElement);
if (argTypes != null) {
generateConstructor(myRefElement, name, argTypes, targetClass, project);
}
else {
putCursor(project, targetClass.getContainingFile(), targetClass);
}
addImportForClass(groovyFile, qualifier, targetClass);
}
};
}
public static IntentionAction createClassFixAction(final GrReferenceElement refElement, CreateClassActionBase.Type type) {
return new CreateClassActionBase(type, refElement) {
@Nullable
private static PsiType[] getArgTypes(GrReferenceElement refElement) {
final AccessToken accessToken = ReadAction.start();
try {
return PsiUtil.getArgumentTypes(refElement, false);
}
finally {
accessToken.finish();
}
}
private static void generateConstructor(@NotNull PsiElement refElement,
@NotNull String name,
@NotNull PsiType[] argTypes,
@NotNull GrTypeDefinition targetClass,
@NotNull Project project) {
final AccessToken writeLock = WriteAction.start();
try {
ChooseTypeExpression[] paramTypesExpressions = new ChooseTypeExpression[argTypes.length];
String[] paramTypes = new String[argTypes.length];
String[] paramNames = new String[argTypes.length];
for (int i = 0; i < argTypes.length; i++) {
PsiType argType = argTypes[i];
if (argType == null) argType = TypesUtil.getJavaLangObject(refElement);
paramTypes[i] = "Object";
paramNames[i] = "o" + i;
paramTypesExpressions[i] = new ChooseTypeExpression(new TypeConstraint[]{SupertypeConstraint.create(argType)}, refElement.getManager());
}
GrMethod method = GroovyPsiElementFactory.getInstance(project).createConstructorFromText(name, paramTypes, paramNames, "{\n}");
method = targetClass.addMemberDeclaration(method, null);
final PsiNameIdentifierOwner context = PsiTreeUtil.getParentOfType(refElement, PsiMethod.class, PsiClass.class);
IntentionUtils.createTemplateForMethod(argTypes, paramTypesExpressions, method, targetClass, new TypeConstraint[0], true, context);
}
finally {
writeLock.finish();
}
}
public static IntentionAction createClassFixAction(final GrReferenceElement refElement, CreateClassKind type) {
return new CreateClassActionBase(type, refElement) {
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!(file instanceof GroovyFileBase)) return;
GroovyFileBase groovyFile = (GroovyFileBase) file;
GroovyFileBase groovyFile = (GroovyFileBase)file;
final String qualifier = groovyFile instanceof GroovyFile ? groovyFile.getPackageName() : "";
final PsiManager manager = PsiManager.getInstance(project);
final String name = myRefElement.getReferenceName();
@@ -109,18 +144,7 @@ public abstract class CreateClassFix {
if (targetDirectory == null) return;
String templateName = null;
switch (getType()) {
case ENUM:
templateName = NewGroovyClassAction.GROOVY_ENUM;
break;
case CLASS:
templateName = NewGroovyClassAction.GROOVY_CLASS;
break;
case INTERFACE:
templateName = NewGroovyClassAction.GROOVY_INTERFACE;
break;
}
String templateName = getTemplateName(getType());
assert name != null;
PsiClass targetClass = createClassByType(targetDirectory, name, manager, myRefElement, templateName);
if (targetClass != null) {
@@ -128,29 +152,39 @@ public abstract class CreateClassFix {
putCursor(project, targetClass.getContainingFile(), targetClass);
}
}
};
}
@Nullable
private static PsiDirectory getTargetDirectory(Project project, String qualifier, String name, Module module, String title) {
GroovyCreateClassDialog dialog = new GroovyCreateClassDialog(project, title, name, qualifier, module);
dialog.show();
if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null;
return dialog.getTargetDirectory();
private static String getTemplateName(CreateClassKind createClassKind) {
switch (createClassKind) {
case ENUM:
return NewGroovyClassAction.GROOVY_ENUM;
case CLASS:
return NewGroovyClassAction.GROOVY_CLASS;
case INTERFACE:
return NewGroovyClassAction.GROOVY_INTERFACE;
case ANNOTATION:
return NewGroovyClassAction.GROOVY_ANNOTATION;
default:
return null;
}
}
protected static void addImportForClass(GroovyFileBase groovyFile, String qualifier, PsiClass targetClass) throws IncorrectOperationException {
if (targetClass != null) {
// add import for created class
String qualifiedName = targetClass.getQualifiedName();
if (qualifiedName != null && qualifiedName.contains(".")) {
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
if (!packageName.equals(qualifier)) {
protected static void addImportForClass(@NotNull GroovyFileBase groovyFile, @NotNull String qualifier, @NotNull PsiClass targetClass)
throws IncorrectOperationException {
// add import for created class
String qualifiedName = targetClass.getQualifiedName();
if (qualifiedName != null && qualifiedName.contains(".")) {
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
if (!packageName.equals(qualifier)) {
final AccessToken accessToken = WriteAction.start();
try {
groovyFile.addImportForClass(targetClass);
}
finally {
accessToken.finish();
}
}
}
}
}