From 027c366b4d14c8d0c49b415af40c75419e8e7363 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 28 Mar 2011 17:20:49 +0200 Subject: [PATCH] IDEA-66656 Suggest static fields in Class Name completion --- ...udeFromCompletionLookupActionProvider.java | 2 +- .../JavaGlobalMemberLookupElement.java | 66 ++++----------- ...GlobalMemberNameCompletionContributor.java | 67 +++++++++++---- .../completion/JavaMethodCallElement.java | 50 ++--------- .../completion/MemberLookupHelper.java | 82 +++++++++++++++++++ .../completion/StaticMemberProcessor.java | 50 +++++++---- .../impl/quickfix/StaticImportMethodFix.java | 8 +- .../GlobalMemberNameCompletionTest.groovy | 30 +++++++ .../GroovyCompletionContributor.java | 15 +++- .../GroovyClassNameCompletionTest.groovy | 40 +++++++++ 10 files changed, 277 insertions(+), 133 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java index 4ce54e2aae20..8a085f2bb25b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ExcludeFromCompletionLookupActionProvider.java @@ -41,7 +41,7 @@ public class ExcludeFromCompletionLookupActionProvider implements LookupActionPr } else if (o instanceof PsiMethod) { final PsiMethod method = (PsiMethod)o; if (method.hasModifierProperty(PsiModifier.STATIC)) { - addExcludes(consumer, method, StaticImportMethodFix.getMethodQualifiedName(method)); + addExcludes(consumer, method, StaticImportMethodFix.getMemberQualifiedName(method)); } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java index 445543400def..2cc6240c91c0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberLookupElement.java @@ -3,9 +3,10 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.DefaultLookupItemRenderer; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementPresentation; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiMember; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -16,92 +17,54 @@ import static com.intellij.util.ObjectUtils.assertNotNull; * @author peter */ public class JavaGlobalMemberLookupElement extends LookupElement implements StaticallyImportable { - private final PsiMember myMember; - private final boolean myMergedOverloads; - private final PsiClass myContainingClass; + private final MemberLookupHelper myHelper; private final InsertHandler myQualifiedInsertion; private final InsertHandler myImportInsertion; - private boolean myShouldImport = false; public JavaGlobalMemberLookupElement(List overloads, PsiClass containingClass, InsertHandler qualifiedInsertion, InsertHandler importInsertion, boolean shouldImport) { - myMember = overloads.get(0); - myContainingClass = containingClass; + myHelper = new MemberLookupHelper(overloads, containingClass, shouldImport); myQualifiedInsertion = qualifiedInsertion; myImportInsertion = importInsertion; - myShouldImport = shouldImport; - myMergedOverloads = true; } public JavaGlobalMemberLookupElement(PsiMember member, PsiClass containingClass, InsertHandler qualifiedInsertion, InsertHandler importInsertion, boolean shouldImport) { - myMember = member; - myContainingClass = containingClass; + myHelper = new MemberLookupHelper(member, containingClass, shouldImport, false); myQualifiedInsertion = qualifiedInsertion; myImportInsertion = importInsertion; - myShouldImport = shouldImport; - myMergedOverloads = false; } @NotNull @Override public PsiMember getObject() { - return myMember; + return myHelper.getMember(); } @NotNull public PsiClass getContainingClass() { - return myContainingClass; + return assertNotNull(myHelper.getContainingClass()); } @NotNull @Override public String getLookupString() { - return assertNotNull(myMember.getName()); + return assertNotNull(getObject().getName()); } @Override public void renderElement(LookupElementPresentation presentation) { - final String className = myContainingClass.getName(); - presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this, presentation.isReal())); - - final String methodName = myMember.getName(); - if (Boolean.FALSE.equals(myShouldImport) && StringUtil.isNotEmpty(className)) { - presentation.setItemText(className + "." + methodName); - } else { - presentation.setItemText(methodName); - } - - final String qname = myContainingClass.getQualifiedName(); - String location = StringUtil.isEmpty(qname) ? "" : " (" + StringUtil.getPackageName(qname) + ")"; - - final String params = myMergedOverloads - ? "(...)" - : myMember instanceof PsiMethod - ? PsiFormatUtil.formatMethod((PsiMethod)myMember, PsiSubstitutor.EMPTY, - PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE) - : ""; - if (Boolean.TRUE.equals(myShouldImport) && StringUtil.isNotEmpty(className)) { - presentation.setTailText(params + " in " + className + location); - } else { - presentation.setTailText(params + location); - } - - final PsiType type = myMember instanceof PsiMethod ? ((PsiMethod)myMember).getReturnType() : ((PsiField) myMember).getType(); - if (type != null) { - presentation.setTypeText(type.getPresentableText()); - } + myHelper.renderElement(presentation, false, PsiSubstitutor.EMPTY); } @Override public void setShouldBeImported(boolean shouldImportStatic) { - myShouldImport = shouldImportStatic; + myHelper.setShouldBeImported(shouldImportStatic); } @Override @@ -111,11 +74,12 @@ public class JavaGlobalMemberLookupElement extends LookupElement implements Stat @Override public boolean willBeImported() { - return myShouldImport; + return myHelper.willBeImported(); } @Override public void handleInsert(InsertionContext context) { - (myShouldImport ? myImportInsertion : myQualifiedInsertion).handleInsert(context, this); + (willBeImported() ? myImportInsertion : myQualifiedInsertion).handleInsert(context, this); } + } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java index 649eb433e314..9368017189ee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaGlobalMemberNameCompletionContributor.java @@ -1,6 +1,7 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.intellij.codeInsight.lookup.VariableLookupItem; import com.intellij.psi.*; import com.intellij.psi.impl.source.PostprocessReformattingAspect; @@ -20,9 +21,7 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib return; } - final PrefixMatcher matcher = result.getPrefixMatcher(); - final String prefix = matcher.getPrefix(); - if (prefix.length() == 0 || !Character.isLowerCase(prefix.charAt(0))) { + if (result.getPrefixMatcher().getPrefix().length() == 0) { return; } @@ -43,24 +42,13 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib final StaticMemberProcessor processor = new StaticMemberProcessor(position) { @NotNull @Override - protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, boolean shouldImport) { + protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, final boolean shouldImport) { if (member instanceof PsiMethod) { final JavaMethodCallElement element = new JavaMethodCallElement((PsiMethod)member, true, false); element.setShouldBeImported(shouldImport); return element; } - return new VariableLookupItem((PsiVariable)member) { - @Override - public void handleInsert(InsertionContext context) { - context.commitDocument(); - final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false); - if (ref != null) { - ref.bindToElementViaStaticImport(containingClass); - PostprocessReformattingAspect.getInstance(ref.getProject()).doPostponedFormatting(); - } - super.handleInsert(context); - } - }; + return new StaticFieldLookupItem((PsiField)member, shouldImport, containingClass); } @Override @@ -86,4 +74,51 @@ public class JavaGlobalMemberNameCompletionContributor extends CompletionContrib return processor; } + private static class StaticFieldLookupItem extends VariableLookupItem implements StaticallyImportable { + private final MemberLookupHelper myHelper; + private final PsiClass myContainingClass; + + public StaticFieldLookupItem(PsiField field, boolean shouldImport, PsiClass containingClass) { + super(field); + myContainingClass = containingClass; + myHelper = new MemberLookupHelper(field, containingClass, shouldImport, false); + } + + @Override + public void setShouldBeImported(boolean shouldImportStatic) { + myHelper.setShouldBeImported(shouldImportStatic); + } + + @Override + public boolean canBeImported() { + return true; + } + + @Override + public boolean willBeImported() { + return myHelper.willBeImported(); + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + super.renderElement(presentation); + myHelper.renderElement(presentation, getAttribute(FORCE_QUALIFY) != null, PsiSubstitutor.EMPTY); + } + + @Override + public void handleInsert(InsertionContext context) { + if (willBeImported()) { + context.commitDocument(); + final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false); + if (ref != null) { + ref.bindToElementViaStaticImport(myContainingClass); + PostprocessReformattingAspect.getInstance(ref.getProject()).doPostponedFormatting(); + } + } else { + context.getDocument().insertString(context.getStartOffset(), "."); + JavaCompletionUtil.insertClassReference(myContainingClass, context.getFile(), context.getStartOffset()); + } + super.handleInsert(context); + } + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index eaa74241a230..406addec2c41 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -24,9 +24,7 @@ import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.ClassConditionKey; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,9 +37,7 @@ public class JavaMethodCallElement extends LookupItem implements Type private static final Key INFERENCE_SUBSTITUTOR = Key.create("INFERENCE_SUBSTITUTOR"); @Nullable private final PsiClass myContainingClass; private final PsiMethod myMethod; - private final boolean myCanImportStatic; - private boolean myShouldImportStatic; - private final boolean myMergedOverloads; + private final MemberLookupHelper myHelper; public JavaMethodCallElement(@NotNull PsiMethod method) { this(method, false, false); @@ -50,9 +46,8 @@ public class JavaMethodCallElement extends LookupItem implements Type public JavaMethodCallElement(PsiMethod method, boolean canImportStatic, boolean mergedOverloads) { super(method, method.getName()); myMethod = method; - myMergedOverloads = mergedOverloads; myContainingClass = method.getContainingClass(); - myCanImportStatic = canImportStatic; + myHelper = canImportStatic ? new MemberLookupHelper(method, myContainingClass, false, mergedOverloads) : null; } public PsiType getType() { @@ -77,18 +72,17 @@ public class JavaMethodCallElement extends LookupItem implements Type @Override public void setShouldBeImported(boolean shouldImportStatic) { - assert myCanImportStatic; - myShouldImportStatic = shouldImportStatic; + myHelper.setShouldBeImported(shouldImportStatic); } @Override public boolean canBeImported() { - return myCanImportStatic; + return myHelper != null; } @Override public boolean willBeImported() { - return myShouldImportStatic; + return canBeImported() && myHelper.willBeImported(); } @Override @@ -108,9 +102,9 @@ public class JavaMethodCallElement extends LookupItem implements Type qualifyMethodCall(file, startOffset, document); insertExplicitTypeParameters(context, refStart); } - else if (myCanImportStatic || getAttribute(FORCE_QUALIFY) != null) { + else if (myHelper != null || getAttribute(FORCE_QUALIFY) != null) { context.commitDocument(); - if (myCanImportStatic && myShouldImportStatic) { + if (myHelper != null && willBeImported()) { final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiReferenceExpression.class, false); if (ref != null && myContainingClass != null) { ref.bindToElementViaStaticImport(myContainingClass); @@ -234,38 +228,12 @@ public class JavaMethodCallElement extends LookupItem implements Type @Override public void renderElement(LookupElementPresentation presentation) { - final String className = myContainingClass == null ? "???" : myContainingClass.getName(); - presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(this, presentation.isReal())); - final String methodName = myMethod.getName(); - final boolean qualify = myCanImportStatic && !myShouldImportStatic || getAttribute(FORCE_QUALIFY) != null; - if (qualify && StringUtil.isNotEmpty(className)) { - presentation.setItemText(className + "." + methodName); - } else { - presentation.setItemText(methodName); - } - - final String qname = myContainingClass == null ? "" : myContainingClass.getQualifiedName(); - String location = !myCanImportStatic || StringUtil.isEmpty(qname) ? "" : " (" + StringUtil.getPackageName(qname) + ")"; - presentation.setStrikeout(JavaElementLookupRenderer.isToStrikeout(this)); presentation.setItemTextBold(getAttribute(HIGHLIGHTED_ATTR) != null); - final String params = myMergedOverloads - ? "(...)" - : PsiFormatUtil.formatMethod(myMethod, PsiSubstitutor.EMPTY, - PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE); - if (myShouldImportStatic && StringUtil.isNotEmpty(className)) { - presentation.setTailText(params + " in " + className + location); - } else { - presentation.setTailText(params + location); - } - - final PsiType type = myMethod.getReturnType(); - if (type != null) { - presentation.setTypeText(getSubstitutor().substitute(type).getPresentableText()); - } + MemberLookupHelper helper = myHelper != null ? myHelper : new MemberLookupHelper(myMethod, myContainingClass, false, false); + helper.renderElement(presentation, getAttribute(FORCE_QUALIFY) != null, getSubstitutor()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java new file mode 100644 index 000000000000..c36c9f9c7fd1 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java @@ -0,0 +1,82 @@ +package com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiFormatUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author peter + */ +public class MemberLookupHelper { + private final PsiMember myMember; + private final boolean myMergedOverloads; + @Nullable private final PsiClass myContainingClass; + private boolean myShouldImport = false; + + public MemberLookupHelper(List overloads, PsiClass containingClass, boolean shouldImport) { + this(overloads.get(0), containingClass, shouldImport, true); + } + + public MemberLookupHelper(PsiMember member, PsiClass containingClass, boolean shouldImport, final boolean mergedOverloads) { + myMember = member; + myContainingClass = containingClass; + myShouldImport = shouldImport; + myMergedOverloads = mergedOverloads; + } + + public PsiMember getMember() { + return myMember; + } + + @Nullable + public PsiClass getContainingClass() { + return myContainingClass; + } + + public void setShouldBeImported(boolean shouldImportStatic) { + myShouldImport = shouldImportStatic; + } + + public boolean willBeImported() { + return myShouldImport; + } + + public void renderElement(LookupElementPresentation presentation, boolean forceQualify, PsiSubstitutor substitutor) { + final String className = myContainingClass == null ? "???" : myContainingClass.getName(); + + final String memberName = myMember.getName(); + if (!myShouldImport && StringUtil.isNotEmpty(className) || forceQualify) { + presentation.setItemText(className + "." + memberName); + } else { + presentation.setItemText(memberName); + } + + final String qname = myContainingClass == null ? "" : myContainingClass.getQualifiedName(); + String pkg = StringUtil.getPackageName(qname); + String location = StringUtil.isEmpty(pkg) ? "" : " (" + pkg + ")"; + + final String params = myMergedOverloads + ? "(...)" + : myMember instanceof PsiMethod + ? PsiFormatUtil.formatMethod((PsiMethod)myMember, PsiSubstitutor.EMPTY, + PsiFormatUtil.SHOW_PARAMETERS, + PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE) + : ""; + if (myShouldImport && StringUtil.isNotEmpty(className)) { + presentation.setTailText(params + " in " + className + location); + } else { + presentation.setTailText(params + location, !(myMember instanceof PsiMethod)); + } + + final PsiType type = myMember instanceof PsiMethod ? ((PsiMethod)myMember).getReturnType() : ((PsiField) myMember).getType(); + if (type != null) { + presentation.setTypeText(substitutor.substitute(type).getPresentableText()); + } + } + + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java index 6f9a091ea05f..26d3eb7be78c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -69,13 +69,7 @@ public abstract class StaticMemberProcessor { if (classes.add(containingClass) && JavaCompletionUtil.isSourceLevelAccessible(myPosition, containingClass, myPackagedContext)) { final boolean shouldImport = myStaticImportedClasses.contains(containingClass); - if (!myHintShown && !shouldImport && CompletionService.getCompletionService().getAdvertisementText() == null) { - final String shortcut = CompletionContributor.getActionShortcut(IdeActions.ACTION_SHOW_INTENTION_ACTIONS); - if (shortcut != null) { - CompletionService.getCompletionService().setAdvertisementText("To import a method statically, press " + shortcut); - } - myHintShown = true; - } + showHint(shouldImport); final PsiMethod[] allMethods = containingClass.getAllMethods(); final List overloads = ContainerUtil.findAll(allMethods, new Condition() { @@ -100,6 +94,32 @@ public abstract class StaticMemberProcessor { } } } + for (final String fieldName : namesCache.getAllFieldNames()) { + if (matcher.prefixMatches(fieldName)) { + for (final PsiField field : namesCache.getFieldsByName(fieldName, scope)) { + if (isStaticallyImportable(field)) { + final PsiClass containingClass = field.getContainingClass(); + assert containingClass != null; + + if (JavaCompletionUtil.isSourceLevelAccessible(myPosition, containingClass, myPackagedContext)) { + final boolean shouldImport = myStaticImportedClasses.contains(containingClass); + showHint(shouldImport); + consumer.consume(createLookupElement(field, containingClass, shouldImport)); + } + } + } + } + } + } + + private void showHint(boolean shouldImport) { + if (!myHintShown && !shouldImport && CompletionService.getCompletionService().getAdvertisementText() == null) { + final String shortcut = CompletionContributor.getActionShortcut(IdeActions.ACTION_SHOW_INTENTION_ACTIONS); + if (shortcut != null) { + CompletionService.getCompletionService().setAdvertisementText("To import a method statically, press " + shortcut); + } + myHintShown = true; + } } public List processMembersOfRegisteredClasses(@Nullable final PrefixMatcher matcher, PairConsumer consumer) { @@ -113,7 +133,7 @@ public abstract class StaticMemberProcessor { } } for (final PsiField field : psiClass.getAllFields()) { - if (matcher == null || matcher.prefixMatches(field.getName())) { + if (matcher == null || matcher.prefixMatches(field. getName())) { if (isStaticallyImportable(field)) { consumer.consume(field, psiClass); } @@ -125,17 +145,11 @@ public abstract class StaticMemberProcessor { private boolean isStaticallyImportable(final PsiMember member) { - if (member.hasModifierProperty(PsiModifier.STATIC) && myResolveHelper.isAccessible(member, myPosition, null)) { - final PsiClass containingClass = member.getContainingClass(); - if (containingClass != null) { - if (!JavaCompletionUtil.isInExcludedPackage(containingClass) && - (!(member instanceof PsiMethod) || !StaticImportMethodFix.isExcluded((PsiMethod)member))) { - return true; - } + return member.hasModifierProperty(PsiModifier.STATIC) && isAccessible(member) && !StaticImportMethodFix.isExcluded(member); + } - } - } - return false; + protected boolean isAccessible(PsiMember member) { + return myResolveHelper.isAccessible(member, myPosition, null); } @NotNull diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java index cc2a3d8a1a9d..1a83dbafc824 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/StaticImportMethodFix.java @@ -142,8 +142,8 @@ public class StaticImportMethodFix implements IntentionAction { return result; } - public static boolean isExcluded(PsiMethod method) { - String name = getMethodQualifiedName(method); + public static boolean isExcluded(PsiMember method) { + String name = getMemberQualifiedName(method); if (name == null) return false; CodeInsightSettings cis = CodeInsightSettings.getInstance(); for (String excluded : cis.EXCLUDED_PACKAGES) { @@ -204,7 +204,7 @@ public class StaticImportMethodFix implements IntentionAction { return FINAL_CHOICE; } - String qname = getMethodQualifiedName(selectedValue); + String qname = getMemberQualifiedName(selectedValue); if (qname == null) return FINAL_CHOICE; List excludableStrings = AddImportAction.getAllExcludableStrings(qname); return new BaseListPopupStep(null, excludableStrings) { @@ -270,7 +270,7 @@ public class StaticImportMethodFix implements IntentionAction { } @Nullable - public static String getMethodQualifiedName(PsiMethod method) { + public static String getMemberQualifiedName(PsiMember method) { PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return null; String className = containingClass.getQualifiedName(); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy index 79cbccaa99a5..2cf4238f1f49 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/GlobalMemberNameCompletionTest.groovy @@ -24,6 +24,36 @@ public class Foo { class Bar {{ abcmethod() }}""" } + public void testFieldName() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + + doTest "class Bar {{ abcf }}", true, """import static foo.Foo.abcfield; + +class Bar {{ abcfield }}""" + } + + public void testFieldNameQualified() throws Exception { + myFixture.addClass(""" +package foo; + +public class Foo { + public static int abcfield = 2 + static final int fieldThatsNotVisible = 3 +} +""") + + doTest "class Bar {{ abcf }}", false, """import foo.Foo; + +class Bar {{ Foo.abcfield }}""" + } + public void testQualifiedMethodName() throws Exception { myFixture.addClass(""" package foo; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index a09bf84e1765..ae429f5cb945 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -235,8 +235,7 @@ public class GroovyCompletionContributor extends CompletionContributor { final PsiElement position = parameters.getPosition(); if (((GrReferenceElement)position.getParent()).getQualifier() != null) return; - final String s = result.getPrefixMatcher().getPrefix(); - if (StringUtil.isEmpty(s) || !Character.isLowerCase(s.charAt(0))) return; + if (StringUtil.isEmpty(result.getPrefixMatcher().getPrefix())) return; completeStaticMembers(position).processStaticMethodsGlobally(result); } @@ -493,6 +492,18 @@ public class GroovyCompletionContributor extends CompletionContributor { return new JavaGlobalMemberLookupElement(overloads, containingClass, QUALIFIED_METHOD_INSERT_HANDLER, STATIC_IMPORT_INSERT_HANDLER, shouldImport); } + + @Override + protected boolean isAccessible(PsiMember member) { + boolean result = super.isAccessible(member); + + if (!result && member instanceof GrField) { + GrAccessorMethod[] getters = ((GrField)member).getGetters(); + return getters.length > 0 && super.isAccessible(getters[0]); + } + + return result; + } }; final PsiFile file = position.getContainingFile(); if (file instanceof GroovyFile) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy index 6ab8b945c9d5..78d50f33f80a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy @@ -128,6 +128,46 @@ def foo() { } + public void testImportedStaticField() throws Exception { + myFixture.addFileToProject("b.groovy", """ +class Foo { + static def abcfield1 + static def abcfield2 +}""") + myFixture.configureByText("a.groovy", """def foo() { + abcfi +}""") + def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + ((StaticallyImportable) item).shouldBeImported = true + myFixture.type('\n') + myFixture.checkResult """import static Foo.abcfield1 + +def foo() { + abcfield1 +}""" + + } + + public void testImportedInterfaceConstant() throws Exception { + myFixture.addFileToProject("b.groovy", """ +interface Foo { + static def abcfield1 = 2 + static def abcfield2 = 3 +}""") + myFixture.configureByText("a.groovy", """def foo() { + abcfi +}""") + def item = myFixture.complete(CompletionType.CLASS_NAME)[0] + ((StaticallyImportable) item).shouldBeImported = true + myFixture.type('\n') + myFixture.checkResult """import static Foo.abcfield1 + +def foo() { + abcfield1 +}""" + + } + public void testQualifiedStaticMethod() throws Exception { myFixture.addFileToProject("foo/b.groovy", """package foo class Foo {