diff --git a/java/java-tests/testData/codeInsight/completion/normal/AfterCommonPrefix.java b/java/java-tests/testData/codeInsight/completion/normal/AfterCommonPrefix.java new file mode 100644 index 000000000000..7fd81dd630dc --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/AfterCommonPrefix.java @@ -0,0 +1,5 @@ +public class SomeClass { + void foo(String param) { + if (param.) + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/AfterCommonPrefix_after.java b/java/java-tests/testData/codeInsight/completion/normal/AfterCommonPrefix_after.java new file mode 100644 index 000000000000..d6745c316251 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/AfterCommonPrefix_after.java @@ -0,0 +1,5 @@ +public class SomeClass { + void foo(String param) { + if (param.equals()) + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index dee8f48c415b..2592beef4082 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -858,6 +858,16 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { assertStringItems("myField1", "myField2"); } + public void testAfterCommonPrefix() throws Throwable { + configure() + type 'eq' + assertStringItems("equals", "equalsIgnoreCase"); + complete() + assertStringItems("equals", "equalsIgnoreCase"); + type '(' + checkResult() + } + public void testClassNameInsideIdentifierInIf() throws Throwable { configure() type '\n' diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index 2d837ed140a3..541bea1174f8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -119,21 +119,19 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { psiFile.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, Boolean.TRUE); CompletionPhase phase = CompletionServiceImpl.getCompletionPhase(); - CompletionProgressIndicator indicator = phase.newCompletionStarted(); - - CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); - - if (indicator != null) { - boolean repeated = indicator.isRepeatedInvocation(myCompletionType, editor); - if (repeated && !indicator.isRunning() && (!isAutocompleteCommonPrefixOnInvocation() || indicator.fillInCommonPrefix(true))) { + CompletionProgressIndicator oldIndicator = phase.indicator; + if (oldIndicator != null) { + boolean repeated = oldIndicator.isRepeatedInvocation(myCompletionType, editor); + if (repeated && isAutocompleteCommonPrefixOnInvocation() && phase instanceof CompletionPhase.ItemsCalculated && oldIndicator.fillInCommonPrefix(true)) { return; } + oldIndicator.closeAndFinish(false); if (repeated) { - time = Math.max(indicator.getParameters().getInvocationCount() + 1, 2); - indicator.restorePrefix(phase); + time = phase.handleRepeatedInvocation(time); } } + CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion); if (time > 1) { if (myCompletionType == CompletionType.CLASS_NAME) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java index cda74f77d6ce..35830b42cee3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionPhase.java @@ -43,8 +43,8 @@ import java.util.EventObject; public abstract class CompletionPhase implements Disposable { public static final CompletionPhase NoCompletion = new CompletionPhase(null) { @Override - public CompletionProgressIndicator newCompletionStarted() { - return null; + public int handleRepeatedInvocation(int time) { + return time; } }; @@ -58,8 +58,7 @@ public abstract class CompletionPhase implements Disposable { public void dispose() { } - @Nullable - public abstract CompletionProgressIndicator newCompletionStarted(); + public abstract int handleRepeatedInvocation(int time); public static class AutoPopupAlarm extends CompletionPhase { public AutoPopupAlarm() { @@ -67,8 +66,8 @@ public abstract class CompletionPhase implements Disposable { } @Override - public CompletionProgressIndicator newCompletionStarted() { - return null; + public int handleRepeatedInvocation(int time) { + return time; } } public static class Synchronous extends CompletionPhase { @@ -77,7 +76,7 @@ public abstract class CompletionPhase implements Disposable { } @Override - public CompletionProgressIndicator newCompletionStarted() { + public int handleRepeatedInvocation(int time) { throw new UnsupportedOperationException("Not implemented"); } } @@ -96,9 +95,8 @@ public abstract class CompletionPhase implements Disposable { } @Override - public CompletionProgressIndicator newCompletionStarted() { - indicator.closeAndFinish(false); - return indicator; + public int handleRepeatedInvocation(int time) { + return indicator.restorePrefix(null); } } public static class ItemsCalculated extends CompletionPhase { @@ -110,9 +108,8 @@ public abstract class CompletionPhase implements Disposable { } @Override - public CompletionProgressIndicator newCompletionStarted() { - indicator.closeAndFinish(false); - return indicator; + public int handleRepeatedInvocation(int time) { + return indicator.restorePrefix(null); } } public static class Restarted extends CompletionPhase { @@ -121,13 +118,12 @@ public abstract class CompletionPhase implements Disposable { } @Override - public CompletionProgressIndicator newCompletionStarted() { - indicator.closeAndFinish(false); - return indicator; + public int handleRepeatedInvocation(int time) { + return indicator.restorePrefix(null); } } - public static class ZombiePhase extends CompletionPhase { + public static abstract class ZombiePhase extends CompletionPhase { protected ZombiePhase(@Nullable final LightweightHint hint, final CompletionProgressIndicator indicator) { super(indicator); @@ -179,10 +175,6 @@ public abstract class CompletionPhase implements Disposable { }); } - @Override - public CompletionProgressIndicator newCompletionStarted() { - return indicator; - } } public static class InsertedSingleItem extends ZombiePhase { @@ -192,21 +184,23 @@ public abstract class CompletionPhase implements Disposable { super(null, indicator); this.restorePrefix = restorePrefix; } + + @Override + public int handleRepeatedInvocation(int time) { + return indicator.restorePrefix(restorePrefix); + } + } public static class NoSuggestionsHint extends ZombiePhase { public NoSuggestionsHint(@Nullable LightweightHint hint, CompletionProgressIndicator indicator) { super(hint, indicator); } - } - public static class PossiblyDisturbingAutoPopup extends CompletionPhase { - public PossiblyDisturbingAutoPopup(CompletionProgressIndicator indicator) { - super(indicator); - } @Override - public CompletionProgressIndicator newCompletionStarted() { - return null; + public int handleRepeatedInvocation(int time) { + return indicator.restorePrefix(null); } + } public static class EmptyAutoPopup extends CompletionPhase { public final Editor editor; @@ -302,8 +296,8 @@ public abstract class CompletionPhase implements Disposable { } @Override - public CompletionProgressIndicator newCompletionStarted() { - return null; + public int handleRepeatedInvocation(int time) { + return time; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 65f67f5484ab..5de10d5c94d4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -526,19 +526,19 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement return aBoolean.booleanValue(); } - public void restorePrefix(final CompletionPhase zombie) { + public int restorePrefix(final Runnable customRestore) { new WriteCommandAction(getProject(), getCompletionCommandName()) { @Override protected void run(Result result) throws Throwable { setMergeCommand(); - if (zombie instanceof CompletionPhase.InsertedSingleItem) { - ((CompletionPhase.InsertedSingleItem)zombie).restorePrefix.run(); + if (customRestore != null) { + customRestore.run(); } getLookup().restorePrefix(); } }.execute(); - + return Math.max(getParameters().getInvocationCount() + 1, 2); } public Editor getEditor() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java index 088fcf277be6..657a5c9a89c4 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/LiftShorterItemsClassifier.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion.impl; import com.intellij.codeInsight.lookup.Classifier; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.SmartList; import com.intellij.util.containers.MultiMap; @@ -40,7 +41,7 @@ class LiftShorterItemsClassifier extends Classifier { @Override public void addElement(LookupElement element) { - final Set strings = element.getAllLookupStrings(); + final Set strings = getAllLookupStrings(element); for (String string : strings) { if (string.length() == 0) continue; @@ -85,7 +86,7 @@ class LiftShorterItemsClassifier extends Classifier { for (LookupElement element : list) { if (processed.add(element)) { final List prefixes = new SmartList(); - for (String string : element.getAllLookupStrings()) { + for (String string : getAllLookupStrings(element)) { prefixes.addAll(myPrefixes.get(string)); } Collections.sort(prefixes); @@ -110,6 +111,14 @@ class LiftShorterItemsClassifier extends Classifier { return result; } + private static Set getAllLookupStrings(LookupElement element) { + HashSet result = new HashSet(); + for (String s : element.getAllLookupStrings()) { + result.add(StringUtil.toLowerCase(s)); + } + return result; + } + @Override public void describeItems(LinkedHashMap map) { final HashSet lifted = new HashSet(); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index d90bdad173ef..0f193d548b92 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -231,6 +231,8 @@ + + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java index 1a2f74a3c24a..58a80da31355 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java @@ -52,15 +52,14 @@ public class GrKindWeigher extends CompletionWeigher { } final PsiElement position = location.getCompletionParameters().getPosition(); - if (!(position.getParent() instanceof GrReferenceElement)) { - if (position.getContainingFile() instanceof GroovyFileBase) { - if (o instanceof PsiClass || o instanceof PsiPackage) return 0; - return 1; - } + if (!(position.getContainingFile() instanceof GroovyFileBase)) { return null; } - if (!(o instanceof PsiElement)) return null; + if (!(position.getParent() instanceof GrReferenceElement)) { + if (o instanceof PsiClass || o instanceof PsiPackage) return 0; + return 1; + } final GrReferenceElement parent = (GrReferenceElement)position.getParent(); @@ -70,6 +69,7 @@ public class GrKindWeigher extends CompletionWeigher { if (o instanceof PsiPackage) return NotQualifiedKind.aPackage; if (isLightElement(o)) return NotQualifiedKind.anImplicitGroovyMethod; if (o instanceof PsiMember) return NotQualifiedKind.aMember; + if (o instanceof String) return NotQualifiedKind.aString; } else { if (o instanceof PsiClass) return QualifiedKind.aClass; @@ -87,6 +87,7 @@ public class GrKindWeigher extends CompletionWeigher { } return QualifiedKind.aMember; } + if (o instanceof String) return QualifiedKind.aString; } return null; } @@ -96,10 +97,10 @@ public class GrKindWeigher extends CompletionWeigher { } static enum NotQualifiedKind { - aPackage, aClass, anImplicitGroovyMethod, aMember, aLocal + aPackage, aClass, anImplicitGroovyMethod, aMember, aLocal, aString } static enum QualifiedKind { - aPackage, aClass, aTrashMethod, anImplicitGroovyMethod, aMember, anEnumConstant + aPackage, aClass, aTrashMethod, anImplicitGroovyMethod, aMember, anEnumConstant, aString } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyTypeDeclarationProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyTypeDeclarationProvider.java new file mode 100644 index 000000000000..52bb0311475b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyTypeDeclarationProvider.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2011 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.lang.psi.impl; + +import com.intellij.codeInsight.navigation.actions.TypeDeclarationProvider; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; + +/** + * @author Sergey Evdokimov + */ +public class GroovyTypeDeclarationProvider implements TypeDeclarationProvider { + @Nullable + public PsiElement[] getSymbolTypeDeclarations(final PsiElement targetElement) { + PsiType type; + if (targetElement instanceof GrVariable){ + type = ((GrVariable)targetElement).getTypeGroovy(); + } + else if (targetElement instanceof GrMethod){ + type = ((GrMethod)targetElement).getInferredReturnType(); + } + else { + return null; + } + if (type == null) return null; + PsiClass psiClass = PsiUtil.resolveClassInType(type); + return psiClass == null ? null : new PsiElement[] {psiClass}; + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGoToTypeDeclarationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGoToTypeDeclarationTest.groovy new file mode 100644 index 000000000000..bf346fb8c1ee --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyGoToTypeDeclarationTest.groovy @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2011 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 + +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import com.intellij.codeInsight.navigation.actions.GotoTypeDeclarationAction +import com.intellij.psi.PsiClass + +/** + * @author Sergey Evdokimov + */ +class GroovyGoToTypeDeclarationTest extends LightCodeInsightFixtureTestCase { + + public void testGoToTypeDeclarationMethod() { + myFixture.configureByText("g.groovy", """ +class A { + + public def method() { + return new B(); + } + + { + method() + } +} + +class B { + +} +""") + + def res = GotoTypeDeclarationAction.findSymbolType(myFixture.editor, myFixture.caretOffset) + assertInstanceOf(res, PsiClass.class) + assertEquals("B", ((PsiClass)res).getName()) + } + + public void testGoToTypeDeclarationVariable() { + myFixture.configureByText("g.groovy", """ +class A { + + { + def a = new B() + println(a) + } +} + +class B { + +} +""") + + def res = GotoTypeDeclarationAction.findSymbolType(myFixture.editor, myFixture.caretOffset) + assertInstanceOf(res, PsiClass.class) + assertEquals("B", ((PsiClass)res).getName()) + } + +}