From a4d2b8a1d1f63ef8074587900b6478e7d53d63d6 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 16 Sep 2015 14:00:49 +0200 Subject: [PATCH] move code out of JavaSmartCompletionContributor to make it a bit more modular --- .../completion/CatchTypeProvider.java | 80 ++++++ .../ExpectedAnnotationsProvider.java | 52 ++++ ...unctionalExpressionCompletionProvider.java | 20 +- .../completion/InstanceofTypeProvider.java | 93 +++++++ .../completion/JavaCompletionContributor.java | 14 +- .../JavaDocCompletionContributor.java | 27 ++- .../JavaSmartCompletionContributor.java | 229 ++---------------- .../completion/LabelReferenceCompletion.java | 52 ++++ .../MethodReferenceCompletionProvider.java | 4 + .../TypeArgumentCompletionProvider.java | 2 + 10 files changed, 353 insertions(+), 220 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/CatchTypeProvider.java create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/ExpectedAnnotationsProvider.java create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/InstanceofTypeProvider.java create mode 100644 java/java-impl/src/com/intellij/codeInsight/completion/LabelReferenceCompletion.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/CatchTypeProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/CatchTypeProvider.java new file mode 100644 index 000000000000..f760a08f95ae --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/CatchTypeProvider.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2015 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.ExceptionUtil; +import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.patterns.ElementPattern; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; + +import static com.intellij.patterns.PlatformPatterns.psiElement; + +/** + * @author peter + */ +class CatchTypeProvider extends CompletionProvider { + static final ElementPattern CATCH_CLAUSE_TYPE = psiElement().insideStarting( + psiElement(PsiTypeElement.class).withParent( + psiElement(PsiCatchSection.class))); + + @Override + protected void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext context, + @NotNull final CompletionResultSet result) { + PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiTryStatement.class); + final PsiCodeBlock tryBlock = tryStatement == null ? null : tryStatement.getTryBlock(); + if (tryBlock == null) return; + + final InheritorsHolder holder = new InheritorsHolder(result); + + for (final PsiClassType type : ExceptionUtil.getThrownExceptions(tryBlock.getStatements())) { + PsiClass typeClass = type.resolve(); + if (typeClass != null) { + result.addElement(createCatchTypeVariant(tryBlock, type)); + holder.registerClass(typeClass); + } + } + + final Collection expectedClassTypes = Collections.singletonList(JavaPsiFacade.getElementFactory( + tryBlock.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE)); + JavaInheritorsGetter.processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(PsiType type) { + final PsiClass psiClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null; + if (psiClass == null || psiClass instanceof PsiTypeParameter) return; + + if (!holder.alreadyProcessed(psiClass)) { + result.addElement(createCatchTypeVariant(tryBlock, (PsiClassType)type)); + } + } + }); + } + + @NotNull + private static LookupElement createCatchTypeVariant(PsiCodeBlock tryBlock, PsiClassType type) { + return TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock), TailType.HUMBLE_SPACE_BEFORE_WORD); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ExpectedAnnotationsProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/ExpectedAnnotationsProvider.java new file mode 100644 index 000000000000..316f6e66eac1 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ExpectedAnnotationsProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 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.patterns.ElementPattern; +import com.intellij.patterns.PsiJavaPatterns; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNameValuePair; +import com.intellij.psi.PsiType; +import com.intellij.psi.filters.getters.ExpectedTypesGetter; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.patterns.StandardPatterns.or; + +/** + * @author peter + */ +class ExpectedAnnotationsProvider extends CompletionProvider { + static final ElementPattern ANNOTATION_ATTRIBUTE_VALUE = or( + PsiJavaPatterns.psiElement().withParent(PsiNameValuePair.class), + PsiJavaPatterns.psiElement().withSuperParent(2, PsiNameValuePair.class)); + + @Override + public void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext context, + @NotNull final CompletionResultSet result) { + final PsiElement element = parameters.getPosition(); + + for (final PsiType type : ExpectedTypesGetter.getExpectedTypes(element, false)) { + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass != null && psiClass.isAnnotationType()) { + result.addElement(AllClassesGetter.createLookupItem(psiClass, AnnotationInsertHandler.INSTANCE)); + } + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java index 02f8b1e6668f..59290e2a35aa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/FunctionalExpressionCompletionProvider.java @@ -26,6 +26,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PatternCondition; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -43,10 +45,26 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import static com.intellij.patterns.PlatformPatterns.psiElement; + /** * User: anna */ public class FunctionalExpressionCompletionProvider extends CompletionProvider { + static final ElementPattern LAMBDA = psiElement().with(new PatternCondition("LAMBDA_CONTEXT") { + @Override + public boolean accepts(@NotNull PsiElement element, ProcessingContext context) { + return isLambdaContext(element); + }}); + + private static boolean isLambdaContext(@NotNull PsiElement element) { + final PsiElement rulezzRef = element.getParent(); + return rulezzRef != null && + rulezzRef instanceof PsiReferenceExpression && + ((PsiReferenceExpression)rulezzRef).getQualifier() == null && + LambdaUtil.isValidLambdaContext(rulezzRef.getParent()); + } + @Override protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @@ -55,7 +73,7 @@ public class FunctionalExpressionCompletionProvider extends CompletionProvider getLambdaVariants(@NotNull CompletionParameters parameters, boolean prioritize) { - if (!PsiUtil.isLanguageLevel8OrHigher(parameters.getOriginalFile())) return Collections.emptyList(); + if (!PsiUtil.isLanguageLevel8OrHigher(parameters.getOriginalFile()) || !isLambdaContext(parameters.getPosition())) return Collections.emptyList(); List result = ContainerUtil.newArrayList(); for (ExpectedTypeInfo expectedType : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/InstanceofTypeProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/InstanceofTypeProvider.java new file mode 100644 index 000000000000..3287750e54c5 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/InstanceofTypeProvider.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2015 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.lookup.LookupElement; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.patterns.ElementPattern; +import com.intellij.psi.*; +import com.intellij.psi.filters.getters.InstanceOfLeftPartTypeGetter; +import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; +import com.intellij.util.ProcessingContext; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashSet; +import java.util.Set; + +import static com.intellij.patterns.PlatformPatterns.psiElement; + +/** + * @author peter + */ +class InstanceofTypeProvider extends CompletionProvider { + static final ElementPattern AFTER_INSTANCEOF = psiElement().afterLeaf(PsiKeyword.INSTANCEOF); + + @Override + protected void addCompletions(@NotNull final CompletionParameters parameters, + final ProcessingContext context, + @NotNull final CompletionResultSet result) { + final PsiElement position = parameters.getPosition(); + final PsiType[] leftTypes = InstanceOfLeftPartTypeGetter.getLeftTypes(position); + final Set expectedClassTypes = new LinkedHashSet(); + final Set parameterizedTypes = new THashSet(); + for (final PsiType type : leftTypes) { + if (type instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType)type; + if (!classType.isRaw()) { + ContainerUtil.addIfNotNull(classType.resolve(), parameterizedTypes); + } + + expectedClassTypes.add(classType.rawType()); + } + } + + JavaInheritorsGetter + .processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer() { + @Override + public void consume(PsiType type) { + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass == null || psiClass instanceof PsiTypeParameter) return; + + //noinspection SuspiciousMethodCalls + if (expectedClassTypes.contains(type)) return; + + result.addElement(createInstanceofLookupElement(psiClass, parameterizedTypes)); + } + }); + } + + private static LookupElement createInstanceofLookupElement(PsiClass psiClass, Set toWildcardInheritors) { + final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters(); + if (typeParameters.length > 0) { + for (final PsiClass parameterizedType : toWildcardInheritors) { + if (psiClass.isInheritor(parameterizedType, true)) { + PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; + final PsiWildcardType wildcard = PsiWildcardType.createUnbounded(psiClass.getManager()); + for (final PsiTypeParameter typeParameter : typeParameters) { + substitutor = substitutor.put(typeParameter, wildcard); + } + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject()); + return PsiTypeLookupItem.createLookupItem(factory.createType(psiClass, substitutor), psiClass); + } + } + } + + return new JavaPsiClassReferenceElement(psiClass); + } +} 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 61e018b43152..d518e8413b3c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -222,13 +222,11 @@ public class JavaCompletionContributor extends CompletionContributor { } final InheritorsHolder inheritors = new InheritorsHolder(result); - if (JavaSmartCompletionContributor.IN_TYPE_ARGS.accepts(position)) { + if (TypeArgumentCompletionProvider.IN_TYPE_ARGS.accepts(position)) { new TypeArgumentCompletionProvider(false, inheritors).addCompletions(parameters, new ProcessingContext(), result); } - if (JavaSmartCompletionContributor.LAMBDA.accepts(parameters.getPosition())) { - result.addAllElements(FunctionalExpressionCompletionProvider.getLambdaVariants(parameters, true)); - } + result.addAllElements(FunctionalExpressionCompletionProvider.getLambdaVariants(parameters, true)); PrefixMatcher matcher = result.getPrefixMatcher(); if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) { @@ -404,7 +402,7 @@ public class JavaCompletionContributor extends CompletionContributor { return; } if (reference instanceof PsiLabelReference) { - processLabelReference(result, (PsiLabelReference)reference); + LabelReferenceCompletion.processLabelReference(result, (PsiLabelReference)reference); return; } @@ -832,12 +830,6 @@ public class JavaCompletionContributor extends CompletionContributor { return null; } - static void processLabelReference(CompletionResultSet result, PsiLabelReference ref) { - for (String s : ref.getVariants()) { - result.addElement(TailTypeDecorator.withTail(LookupElementBuilder.create(s), TailType.SEMICOLON)); - } - } - private static class IndentingDecorator extends LookupElementDecorator { public IndentingDecorator(LookupElement delegate) { super(delegate); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index 5c8e7056d372..c8d31faa253f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -53,10 +53,10 @@ import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.StringTokenizer; +import java.util.*; + +import static com.intellij.patterns.PlatformPatterns.psiElement; +import static com.intellij.patterns.StandardPatterns.string; /** * Created by IntelliJ IDEA. @@ -132,6 +132,25 @@ public class JavaDocCompletionContributor extends CompletionContributor { return LookupItemUtil.objectToLookupItem(element); } }); + + extend(CompletionType.SMART, psiElement().inside( + psiElement(PsiDocTag.class).withName( + string().oneOf(PsiKeyword.THROWS, "exception"))), new CompletionProvider() { + @Override + public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { + final PsiElement element = parameters.getPosition(); + final Set throwsSet = new HashSet(); + final PsiMethod method = PsiTreeUtil.getContextOfType(element, PsiMethod.class, true); + if(method != null){ + for (PsiClassType ref : method.getThrowsList().getReferencedTypes()) { + final PsiClass exception = ref.resolve(); + if (exception != null && throwsSet.add(exception)) { + result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception), TailType.HUMBLE_SPACE_BEFORE_WORD)); + } + } + } + } + }); } private static PsiParameter getDocTagParam(PsiElement tag) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 8b0b052b7a85..c8e80f544042 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -15,43 +15,36 @@ */ package com.intellij.codeInsight.completion; -import com.intellij.codeInsight.ExceptionUtil; -import com.intellij.codeInsight.*; +import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.ExpectedTypeInfoImpl; +import com.intellij.codeInsight.ExpectedTypesProvider; +import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; -import com.intellij.codeInsight.lookup.*; -import com.intellij.openapi.util.Key; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementDecorator; import com.intellij.patterns.ElementPattern; -import com.intellij.patterns.PatternCondition; -import com.intellij.patterns.PsiElementPattern; -import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.filters.ElementExtractorFilter; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.OrFilter; import com.intellij.psi.filters.getters.ExpectedTypesGetter; -import com.intellij.psi.filters.getters.InstanceOfLeftPartTypeGetter; import com.intellij.psi.filters.getters.JavaMembersGetter; import com.intellij.psi.filters.types.AssignableFromFilter; import com.intellij.psi.filters.types.AssignableToFilter; -import com.intellij.psi.impl.source.PsiLabelReference; import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; import com.intellij.psi.infos.CandidateInfo; -import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import gnu.trove.TObjectHashingStrategy; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import static com.intellij.patterns.PlatformPatterns.psiElement; -import static com.intellij.patterns.PsiJavaPatterns.psiMethod; -import static com.intellij.patterns.StandardPatterns.*; +import static com.intellij.patterns.StandardPatterns.or; /** * @author peter @@ -70,7 +63,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor { }; private static final ElementExtractorFilter THROWABLES_FILTER = new ElementExtractorFilter(new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE)); - @NonNls private static final String EXCEPTION_TAG = "exception"; public static final ElementPattern AFTER_NEW = psiElement().afterLeaf( psiElement().withText(PsiKeyword.NEW).andNot( @@ -86,32 +78,19 @@ public class JavaSmartCompletionContributor extends CompletionContributor { static final ElementPattern INSIDE_TYPECAST_EXPRESSION = psiElement().withParent( psiElement(PsiReferenceExpression.class).afterLeaf( psiElement().withText(")").withParent(PsiTypeCastExpression.class))); - static final PsiElementPattern.Capture IN_TYPE_ARGS = - psiElement().inside(psiElement(PsiReferenceParameterList.class)); - static final PsiElementPattern.Capture LAMBDA = psiElement().with(new PatternCondition("LAMBDA_CONTEXT") { - @Override - public boolean accepts(@NotNull PsiElement element, ProcessingContext context) { - final PsiElement rulezzRef = element.getParent(); - return rulezzRef != null && - rulezzRef instanceof PsiReferenceExpression && - ((PsiReferenceExpression)rulezzRef).getQualifier() == null && - LambdaUtil.isValidLambdaContext(rulezzRef.getParent()); - }}); - - static final PsiElementPattern.Capture METHOD_REFERENCE = psiElement().with(new PatternCondition("METHOD_REFERENCE_CONTEXT") { - @Override - public boolean accepts(@NotNull PsiElement element, ProcessingContext context) { - final PsiElement rulezzRef = element.getParent(); - return rulezzRef != null && - LambdaUtil.isValidLambdaContext(rulezzRef.getParent()); - }}); @Nullable - private static ElementFilter getReferenceFilter(PsiElement element) { + private static ElementFilter getClassReferenceFilter(PsiElement element) { //throw new foo if (AFTER_THROW_NEW.accepts(element)) { return THROWABLES_FILTER; } + + //throws list + PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); + if (method != null && PsiTreeUtil.isAncestor(method.getThrowsList(), element, true)) { + return THROWABLES_FILTER; + } //new xxx.yyy if (psiElement().afterLeaf(psiElement().withText(".")).withSuperParent(2, psiElement(PsiNewExpression.class)).accepts(element)) { @@ -138,39 +117,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { extend(CompletionType.SMART, MethodReturnTypeProvider.IN_METHOD_RETURN_TYPE, new MethodReturnTypeProvider()); - extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.INSTANCEOF), new CompletionProvider() { - @Override - protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - final PsiElement position = parameters.getPosition(); - final PsiType[] leftTypes = InstanceOfLeftPartTypeGetter.getLeftTypes(position); - final Set expectedClassTypes = new LinkedHashSet(); - final Set parameterizedTypes = new THashSet(); - for (final PsiType type : leftTypes) { - if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; - if (!classType.isRaw()) { - ContainerUtil.addIfNotNull(classType.resolve(), parameterizedTypes); - } - - expectedClassTypes.add(classType.rawType()); - } - } - - JavaInheritorsGetter - .processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer() { - @Override - public void consume(PsiType type) { - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass == null || psiClass instanceof PsiTypeParameter) return; - - //noinspection SuspiciousMethodCalls - if (expectedClassTypes.contains(type)) return; - - result.addElement(createInstanceofLookupElement(psiClass, parameterizedTypes)); - } - }); - } - }); + extend(CompletionType.SMART, InstanceofTypeProvider.AFTER_INSTANCEOF, new InstanceofTypeProvider()); extend(CompletionType.SMART, psiElement(), new CompletionProvider() { @Override @@ -180,7 +127,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { final PsiElement element = parameters.getPosition(); final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset()); if (reference != null) { - ElementFilter filter = getReferenceFilter(element); + ElementFilter filter = getClassReferenceFilter(element); if (filter != null) { final List infos = Arrays.asList(getExpectedTypes(parameters)); for (final LookupElement item : completeReference(element, reference, filter, true, false, parameters, result.getPrefixMatcher())) { @@ -203,23 +150,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } }); - //method throws clause - extend(CompletionType.SMART, psiElement().inside( - psiElement(PsiReferenceList.class).save("refList").withParent( - psiMethod().withThrowsList(get("refList")))), new CompletionProvider() { - @Override - protected void addCompletions(@NotNull CompletionParameters parameters, - ProcessingContext context, - @NotNull CompletionResultSet result) { - final PsiElement element = parameters.getPosition(); - final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset()); - assert reference != null; - for (final LookupElement item : completeReference(element, reference, THROWABLES_FILTER, true, false, parameters, result.getPrefixMatcher())) { - result.addElement(item); - } - } - }); - extend(CompletionType.SMART, INSIDE_EXPRESSION, new ExpectedTypeBasedCompletionProvider() { @Override protected void addCompletions(final CompletionParameters params, final CompletionResultSet result, final Collection _infos) { @@ -245,12 +175,9 @@ public class JavaSmartCompletionContributor extends CompletionContributor { BasicExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(params, info), new Consumer() { @Override public void consume(LookupElement lookupElement) { - final TypedLookupItem typed = lookupElement.as(TypedLookupItem.CLASS_CONDITION_KEY); - if (typed != null) { - final PsiType psiType = typed.getType(); - if (psiType != null && info.getType().isAssignableFrom(psiType)) { - result.addElement(decorate(lookupElement, _infos)); - } + final PsiType psiType = JavaCompletionUtil.getLookupElementType(lookupElement); + if (psiType != null && info.getType().isAssignableFrom(psiType)) { + result.addElement(decorate(lookupElement, _infos)); } } }, result.getPrefixMatcher()); @@ -269,103 +196,18 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.SMART, or( - PsiJavaPatterns.psiElement().withParent(PsiNameValuePair.class), - PsiJavaPatterns.psiElement().withSuperParent(2, PsiNameValuePair.class)), new CompletionProvider() { - @Override - public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - final PsiElement element = parameters.getPosition(); + extend(CompletionType.SMART, ExpectedAnnotationsProvider.ANNOTATION_ATTRIBUTE_VALUE, new ExpectedAnnotationsProvider()); - for (final PsiType type : ExpectedTypesGetter.getExpectedTypes(element, false)) { - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass != null && psiClass.isAnnotationType()) { - result.addElement(AllClassesGetter.createLookupItem(psiClass, AnnotationInsertHandler.INSTANCE)); - } - } - - } - }); - - extend(CompletionType.SMART, psiElement().inside( - psiElement(PsiDocTag.class).withName( - string().oneOf(PsiKeyword.THROWS, EXCEPTION_TAG))), new CompletionProvider() { - @Override - public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - final PsiElement element = parameters.getPosition(); - final Set throwsSet = new HashSet(); - final PsiMethod method = PsiTreeUtil.getContextOfType(element, PsiMethod.class, true); - if(method != null){ - for (PsiClassType ref : method.getThrowsList().getReferencedTypes()) { - final PsiClass exception = ref.resolve(); - if (exception != null && throwsSet.add(exception)) { - result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception), TailType.HUMBLE_SPACE_BEFORE_WORD)); - } - } - } - - } - }); - - final Key tryKey = Key.create("try"); - extend(CompletionType.SMART, psiElement().insideStarting( - psiElement(PsiTypeElement.class).withParent( - psiElement(PsiCatchSection.class).withParent( - psiElement(PsiTryStatement.class).save(tryKey)))), new CompletionProvider() { - @Override - protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - final PsiCodeBlock tryBlock = context.get(tryKey).getTryBlock(); - if (tryBlock == null) return; - - final InheritorsHolder holder = new InheritorsHolder(result); - - for (final PsiClassType type : ExceptionUtil.getThrownExceptions(tryBlock.getStatements())) { - PsiClass typeClass = type.resolve(); - if (typeClass != null) { - result.addElement(createCatchTypeVariant(tryBlock, type)); - holder.registerClass(typeClass); - } - } - - final Collection expectedClassTypes = ContainerUtil.createMaybeSingletonList(JavaPsiFacade.getElementFactory( - tryBlock.getProject()).createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE)); - JavaInheritorsGetter.processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer() { - @Override - public void consume(PsiType type) { - final PsiClass psiClass = type instanceof PsiClassType ? ((PsiClassType)type).resolve() : null; - if (psiClass == null || psiClass instanceof PsiTypeParameter) return; - - if (!holder.alreadyProcessed(psiClass)) { - result.addElement(createCatchTypeVariant(tryBlock, (PsiClassType)type)); - } - } - }); - } - - @NotNull - private LookupElement createCatchTypeVariant(PsiCodeBlock tryBlock, PsiClassType type) { - return TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock), TailType.HUMBLE_SPACE_BEFORE_WORD); - } - }); - - extend(CompletionType.SMART, IN_TYPE_ARGS, new TypeArgumentCompletionProvider(true, null)); + extend(CompletionType.SMART, CatchTypeProvider.CATCH_CLAUSE_TYPE, new CatchTypeProvider()); + extend(CompletionType.SMART, TypeArgumentCompletionProvider.IN_TYPE_ARGS, new TypeArgumentCompletionProvider(true, null)); extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE)); - extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.BREAK, PsiKeyword.CONTINUE), new CompletionProvider() { - @Override - protected void addCompletions(@NotNull CompletionParameters parameters, - ProcessingContext context, - @NotNull CompletionResultSet result) { - PsiReference ref = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset()); - if (ref instanceof PsiLabelReference) { - JavaCompletionContributor.processLabelReference(result, (PsiLabelReference)ref); - } - } - }); + extend(CompletionType.SMART, LabelReferenceCompletion.LABEL_REFERENCE, new LabelReferenceCompletion()); - extend(CompletionType.SMART, LAMBDA, new FunctionalExpressionCompletionProvider()); - extend(CompletionType.SMART, METHOD_REFERENCE, new MethodReferenceCompletionProvider()); + extend(CompletionType.SMART, psiElement(), new FunctionalExpressionCompletionProvider()); + extend(CompletionType.SMART, psiElement(), new MethodReferenceCompletionProvider()); } @NotNull @@ -402,27 +244,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return new SmartCompletionDecorator(lookupElement, infos); } - private static LookupElement createInstanceofLookupElement(PsiClass psiClass, Set toWildcardInheritors) { - final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters(); - if (typeParameters.length > 0) { - for (final PsiClass parameterizedType : toWildcardInheritors) { - if (psiClass.isInheritor(parameterizedType, true)) { - PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; - final PsiWildcardType wildcard = PsiWildcardType.createUnbounded(psiClass.getManager()); - for (final PsiTypeParameter typeParameter : typeParameters) { - substitutor = substitutor.put(typeParameter, wildcard); - } - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject()); - return PsiTypeLookupItem.createLookupItem(factory.createType(psiClass, substitutor), psiClass); - } - } - } - - - return new JavaPsiClassReferenceElement(psiClass); - } - - @NotNull public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) { return getExpectedTypes(parameters, parameters.getCompletionType() == CompletionType.SMART); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/LabelReferenceCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/LabelReferenceCompletion.java new file mode 100644 index 000000000000..497214cd5f16 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/LabelReferenceCompletion.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 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.TailType; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.patterns.ElementPattern; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiKeyword; +import com.intellij.psi.PsiReference; +import com.intellij.psi.impl.source.PsiLabelReference; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.patterns.PlatformPatterns.psiElement; + +/** + * @author peter + */ +class LabelReferenceCompletion extends CompletionProvider { + static final ElementPattern LABEL_REFERENCE = psiElement().afterLeaf(PsiKeyword.BREAK, PsiKeyword.CONTINUE); + + static void processLabelReference(CompletionResultSet result, PsiLabelReference ref) { + for (String s : ref.getVariants()) { + result.addElement(TailTypeDecorator.withTail(LookupElementBuilder.create(s), TailType.SEMICOLON)); + } + } + + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + ProcessingContext context, + @NotNull CompletionResultSet result) { + PsiReference ref = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset()); + if (ref instanceof PsiLabelReference) { + processLabelReference(result, (PsiLabelReference)ref); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java index 4bf336995b1f..0dccb6175566 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MethodReferenceCompletionProvider.java @@ -40,6 +40,10 @@ public class MethodReferenceCompletionProvider extends CompletionProvider { + static final ElementPattern IN_TYPE_ARGS = psiElement().inside(PsiReferenceParameterList.class); private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.TypeArgumentCompletionProvider"); private final boolean mySmart; @Nullable private final InheritorsHolder myInheritors;