IDEA-51893: Quick Fix "​Create Field" when using Groovy named parameters
authorMaxim Medvedev <maxim.medvedev@jetbrains.com>
Wed, 3 Feb 2010 15:39:26 +0000 (18:39 +0300)
committerMaxim Medvedev <maxim.medvedev@jetbrains.com>
Wed, 3 Feb 2010 15:39:26 +0000 (18:39 +0300)
16 files changed:
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFix.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFromConstructorLabelFix.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFromUsageFix.java
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/QuickfixUtil.java
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicMethodFix.java [moved from plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicFix.java with 75% similarity]
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicPropertyFix.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicDialog.java
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicMethodDialog.java
plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicPropertyDialog.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/arguments/GrArgumentLabel.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/arguments/GrNamedArgument.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrNamedArgumentImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/TypesUtil.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/dynamic/DynamicTest.java

index b9b4e0426248968dfb960af32d04208fd48c3b55..6c231f23a169ec9db0dff9f93189d756887998a6 100644 (file)
@@ -34,7 +34,8 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.GroovyBundle;
 import org.jetbrains.plugins.groovy.annotator.intentions.*;
-import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicFix;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMethodFix;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicPropertyFix;
 import org.jetbrains.plugins.groovy.codeInspection.GroovyImportsTracker;
 import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
 import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter;
@@ -374,7 +375,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
     if (constructorResolveResult.getElement() != null) {
       checkMethodApplicability(constructorResolveResult, refElement, myHolder);
       final GrArgumentList argList = newExpression.getArgumentList();
-      if (argList != null && argList.getExpressionArguments().length == 0) checkDefaultMapConstructor(myHolder, argList);
+      if (argList != null && argList.getExpressionArguments().length == 0) checkDefaultMapConstructor(myHolder, argList, constructorResolveResult);
     }
     else {
       final GroovyResolveResult[] results = newExpression.multiResolveConstructor();
@@ -393,7 +394,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
             String message = GroovyBundle.message("cannot.find.default.constructor", ((PsiClass)element).getName());
             myHolder.createWarningAnnotation(toHighlight, message);
           }
-          else checkDefaultMapConstructor(myHolder, argList);
+          else checkDefaultMapConstructor(myHolder, argList, constructorResolveResult);
         }
       }
     }
@@ -999,8 +1000,12 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
       return;
     }
 
-    annotation
-      .registerFix(new DynamicFix(QuickfixUtil.isCall(referenceExpression), referenceExpression), referenceExpression.getTextRange());
+    if (QuickfixUtil.isCall(referenceExpression)) {
+      annotation.registerFix(new DynamicMethodFix(referenceExpression), referenceExpression.getTextRange());
+    }
+    else {
+      annotation.registerFix(new DynamicPropertyFix(referenceExpression), referenceExpression.getTextRange());
+    }
   }
 
   private static void highlightMemberResolved(AnnotationHolder holder, GrReferenceExpression refExpr, PsiMember member) {
@@ -1111,7 +1116,9 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
     }
   }
 
-  private static void checkDefaultMapConstructor(AnnotationHolder holder, GrArgumentList argList) {
+  private static void checkDefaultMapConstructor(AnnotationHolder holder,
+                                                 GrArgumentList argList,
+                                                 GroovyResolveResult constructorResolveResult) {
     if (argList != null) {
       final GrNamedArgument[] args = argList.getNamedArguments();
       for (GrNamedArgument arg : args) {
@@ -1133,7 +1140,18 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
         else {
           final PsiElement resolved = label.resolve();
           if (resolved == null) {
-            holder.createWarningAnnotation(label, GroovyBundle.message("no.such.property", label.getName()));
+            final Annotation annotation = holder.createWarningAnnotation(label, GroovyBundle.message("no.such.property", label.getName()));
+
+            PsiElement element = constructorResolveResult.getElement();
+            if (element instanceof PsiMember) {
+              element = ((PsiMember)element).getContainingClass();
+            }
+            if (element instanceof GrMemberOwner) {
+              annotation.registerFix(new CreateFieldFromConstructorLabelFix((GrMemberOwner)element, label.getNamedArgument()));
+            }
+            if (element instanceof PsiClass) {
+              annotation.registerFix(new DynamicPropertyFix(label, (PsiClass)element));
+            }
           }
         }
       }
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFix.java
new file mode 100644 (file)
index 0000000..733312c
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2010 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.CodeInsightUtilBase;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.template.Template;
+import com.intellij.codeInsight.template.TemplateBuilderImpl;
+import com.intellij.codeInsight.template.TemplateManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiClassType;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.GroovyBundle;
+import org.jetbrains.plugins.groovy.lang.editor.template.expressions.ChooseTypeExpression;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public abstract class CreateFieldFix implements IntentionAction {
+  private final GrMemberOwner myTargetClass;
+
+  protected GrMemberOwner getTargetClass() {
+    return myTargetClass;
+  }
+
+  protected CreateFieldFix(GrMemberOwner targetClass) {
+    myTargetClass = targetClass;
+  }
+
+  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
+    return myTargetClass.isValid();
+  }
+
+  @NotNull
+  public String getText() {
+    return GroovyBundle.message("create.field.from.usage", getFieldName());
+  }
+
+  @NotNull
+  public String getFamilyName() {
+    return GroovyBundle.message("create.from.usage.family.name");
+  }
+
+  @Nullable
+  protected abstract String getFieldName();
+
+
+  public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
+    PsiClassType type =
+      JavaPsiFacade.getInstance(project).getElementFactory().createTypeByFQClassName("Object", GlobalSearchScope.allScope(project));
+    String[] modifiers = generateModifiers();
+    GrVariableDeclaration fieldDecl = GroovyPsiElementFactory.getInstance(project).createFieldDeclaration(modifiers, getFieldName(), null, type);
+    fieldDecl = myTargetClass.addMemberDeclaration(fieldDecl, null);
+    GrTypeElement typeElement = fieldDecl.getTypeElementGroovy();
+    assert typeElement != null;
+
+    TypeConstraint[] constraints = calculateTypeConstrains();
+    ChooseTypeExpression expr = new ChooseTypeExpression(constraints, PsiManager.getInstance(project));
+    TemplateBuilderImpl builder = new TemplateBuilderImpl(fieldDecl);
+    builder.replaceElement(typeElement, expr);
+    fieldDecl = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(fieldDecl);
+    if (fieldDecl == null) {
+      return;
+    }
+
+    Template template = builder.buildTemplate();
+
+    Editor newEditor = QuickfixUtil.positionCursor(project, myTargetClass.getContainingFile(), fieldDecl);
+    TextRange range = fieldDecl.getTextRange();
+    newEditor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset());
+
+    TemplateManager manager = TemplateManager.getInstance(project);
+    manager.startTemplate(newEditor, template);
+  }
+
+  protected abstract TypeConstraint[] calculateTypeConstrains();
+
+  protected abstract String[] generateModifiers();
+
+  public boolean startInWriteAction() {
+    return true;
+  }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFromConstructorLabelFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/CreateFieldFromConstructorLabelFix.java
new file mode 100644 (file)
index 0000000..798bc31
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2010 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.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiType;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class CreateFieldFromConstructorLabelFix extends CreateFieldFix {
+  private final GrNamedArgument myNamedArgument;
+
+  public CreateFieldFromConstructorLabelFix(GrMemberOwner targetClass, GrNamedArgument namedArgument) {
+    super(targetClass);
+    myNamedArgument = namedArgument;
+  }
+
+  @Nullable
+  @Override
+  protected String getFieldName() {
+    final GrArgumentLabel label = myNamedArgument.getLabel();
+    assert label != null;
+    return label.getName();
+  }
+
+  @Override
+  protected TypeConstraint[] calculateTypeConstrains() {
+    final GrExpression expression = myNamedArgument.getExpression();
+    PsiType type = null;
+    if (expression != null) {
+      type = expression.getType();
+    }
+    return new TypeConstraint[]{SupertypeConstraint.create(type, type)};
+  }
+
+  @Override
+  protected String[] generateModifiers() {
+    return ArrayUtil.EMPTY_STRING_ARRAY;
+  }
+
+  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
+    return super.isAvailable(project, editor, file) && myNamedArgument.isValid();
+  }
+}
index a11b8326c001923180a4dea0dfcb6c724d26dbcc..5c06006dbaab053f255a79ab8a5972606217adf8 100644 (file)
  */
 package org.jetbrains.plugins.groovy.annotator.intentions;
 
-import com.intellij.codeInsight.CodeInsightUtilBase;
-import com.intellij.codeInsight.intention.IntentionAction;
-import com.intellij.codeInsight.template.Template;
-import com.intellij.codeInsight.template.TemplateBuilderImpl;
-import com.intellij.codeInsight.template.TemplateManager;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.*;
-import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiModifier;
 import com.intellij.util.ArrayUtil;
-import com.intellij.util.IncorrectOperationException;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.GroovyBundle;
-import org.jetbrains.plugins.groovy.lang.editor.template.expressions.ChooseTypeExpression;
-import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
-import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
 import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesUtil;
 import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.TypeConstraint;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
@@ -42,18 +32,17 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 /**
  * @author ven
  */
-public class CreateFieldFromUsageFix implements IntentionAction {
-  private final GrMemberOwner myTargetClass;
+public class CreateFieldFromUsageFix extends CreateFieldFix {
   private final GrReferenceExpression myRefExpression;
 
   public CreateFieldFromUsageFix(GrReferenceExpression refExpression, GrMemberOwner targetClass) {
+    super(targetClass);
     myRefExpression = refExpression;
-    myTargetClass = targetClass;
   }
 
-  @NotNull
-  public String getText() {
-    return GroovyBundle.message("create.field.from.usage", myRefExpression.getReferenceName());
+  @Nullable
+  protected String getFieldName() {
+    return myRefExpression.getReferenceName();
   }
 
   @NotNull
@@ -62,37 +51,18 @@ public class CreateFieldFromUsageFix implements IntentionAction {
   }
 
   public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
-    return myTargetClass.isValid() && myRefExpression.isValid();
+    return super.isAvailable(project, editor, file) && myRefExpression.isValid();
   }
 
-  public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
-    PsiClassType type = JavaPsiFacade.getInstance(project).getElementFactory().createTypeByFQClassName("Object", GlobalSearchScope.allScope(project));
-    String[] modifiers = PsiUtil.isInStaticContext(myRefExpression, myTargetClass) ? new String[]{PsiModifier.STATIC} : ArrayUtil.EMPTY_STRING_ARRAY;
-    GrVariableDeclaration fieldDecl = GroovyPsiElementFactory.getInstance(project).createFieldDeclaration(modifiers,
-        myRefExpression.getReferenceName(), null, type);
-    fieldDecl = myTargetClass.addMemberDeclaration(fieldDecl, null);
-    GrTypeElement typeElement = fieldDecl.getTypeElementGroovy();
-    assert typeElement != null;
-    TypeConstraint[] constraints = GroovyExpectedTypesUtil.calculateTypeConstraints(myRefExpression);
-    ChooseTypeExpression expr = new ChooseTypeExpression(constraints, PsiManager.getInstance(project));
-    TemplateBuilderImpl builder = new TemplateBuilderImpl(fieldDecl);
-    builder.replaceElement(typeElement, expr);
-    fieldDecl = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(fieldDecl);
-    if (fieldDecl == null) {
-      return;
+  protected String[] generateModifiers() {
+    if (myRefExpression != null && PsiUtil.isInStaticContext(myRefExpression, getTargetClass())) {
+      return new String[]{PsiModifier.STATIC};
     }
-
-    Template template = builder.buildTemplate();
-
-    Editor newEditor = QuickfixUtil.positionCursor(project, myTargetClass.getContainingFile(), fieldDecl);
-    TextRange range = fieldDecl.getTextRange();
-    newEditor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset());
-
-    TemplateManager manager = TemplateManager.getInstance(project);
-    manager.startTemplate(newEditor, template);
+    return ArrayUtil.EMPTY_STRING_ARRAY;
   }
 
-  public boolean startInWriteAction() {
-    return true;
+  protected TypeConstraint[] calculateTypeConstrains() {
+    return GroovyExpectedTypesUtil.calculateTypeConstraints(myRefExpression);
+
   }
 }
index 76a77e901217fec6c24336e1bf1a0b0e9d2fe78a..cc819fbe7266566042c01cf711063ed3398d0989 100644 (file)
@@ -32,17 +32,18 @@ import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.util.PsiTypesUtil;
 import com.intellij.util.ArrayUtil;
 import gnu.trove.THashSet;
-import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.MyPair;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
 import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
-import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
 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.api.statements.typedef.GrTypeDefinition;
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
 
@@ -227,4 +228,17 @@ public class QuickfixUtil {
     }
     return settings;
   }
+
+  public static DynamicElementSettings createSettings(GrArgumentLabel label, PsiClass targetClass) {
+    DynamicElementSettings settings = new DynamicElementSettings();
+
+    assert targetClass != null;
+    String className = targetClass.getQualifiedName();
+    className = className == null ? targetClass.getContainingFile().getName() : className;
+
+    settings.setContainingClassName(className);
+    settings.setName(label.getName());
+
+    return settings;
+  }
 }
\ No newline at end of file
similarity index 75%
rename from plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicFix.java
rename to plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicMethodFix.java
index 933df2e1d5d8d5066a3f8b89c4f1e24a0c1c9ed2..2da0f65cd2445b2e4c03ea97fa2de4808a76866a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2010 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.
@@ -27,29 +27,21 @@ import org.jetbrains.plugins.groovy.annotator.intentions.QuickfixUtil;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicDialog;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicMethodDialog;
-import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicPropertyDialog;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 
 /**
- * User: Dmitry.Krasilschikov
- * Date: 22.11.2007
+ * @author Maxim.Medvedev
  */
-public class DynamicFix implements IntentionAction {
+public class DynamicMethodFix implements IntentionAction {
   private final GrReferenceExpression myReferenceExpression;
-  private final boolean myIsMethod;
 
-  public DynamicFix(boolean isMethod, GrReferenceExpression referenceExpression) {
-    myIsMethod = isMethod;
+  public DynamicMethodFix(GrReferenceExpression referenceExpression) {
     myReferenceExpression = referenceExpression;
   }
 
   @NotNull
   public String getText() {
-    if (!myIsMethod){
-      return GroovyBundle.message("add.dynamic.property", myReferenceExpression.getName());
-    }
-
     final PsiType[] methodArgumentsTypes = PsiUtil.getArgumentTypes(myReferenceExpression, false, false);
     StringBuilder builder = new StringBuilder(" '").append(myReferenceExpression.getName());
     builder.append("(");
@@ -58,7 +50,7 @@ public class DynamicFix implements IntentionAction {
     for (int i = 0; i < methodArgumentsTypes.length; i++) {
       PsiType type = methodArgumentsTypes[i];
 
-      if (i > 0){
+      if (i > 0) {
         builder.append(", ");
       }
       builder.append(type.getPresentableText());
@@ -79,32 +71,20 @@ public class DynamicFix implements IntentionAction {
   }
 
   public void invoke(@NotNull Project project, Editor editor, PsiFile psiFile) throws IncorrectOperationException {
-    DynamicDialog dialog = myIsMethod ?
-                           new DynamicMethodDialog(myReferenceExpression) :
-                           new DynamicPropertyDialog(myReferenceExpression);
-
+    DynamicDialog dialog = new DynamicMethodDialog(myReferenceExpression);
     dialog.show();
   }
 
   public void invoke(Project project) throws IncorrectOperationException {
     final DynamicElementSettings settings = QuickfixUtil.createSettings(myReferenceExpression);
-
-    if (myIsMethod) {
-      DynamicManager.getInstance(project).addMethod(settings);
-    } else {
-      DynamicManager.getInstance(project).addProperty(settings);
-    }
+    DynamicManager.getInstance(project).addMethod(settings);
   }
 
   public boolean startInWriteAction() {
     return false;
   }
 
-  public boolean isMethod() {
-    return myIsMethod;
-  }
-
   public GrReferenceExpression getReferenceExpression() {
     return myReferenceExpression;
   }
-}
\ No newline at end of file
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicPropertyFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/DynamicPropertyFix.java
new file mode 100644 (file)
index 0000000..ea9f840
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2000-2010 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.dynamic;
+
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.GroovyBundle;
+import org.jetbrains.plugins.groovy.annotator.intentions.QuickfixUtil;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicDialog;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicPropertyDialog;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class DynamicPropertyFix implements IntentionAction {
+  private final GrReferenceExpression myReferenceExpression;
+  private final GrArgumentLabel myArgumentLabel;
+  private final PsiClass myTargetClass;
+
+  public DynamicPropertyFix(GrReferenceExpression referenceExpression) {
+    myReferenceExpression = referenceExpression;
+    myArgumentLabel = null;
+    myTargetClass = null;
+  }
+
+  public DynamicPropertyFix(GrArgumentLabel argumentLabel, PsiClass targetClass) {
+    myArgumentLabel = argumentLabel;
+    myReferenceExpression = null;
+    myTargetClass = targetClass;
+  }
+
+  @NotNull
+  public String getText() {
+    return GroovyBundle.message("add.dynamic.property", getName());
+  }
+
+  private String getName() {
+    if (myReferenceExpression != null) {
+      return myReferenceExpression.getName();
+    }
+    else {
+      return myArgumentLabel.getName();
+    }
+  }
+
+  @NotNull
+  public String getFamilyName() {
+    return GroovyBundle.message("add.dynamic.element");
+  }
+
+  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile psiFile) {
+    return (myReferenceExpression == null || myReferenceExpression.isValid()) && (myArgumentLabel == null || myArgumentLabel.isValid());
+  }
+
+  public void invoke(@NotNull Project project, Editor editor, PsiFile psiFile) throws IncorrectOperationException {
+    DynamicDialog dialog;
+    if (myReferenceExpression != null) {
+      dialog = new DynamicPropertyDialog(myReferenceExpression);
+    }
+    else {
+      dialog = new DynamicPropertyDialog(myArgumentLabel, myTargetClass);
+    }
+    dialog.show();
+  }
+
+  public void invoke(Project project) throws IncorrectOperationException {
+    final DynamicElementSettings settings;
+    if (myReferenceExpression != null) {
+      settings = QuickfixUtil.createSettings(myReferenceExpression);
+    }
+    else {
+      settings = QuickfixUtil.createSettings(myArgumentLabel, myTargetClass);
+    }
+    DynamicManager.getInstance(project).addProperty(settings);
+  }
+
+  public boolean startInWriteAction() {
+    return false;
+  }
+
+  public GrReferenceExpression getReferenceExpression() {
+    return myReferenceExpression;
+  }
+}
index 7049f596e16aa2df638b2807e3b68d8f15afcc46..95aa07dbf932dc68606da8ff9c156daed385d717 100644 (file)
@@ -27,6 +27,7 @@ import com.intellij.openapi.ui.DialogWrapper;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.util.IconLoader;
 import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.search.ProjectScope;
 import com.intellij.ui.EditorComboBoxEditor;
 import com.intellij.ui.EditorTextField;
@@ -42,10 +43,7 @@ import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.elements.DItemE
 import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
 import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment;
 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
-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.api.types.GrTypeElement;
-import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesUtil;
 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.util.PsiUtil;
@@ -76,28 +74,28 @@ public abstract class DynamicDialog extends DialogWrapper {
   private final DynamicManager myDynamicManager;
   private final Project myProject;
   private final EventListenerList myListenerList = new EventListenerList();
-  private final GrReferenceExpression myReferenceExpression;
+  private final PsiElement myContext;
   private final DynamicElementSettings mySettings;
 
   private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicDialog");
 
-  public DynamicDialog(GrReferenceExpression referenceExpression) {
-    super(referenceExpression.getProject(), true);
-    myProject = referenceExpression.getProject();
+  public DynamicDialog(PsiElement context, DynamicElementSettings settings, TypeConstraint[] typeConstraints) {
+    super(context.getProject(), true);
+    myProject = context.getProject();
 
     if (!isTableVisible()) {
       myParametersTable.setVisible(false);
       myTableLabel.setVisible(false);
     }
-    myReferenceExpression = referenceExpression;
+    myContext = context;
     setTitle(GroovyInspectionBundle.message("dynamic.element"));
     myDynamicManager = DynamicManager.getInstance(myProject);
 
     init();
 
-    mySettings = QuickfixUtil.createSettings(myReferenceExpression);
+    mySettings = settings;
 
-    setUpTypeComboBox();
+    setUpTypeComboBox(typeConstraints);
     setUpContainingClassComboBox();
     setUpStatusLabel();
     setUpStaticComboBox();
@@ -154,10 +152,13 @@ public abstract class DynamicDialog extends DialogWrapper {
     pack();
   }
 
+  @Nullable
+  public PsiClass getTargetClass() {
+    return JavaPsiFacade.getInstance(myProject).findClass(mySettings.getContainingClassName(), GlobalSearchScope.allScope(myProject));
+  }
 
   private void setUpContainingClassComboBox() {
-    PsiClass targetClass = QuickfixUtil.findTargetClass(myReferenceExpression);
-
+    PsiClass targetClass = getTargetClass();
     if (targetClass == null || targetClass instanceof SyntheticElement) {
       try {
         final GrTypeElement typeElement = GroovyPsiElementFactory.getInstance(myProject).createTypeElement("java.lang.Object");
@@ -188,11 +189,11 @@ public abstract class DynamicDialog extends DialogWrapper {
   @Nullable
   private Document createDocument(final String text) {
     GroovyCodeFragment fragment = new GroovyCodeFragment(myProject, text);
-    fragment.setContext(myReferenceExpression);
+    fragment.setContext(myContext);
     return PsiDocumentManager.getInstance(myProject).getDocument(fragment);
   }
 
-  private void setUpTypeComboBox() {
+  private void setUpTypeComboBox(TypeConstraint[] typeConstraints) {
     final EditorComboBoxEditor comboEditor = new EditorComboBoxEditor(myProject, GroovyFileType.GROOVY_FILE_TYPE);
 
     final Document document = createDocument("");
@@ -232,9 +233,10 @@ public abstract class DynamicDialog extends DialogWrapper {
       }
     });
 
-    final TypeConstraint[] constrants = GroovyExpectedTypesUtil.calculateTypeConstraints(QuickfixUtil.isCall(myReferenceExpression) ? (GrExpression) myReferenceExpression.getParent() : myReferenceExpression);
-
-    PsiType type = constrants.length == 1 ? constrants[0].getDefaultType() : TypesUtil.getJavaLangObject(myReferenceExpression);
+    PsiType type = typeConstraints.length == 1 ? typeConstraints[0].getDefaultType() : TypesUtil.getJavaLangObject(myContext);
+    if (type == null) {
+      type = TypesUtil.getJavaLangObject(myContext);
+    }
     myTypeComboBox.getEditor().setItem(createDocument(type.getCanonicalText()));
   }
 
@@ -328,7 +330,7 @@ public abstract class DynamicDialog extends DialogWrapper {
       }
     }
 
-    Document document = PsiDocumentManager.getInstance(myProject).getDocument(myReferenceExpression.getContainingFile());
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(myContext.getContainingFile());
     final DocumentReference[] refs = new DocumentReference[]{DocumentReferenceManager.getInstance().create(document)};
 
     CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
index fab789ea7284984fd0341aabac8330aca4733a69..1275eda5cd648cd97bcd1ba84ae5243a1d1c633f 100644 (file)
@@ -24,7 +24,9 @@ import org.jetbrains.plugins.groovy.GroovyBundle;
 import org.jetbrains.plugins.groovy.annotator.intentions.QuickfixUtil;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.MyPair;
 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
+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.GroovyExpectedTypesUtil;
 
 import javax.swing.*;
 import javax.swing.event.CellEditorListener;
@@ -41,9 +43,11 @@ import java.util.List;
  * Date: 18.02.2008
  */
 public class DynamicMethodDialog extends DynamicDialog {
-  public DynamicMethodDialog(GrReferenceExpression referenceExpression) {
-    super(referenceExpression);
+  private final GrReferenceExpression myReferenceExpression;
 
+  public DynamicMethodDialog(GrReferenceExpression referenceExpression) {
+    super(referenceExpression, QuickfixUtil.createSettings(referenceExpression), GroovyExpectedTypesUtil.calculateTypeConstraints((GrExpression)referenceExpression.getParent()));
+    myReferenceExpression = referenceExpression;
     assert getSettings().isMethod();
 
     final List<MyPair> pairs = getSettings().getPairs();
@@ -71,7 +75,7 @@ public class DynamicMethodDialog extends DynamicDialog {
         final int editingRow = table.getSelectedRow();
         if (editingRow < 0 || editingRow >= pairs.size()) return;
 
-        String newNameValue = ((MySuggestedNameCellEditor) e.getSource()).getCellEditorValue();
+        String newNameValue = ((MySuggestedNameCellEditor)e.getSource()).getCellEditorValue();
 
         final MyPair editingPair = pairs.get(editingRow);
         editingPair.setFirst(newNameValue);
@@ -133,7 +137,8 @@ public class DynamicMethodDialog extends DynamicDialog {
       PsiType type;
       try {
         type = GroovyPsiElementFactory.getInstance(getProject()).createTypeElement(value).getType();
-      } catch (IncorrectOperationException e) {
+      }
+      catch (IncorrectOperationException e) {
         return;
       }
 
@@ -179,7 +184,7 @@ public class DynamicMethodDialog extends DynamicDialog {
 
     public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
       if (value instanceof String) {
-        myNameField.setText((String) value);
+        myNameField.setText((String)value);
       }
       return myNameField;
     }
index 0626f7cff2956e065d11ee18a90d14702e0c5280..3bd0191d323d9efcd8d12b48f29d2ed9c61e0d91 100644 (file)
  */
 package org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui;
 
+import com.intellij.psi.PsiClass;
 import org.jetbrains.plugins.groovy.GroovyBundle;
+import org.jetbrains.plugins.groovy.annotator.intentions.QuickfixUtil;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesUtil;
+import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
 
 /**
  * User: Dmitry.Krasilschikov
  * Date: 18.02.2008
  */
 public class DynamicPropertyDialog extends DynamicDialog {
-  public DynamicPropertyDialog(GrReferenceExpression referenceExpression) {
-    super(referenceExpression);
+  private final GrReferenceExpression myReferenceExpression;
+  private final GrArgumentLabel myLabel;
 
+  public DynamicPropertyDialog(GrReferenceExpression referenceExpression) {
+    super(referenceExpression, QuickfixUtil.createSettings(referenceExpression), GroovyExpectedTypesUtil.calculateTypeConstraints(referenceExpression));
+    myReferenceExpression = referenceExpression;
+    myLabel = null;
     setTitle(GroovyBundle.message("add.dynamic.property", referenceExpression.getReferenceName()));
     setUpTypeLabel(GroovyBundle.message("dynamic.method.property.type"));
   }
+
+  public DynamicPropertyDialog(GrArgumentLabel label, PsiClass targetClass) {
+    super(label, QuickfixUtil.createSettings(label, targetClass), new SupertypeConstraint[]{SupertypeConstraint.create(label.getNamedArgument().getExpression().getType())});
+    myLabel = label;
+    myReferenceExpression = null;
+  }
 }
index 1f267814fc7d1480629c90cd8a369387e02e7c3c..cb703dcfadc229becbb14b6f39ba4aa43b53ebff 100644 (file)
@@ -38,4 +38,6 @@ public interface GrArgumentLabel extends GroovyPsiElement, PsiReference {
 
   @Nullable
   PsiType getExpectedArgumentType();
+
+  GrNamedArgument getNamedArgument();
 }
index 2645990e8bbe09305325b3bf1fe60a1529645418..a43ff75678dc6bf21bdf2d88096f84f5a2fa2bf4 100644 (file)
@@ -24,10 +24,11 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
  * @author ilyas
  */
 public interface GrNamedArgument extends GroovyPsiElement {
-  public static final GrNamedArgument[] EMPTY_ARRAY = new GrNamedArgument[0];
+  GrNamedArgument[] EMPTY_ARRAY = new GrNamedArgument[0];
 
   @Nullable
   GrArgumentLabel getLabel();
 
+  @Nullable
   GrExpression getExpression();
 }
index 381e907f60daca64ff16e7645e98ec835d3984b7..01902ba2abf47c4a65f4a222e434d63ec2bad089 100644 (file)
@@ -31,6 +31,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
@@ -210,4 +211,10 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum
 
     return null;
   }
+
+  public GrNamedArgument getNamedArgument() {
+    final PsiElement parent = getParent();
+    assert parent instanceof GrNamedArgument;
+    return (GrNamedArgument)parent;
+  }
 }
\ No newline at end of file
index f151efe61f6656621ce2ae10f3d3d6a8e2aa43e3..ad05384a150bf18bc25621c283604c77d71e2652 100644 (file)
@@ -48,11 +48,8 @@ public class GrNamedArgumentImpl extends GroovyPsiElementImpl implements GrNamed
   }
 
 
+  @Nullable
   public GrExpression getExpression() {
     return findChildByClass(GrExpression.class);
   }
-
-  public GrArgumentLabel getElementToCompare() {
-    return getLabel();
-  }
 }
\ No newline at end of file
index 6e474a66363dba2b4b6664bcfd6d1099e9368dcc..e3049b8a6498c17c3e9c61f47c422867e163d6e6 100644 (file)
@@ -309,7 +309,7 @@ public class TypesUtil {
     return facade.getElementFactory().createTypeByFQClassName(fqName, context.getResolveScope());
   }
 
-  public static PsiClassType getJavaLangObject(GroovyPsiElement context) {
+  public static PsiClassType getJavaLangObject(PsiElement context) {
     return PsiType.getJavaLangObject(context.getManager(), context.getResolveScope());
   }
 
index 022a6563c7c98b94a0eecfea1d08a3406821cdb4..3c462a15c4a9f6bd37f13e606c98009c818c7c41 100644 (file)
@@ -6,8 +6,9 @@ import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
 import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.plugins.groovy.annotator.intentions.QuickfixUtil;
-import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicFix;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicManager;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMethodFix;
+import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicPropertyFix;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.MyPair;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.elements.DClassElement;
 import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.elements.DRootElement;
@@ -54,9 +55,16 @@ public class DynamicTest extends JavaCodeInsightFixtureTestCase {
   private GrReferenceExpression doDynamicFix() throws Throwable {
     final List<IntentionAction> actions = myFixture.getAvailableIntentions(getTestName(false) + ".groovy");
 
-    DynamicFix dynamicFix = ContainerUtil.findInstance(actions, DynamicFix.class);
-    dynamicFix.invoke(getProject());
-    return dynamicFix.getReferenceExpression();
+    DynamicPropertyFix dynamicFix = ContainerUtil.findInstance(actions, DynamicPropertyFix.class);
+    if (dynamicFix != null) {
+      dynamicFix.invoke(getProject());
+      return dynamicFix.getReferenceExpression();
+    }
+    else {
+      final DynamicMethodFix fix = ContainerUtil.findInstance(actions, DynamicMethodFix.class);
+      fix.invoke(getProject());
+      return fix.getReferenceExpression();
+    }
   }
 
 }