From 44a2ffa2fff97e6bd18172652d3d8b4f6a1001e8 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 13 Oct 2017 09:30:16 +0200 Subject: [PATCH] JavaKeywordCompletion: simplify make short code out of long ElementFilters remove dead logic cleanup unused filters also fixes IDEA-179855 Double "final" suggestion after annotation --- .../completion/JavaKeywordCompletion.java | 113 +++++------------- .../completion/ModifierChooser.java | 11 +- .../filters/position/AfterElementFilter.java | 45 ------- .../filters/position/StartElementFilter.java | 33 ----- .../psi/filters/position/TokenTypeFilter.java | 53 -------- .../finalAfterAnnotationAttributes.java | 3 + .../finalAfterAnnotationAttributes_after.java | 3 + .../completion/KeywordCompletionTest.java | 2 + .../position/PositionElementFilter.java | 8 -- .../psi/filters/position/AfterElement.java | 42 ------- .../psi/filters/position/LeftNeighbour.java | 3 + .../filters/position/SuperParentFilter.java | 41 ------- 12 files changed, 42 insertions(+), 315 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/psi/filters/position/AfterElementFilter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/position/StartElementFilter.java delete mode 100644 java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java create mode 100644 java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes.java create mode 100644 java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes_after.java delete mode 100644 platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java delete mode 100644 platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java index fe58d856404f..c5eb545fe984 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaKeywordCompletion.java @@ -21,17 +21,11 @@ import com.intellij.codeInsight.TailTypes; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; import com.intellij.codeInsight.lookup.*; -import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.Conditions; -import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PsiElementPattern; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.filters.*; -import com.intellij.psi.filters.position.*; -import com.intellij.psi.impl.source.jsp.jspJava.JspClassLevelDeclarationStatement; -import com.intellij.psi.jsp.JspElementType; import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -41,7 +35,6 @@ import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -63,59 +56,33 @@ public class JavaKeywordCompletion { psiElement().withTreeParent( psiElement(PsiParameterList.class).andNot(psiElement(PsiAnnotationParameterList.class))))); - private static final AndFilter START_OF_CODE_FRAGMENT = new AndFilter( - new ScopeFilter(new AndFilter( - new ClassFilter(JavaCodeFragment.class), - new ClassFilter(PsiExpressionCodeFragment.class, false), - new ClassFilter(PsiJavaCodeReferenceCodeFragment.class, false), - new ClassFilter(PsiTypeCodeFragment.class, false) - )), - new StartElementFilter() - ); + private static boolean isStatementCodeFragment(PsiFile file) { + return file instanceof JavaCodeFragment && + !(file instanceof PsiExpressionCodeFragment || + file instanceof PsiJavaCodeReferenceCodeFragment || + file instanceof PsiTypeCodeFragment); + } - static final NotNullLazyValue END_OF_BLOCK = new AtomicNotNullLazyValue() { - @NotNull - @Override - protected ElementFilter compute() { - return new OrFilter( - new AndFilter( - new LeftNeighbour( - new OrFilter( - new AndFilter ( - new TextFilter("{", "}", ";", ":", "else"), - new NotFilter ( - new SuperParentFilter(new ClassFilter(PsiAnnotation.class)) - ) - ), - new ElementFilter() { - @Override - public boolean isAcceptable(Object element, @Nullable PsiElement context) { - return ((PsiElement)element).getText().endsWith("*/"); - } - - @Override - public boolean isClassAcceptable(Class hintClass) { - return true; - } - }, - new TokenTypeFilter(JspElementType.HOLDER_TEMPLATE_DATA), - new ClassFilter(OuterLanguageElement.class), - new AndFilter( - new TextFilter(")"), - new NotFilter( - new OrFilter( - new ParentElementFilter(new ClassFilter(PsiExpressionList.class)), - new ParentElementFilter(new ClassFilter(PsiParameterList.class)), - new ParentElementFilter(new ClassFilter(PsiTypeCastExpression.class)) - ) - ) - ))), - new NotFilter(new TextFilter(".")) - ), - START_OF_CODE_FRAGMENT - ); + static boolean isEndOfBlock(@NotNull PsiElement element) { + PsiElement prev = prevSignificantLeaf(element); + if (prev == null) { + PsiFile file = element.getContainingFile(); + return !(file instanceof PsiCodeFragment) || isStatementCodeFragment(file); } - }; + + if (psiElement().inside(psiAnnotation()).accepts(prev)) return false; + + if (prev instanceof OuterLanguageElement) return true; + if (psiElement().withText(string().oneOf("{", "}", ";", ":", "else")).accepts(prev)) return true; + if (prev.textMatches(")")) { + PsiElement parent = prev.getParent(); + return !(parent instanceof PsiExpressionList || + parent instanceof PsiParameterList || + parent instanceof PsiTypeCastExpression); + } + + return false; + } static final ElementPattern START_SWITCH = psiElement().afterLeaf(psiElement().withText("{").withParents(PsiCodeBlock.class, PsiSwitchStatement.class)); @@ -135,16 +102,6 @@ public class JavaKeywordCompletion { PsiKeyword.CHAR, PsiKeyword.BYTE ); - private static final NotNullLazyValue CLASS_BODY = new AtomicNotNullLazyValue() { - @NotNull - @Override - protected ElementFilter compute() { - return new OrFilter( - new AfterElementFilter(new TextFilter("{")), - new ScopeFilter(new ClassFilter(JspClassLevelDeclarationStatement.class))); - } - }; - static final PsiElementPattern START_FOR = psiElement().afterLeaf(psiElement().withText("(").afterLeaf("for")); private static final ElementPattern CLASS_REFERENCE = psiElement().withParent(psiReferenceExpression().referencing(psiClass().andNot(psiElement(PsiTypeParameter.class)))); @@ -165,7 +122,6 @@ public class JavaKeywordCompletion { private final CompletionParameters myParameters; private final JavaCompletionSession mySession; private final PsiElement myPosition; - private final String myPrefix; private final PrefixMatcher myKeywordMatcher; private final List myResults = new ArrayList<>(); private final PsiElement myPrevLeaf; @@ -173,8 +129,7 @@ public class JavaKeywordCompletion { JavaKeywordCompletion(CompletionParameters parameters, JavaCompletionSession session) { myParameters = parameters; mySession = session; - myPrefix = session.getMatcher().getPrefix(); - myKeywordMatcher = new FixingLayoutPlainMatcher(myPrefix); + myKeywordMatcher = new FixingLayoutPlainMatcher(session.getMatcher().getPrefix()); myPosition = parameters.getPosition(); myPrevLeaf = prevSignificantLeaf(myPosition); @@ -494,7 +449,7 @@ public class JavaKeywordCompletion { addKeyword(new OverridableSpace(createKeyword(PsiKeyword.PACKAGE), TailType.HUMBLE_SPACE_BEFORE_WORD)); addKeyword(new OverridableSpace(createKeyword(PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD)); } - else if (END_OF_BLOCK.getValue().isAcceptable(myPosition, myPosition) && PsiTreeUtil.getParentOfType(myPosition, PsiMember.class) == null) { + else if (isEndOfBlock(myPosition) && PsiTreeUtil.getParentOfType(myPosition, PsiMember.class) == null) { addKeyword(new OverridableSpace(createKeyword(PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD)); } } @@ -637,7 +592,7 @@ public class JavaKeywordCompletion { return true; } - return END_OF_BLOCK.getValue().isAcceptable(position, position); + return isEndOfBlock(position); } static boolean isAfterPrimitiveOrArrayType(PsiElement element) { @@ -708,16 +663,6 @@ public class JavaKeywordCompletion { static boolean isDeclarationStart(@NotNull PsiElement position) { if (psiElement().afterLeaf("@", ".").accepts(position)) return false; - if (new FilterPattern(CLASS_BODY.getValue()).accepts(position)) { - if (new FilterPattern(END_OF_BLOCK.getValue()).accepts(position)) return true; - if (psiElement().afterLeaf(or( - psiElement().inside(PsiModifierList.class), - psiElement().withElementType(JavaTokenType.GT).inside(PsiTypeParameterList.class) - )).accepts(position)) { - return true; - } - } - PsiElement parent = position.getParent(); if (parent instanceof PsiJavaCodeReferenceElement && parent.getParent() instanceof PsiTypeElement) { PsiElement typeHolder = psiApi().parents(parent.getParent()).skipWhile(Conditions.instanceOf(PsiTypeElement.class)).first(); @@ -780,7 +725,7 @@ public class JavaKeywordCompletion { return false; } - if (END_OF_BLOCK.getValue().isAcceptable(position, position) && + if (isEndOfBlock(position) && PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, true, PsiMember.class) != null) { return !isForLoopMachinery(position); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java b/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java index bb41372cf570..b69b22681179 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ModifierChooser.java @@ -150,14 +150,7 @@ public class ModifierChooser { if (parent == null) return false; - PsiElement prev = FilterPositionUtil.searchNonSpaceNonCommentBack(element); - - if (parent instanceof PsiJavaFile || parent instanceof PsiClass) { - if (prev == null || JavaKeywordCompletion.END_OF_BLOCK.getValue().isAcceptable(element, prev.getParent())) { - return true; - } - } - - return false; + return (parent instanceof PsiJavaFile || parent instanceof PsiClass) && + JavaKeywordCompletion.isEndOfBlock(element); } } diff --git a/java/java-impl/src/com/intellij/psi/filters/position/AfterElementFilter.java b/java/java-impl/src/com/intellij/psi/filters/position/AfterElementFilter.java deleted file mode 100644 index b9b31ea56d35..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/position/AfterElementFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.psi.filters.position; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; - -public class AfterElementFilter extends PositionElementFilter{ - public AfterElementFilter(ElementFilter filter){ - setFilter(filter); - } - - @Override - public boolean isAcceptable(Object element, PsiElement scope){ - if (!(element instanceof PsiElement)) return false; - PsiElement currentChild = getOwnerChild(scope, (PsiElement) element); - PsiElement currentElement = scope.getFirstChild(); - while(currentElement != null){ - if(currentElement == currentChild) - break; - if(getFilter().isAcceptable(currentElement, scope)){ - return true; - } - currentElement = currentElement.getNextSibling(); - } - return false; - } - - public String toString(){ - return "after(" + getFilter().toString() + ")"; - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/position/StartElementFilter.java b/java/java-impl/src/com/intellij/psi/filters/position/StartElementFilter.java deleted file mode 100644 index 4616851596c6..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/position/StartElementFilter.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.psi.filters.position; - -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.FilterUtil; -import org.jdom.Element; - -public class StartElementFilter extends PositionElementFilter{ - @Override - public boolean isAcceptable(Object element, PsiElement context){ - if (!(element instanceof PsiElement)) return false; - return FilterUtil.getPreviousElement((PsiElement) element, false) == null; - } - - public String toString(){ - return "start"; - } -} diff --git a/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java b/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java deleted file mode 100644 index 8bbd784b9f50..000000000000 --- a/java/java-impl/src/com/intellij/psi/filters/position/TokenTypeFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2000-2014 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.psi.filters.position; - -import com.intellij.lang.ASTNode; -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.javadoc.PsiDocToken; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.xml.XmlToken; -import com.intellij.util.ReflectionUtil; - -public class TokenTypeFilter implements ElementFilter{ - private final IElementType myType; - - public TokenTypeFilter(IElementType type){ - myType = type; - } - - @Override - public boolean isClassAcceptable(Class hintClass){ - return ReflectionUtil.isAssignable(PsiDocToken.class, hintClass) || ReflectionUtil.isAssignable(XmlToken.class, hintClass); - } - - @Override - public boolean isAcceptable(Object element, PsiElement context){ - if(element instanceof PsiElement) { - final ASTNode node = ((PsiElement)element).getNode(); - return node != null && node.getElementType() == myType; - } - else if(element instanceof ASTNode){ - return ((ASTNode)element).getElementType() == myType; - } - return false; - } - - public String toString(){ - return "token-type(" + myType + ")"; - } -} diff --git a/java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes.java b/java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes.java new file mode 100644 index 000000000000..3166367db2a2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes.java @@ -0,0 +1,3 @@ +class A { + void foo(@Anno() fi) +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes_after.java b/java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes_after.java new file mode 100644 index 000000000000..0619c5c8262f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/finalAfterAnnotationAttributes_after.java @@ -0,0 +1,3 @@ +class A { + void foo(@Anno() final ) +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java index e90a9aafa7ee..1581c8dae3c0 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/KeywordCompletionTest.java @@ -164,6 +164,8 @@ public class KeywordCompletionTest extends LightCompletionTestCase { checkResultByTestName(); } + public void testFinalAfterAnnotationAttributes() { doTest(); } + public void testTryInExpression() { configureByTestName(); assertEquals("toString", myItems[0].getLookupString()); diff --git a/platform/core-impl/src/com/intellij/psi/filters/position/PositionElementFilter.java b/platform/core-impl/src/com/intellij/psi/filters/position/PositionElementFilter.java index 62233bbb2674..6fb65c10e20b 100644 --- a/platform/core-impl/src/com/intellij/psi/filters/position/PositionElementFilter.java +++ b/platform/core-impl/src/com/intellij/psi/filters/position/PositionElementFilter.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.filters.position; -import com.intellij.psi.PsiElement; import com.intellij.psi.filters.ElementFilter; public abstract class PositionElementFilter implements ElementFilter { @@ -33,11 +32,4 @@ public abstract class PositionElementFilter implements ElementFilter { public boolean isClassAcceptable(Class hintClass) { return true; } - - protected static PsiElement getOwnerChild(final PsiElement scope, PsiElement element) { - while (element != null && element.getParent() != scope) { - element = element.getParent(); - } - return element; - } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java b/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java deleted file mode 100644 index ee4feebabd79..000000000000 --- a/platform/lang-impl/src/com/intellij/psi/filters/position/AfterElement.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.filters.position; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.filters.FilterPositionUtil; -import org.jetbrains.annotations.Nullable; - -public class AfterElement extends PositionElementFilter { - - public AfterElement(ElementFilter filter){ - setFilter(filter); - } - - @Override - public boolean isAcceptable(Object element, @Nullable PsiElement context){ - if (!(element instanceof PsiElement)) return false; - final PsiElement previous = FilterPositionUtil.searchNonSpaceNonCommentBack((PsiElement) element, true); - if(previous != null){ - return getFilter().isAcceptable(previous, context); - } - return false; - } - - public String toString(){ - return "after(" +getFilter()+")"; - } -} diff --git a/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java b/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java index b5b759eab99e..f51c2d79badc 100644 --- a/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java +++ b/platform/lang-impl/src/com/intellij/psi/filters/position/LeftNeighbour.java @@ -20,6 +20,9 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.FilterPositionUtil; +/** + * @deprecated please consider using {@link com.intellij.patterns.ElementPattern} or checks in code instead + */ public class LeftNeighbour extends PositionElementFilter{ public LeftNeighbour(ElementFilter filter){ diff --git a/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java b/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java deleted file mode 100644 index 28de3faf3926..000000000000 --- a/platform/lang-impl/src/com/intellij/psi/filters/position/SuperParentFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.psi.filters.position; - -import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.ElementFilter; - -public class SuperParentFilter extends PositionElementFilter{ - public SuperParentFilter(ElementFilter filter){ - setFilter(filter); - } - - @Override - public boolean isAcceptable(Object element, PsiElement scope){ - if (!(element instanceof PsiElement)) return false; - while((element = ((PsiElement) element).getParent()) != null){ - if(getFilter().isAcceptable(element, scope)) - return true; - } - return false; - } - - - public String toString(){ - return "super-parent(" +getFilter()+")"; - } -}