2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInsight.completion;
18 import com.intellij.codeInsight.ExpectedTypeInfo;
19 import com.intellij.codeInsight.TailType;
20 import com.intellij.codeInsight.TailTypes;
21 import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
22 import com.intellij.codeInsight.lookup.LookupElement;
23 import com.intellij.codeInsight.lookup.LookupItem;
24 import com.intellij.codeInsight.lookup.TailTypeDecorator;
25 import com.intellij.patterns.*;
26 import com.intellij.pom.java.LanguageLevel;
27 import com.intellij.psi.*;
28 import com.intellij.psi.filters.*;
29 import com.intellij.psi.filters.classes.EnumOrAnnotationTypeFilter;
30 import com.intellij.psi.filters.classes.InterfaceFilter;
31 import com.intellij.psi.filters.element.ReferenceOnFilter;
32 import com.intellij.psi.filters.getters.JavaMembersGetter;
33 import com.intellij.psi.filters.position.*;
34 import com.intellij.psi.filters.types.TypeCodeFragmentIsVoidEnabledFilter;
35 import com.intellij.psi.impl.source.jsp.jspJava.JspClassLevelDeclarationStatement;
36 import com.intellij.psi.jsp.JspElementType;
37 import com.intellij.psi.templateLanguages.OuterLanguageElement;
38 import com.intellij.psi.util.PsiTreeUtil;
39 import com.intellij.psi.util.PsiUtil;
40 import com.intellij.util.Consumer;
41 import com.intellij.util.ProcessingContext;
42 import org.jetbrains.annotations.NonNls;
44 import static com.intellij.patterns.PsiJavaPatterns.*;
45 import static com.intellij.patterns.StandardPatterns.not;
47 public class JavaCompletionData extends JavaAwareCompletionData{
49 private static final @NonNls String[] ourBlockFinalizers = {"{", "}", ";", ":", "else"};
50 private static final PsiElementPattern<PsiElement,?> AFTER_DOT = psiElement().afterLeaf(".");
51 public static final LeftNeighbour INSTANCEOF_PLACE = new LeftNeighbour(new OrFilter(
52 new ReferenceOnFilter(new ClassFilter(PsiVariable.class)),
53 new TextFilter(PsiKeyword.THIS),
54 new AndFilter(new TextFilter(")"), new ParentElementFilter(new AndFilter(
55 new ClassFilter(PsiTypeCastExpression.class, false),
57 new ParentElementFilter(new ClassFilter(PsiExpression.class)),
58 new ClassFilter(PsiExpression.class))))),
59 new AndFilter(new TextFilter("]"), new ParentElementFilter(new ClassFilter(PsiArrayAccessExpression.class)))));
60 public static final PsiJavaElementPattern.Capture<PsiElement> VARIABLE_AFTER_FINAL =
61 PsiJavaPatterns.psiElement().afterLeaf(PsiKeyword.FINAL).inside(PsiDeclarationStatement.class);
62 public static final LeftNeighbour AFTER_TRY_BLOCK = new LeftNeighbour(new AndFilter(
64 new ParentElementFilter(new AndFilter(
65 new LeftNeighbour(new TextFilter(PsiKeyword.TRY)),
66 new ParentElementFilter(new ClassFilter(PsiTryStatement.class)))
68 public static final PsiJavaElementPattern.Capture<PsiElement> INSIDE_PARAMETER_LIST =
69 PsiJavaPatterns.psiElement().withParent(
70 psiElement(PsiJavaCodeReferenceElement.class).insideStarting(
71 psiElement().withTreeParent(
72 psiElement(PsiParameterList.class).andNot(psiElement(PsiAnnotationParameterList.class)))));
74 private static final AndFilter START_OF_CODE_FRAGMENT = new AndFilter(
75 new ScopeFilter(new AndFilter(
76 new ClassFilter(JavaCodeFragment.class),
77 new ClassFilter(PsiExpressionCodeFragment.class, false),
78 new ClassFilter(PsiJavaCodeReferenceCodeFragment.class, false),
79 new ClassFilter(PsiTypeCodeFragment.class, false)
81 new StartElementFilter()
84 static final ElementFilter END_OF_BLOCK = new OrFilter(
89 new TextFilter(ourBlockFinalizers),
91 new SuperParentFilter(new ClassFilter(PsiAnnotation.class))
95 new TokenTypeFilter(JspElementType.HOLDER_TEMPLATE_DATA),
96 new ClassFilter(OuterLanguageElement.class),
101 new ParentElementFilter(new ClassFilter(PsiExpressionList.class)),
102 new ParentElementFilter(new ClassFilter(PsiParameterList.class)),
103 new ParentElementFilter(new ClassFilter(PsiTypeCastExpression.class))
107 new NotFilter(new TextFilter("."))
109 START_OF_CODE_FRAGMENT
112 static final ElementPattern<PsiElement> START_SWITCH = psiElement().afterLeaf(psiElement().withText("{").withParents(PsiCodeBlock.class, PsiSwitchStatement.class));
114 private static final ElementPattern<PsiElement> SUPER_OR_THIS_PATTERN =
115 and(JavaSmartCompletionContributor.INSIDE_EXPRESSION,
116 not(psiElement().afterLeaf(PsiKeyword.CASE)),
117 not(psiElement().afterLeaf(psiElement().withText(".").afterLeaf(PsiKeyword.THIS, PsiKeyword.SUPER))),
121 public static final AndFilter CLASS_START = new AndFilter(
124 new PatternFilter(psiElement().afterLeaf(
126 psiElement().withoutText(".").inside(psiElement(PsiModifierList.class)),
127 psiElement().isNull())))
129 new PatternFilter(not(psiElement().afterLeaf("@"))));
131 private static final String[] PRIMITIVE_TYPES = new String[]{
132 PsiKeyword.SHORT, PsiKeyword.BOOLEAN,
133 PsiKeyword.DOUBLE, PsiKeyword.LONG,
134 PsiKeyword.INT, PsiKeyword.FLOAT,
135 PsiKeyword.CHAR, PsiKeyword.BYTE
138 final static ElementFilter CLASS_BODY = new OrFilter(
139 new AfterElementFilter(new TextFilter("{")),
140 new ScopeFilter(new ClassFilter(JspClassLevelDeclarationStatement.class)));
141 public static final ElementPattern<PsiElement> START_FOR =
142 psiElement().afterLeaf(psiElement().withText("(").afterLeaf("for")).withParents(PsiJavaCodeReferenceElement.class,
143 PsiExpressionStatement.class, PsiForStatement.class);
144 private static final PsiJavaElementPattern.Capture<PsiElement> CLASS_REFERENCE =
145 psiElement().withParent(psiReferenceExpression().referencing(psiClass()));
146 public static final ElementPattern<PsiElement> EXPR_KEYWORDS = and(
147 psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(
149 or(psiElement(PsiTypeCastExpression.class),
150 psiElement(PsiSwitchLabelStatement.class),
151 psiElement(PsiExpressionStatement.class)
155 not(psiElement().afterLeaf("."))
158 public JavaCompletionData(){
159 declareCompletionSpaces();
161 initVariantsInFileScope();
162 initVariantsInClassScope();
163 initVariantsInMethodScope();
165 defineScopeEquivalence(PsiMethod.class, PsiClassInitializer.class);
166 defineScopeEquivalence(PsiMethod.class, JavaCodeFragment.class);
169 public static final ElementPattern<PsiElement> DECLARATION_START = psiElement().andNot(psiElement().afterLeaf("@", ".")).
171 psiElement().and(new FilterPattern(CLASS_BODY)).
173 new FilterPattern(END_OF_BLOCK),
174 psiElement().afterLeaf(or(
175 psiElement().inside(PsiModifierList.class),
176 psiElement().withElementType(JavaTokenType.GT).inside(PsiTypeParameterList.class)
178 psiElement().withParents(PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiMember.class),
179 psiElement().withParents(PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiClassLevelDeclarationStatement.class)
182 private void declareCompletionSpaces() {
183 declareFinalScope(PsiFile.class);
187 final CompletionVariant variant = new CompletionVariant(CLASS_BODY);
188 variant.includeScopeClass(PsiClass.class, true);
189 registerVariant(variant);
193 final CompletionVariant variant = new CompletionVariant(new AndFilter(new InsideElementFilter(new ClassFilter(PsiCodeBlock.class)),
194 new NotFilter(new InsideElementFilter(new ClassFilter(JspClassLevelDeclarationStatement.class)))));
195 variant.includeScopeClass(PsiMethod.class, true);
196 variant.includeScopeClass(PsiClassInitializer.class, true);
197 registerVariant(variant);
202 final CompletionVariant variant = new CompletionVariant(new AfterElementFilter(new TextFilter("=")));
203 variant.includeScopeClass(PsiField.class, true);
204 registerVariant(variant);
207 declareFinalScope(PsiLiteralExpression.class);
208 declareFinalScope(PsiComment.class);
211 protected void initVariantsInFileScope(){
212 // package keyword completion
214 final CompletionVariant variant = new CompletionVariant(PsiJavaFile.class, new StartElementFilter());
215 variant.addCompletion(PsiKeyword.PACKAGE, TailType.INSERT_SPACE);
216 registerVariant(variant);
219 // import keyword completion
221 final CompletionVariant variant = new CompletionVariant(PsiJavaFile.class, new OrFilter(
222 new StartElementFilter(),
225 variant.addCompletion(PsiKeyword.IMPORT);
227 registerVariant(variant);
229 // other in file scope
231 final CompletionVariant variant = new CompletionVariant(PsiJavaFile.class, CLASS_START);
232 variant.includeScopeClass(PsiClass.class);
234 variant.addCompletion(PsiKeyword.CLASS);
235 variant.addCompletion(PsiKeyword.INTERFACE);
237 registerVariant(variant);
241 final CompletionVariant variant = new CompletionVariant(PsiTypeCodeFragment.class, new StartElementFilter());
242 addPrimitiveTypes(variant, TailType.NONE);
243 final CompletionVariant variant1 = new CompletionVariant(PsiTypeCodeFragment.class,
245 new StartElementFilter(),
246 new TypeCodeFragmentIsVoidEnabledFilter()
249 variant1.addCompletion(PsiKeyword.VOID, TailType.NONE);
250 registerVariant(variant);
251 registerVariant(variant1);
258 * aClass == null for JspDeclaration scope
260 protected void initVariantsInClassScope() {
261 // Completion for extends keyword
264 final ElementFilter position = new AndFilter(
265 new NotFilter(CLASS_BODY),
266 new NotFilter(new AfterElementFilter(new ContentFilter(new TextFilter(PsiKeyword.EXTENDS)))),
267 new NotFilter(new AfterElementFilter(new ContentFilter(new TextFilter(PsiKeyword.IMPLEMENTS)))),
268 new NotFilter(new LeftNeighbour(new LeftNeighbour(new TextFilter("<", ",")))),
269 new NotFilter(new ScopeFilter(new EnumOrAnnotationTypeFilter())),
270 new LeftNeighbour(new OrFilter(
271 new ClassFilter(PsiIdentifier.class),
272 new TextFilter(">"))));
274 final CompletionVariant variant = new CompletionVariant(position);
275 variant.includeScopeClass(PsiClass.class, true);
276 variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
277 variant.excludeScopeClass(PsiAnonymousClass.class);
278 variant.excludeScopeClass(PsiTypeParameter.class);
280 registerVariant(variant);
282 // Completion for implements keyword
285 final ElementFilter position = new AndFilter(
286 new NotFilter(CLASS_BODY),
287 new NotFilter(new BeforeElementFilter(new ContentFilter(new TextFilter(PsiKeyword.EXTENDS)))),
288 new NotFilter(new AfterElementFilter(new ContentFilter(new TextFilter(PsiKeyword.IMPLEMENTS)))),
289 new NotFilter(new LeftNeighbour(new LeftNeighbour(new TextFilter("<", ",")))),
290 new LeftNeighbour(new OrFilter(
291 new ClassFilter(PsiIdentifier.class),
292 new TextFilter(">"))),
293 new NotFilter(new ScopeFilter(new InterfaceFilter())));
295 final CompletionVariant variant = new CompletionVariant(position);
296 variant.includeScopeClass(PsiClass.class, true);
297 variant.addCompletion(PsiKeyword.IMPLEMENTS, TailType.HUMBLE_SPACE_BEFORE_WORD);
298 variant.excludeScopeClass(PsiAnonymousClass.class);
300 registerVariant(variant);
305 final CompletionVariant variant = new CompletionVariant(PsiElement.class, psiElement().afterLeaf(
306 psiElement(PsiIdentifier.class).afterLeaf(
307 psiElement().withText(string().oneOf(",", "<")).withParent(PsiTypeParameterList.class))));
308 //variant.includeScopeClass(PsiClass.class, true);
309 variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
310 registerVariant(variant);
314 private void initVariantsInMethodScope() {
315 // Completion for classes in method throws section
318 final ElementFilter position = new LeftNeighbour(new AndFilter(
320 new ParentElementFilter(new ClassFilter(PsiParameterList.class))));
323 CompletionVariant variant = new CompletionVariant(PsiMethod.class, position);
324 variant.includeScopeClass(PsiClass.class); // for throws on separate line
325 variant.addCompletion(PsiKeyword.THROWS);
327 registerVariant(variant);
329 //in annotation methods
330 variant = new CompletionVariant(PsiAnnotationMethod.class, position);
331 variant.addCompletion(PsiKeyword.DEFAULT);
332 registerVariant(variant);
336 // instanceof keyword
337 final ElementFilter position = INSTANCEOF_PLACE;
338 final CompletionVariant variant = new CompletionVariant(position);
339 variant.includeScopeClass(PsiExpression.class, true);
340 variant.includeScopeClass(PsiMethod.class);
341 variant.addCompletion(PsiKeyword.INSTANCEOF);
343 registerVariant(variant);
347 // Keyword completion in returns !!!!
348 final CompletionVariant variant = new CompletionVariant(PsiMethod.class, new LeftNeighbour(new TextFilter(PsiKeyword.RETURN)));
349 variant.addCompletion(PsiKeyword.TRUE, TailType.NONE);
350 variant.addCompletion(PsiKeyword.FALSE, TailType.NONE);
351 registerVariant(variant);
355 // Catch/Finally completion
357 final ElementFilter position = AFTER_TRY_BLOCK;
359 final CompletionVariant variant = new CompletionVariant(position);
360 variant.includeScopeClass(PsiCodeBlock.class, true);
361 variant.addCompletion(PsiKeyword.CATCH, TailTypes.CATCH_LPARENTH);
362 variant.addCompletion(PsiKeyword.FINALLY, TailTypes.FINALLY_LBRACE);
363 registerVariant(variant);
366 // Catch/Finnaly completion
368 final ElementFilter position = new LeftNeighbour(new AndFilter(
370 new ParentElementFilter(new AndFilter(
371 new LeftNeighbour(new NotFilter(new TextFilter(PsiKeyword.TRY))),
373 new ParentElementFilter(new ClassFilter(PsiTryStatement.class)),
374 new ParentElementFilter(new ClassFilter(PsiCatchSection.class)))
377 final CompletionVariant variant = new CompletionVariant(position);
378 variant.includeScopeClass(PsiCodeBlock.class, false);
379 variant.addCompletion(PsiKeyword.CATCH, TailTypes.CATCH_LPARENTH);
380 variant.addCompletion(PsiKeyword.FINALLY, TailTypes.FINALLY_LBRACE);
381 registerVariant(variant);
384 // Completion for else expression
387 final ElementFilter position = new LeftNeighbour(
389 new AndFilter(new TextFilter("}"),new ParentElementFilter(new ClassFilter(PsiIfStatement.class), 3)),
390 new AndFilter(new TextFilter(";"),new ParentElementFilter(new ClassFilter(PsiIfStatement.class), 2))
392 final CompletionVariant variant = new CompletionVariant(PsiMethod.class, position);
393 variant.addCompletion(PsiKeyword.ELSE);
395 registerVariant(variant);
400 private static void addPrimitiveTypes(CompletionVariant variant, TailType tailType){
401 variant.addCompletion(PRIMITIVE_TYPES, tailType);
404 private static TailType getReturnTail(PsiElement position) {
405 PsiElement scope = position;
407 if (scope instanceof PsiFile || scope instanceof PsiClassInitializer){
408 return TailType.NONE;
411 if (scope instanceof PsiMethod){
412 final PsiMethod method = (PsiMethod)scope;
413 if(method.isConstructor() || PsiType.VOID.equals(method.getReturnType())) {
414 return TailType.SEMICOLON;
417 return TailType.HUMBLE_SPACE_BEFORE_WORD;
419 scope = scope.getParent();
423 private static void addStatementKeywords(CompletionResultSet variant, PsiElement position) {
424 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.SWITCH), TailTypes.SWITCH_LPARENTH));
425 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.WHILE), TailTypes.WHILE_LPARENTH));
426 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DO), TailType.createSimpleTailType('{')));
427 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.FOR), TailTypes.FOR_LPARENTH));
428 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.IF), TailTypes.IF_LPARENTH));
429 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.TRY), TailType.createSimpleTailType('{')));
430 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.THROW), TailType.INSERT_SPACE));
431 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE));
432 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.SYNCHRONIZED), TailTypes.SYNCHRONIZED_LPARENTH));
434 if (PsiUtil.getLanguageLevel(position).isAtLeast(LanguageLevel.JDK_1_4)) {
435 variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.ASSERT), TailType.INSERT_SPACE));
438 TailType returnTail = getReturnTail(position);
439 LookupElement ret = createKeyword(position, PsiKeyword.RETURN);
440 if (returnTail != TailType.NONE) {
441 ret = new OverrideableSpace(ret, returnTail);
443 variant.addElement(ret);
447 public void fillCompletions(CompletionParameters parameters, final CompletionResultSet result) {
448 final PsiElement position = parameters.getPosition();
449 if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) {
453 PsiStatement statement = PsiTreeUtil.getParentOfType(position, PsiExpressionStatement.class);
454 if (statement == null) {
455 statement = PsiTreeUtil.getParentOfType(position, PsiDeclarationStatement.class);
457 if (statement != null && statement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) {
458 if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).accepts(statement)) {
459 result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
463 if (isStatementPosition(position)) {
464 if (PsiTreeUtil.getParentOfType(position, PsiSwitchStatement.class, false, PsiMember.class) != null) {
465 result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.CASE), TailType.INSERT_SPACE));
466 result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.CASE_COLON));
467 if (START_SWITCH.accepts(position)) {
472 addBreakContinue(result, position);
473 addStatementKeywords(result, position);
476 if (SUPER_OR_THIS_PATTERN.accepts(position)) {
477 if (!AFTER_DOT.accepts(position) || isInsideQualifierClass(position)) {
478 result.addElement(createKeyword(position, PsiKeyword.THIS));
480 final LookupItem superItem = (LookupItem)createKeyword(position, PsiKeyword.SUPER);
481 if (psiElement().afterLeaf(psiElement().withText("{").withSuperParent(2, psiMethod().constructor(true))).accepts(position)) {
482 final PsiMethod method = PsiTreeUtil.getParentOfType(position, PsiMethod.class, false, PsiClass.class);
483 assert method != null;
484 final boolean hasParams = superConstructorHasParameters(method);
485 superItem.setInsertHandler(new ParenthesesInsertHandler<LookupElement>() {
487 protected boolean placeCaretInsideParentheses(InsertionContext context, LookupElement item) {
492 public void handleInsert(InsertionContext context, LookupElement item) {
493 super.handleInsert(context, item);
494 TailType.insertChar(context.getEditor(), context.getTailOffset(), ';');
499 result.addElement(superItem);
503 if (EXPR_KEYWORDS.accepts(position)) {
504 result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE));
505 result.addElement(createKeyword(position, PsiKeyword.NULL));
506 result.addElement(createKeyword(position, PsiKeyword.TRUE));
507 result.addElement(createKeyword(position, PsiKeyword.FALSE));
510 if (INSIDE_PARAMETER_LIST.accepts(position) && !psiElement().afterLeaf(PsiKeyword.FINAL).accepts(position) && !AFTER_DOT.accepts(position)) {
511 result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
514 if (CLASS_START.isAcceptable(position, position) &&
515 PsiTreeUtil.getNonStrictParentOfType(position, PsiLiteralExpression.class, PsiComment.class) == null) {
516 for (String s : ModifierChooser.getKeywords(position)) {
517 result.addElement(new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE_BEFORE_WORD));
521 addPrimitiveTypes(result, position);
523 if (isAfterTypeDot(position)) {
524 result.addElement(createKeyword(position, PsiKeyword.CLASS));
527 addUnfinishedMethodTypeParameters(position, result);
529 if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) &&
530 !BasicExpressionCompletionContributor.AFTER_DOT.accepts(position) &&
531 !(position.getParent() instanceof PsiLiteralExpression)) {
532 for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) {
533 new JavaMembersGetter(info.getDefaultType(), position).addMembers(parameters, parameters.getInvocationCount() > 1, new Consumer<LookupElement>() {
535 public void consume(LookupElement element) {
536 result.addElement(element);
543 private static void addUnfinishedMethodTypeParameters(PsiElement position, CompletionResultSet result) {
544 final ProcessingContext context = new ProcessingContext();
545 if (psiElement().inside(
546 psiElement(PsiTypeElement.class).afterLeaf(
547 psiElement().withText(">").withParent(
548 psiElement(PsiTypeParameterList.class).withParent(PsiErrorElement.class).save("typeParameterList")))).accepts(position, context)) {
549 final PsiTypeParameterList list = (PsiTypeParameterList)context.get("typeParameterList");
550 PsiElement current = list.getParent().getParent();
551 if (current instanceof PsiField) {
552 current = current.getParent();
554 if (current instanceof PsiClass) {
555 for (PsiTypeParameter typeParameter : list.getTypeParameters()) {
556 result.addElement(new JavaPsiClassReferenceElement(typeParameter));
562 static boolean isAfterPrimitiveOrArrayType(PsiElement element) {
563 return psiElement().withParent(
564 psiReferenceExpression().withFirstChild(
565 psiElement(PsiClassObjectAccessExpression.class).withLastChild(
566 not(psiElement().withText(PsiKeyword.CLASS))))).accepts(element);
569 static boolean isAfterTypeDot(PsiElement position) {
570 if (INSIDE_PARAMETER_LIST.accepts(position) || position.getContainingFile() instanceof PsiJavaCodeReferenceCodeFragment) {
574 return psiElement().afterLeaf(psiElement().withText(".").afterLeaf(CLASS_REFERENCE)).accepts(position) ||
575 isAfterPrimitiveOrArrayType(position);
578 private static void addPrimitiveTypes(CompletionResultSet result, PsiElement position) {
579 boolean inCast = psiElement()
580 .afterLeaf(psiElement().withText("(").withParent(psiElement(PsiParenthesizedExpression.class, PsiTypeCastExpression.class)))
583 boolean declaration = DECLARATION_START.accepts(position);
584 if (START_FOR.accepts(position) ||
585 INSIDE_PARAMETER_LIST.accepts(position) && !AFTER_DOT.accepts(position) ||
586 VARIABLE_AFTER_FINAL.accepts(position) ||
589 isStatementPosition(position)) {
590 for (String primitiveType : PRIMITIVE_TYPES) {
591 LookupElement keyword = createKeyword(position, primitiveType);
592 result.addElement(inCast ? keyword : new OverrideableSpace(keyword, TailType.HUMBLE_SPACE_BEFORE_WORD));
596 result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.VOID), TailType.HUMBLE_SPACE_BEFORE_WORD));
600 private static void addBreakContinue(CompletionResultSet result, PsiElement position) {
601 PsiLoopStatement loop = PsiTreeUtil.getParentOfType(position, PsiLoopStatement.class);
603 LookupElement br = createKeyword(position, PsiKeyword.BREAK);
604 LookupElement cont = createKeyword(position, PsiKeyword.CONTINUE);
606 if (psiElement().insideSequence(true, psiElement(PsiLabeledStatement.class),
607 or(psiElement(PsiFile.class), psiElement(PsiMethod.class),
608 psiElement(PsiClassInitializer.class))).accepts(position)) {
609 tailType = TailType.HUMBLE_SPACE_BEFORE_WORD;
612 tailType = TailType.SEMICOLON;
614 br = TailTypeDecorator.withTail(br, tailType);
615 cont = TailTypeDecorator.withTail(cont, tailType);
617 if (loop != null && new InsideElementFilter(new ClassFilter(PsiStatement.class)).isAcceptable(position, loop)) {
618 result.addElement(br);
619 result.addElement(cont);
621 if (psiElement().inside(PsiSwitchStatement.class).accepts(position)) {
622 result.addElement(br);
626 private static boolean isStatementPosition(PsiElement position) {
627 if (PsiTreeUtil.getNonStrictParentOfType(position, PsiLiteralExpression.class, PsiComment.class) != null) {
631 if (psiElement().withSuperParent(2, PsiConditionalExpression.class).accepts(position)) {
635 if (END_OF_BLOCK.isAcceptable(position, position) &&
636 PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, true, PsiMember.class) != null) {
640 if (psiElement().withParents(PsiReferenceExpression.class, PsiExpressionStatement.class, PsiIfStatement.class).accepts(position)) {
641 PsiElement stmt = position.getParent().getParent();
642 PsiIfStatement ifStatement = (PsiIfStatement)stmt.getParent();
643 if (ifStatement.getElseBranch() == stmt || ifStatement.getThenBranch() == stmt) {
651 private static LookupElement createKeyword(PsiElement position, String keyword) {
652 return BasicExpressionCompletionContributor.createKeywordLookupItem(position, keyword);
655 private static boolean isInsideQualifierClass(PsiElement position) {
656 if (position.getParent() instanceof PsiJavaCodeReferenceElement) {
657 final PsiElement qualifier = ((PsiJavaCodeReferenceElement)position.getParent()).getQualifier();
658 if (qualifier instanceof PsiJavaCodeReferenceElement) {
659 final PsiElement qualifierClass = ((PsiJavaCodeReferenceElement)qualifier).resolve();
660 if (qualifierClass instanceof PsiClass) {
661 PsiElement parent = position;
662 final PsiManager psiManager = position.getManager();
663 while ((parent = PsiTreeUtil.getParentOfType(parent, PsiClass.class, true)) != null) {
664 if (psiManager.areElementsEquivalent(parent, qualifierClass)) {
674 private static boolean superConstructorHasParameters(PsiMethod method) {
675 final PsiClass psiClass = method.getContainingClass();
676 if (psiClass == null) {
680 final PsiClass superClass = psiClass.getSuperClass();
681 if (superClass != null) {
682 for (final PsiMethod psiMethod : superClass.getConstructors()) {
683 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(method.getProject()).getResolveHelper();
684 if (resolveHelper.isAccessible(psiMethod, method, null) && psiMethod.getParameterList().getParameters().length > 0) {
692 private static class OverrideableSpace extends TailTypeDecorator<LookupElement> {
693 private final TailType myTail;
695 public OverrideableSpace(LookupElement keyword, TailType tail) {
701 protected TailType computeTailType(InsertionContext context) {
702 return context.shouldAddCompletionChar() ? TailType.NONE : myTail;