mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 09:19:13 +07:00
JavaKeywordCompletion: simplify
make short code out of long ElementFilters remove dead logic cleanup unused filters also fixes IDEA-179855 Double "final" suggestion after annotation
This commit is contained in:
@@ -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<ElementFilter> END_OF_BLOCK = new AtomicNotNullLazyValue<ElementFilter>() {
|
||||
@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<PsiElement> 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<ElementFilter> CLASS_BODY = new AtomicNotNullLazyValue<ElementFilter>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected ElementFilter compute() {
|
||||
return new OrFilter(
|
||||
new AfterElementFilter(new TextFilter("{")),
|
||||
new ScopeFilter(new ClassFilter(JspClassLevelDeclarationStatement.class)));
|
||||
}
|
||||
};
|
||||
|
||||
static final PsiElementPattern<PsiElement,?> START_FOR = psiElement().afterLeaf(psiElement().withText("(").afterLeaf("for"));
|
||||
private static final ElementPattern<PsiElement> 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<LookupElement> 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() + ")";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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 + ")";
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class A {
|
||||
void foo(@Anno() fi<caret>)
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class A {
|
||||
void foo(@Anno() final <caret>)
|
||||
}
|
||||
+2
@@ -164,6 +164,8 @@ public class KeywordCompletionTest extends LightCompletionTestCase {
|
||||
checkResultByTestName();
|
||||
}
|
||||
|
||||
public void testFinalAfterAnnotationAttributes() { doTest(); }
|
||||
|
||||
public void testTryInExpression() {
|
||||
configureByTestName();
|
||||
assertEquals("toString", myItems[0].getLookupString());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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()+")";
|
||||
}
|
||||
}
|
||||
@@ -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){
|
||||
|
||||
@@ -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()+")";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user