diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 35f3c64af89b..286a852a88b0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -43,11 +43,9 @@ import com.intellij.psi.filters.classes.AssignableFromContextFilter; import com.intellij.psi.filters.element.ExcludeDeclaredFilter; import com.intellij.psi.filters.element.ModifierFilter; import com.intellij.psi.filters.getters.ExpectedTypesGetter; -import com.intellij.psi.filters.types.AssignableFromFilter; import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl; import com.intellij.psi.impl.source.PsiLabelReference; import com.intellij.psi.impl.source.tree.ElementType; -import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -106,21 +104,6 @@ public class JavaCompletionContributor extends CompletionContributor { private static final ElementPattern IMPORT_REFERENCE = psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class).withParent(PsiImportStatementBase.class)); - static final ElementPattern IN_CATCH_TYPE = - psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class). - withParent(psiElement(PsiTypeElement.class). - withParent(or(psiElement(PsiCatchSection.class), - psiElement(PsiVariable.class).withParent(PsiCatchSection.class))))); - static final ElementPattern IN_MULTI_CATCH_TYPE = - or(psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiCatchSection.class)), - psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiParameter.class).withSuperParent(3, PsiCatchSection.class))); - static final ElementPattern INSIDE_METHOD_THROWS_CLAUSE = - psiElement().afterLeaf(PsiKeyword.THROWS, ",").inside(psiElement(JavaElementType.THROWS_LIST)); - static final ElementPattern IN_RESOURCE_TYPE = - psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class). - withParent(psiElement(PsiTypeElement.class). - withParent(or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class))))); - @Nullable public static ElementFilter getReferenceFilter(PsiElement position) { // Completion after extends in interface, type parameter and implements in class @@ -134,10 +117,6 @@ public class JavaCompletionContributor extends CompletionContributor { return new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.PACKAGE_FILTER); } - if (INSIDE_METHOD_THROWS_CLAUSE.accepts(position)) { - return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE); - } - if (psiElement().afterLeaf(PsiKeyword.INSTANCEOF).accepts(position)) { return new ElementExtractorFilter(ElementClassFilter.CLASS); } @@ -157,18 +136,6 @@ public class JavaCompletionContributor extends CompletionContributor { return new OrFilter(ElementClassFilter.CLASS, ElementClassFilter.VARIABLE); } - if (IN_CATCH_TYPE.accepts(position) || IN_MULTI_CATCH_TYPE.accepts(position)) { - return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE); - } - - if (IN_RESOURCE_TYPE.accepts(position)) { - return new AssignableFromFilter(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE); - } - - if (JavaSmartCompletionContributor.AFTER_THROW_NEW.accepts(position)) { - return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE); - } - if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) { return ElementClassFilter.CLASS; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index 821964c1d88e..3a96b71d9076 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -62,7 +62,7 @@ public class JavaCompletionSorting { ContainerUtil.addIfNotNull(afterNegativeStats, preferStatics(position, expectedTypes)); } if (!JavaCompletionData.START_FOR.accepts(position)) { - afterNegativeStats.add(new PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(type, position)); + afterNegativeStats.add(new PreferByKindWeigher(type, position)); } ContainerUtil.addIfNotNull(afterNegativeStats, recursion(parameters, expectedTypes)); if (!smart && !afterNew) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java similarity index 67% rename from java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java rename to java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java index 291e5d5d2c59..f062614f7cf2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java @@ -1,140 +1,179 @@ -/* - * Copyright 2000-2009 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 com.intellij.codeInsight.completion; - -import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementWeigher; -import com.intellij.psi.*; -import com.intellij.psi.filters.getters.MembersGetter; -import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -/** - * @author peter -*/ -public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupElementWeigher { - private final CompletionType myCompletionType; - private final PsiElement myPosition; - private final Set myNonInitializedFields; - - public PreferLocalVariablesLiteralsAndAnnoMethodsWeigher(CompletionType completionType, PsiElement position) { - super("local"); - myCompletionType = completionType; - myPosition = position; - myNonInitializedFields = JavaCompletionProcessor.getNonInitializedFields(position); - } - - enum MyResult { - annoMethod, - probableKeyword, - localOrParameter, - qualifiedWithField, - qualifiedWithGetter, - superMethodParameters, - normal, - collectionFactory, - expectedTypeMember, - nonInitialized, - classLiteral, - classNameOrGlobalStatic, - } - - @NotNull - @Override - public MyResult weigh(@NotNull LookupElement item) { - final Object object = item.getObject(); - - if (object instanceof PsiKeyword) { - String keyword = ((PsiKeyword)object).getText(); - if (PsiKeyword.RETURN.equals(keyword) && isLastStatement(PsiTreeUtil.getParentOfType(myPosition, PsiStatement.class))) { - return MyResult.probableKeyword; - } - if (PsiKeyword.ELSE.equals(keyword) || PsiKeyword.FINALLY.equals(keyword)) { - return MyResult.probableKeyword; - } - } - - if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) { - return MyResult.localOrParameter; - } - - if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) { - return MyResult.superMethodParameters; - } - - if (myCompletionType == CompletionType.SMART) { - if (item.getUserData(CollectionsUtilityMethodsProvider.COLLECTION_FACTORY) != null) { - return MyResult.collectionFactory; - } - if (Boolean.TRUE.equals(item.getUserData(MembersGetter.EXPECTED_TYPE_INHERITOR_MEMBER))) { - return MyResult.expectedTypeMember; - } - - final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY); - if (chain != null) { - Object qualifier = chain.getQualifier().getObject(); - if (qualifier instanceof PsiLocalVariable || qualifier instanceof PsiParameter) { - return MyResult.localOrParameter; - } - if (qualifier instanceof PsiField) { - return MyResult.qualifiedWithField; - } - if (qualifier instanceof PsiMethod && PropertyUtil.isSimplePropertyGetter((PsiMethod)qualifier)) { - return MyResult.qualifiedWithGetter; - } - } - - return MyResult.normal; - } - - if (myCompletionType == CompletionType.BASIC) { - StaticallyImportable callElement = item.as(StaticallyImportable.CLASS_CONDITION_KEY); - if (callElement != null && callElement.canBeImported() && !callElement.willBeImported()) { - return MyResult.classNameOrGlobalStatic; - } - - if (object instanceof PsiKeyword && PsiKeyword.CLASS.equals(item.getLookupString())) { - return MyResult.classLiteral; - } - - if (object instanceof PsiAnnotationMethod && ((PsiAnnotationMethod)object).getContainingClass().isAnnotationType()) { - return MyResult.annoMethod; - } - - if (object instanceof PsiClass) { - return MyResult.classNameOrGlobalStatic; - } - - if (object instanceof PsiField && myNonInitializedFields.contains(object)) { - return MyResult.nonInitialized; - } - } - - return MyResult.normal; - } - - private static boolean isLastStatement(PsiStatement statement) { - if (statement == null || !(statement.getParent() instanceof PsiCodeBlock)) { - return true; - } - PsiStatement[] siblings = ((PsiCodeBlock)statement.getParent()).getStatements(); - return statement == siblings[siblings.length - 1]; - } -} +/* + * Copyright 2000-2009 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 com.intellij.codeInsight.completion; + +import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementWeigher; +import com.intellij.patterns.ElementPattern; +import com.intellij.psi.*; +import com.intellij.psi.filters.getters.MembersGetter; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +import static com.intellij.patterns.PsiJavaPatterns.psiElement; +import static com.intellij.patterns.StandardPatterns.or; + +/** + * @author peter +*/ +public class PreferByKindWeigher extends LookupElementWeigher { + static final ElementPattern IN_CATCH_TYPE = + psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class). + withParent(psiElement(PsiTypeElement.class). + withParent(or(psiElement(PsiCatchSection.class), + psiElement(PsiVariable.class).withParent(PsiCatchSection.class))))); + static final ElementPattern IN_MULTI_CATCH_TYPE = + or(psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiCatchSection.class)), + psiElement().afterLeaf(psiElement().withText("|").withParent(PsiTypeElement.class).withSuperParent(2, PsiParameter.class).withSuperParent(3, PsiCatchSection.class))); + static final ElementPattern INSIDE_METHOD_THROWS_CLAUSE = + psiElement().afterLeaf(PsiKeyword.THROWS, ",").inside(psiElement(JavaElementType.THROWS_LIST)); + static final ElementPattern IN_RESOURCE_TYPE = + psiElement().withParent(psiElement(PsiJavaCodeReferenceElement.class). + withParent(psiElement(PsiTypeElement.class). + withParent(or(psiElement(PsiResourceVariable.class), psiElement(PsiResourceList.class))))); + private final CompletionType myCompletionType; + private final PsiElement myPosition; + private final Set myNonInitializedFields; + @Nullable private final String myRequiredSuper; + + public PreferByKindWeigher(CompletionType completionType, PsiElement position) { + super("local"); + myCompletionType = completionType; + myPosition = position; + myNonInitializedFields = JavaCompletionProcessor.getNonInitializedFields(position); + + if (IN_CATCH_TYPE.accepts(position) || + IN_MULTI_CATCH_TYPE.accepts(position) || + JavaSmartCompletionContributor.AFTER_THROW_NEW.accepts(position) || + INSIDE_METHOD_THROWS_CLAUSE.accepts(position)) { + myRequiredSuper = CommonClassNames.JAVA_LANG_THROWABLE; + } + else if (IN_RESOURCE_TYPE.accepts(position)) { + myRequiredSuper = CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE; + } + else { + myRequiredSuper = null; + } + } + + enum MyResult { + annoMethod, + probableKeyword, + localOrParameter, + qualifiedWithField, + qualifiedWithGetter, + superMethodParameters, + normal, + collectionFactory, + expectedTypeMember, + suitableClass, + nonInitialized, + classLiteral, + classNameOrGlobalStatic, + } + + @NotNull + @Override + public MyResult weigh(@NotNull LookupElement item) { + final Object object = item.getObject(); + + if (object instanceof PsiKeyword) { + String keyword = ((PsiKeyword)object).getText(); + if (PsiKeyword.RETURN.equals(keyword) && isLastStatement(PsiTreeUtil.getParentOfType(myPosition, PsiStatement.class))) { + return MyResult.probableKeyword; + } + if (PsiKeyword.ELSE.equals(keyword) || PsiKeyword.FINALLY.equals(keyword)) { + return MyResult.probableKeyword; + } + } + + if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) { + return MyResult.localOrParameter; + } + + if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) { + return MyResult.superMethodParameters; + } + + if (myCompletionType == CompletionType.SMART) { + if (item.getUserData(CollectionsUtilityMethodsProvider.COLLECTION_FACTORY) != null) { + return MyResult.collectionFactory; + } + if (Boolean.TRUE.equals(item.getUserData(MembersGetter.EXPECTED_TYPE_INHERITOR_MEMBER))) { + return MyResult.expectedTypeMember; + } + + final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY); + if (chain != null) { + Object qualifier = chain.getQualifier().getObject(); + if (qualifier instanceof PsiLocalVariable || qualifier instanceof PsiParameter) { + return MyResult.localOrParameter; + } + if (qualifier instanceof PsiField) { + return MyResult.qualifiedWithField; + } + if (qualifier instanceof PsiMethod && PropertyUtil.isSimplePropertyGetter((PsiMethod)qualifier)) { + return MyResult.qualifiedWithGetter; + } + } + + return MyResult.normal; + } + + if (myCompletionType == CompletionType.BASIC) { + StaticallyImportable callElement = item.as(StaticallyImportable.CLASS_CONDITION_KEY); + if (callElement != null && callElement.canBeImported() && !callElement.willBeImported()) { + return MyResult.classNameOrGlobalStatic; + } + + if (object instanceof PsiKeyword && PsiKeyword.CLASS.equals(item.getLookupString())) { + return MyResult.classLiteral; + } + + if (object instanceof PsiAnnotationMethod && ((PsiAnnotationMethod)object).getContainingClass().isAnnotationType()) { + return MyResult.annoMethod; + } + + if (object instanceof PsiClass) { + if (myRequiredSuper != null && InheritanceUtil.isInheritor((PsiClass)object, myRequiredSuper)) { + return MyResult.suitableClass; + } + return MyResult.classNameOrGlobalStatic; + } + + if (object instanceof PsiField && myNonInitializedFields.contains(object)) { + return MyResult.nonInitialized; + } + } + + return MyResult.normal; + } + + private static boolean isLastStatement(PsiStatement statement) { + if (statement == null || !(statement.getParent() instanceof PsiCodeBlock)) { + return true; + } + PsiStatement[] siblings = ((PsiCodeBlock)statement.getParent()).getStatements(); + return statement == siblings[siblings.length - 1]; + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/ResourceParentInResourceList.java b/java/java-tests/testData/codeInsight/completion/normal/ResourceParentInResourceList.java new file mode 100644 index 000000000000..231eaa286b44 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ResourceParentInResourceList.java @@ -0,0 +1,10 @@ +class MyClass { + static class InnerResource implements AutoCloseable { } +} +class MyOuterResource implements AutoCloseable { } +class Main { + void f() { + try (My r) { + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/ResourceParentInResourceList_after.java b/java/java-tests/testData/codeInsight/completion/normal/ResourceParentInResourceList_after.java new file mode 100644 index 000000000000..3e48f0a65ed1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ResourceParentInResourceList_after.java @@ -0,0 +1,10 @@ +class MyClass { + static class InnerResource implements AutoCloseable { } +} +class MyOuterResource implements AutoCloseable { } +class Main { + void f() { + try (MyClass r) { + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal17CompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal17CompletionTest.groovy index 63eaaa22dc22..98256866a1c1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal17CompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/Normal17CompletionTest.groovy @@ -39,8 +39,16 @@ public class Normal17CompletionTest extends LightFixtureCompletionTestCase { public void testOnlyResourcesInResourceList3() { doTest() } public void testOnlyResourcesInResourceList4() { doTest() } + public void testResourceParentInResourceList() { + configureByFile(getTestName(false) + ".java") + assert 'MyOuterResource' == myFixture.lookupElementStrings[0] + assert 'MyClass' in myFixture.lookupElementStrings + myFixture.type('C\n') + checkResultByFile(getTestName(false) + "_after.java") } + private void doTest() { configureByFile(getTestName(false) + ".java") + myFixture.type('\n') checkResultByFile(getTestName(false) + "_after.java") } } 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 d6278ab25f97..4d58019f3fe1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -266,8 +266,8 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { public void testObjectsInThrowsBlock() throws Exception { configureByFile("InThrowsCompletion.java"); - assert "C" in myFixture.lookupElementStrings - assert !("B" in myFixture.lookupElementStrings) + assert "C" == myFixture.lookupElementStrings[0] + assert "B" in myFixture.lookupElementStrings } public void testAfterInstanceof() throws Exception { @@ -1028,10 +1028,10 @@ public class ListUtils { public void testOnlyAnnotationsAfterAt() throws Throwable { doTest() } - public void testOnlyExceptionsInCatch1() throws Exception { doTest() } - public void testOnlyExceptionsInCatch2() throws Exception { doTest() } - public void testOnlyExceptionsInCatch3() throws Exception { doTest() } - public void testOnlyExceptionsInCatch4() throws Exception { doTest() } + public void testOnlyExceptionsInCatch1() throws Exception { doTest('\n') } + public void testOnlyExceptionsInCatch2() throws Exception { doTest('\n') } + public void testOnlyExceptionsInCatch3() throws Exception { doTest('\n') } + public void testOnlyExceptionsInCatch4() throws Exception { doTest('\n') } public void testCommaAfterVariable() throws Throwable { doTest(',') }