Merge branch 'alias'
authorMaxim Medvedev <maxim.medvedev@jetbrains.com>
Sun, 13 Jun 2010 12:48:07 +0000 (16:48 +0400)
committerMaxim Medvedev <maxim.medvedev@jetbrains.com>
Sun, 13 Jun 2010 12:48:07 +0000 (16:48 +0400)
13 files changed:
plugins/groovy/src/META-INF/plugin.xml
plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AccessorReferencesSearcher.java
plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/toplevel/imports/GrImportStatementImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyPropertyUtils.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/findUsages/FindUsagesTest.java
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy
plugins/groovy/testdata/findUsages/aliasImportedProperty/A.groovy [new file with mode: 0644]
plugins/groovy/testdata/findUsages/getterWhenAliasedImportedProperty/A.groovy [new file with mode: 0644]
plugins/groovy/testdata/findUsages/methodAlias/A.groovy [new file with mode: 0644]

index 32f2135717067616afa4e8ad0b0876aa34073105..9cc9d2b1bb2eff16b429a3c8279469cff7bc57ac 100644 (file)
     <stubIndex implementation="org.jetbrains.plugins.groovy.lang.psi.stubs.index.GrAnonymousClassIndex"/>
 
     <referencesSearch implementation="org.jetbrains.plugins.groovy.findUsages.ConstructorReferencesSearcher"/>
+    <referencesSearch implementation="org.jetbrains.plugins.groovy.findUsages.GrAliasedImportedElementSearcher"/>
+
     <antCustomCompiler implementation="org.jetbrains.plugins.groovy.ant.GroovyAntCustomCompilerProvider"/>
 
     <project.converterProvider implementation="org.jetbrains.plugins.groovy.config.GroovyModuleConverterProvider"/>
index de1510920eaad804cc0a7be56dbebd5aaf728812..4c245a70493be80cb42e3295e1c395daec81ca4e 100644 (file)
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.findUsages;
 
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.NullableComputable;
 import com.intellij.psi.*;
 import com.intellij.psi.search.PsiSearchHelper;
 import com.intellij.psi.search.SearchScope;
@@ -26,6 +27,7 @@ import com.intellij.psi.search.UsageSearchContext;
 import com.intellij.psi.search.searches.MethodReferencesSearch;
 import com.intellij.util.Processor;
 import com.intellij.util.QueryExecutor;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 
@@ -60,15 +62,13 @@ public class AccessorReferencesSearcher implements QueryExecutor<PsiReference, M
       }
     };
 
-    return helper.processElementsWithWord(processor,
-                                          searchScope,
-                                          propertyName,
-                                          UsageSearchContext.IN_CODE,
-                                          false);
+    return helper.processElementsWithWord(processor, searchScope, propertyName, UsageSearchContext.IN_CODE, false);
   }
 
-  private String getPropertyName(final PsiMethod method) {
-    return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+  @Nullable
+  private static String getPropertyName(final PsiMethod method) {
+    return ApplicationManager.getApplication().runReadAction(new NullableComputable<String>() {
+      @Nullable
       public String compute() {
         return GroovyPropertyUtils.getPropertyName(method);
       }
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrAliasedImportedElementSearcher.java
new file mode 100644 (file)
index 0000000..d67bdbd
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.findUsages;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.NullableComputable;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.TextOccurenceProcessor;
+import com.intellij.psi.search.UsageSearchContext;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.util.Processor;
+import com.intellij.util.QueryExecutor;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
+import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
+import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrAliasedImportedElementSearcher implements QueryExecutor<PsiReference, ReferencesSearch.SearchParameters> {
+  private static final ThreadLocal<Object> I_WAS_HERE = new ThreadLocal<Object>();
+
+  public boolean execute(final ReferencesSearch.SearchParameters parameters, final Processor<PsiReference> consumer) {
+    final PsiElement elementToSearch = parameters.getElementToSearch();
+    if (!(elementToSearch instanceof PsiMember)) return true;
+    if (I_WAS_HERE.get() != null) return true;
+
+    try {
+      I_WAS_HERE.set(Boolean.TRUE);
+      final TextOccurenceProcessor processor = new MyTextOccurenceProcessor(elementToSearch, consumer);
+
+      final SearchScope groovySearchScope = PsiUtil.restrictScopeToGroovyFiles(new Computable<SearchScope>() {
+        public SearchScope compute() {
+          return parameters.getEffectiveSearchScope();
+        }
+      });
+
+      if (!ReferencesSearch.search(elementToSearch, groovySearchScope).forEach(new MyProcessor(null, processor))) return false;
+
+      if (elementToSearch instanceof PsiMethod && isAccessor(elementToSearch)) {
+        final PsiField field = ApplicationManager.getApplication().runReadAction(new Computable<PsiField>() {
+          public PsiField compute() {
+            return GroovyPropertyUtils.findFieldForAccessor((PsiMethod)elementToSearch, true);
+          }
+        });
+        if (field != null) {
+          final String prefix = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+            public String compute() {
+              return GroovyPropertyUtils.getAccessorPrefix((PsiMethod)elementToSearch);
+            }
+          });
+          if (prefix == null) return true;
+          if (!ReferencesSearch.search(field, groovySearchScope).forEach(new MyProcessor(prefix, processor))) return false;
+        }
+      }
+      return true;
+    }
+    finally {
+      I_WAS_HERE.set(null);
+    }
+
+  }
+
+  private static Boolean isAccessor(final PsiElement elementToSearch) {
+    return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
+      public Boolean compute() {
+        return GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)elementToSearch);
+      }
+    });
+  }
+
+  static class MyProcessor implements Processor<PsiReference> {
+    private final String prefix;
+    private final TextOccurenceProcessor processor;
+
+    MyProcessor(@Nullable String prefix, TextOccurenceProcessor processor) {
+      this.prefix = prefix;
+      this.processor = processor;
+    }
+
+    public boolean process(PsiReference psiReference) {
+      final PsiElement element = psiReference.getElement();
+      if (element == null) return true;
+
+      String alias = getAlias(element);
+      if (alias == null) return true;
+
+      final PsiFile containingFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
+        public PsiFile compute() {
+          return element.getContainingFile();
+        }
+      });
+
+      if (prefix != null) {
+        if (!PsiManager.getInstance(element.getProject()).getSearchHelper()
+          .processElementsWithWord(processor, GlobalSearchScope.fileScope(containingFile), prefix + GroovyPropertyUtils.capitalize(alias),
+                                   UsageSearchContext.IN_CODE,
+                                   false)) {
+          return false;
+        }
+      }
+
+      return PsiManager.getInstance(element.getProject()).getSearchHelper()
+        .processElementsWithWord(processor, GlobalSearchScope.fileScope(containingFile), alias, UsageSearchContext.IN_CODE, false);
+    }
+
+    private static String getAlias(final PsiElement element) {
+      return ApplicationManager.getApplication().runReadAction(new NullableComputable<String>() {
+        public String compute() {
+          if (!(element.getParent() instanceof GrImportStatement)) return null;
+          final GrImportStatement importStatement = (GrImportStatement)element.getParent();
+          if (!importStatement.isAliasedImport()) return null;
+          return importStatement.getImportedName();
+        }
+      });
+    }
+
+  }
+
+static class MyTextOccurenceProcessor implements TextOccurenceProcessor {
+    private final PsiElement elementToSearch;
+    private final Processor<PsiReference> consumer;
+
+    public MyTextOccurenceProcessor(PsiElement elementToSearch, Processor<PsiReference> consumer) {
+      this.elementToSearch = elementToSearch;
+      this.consumer = consumer;
+    }
+
+    public boolean execute(PsiElement element, int offsetInElement) {
+      final PsiReference[] refs = element.getParent().getReferences();
+      for (PsiReference ref : refs) {
+        if (ReferenceRange.containsOffsetInElement(ref, offsetInElement)) {
+          if (ref.isReferenceTo(elementToSearch)) {
+            return consumer.process(ref);
+          }
+        }
+      }
+      return true;
+    }
+  }
+}
index 1d9367cca069db022c23ca1f40060dca244fc65a..b1760594c8bb95f01eebcfe510adb9e2430295e0 100644 (file)
 package org.jetbrains.plugins.groovy.lang.completion;
 
 import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.*;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.codeInsight.lookup.LookupItem;
+import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.editor.ex.EditorEx;
 import com.intellij.openapi.editor.highlighter.HighlighterIterator;
@@ -109,11 +112,14 @@ public class GroovyCompletionContributor extends CompletionContributor {
             public void consume(Object element) {
               if (element instanceof PsiClass) {
                 final PsiClass clazz = (PsiClass)element;
-                final MutableLookupElement<PsiClass> lookupElement = LookupElementFactory.getInstance().createLookupElement(clazz);
+                final LookupElement lookupElement = GroovyCompletionUtil.getLookupElement(clazz);
                 result.addElement(GroovyCompletionUtil.setTailTypeForConstructor(clazz, lookupElement));
+              } else if (element instanceof LookupElement && ((LookupElement)element).getObject() instanceof PsiClass) {
+                result.addElement(GroovyCompletionUtil
+                                    .setTailTypeForConstructor(((PsiClass)((LookupElement)element).getObject()), ((LookupElement)element)));
               }
               else {
-                result.addElement(LookupItemUtil.objectToLookupItem(element));
+                result.addElement(GroovyCompletionUtil.getLookupElement(element));
               }
             }
           });
@@ -123,11 +129,8 @@ public class GroovyCompletionContributor extends CompletionContributor {
 //          final boolean addGDKMethods = parameters.getInvocationCount() > 1;
           ((GrReferenceElement)reference).processVariants(new Consumer<Object>() {
             public void consume(Object element) {
-              LookupElement lookupElement = LookupItemUtil.objectToLookupItem(element);
+              LookupElement lookupElement = GroovyCompletionUtil.getLookupElement(element);
 //              if (lookupElement.getObject() instanceof GrGdkMethod && !addGDKMethods) return;
-              if (lookupElement instanceof LookupItem) {
-                lookupElement = ((LookupItem)lookupElement).setInsertHandler(new GroovyInsertHandlerAdapter());
-              }
               result.addElement(lookupElement);
             }
           });
index 3969ebb13f533bd0490364e907f841ecbc387497..f09e23bc2fd717d48d86cb01d85759ca52caea15 100644 (file)
@@ -20,13 +20,18 @@ import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
 import com.intellij.codeInsight.lookup.LookupElement;
 import com.intellij.codeInsight.lookup.LookupElementBuilder;
 import com.intellij.codeInsight.lookup.LookupElementDecorator;
+import com.intellij.openapi.util.Iconable;
+import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
 import com.intellij.psi.tree.TokenSet;
+import com.intellij.psi.util.PsiFormatUtil;
+import com.intellij.util.Function;
+import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
 import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
 import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
-import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
@@ -44,10 +49,15 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
 
+import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.*;
+
 /**
  * @author ilyas
  */
-public abstract class GroovyCompletionUtil {
+public class GroovyCompletionUtil {
+
+  private GroovyCompletionUtil() {
+  }
 
   /**
    * Return true if last element of curren statement is expression
@@ -57,7 +67,7 @@ public abstract class GroovyCompletionUtil {
    */
   public static boolean endsWithExpression(PsiElement statement) {
     while (statement != null &&
-        !(statement instanceof GrExpression)) {
+           !(statement instanceof GrExpression)) {
       statement = statement.getLastChild();
     }
     return statement != null;
@@ -67,7 +77,7 @@ public abstract class GroovyCompletionUtil {
   public static PsiElement nearestLeftSibling(PsiElement elem) {
     elem = elem.getPrevSibling();
     while (elem != null &&
-        (elem instanceof PsiWhiteSpace ||
+           (elem instanceof PsiWhiteSpace ||
             elem instanceof PsiComment ||
             GroovyTokenTypes.mNLS.equals(elem.getNode().getElementType()))) {
       elem = elem.getPrevSibling();
@@ -75,15 +85,6 @@ public abstract class GroovyCompletionUtil {
     return elem;
   }
 
-  public static boolean isIncomplete(PsiElement element) {
-    while (element != null) {
-      final PsiElement child = element.getLastChild();
-      if (child instanceof PsiErrorElement) return true;
-      element = child;
-    }
-    return false;
-  }
-
   /**
    * Shows wether keyword may be placed asas a new statement beginning
    *
@@ -100,6 +101,7 @@ public abstract class GroovyCompletionUtil {
     return (previousLeaf == null || SEPARATORS.contains(previousLeaf.getNode().getElementType()));
   }
 
+  @Nullable
   public static PsiElement getLeafByOffset(int offset, PsiElement element) {
     if (offset < 0) {
       return null;
@@ -131,40 +133,25 @@ public abstract class GroovyCompletionUtil {
     return variableDeclaration.getVariables()[0] == parent;
   }
 
-  /**
-     * Checks next element after modifier candidate to be appropriate
-     *
-     * @param element
-     * @return
-     */
-  public static boolean canBeModifier(PsiElement element) {
-    PsiElement next = element.getNextSibling();
-    while (next != null && (next instanceof PsiWhiteSpace ||
-        next instanceof PsiComment)) {
-      next = next.getNextSibling();
-    }
-    return (next == null || SEPARATORS.contains(next.getNode().getElementType()));
-  }
-
   private static final TokenSet SEPARATORS = TokenSet.create(GroovyElementTypes.mNLS,
-      GroovyElementTypes.mSEMI);
+                                                             GroovyElementTypes.mSEMI);
 
   public static boolean asSimpleVariable(PsiElement context) {
     return isInTypeDefinitionBody(context) &&
-        isNewStatement(context, true);
+           isNewStatement(context, true);
   }
 
   public static boolean isInTypeDefinitionBody(PsiElement context) {
     return (context.getParent() instanceof GrCodeReferenceElement &&
-        context.getParent().getParent() instanceof GrClassTypeElement &&
-        context.getParent().getParent().getParent() instanceof GrTypeDefinitionBody) ||
-        context.getParent() instanceof GrTypeDefinitionBody;
+            context.getParent().getParent() instanceof GrClassTypeElement &&
+            context.getParent().getParent().getParent() instanceof GrTypeDefinitionBody) ||
+           context.getParent() instanceof GrTypeDefinitionBody;
   }
 
   public static boolean asVariableInBlock(PsiElement context) {
     if (context.getParent() instanceof GrReferenceExpression &&
         (context.getParent().getParent() instanceof GrOpenBlock ||
-            context.getParent().getParent() instanceof GrClosableBlock) &&
+         context.getParent().getParent() instanceof GrClosableBlock) &&
         isNewStatement(context, true)) {
       return true;
     }
@@ -172,46 +159,54 @@ public abstract class GroovyCompletionUtil {
     if (context.getParent() instanceof GrReferenceExpression &&
         context.getParent().getParent() instanceof GrApplicationStatement &&
         (context.getParent().getParent().getParent() instanceof GrOpenBlock ||
-            context.getParent().getParent().getParent() instanceof GrClosableBlock) &&
+         context.getParent().getParent().getParent() instanceof GrClosableBlock) &&
         isNewStatement(context, true)) {
       return true;
     }
 
     return context.getParent() instanceof GrTypeDefinitionBody &&
-        isNewStatement(context, true);
-  }
-
-  public static boolean inMemberDeclaration(PsiElement context) {
-    if (context.getParent() instanceof GrReferenceElement &&
-        context.getParent().getParent() instanceof GrTypeElement) {
-      PsiElement parent = context.getParent().getParent().getParent();
-      if (parent instanceof GrMethod || parent instanceof GrVariableDeclaration) {
-        return parent.getParent() instanceof GrTypeDefinitionBody || parent.getParent() instanceof GroovyFile;
-      }
-    }
-    return false;
+           isNewStatement(context, true);
   }
 
   public static boolean asTypedMethod(PsiElement context) {
     return context.getParent() instanceof GrReferenceElement &&
-        context.getParent().getParent() instanceof GrTypeElement &&
-        context.getParent().getParent().getParent() instanceof GrMethod &&
-        context.getParent().getParent().getParent().getParent() instanceof GrTypeDefinitionBody &&
-        context.getTextRange().getStartOffset() == context.getParent().getParent().getParent().getParent().getTextRange().getStartOffset();
+           context.getParent().getParent() instanceof GrTypeElement &&
+           context.getParent().getParent().getParent() instanceof GrMethod &&
+           context.getParent().getParent().getParent().getParent() instanceof GrTypeDefinitionBody &&
+           context.getTextRange().getStartOffset() ==
+           context.getParent().getParent().getParent().getParent().getTextRange().getStartOffset();
 
   }
 
 
   public static Object[] getCompletionVariants(GroovyResolveResult[] candidates) {
     Object[] result = new Object[candidates.length];
+    Outer:
     for (int i = 0; i < result.length; i++) {
       final PsiElement element = candidates[i].getElement();
       final PsiElement context = candidates[i].getCurrentFileResolveContext();
-      if (context instanceof GrImportStatement) {
-        final String importedName = ((GrImportStatement) context).getImportedName();
-        if (importedName != null && element != null) {
-          result[i] = LookupElementBuilder.create(element, importedName).setPresentableText(importedName);
-          continue;
+      if (context instanceof GrImportStatement && element != null) {
+        final String importedName = ((GrImportStatement)context).getImportedName();
+        if (importedName != null) {
+          final GrCodeReferenceElement importReference = ((GrImportStatement)context).getImportReference();
+          if (importReference != null) {
+            final GroovyResolveResult[] results = importReference.multiResolve(false);
+            for (GroovyResolveResult r : results) {
+              final PsiElement resolved = r.getElement();
+              if (PsiManager.getInstance(context.getProject()).areElementsEquivalent(resolved, element)) {
+                result[i] = generateLookupForImportedElement(candidates[i], importedName);
+                continue Outer;
+              }
+              else {
+                if (resolved instanceof PsiField && element instanceof PsiMethod && isAccessorFor((PsiMethod)element, (PsiField)resolved)) {
+                  result[i] =
+                    generateLookupForImportedElement(candidates[i], getAccessorPrefix((PsiMethod)element) + capitalize(importedName));
+                  continue Outer;
+                }
+              }
+
+            }
+          }
         }
       }
       result[i] = element;
@@ -220,8 +215,75 @@ public abstract class GroovyCompletionUtil {
     return result;
   }
 
-  public static LookupElement setTailTypeForConstructor(PsiClass clazz, LookupElement lookupElement) {
-    return LookupElementDecorator.withInsertHandler(lookupElement, ParenthesesInsertHandler.getInstance(hasConstructorParameters(clazz)));
+  private static LookupElementBuilder generateLookupForImportedElement(GroovyResolveResult resolveResult, String importedName) {
+    final PsiElement element = resolveResult.getElement();
+    assert element != null;
+    final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
+    LookupElementBuilder builder = LookupElementBuilder.create(element, importedName).setPresentableText(importedName);
+    return setupLookupBuilder(element, substitutor, builder);
+  }
+
+  public static LookupElement getLookupElement(Object o) {
+    if (o instanceof LookupElement) return (LookupElement)o;
+    if (o instanceof PsiNamedElement) return generateLookupElement((PsiNamedElement)o);
+    if (o instanceof PsiElement) return setupLookupBuilder((PsiElement)o, PsiSubstitutor.EMPTY, LookupElementBuilder.create(o, ((PsiElement)o).getText()));
+    return LookupElementBuilder.create(o, o.toString());
+  }
+  public static LookupElementBuilder generateLookupElement(PsiNamedElement element) {
+    LookupElementBuilder builder = LookupElementBuilder.create(element);
+    return setupLookupBuilder(element, PsiSubstitutor.EMPTY, builder);
+  }
+
+  public static LookupElementBuilder setupLookupBuilder(PsiElement element, PsiSubstitutor substitutor, LookupElementBuilder builder) {
+    builder = builder.setIcon(element.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS))
+      .setInsertHandler(new GroovyInsertHandler());
+    builder = setTailText(element, builder, substitutor);
+    builder = setTypeText(element, builder, substitutor);
+    return builder;
+  }
+
+  private static LookupElementBuilder setTailText(PsiElement element, LookupElementBuilder builder, PsiSubstitutor substitutor) {
+    if (element instanceof PsiMethod) {
+      builder = builder.setTailText(PsiFormatUtil.formatMethod((PsiMethod)element, substitutor, PsiFormatUtil.SHOW_PARAMETERS,
+                                                               PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE));
+    }
+    else if (element instanceof PsiClass) {
+      String tailText = getPackageText((PsiClass)element);
+      final PsiClass psiClass = (PsiClass)element;
+      if ((substitutor == null || substitutor.getSubstitutionMap().size() == 0) && psiClass.getTypeParameters().length > 0) {
+        tailText = "<" + StringUtil.join(psiClass.getTypeParameters(), new Function<PsiTypeParameter, String>() {
+          public String fun(PsiTypeParameter psiTypeParameter) {
+            return psiTypeParameter.getName();
+          }
+        }, "," + (showSpaceAfterComma(psiClass) ? " " : "")) + ">" + tailText;
+      }
+      builder = builder.setTailText(tailText, true);
+    }
+    return builder;
+  }
+
+  private static String getPackageText(PsiClass psiClass) {
+    @NonNls String packageName = PsiFormatUtil.getPackageDisplayName(psiClass);
+    return " (" + packageName + ")";
+  }
+
+
+  private static boolean showSpaceAfterComma(PsiClass element) {
+    return CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_AFTER_COMMA;
+  }
+
+
+  private static LookupElementBuilder setTypeText(PsiElement element, LookupElementBuilder builder, PsiSubstitutor substitutor) {
+    if (element instanceof PsiVariable) {
+      builder = builder.setTypeText(substitutor.substitute(((PsiVariable)element).getType()).getPresentableText());
+    }
+    else if (element instanceof PsiMethod) {
+      final PsiType type = substitutor.substitute(((PsiMethod)element).getReturnType());
+      if (type != null) {
+        builder = builder.setTypeText(type.getPresentableText());
+      }
+    }
+    return builder;
   }
 
   public static boolean hasConstructorParameters(PsiClass clazz) {
@@ -233,5 +295,7 @@ public abstract class GroovyCompletionUtil {
     return false;
   }
 
-
+  public static LookupElement setTailTypeForConstructor(PsiClass clazz, LookupElement lookupElement) {
+    return LookupElementDecorator.withInsertHandler(lookupElement, ParenthesesInsertHandler.getInstance(hasConstructorParameters(clazz)));
+  }
 }
index 39b9b21e3f776b854e7fb48d82efbcc710d18436..f1424fb74903e57f28dede18001cc4ef01f1c174 100644 (file)
@@ -32,7 +32,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiElementImpl;
 import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
-import org.jetbrains.plugins.groovy.lang.resolve.processors.AccessorResolverProcessor;
 import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
 
 /**
@@ -61,86 +60,97 @@ public class GrImportStatementImpl extends GroovyPsiElementImpl implements GrImp
     }
 
     ResolveState state = _state.put(ResolverProcessor.RESOLVE_CONTEXT, this);
-    JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
     if (isOnDemand()) {
-      GrCodeReferenceElement ref = getImportReference();
-      if (ref != null) {
-        if (isStatic()) {
-          final PsiElement resolved = ref.resolve();
-          if (resolved instanceof PsiClass) {
-            final PsiClass clazz = (PsiClass)resolved;
-            if (clazz != null) {
-              if (!processAllMembers(processor, clazz)) return false;
+      if (!processDeclarationsForMultipleElements(processor, lastParent, place, state)) return false;
+    }
+    else {
+      if (!processDeclarationsForSingleElement(processor, state)) return false;
+    }
+
+    return true;
+  }
+
+  private boolean processDeclarationsForSingleElement(PsiScopeProcessor processor, ResolveState state) {
+    JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
+    String name = getImportedName();
+    if (name == null) return true;
+
+    NameHint nameHint = processor.getHint(NameHint.KEY);
+
+    GrCodeReferenceElement ref = getImportReference();
+    if (ref == null) return true;
+
+    String qName = ref.getCanonicalText();
+    if (qName.indexOf('.') <= 0) return true;
+
+    if (isStatic()) {
+      final int i = qName.lastIndexOf('.');
+      if (i > 0) {
+        final String classQName = qName.substring(0, i);
+        PsiClass clazz = facade.findClass(classQName, getResolveScope());
+        if (clazz != null) {
+          final String refName = ref.getReferenceName();
+          if (nameHint == null || name.equals(nameHint.getName(state))) {
+            final PsiField field = clazz.findFieldByName(refName, false);
+            if (field != null && field.hasModifierProperty(PsiModifier.STATIC)) {
+              if (!processor.execute(field, state)) return false;
             }
-          }
-        }
-        else {
-          String qName = PsiUtil.getQualifiedReferenceText(ref);
-          if (qName != null) {
-            PsiPackage aPackage = facade.findPackage(qName);
-            if (aPackage != null) {
-              if (!aPackage.processDeclarations(processor, state, lastParent, place)) return false;
+
+            for (PsiMethod method : clazz.findMethodsByName(refName, false)) {
+              if (method.hasModifierProperty(PsiModifier.STATIC)) {
+                if (!processor.execute(method, state)) return false;
+              }
             }
           }
+
+          final PsiMethod getter = GroovyPropertyUtils.findPropertyGetter(clazz, refName, true, true);
+          if (getter != null &&
+              (nameHint == null || name.equals(GroovyPropertyUtils.getPropertyNameByGetterName(nameHint.getName(state), true)))) {
+            if (!processor.execute(getter, state)) return false;
+          }
+
+          final PsiMethod setter = GroovyPropertyUtils.findPropertySetter(clazz, refName, true, true);
+          if (setter != null &&
+              (nameHint == null || name.equals(GroovyPropertyUtils.getPropertyNameBySetterName(nameHint.getName(state))))) {
+            if (!processor.execute(setter, state)) return false;
+          }
         }
       }
     }
     else {
-      String name = getImportedName();
-      if (name != null) {
-        NameHint nameHint = processor.getHint(NameHint.KEY);
-        //todo [DIANA] look more carefully
-
-        GrCodeReferenceElement ref = getImportReference();
-        if (ref != null) {
-          String qName = ref.getCanonicalText();
-          if (qName != null && qName.indexOf('.') > 0) {
-            if (!isStatic()) {
-              if (nameHint == null || name.equals(nameHint.getName(state))) {
-                PsiClass clazz = facade.findClass(qName, getResolveScope());
-                if (clazz != null && !processor.execute(clazz, state)) return false;
-              }
-            }
-            else {
-              final int i = qName.lastIndexOf('.');
-              if (i > 0) {
-                final String classQName = qName.substring(0, i);
-                PsiClass clazz = facade.findClass(classQName, getResolveScope());
-                if (clazz != null) {
-                  final String refName = ref.getReferenceName();
-                  if (nameHint == null || name.equals(nameHint.getName(state))) {
-                    final PsiField field = clazz.findFieldByName(refName, false);
-                    if (field != null && field.hasModifierProperty(PsiModifier.STATIC) && !processor.execute(field, state)) {
-                      return false;
-                    }
-
-                    for (PsiMethod method : clazz.findMethodsByName(refName, false)) {
-                      if (method.hasModifierProperty(PsiModifier.STATIC) && !processor.execute(method, state)) return false;
-                    }
-                  }
-
-                  if (processor instanceof AccessorResolverProcessor) {
-                    final PsiMethod getter = GroovyPropertyUtils.findPropertyGetter(clazz, refName, true, true);
-                    if (getter != null &&
-                        (nameHint == null ||
-                         name.equals(GroovyPropertyUtils.getPropertyNameByGetterName(nameHint.getName(state), true)))) {
-                      processor.execute(getter, state);
-                    }
-
-                    final PsiMethod setter = GroovyPropertyUtils.findPropertySetter(clazz, refName, true, true);
-                    if (setter != null &&
-                        (nameHint == null || name.equals(GroovyPropertyUtils.getPropertyNameBySetterName(nameHint.getName(state))))) {
-                      processor.execute(setter, state);
-                    }
-                  }
-                }
-              }
-            }
-          }
+      if (nameHint == null || name.equals(nameHint.getName(state))) {
+        PsiClass clazz = facade.findClass(qName, getResolveScope());
+        if (clazz != null) {
+          if (!processor.execute(clazz, state)) return false;
         }
       }
     }
+    return true;
+  }
 
+  private boolean processDeclarationsForMultipleElements(PsiScopeProcessor processor,
+                                                         PsiElement lastParent,
+                                                         PsiElement place,
+                                                         ResolveState state) {
+    GrCodeReferenceElement ref = getImportReference();
+    if (ref == null) return true;
+
+    if (isStatic()) {
+      final PsiElement resolved = ref.resolve();
+      if (resolved instanceof PsiClass) {
+        final PsiClass clazz = (PsiClass)resolved;
+        if (!processAllMembers(processor, clazz)) return false;
+      }
+    }
+    else {
+      String qName = PsiUtil.getQualifiedReferenceText(ref);
+      if (qName != null) {
+        PsiPackage aPackage = JavaPsiFacade.getInstance(getProject()).findPackage(qName);
+        if (aPackage != null) {
+          if (!aPackage.processDeclarations(processor, state, lastParent, place)) return false;
+        }
+      }
+    }
     return true;
   }
 
index 19f5b023c1bec65bd322b91712165e2fbd60de49..f92c116ed874b458d0c246ef6b6af7c73d7b418b 100644 (file)
@@ -195,7 +195,14 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl implement
   }
 
   public boolean isReferenceTo(PsiElement element) {
-    return getManager().areElementsEquivalent(element, resolve());
+    final PsiManager manager = getManager();
+    if (element instanceof PsiNamedElement && getParent() instanceof GrImportStatement) {
+      final GroovyResolveResult[] results = multiResolve(false);
+      for (GroovyResolveResult result : results) {
+        if (manager.areElementsEquivalent(result.getElement(), element)) return true;
+      }
+    }
+    return manager.areElementsEquivalent(element, resolve());
   }
 
   @NotNull
index 34b6645480c68aebf250c3a34441640820d2c8cb..028940bb46af7abbce793f18809e0cecbe748faf 100644 (file)
@@ -19,9 +19,11 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.*;
 import com.intellij.psi.util.PropertyUtil;
+import com.intellij.util.ArrayUtil;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
 
@@ -33,6 +35,7 @@ import java.beans.Introspector;
 public class GroovyPropertyUtils {
   private static final String IS_PREFIX = "is";
   private static final String GET_PREFIX = "get";
+  private static final String SET_PREFIX = "set";
 
   private GroovyPropertyUtils() {
   }
@@ -166,7 +169,7 @@ public class GroovyPropertyUtils {
 
   @Nullable
   public static String getPropertyNameBySetterName(String methodName) {
-    if (methodName.startsWith("set") && methodName.length() > 3) {
+    if (methodName.startsWith(SET_PREFIX) && methodName.length() > 3) {
       return StringUtil.decapitalize(methodName.substring(3));
     }
     else {
@@ -200,6 +203,7 @@ public class GroovyPropertyUtils {
 
   /**
    * Returns getter names in priority order
+   *
    * @param name property name
    * @return getter names
    */
@@ -208,11 +212,11 @@ public class GroovyPropertyUtils {
   }
 
   public static String[] suggestSettersName(@NotNull String name) {
-    return new String[]{"set"+capitalize(name)};
+    return new String[]{SET_PREFIX + capitalize(name)};
   }
 
   public static boolean isSetterName(String name) {
-    return name != null && name.startsWith("set") && name.length() > 3 && isUpperCase(name.charAt(3));
+    return name != null && name.startsWith(SET_PREFIX) && name.length() > 3 && isUpperCase(name.charAt(3));
   }
 
   public static boolean isProperty(@Nullable PsiClass aClass, @Nullable String propertyName, boolean isStatic) {
@@ -253,4 +257,65 @@ public class GroovyPropertyUtils {
     return Introspector.decapitalize(s);
   }
 
+  @Nullable
+  public static PsiField findFieldForAccessor(PsiMethod accessor, boolean checkSuperClasses) {
+    final PsiClass psiClass = accessor.getContainingClass();
+    if (psiClass == null) return null;
+    PsiField field = null;
+    if (!checkSuperClasses) {
+      field = psiClass.findFieldByName(getPropertyNameByAccessorName(accessor.getName()), true);
+    }
+    else {
+      final String name = getPropertyNameByAccessorName(accessor.getName());
+      assert name != null;
+      final PsiField[] allFields = psiClass.getAllFields();
+      for (PsiField psiField : allFields) {
+        if (name.equals(psiField.getName())) {
+          field = psiField;
+          break;
+        }
+      }
+    }
+    if (field == null) return null;
+    if (field.hasModifierProperty(GrModifier.STATIC) == accessor.hasModifierProperty(GrModifier.STATIC)) {
+      return field;
+    }
+    return null;
+  }
+
+  @Nullable
+  public static String getGetterPrefix(PsiMethod getter) {
+    final String name = getter.getName();
+    if (name.startsWith(GET_PREFIX)) return GET_PREFIX;
+    if (name.startsWith(IS_PREFIX)) return IS_PREFIX;
+
+    return null;
+  }
+
+  @Nullable
+  public static String getSetterPrefix(PsiMethod setter) {
+    if (setter.getName().startsWith(SET_PREFIX)) return SET_PREFIX;
+    return null;
+  }
+
+  @Nullable
+  public static String getAccessorPrefix(PsiMethod method) {
+    final String prefix = getGetterPrefix(method);
+    if (prefix != null) return prefix;
+
+    return getSetterPrefix(method);
+  }
+
+  public static boolean isAccessorFor(PsiMethod accessor, PsiField field) {
+    final String accessorName = accessor.getName();
+    final String fieldName = field.getName();
+    if (!ArrayUtil.contains(accessorName, suggestGettersName(fieldName)) &&
+        !ArrayUtil.contains(accessorName, suggestSettersName(fieldName))) {
+      return false;
+    }
+    final PsiClass accessorClass = accessor.getContainingClass();
+    final PsiClass fieldClass = field.getContainingClass();
+    if (!field.getManager().areElementsEquivalent(accessorClass, fieldClass)) return false;
+    return accessor.hasModifierProperty(GrModifier.STATIC) == field.hasModifierProperty(GrModifier.STATIC);
+  }
 }
index b58675e1b321d38ef74015f68f716a54b1d90259..44c7dba2cf5fc6720efe09f3d17af87147b6aff6 100644 (file)
@@ -110,9 +110,23 @@ public class FindUsagesTest extends LightGroovyTestCase {
   }
 
   public void testTypeAlias() throws Throwable {
+    doTestImpl("A.groovy", 2);
+  }
+
+  public void testMethodAlias() throws Throwable {
+    doTestImpl("A.groovy", 2);
+  }
+
+  public void testAliasImportedProperty() throws Throwable {
+    myFixture.addFileToProject("Abc.groovy", "class Abc {static def foo}");
     doTestImpl("A.groovy", 1);
   }
 
+  public void testGetterWhenAliasedImportedProperty() throws Throwable {
+    myFixture.addFileToProject("Abc.groovy", "class Abc {static def foo}");
+    doTestImpl("A.groovy", 2);
+  }
+
   public void testForInParameter() throws Throwable {
     doTestImpl("A.groovy", 1);
   }
index 7402d5dcbff06c1e202585741740e28fea4215bd..55f7ceec3a422f8135c6611d93b3583ec56b4505 100644 (file)
@@ -497,7 +497,7 @@ set<caret>Bar(2)
 """)
     def ref = findReference()
     def resolved = ref.resolve()
-    assertNull resolved
+    assertInstanceOf resolved, GrAccessorMethod
   }
 
   public void testPropertyInCallExpression() {
@@ -545,4 +545,29 @@ print new X().@f<caret>oo
     def resolved = ref.resolve()
     assertInstanceOf(resolved, GrField)
   }
+
+  public void testSetterToAliasedImportedProperty() {
+    myFixture.addFileToProject("a.groovy", """class Foo {
+  static def bar
+}""")
+    myFixture.configureByText("b.groovy", """import static Foo.bar as foo
+set<caret>Foo(2)
+""")
+    def ref = findReference()
+    def resolved = ref.resolve()
+    assertInstanceOf resolved, GrAccessorMethod
+  }
+
+  public void testPhysicalSetterToStaticallyImportedProperty() {
+    myFixture.addFileToProject("a.groovy", """class Foo {
+  static def bar
+  static def setBar(def bar){}
+}""")
+    myFixture.configureByText("b.groovy", """import static Foo.bar as foo
+set<caret>Foo(2)
+""")
+    def ref = findReference()
+    def resolved = ref.resolve()
+    assertInstanceOf resolved, GrMethod
+  }
 }
\ No newline at end of file
diff --git a/plugins/groovy/testdata/findUsages/aliasImportedProperty/A.groovy b/plugins/groovy/testdata/findUsages/aliasImportedProperty/A.groovy
new file mode 100644 (file)
index 0000000..502c2b1
--- /dev/null
@@ -0,0 +1,8 @@
+import static Abc.f<caret>oo as bar
+
+print getBar()
+
+setBar 2
+
+bar = 4;
+bar++
\ No newline at end of file
diff --git a/plugins/groovy/testdata/findUsages/getterWhenAliasedImportedProperty/A.groovy b/plugins/groovy/testdata/findUsages/getterWhenAliasedImportedProperty/A.groovy
new file mode 100644 (file)
index 0000000..9dc2d5b
--- /dev/null
@@ -0,0 +1,8 @@
+import static Abc.foo as bar
+
+print getBa<caret>r()
+
+setBar 2
+
+bar = 4;
+bar++
\ No newline at end of file
diff --git a/plugins/groovy/testdata/findUsages/methodAlias/A.groovy b/plugins/groovy/testdata/findUsages/methodAlias/A.groovy
new file mode 100644 (file)
index 0000000..4528895
--- /dev/null
@@ -0,0 +1,3 @@
+import static java.lang.Math.min as alias
+
+print al<caret>ias(1, 2)
\ No newline at end of file