blob: 5791f4c48fb73482777fb828160ef26d3451fe67 [file] [log] [blame]
/*
* 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 org.jetbrains.plugins.groovy.lang.completion;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.TailTypes;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.JavaCompletionData;
import com.intellij.codeInsight.completion.ModifierChooser;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.lang.ASTNode;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.patterns.StandardPatterns;
import com.intellij.psi.*;
import com.intellij.psi.templateLanguages.OuterLanguageElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.lang.groovydoc.lexer.GroovyDocTokenTypes;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocInlinedTag;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.formatter.GrControlStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAnnotationMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
/**
* @author ilyas
*/
public class GroovyCompletionData {
public static final String[] BUILT_IN_TYPES = {"boolean", "byte", "char", "short", "int", "float", "long", "double", "void"};
public static final String[] MODIFIERS = new String[]{"private", "public", "protected", "transient", "abstract", "native", "volatile", "strictfp", "static"};
public static final ElementPattern<PsiElement> IN_CAST_TYPE_ELEMENT = StandardPatterns.or(
PsiJavaPatterns.psiElement().afterLeaf(PsiJavaPatterns.psiElement().withText("(").withParent(
PsiJavaPatterns.psiElement(GrParenthesizedExpression.class, GrTypeCastExpression.class))),
PsiJavaPatterns
.psiElement().afterLeaf(PsiJavaPatterns.psiElement().withElementType(GroovyTokenTypes.kAS).withParent(GrSafeCastExpression.class))
);
static final String[] INLINED_DOC_TAGS = {"code", "docRoot", "inheritDoc", "link", "linkplain", "literal"};
static final String[] DOC_TAGS = {"author", "deprecated", "exception", "param", "return", "see", "serial", "serialData",
"serialField", "since", "throws", "version"};
public static void addGroovyKeywords(CompletionParameters parameters, CompletionResultSet result) {
PsiElement position = parameters.getPosition();
PsiElement parent = position.getParent();
if (parent instanceof GrLiteral) {
return;
}
final String[] extendsImplements = addExtendsImplements(position);
for (String keyword : extendsImplements) {
result.addElement(keyword(keyword, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
if (extendsImplements.length > 0) {
return;
}
if (parent instanceof GrExpression && parent.getParent() instanceof GrAnnotationNameValuePair) {
addKeywords(result, false, PsiKeyword.TRUE, PsiKeyword.FALSE, PsiKeyword.NULL);
return;
}
if (afterAtInType(position)) {
result.addElement(keyword(PsiKeyword.INTERFACE, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
if (!PlatformPatterns.psiElement().afterLeaf(".", ".&", "@", "*.", "?.").accepts(position)) {
if (afterAbstractMethod(position, false, true)) {
result.addElement(keyword(PsiKeyword.THROWS, TailType.HUMBLE_SPACE_BEFORE_WORD));
if (afterAbstractMethod(position, false, false)) return;
}
if (suggestPackage(position)) {
result.addElement(keyword(PsiKeyword.PACKAGE, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
if (suggestImport(position)) {
result.addElement(keyword(PsiKeyword.IMPORT, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
addTypeDefinitionKeywords(result, position);
if (isAfterAnnotationMethodIdentifier(position)) {
result.addElement(keyword(PsiKeyword.DEFAULT, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
addExtendsForTypeParams(position, result);
registerControlCompletion(position, result);
if (parent instanceof GrExpression || isInfixOperatorPosition(position)) {
addKeywords(result, false, PsiKeyword.TRUE, PsiKeyword.FALSE, PsiKeyword.NULL, PsiKeyword.SUPER, PsiKeyword.THIS);
result.addElement(keyword(PsiKeyword.NEW, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
if (isAfterForParameter(position)) {
result.addElement(keyword("in", TailType.HUMBLE_SPACE_BEFORE_WORD));
}
if (isInfixOperatorPosition(position)) {
addKeywords(result, true, "as", "in", PsiKeyword.INSTANCEOF);
}
if (suggestPrimitiveTypes(position)) {
final boolean addSpace = !IN_CAST_TYPE_ELEMENT.accepts(position) && !GroovySmartCompletionContributor.AFTER_NEW.accepts(position) && !isInExpression(position);
addKeywords(result, addSpace, BUILT_IN_TYPES);
}
if (PsiJavaPatterns.psiElement(GrReferenceExpression.class).inside(
StandardPatterns.or(PsiJavaPatterns.psiElement(GrWhileStatement.class), PsiJavaPatterns.psiElement(GrForStatement.class))).accepts(parent)) {
addKeywords(result, false, PsiKeyword.BREAK, PsiKeyword.CONTINUE);
}
else if (PsiJavaPatterns.psiElement(GrReferenceExpression.class).inside(GrCaseSection.class).accepts(parent)) {
addKeywords(result, false, PsiKeyword.BREAK);
}
if (PsiJavaPatterns.psiElement().withSuperParent(2, GrImportStatement.class).accepts(position)) {
if (PsiJavaPatterns.psiElement().afterLeaf(PsiKeyword.IMPORT).accepts(position)) {
addKeywords(result, true, PsiKeyword.STATIC);
}
} else {
if (suggestModifiers(position)) {
addModifiers(position, result);
}
if (PsiJavaPatterns.psiElement().afterLeaf(MODIFIERS).accepts(position) ||
GroovyCompletionUtil.isInTypeDefinitionBody(position) && GroovyCompletionUtil.isNewStatement(position, true)) {
addKeywords(result, true, PsiKeyword.SYNCHRONIZED);
}
if (suggestFinalDef(position) || PsiJavaPatterns
.psiElement().afterLeaf(PsiJavaPatterns.psiElement().withText("(").withParent(GrForStatement.class)).accepts(position)) {
addKeywords(result, true, PsiKeyword.FINAL, "def");
}
}
}
}
private static boolean isAfterAnnotationMethodIdentifier(@NotNull PsiElement position) {
final PsiElement parent = position.getParent();
if (parent instanceof GrTypeDefinitionBody) {
final GrTypeDefinition containingClass = (GrTypeDefinition)parent.getParent();
if (containingClass.isAnnotationType()) {
PsiElement sibling = PsiUtil.skipWhitespacesAndComments(position.getPrevSibling(), false);
if (sibling instanceof PsiErrorElement) {
sibling = PsiUtil.skipWhitespacesAndComments(sibling.getPrevSibling(), false);
}
return sibling instanceof GrAnnotationMethod && ((GrAnnotationMethod)sibling).getDefaultValue() == null;
}
}
return false;
}
/**
* checks whether promitive type used in expression
*/
private static boolean isInExpression(PsiElement position) {
final PsiElement actual = position.getParent();
final PsiElement parent = actual.getParent();
return parent instanceof GrArgumentList || parent instanceof GrBinaryExpression;
}
private static void addExtendsForTypeParams(PsiElement position, CompletionResultSet result) {
if (GroovyCompletionUtil.isWildcardCompletion(position)) {
addKeywords(result, true, PsiKeyword.EXTENDS, PsiKeyword.SUPER);
}
}
private static boolean isAfterForParameter(PsiElement position) {
ElementPattern<PsiElement> forParameter =
PsiJavaPatterns.psiElement().withParents(GrParameter.class, GrTraditionalForClause.class, GrForStatement.class);
return PsiJavaPatterns.psiElement().withParent(GrReferenceExpression.class).afterLeaf(forParameter).accepts(position) ||
forParameter.accepts(position) && PsiJavaPatterns.psiElement().afterLeaf(PsiJavaPatterns.psiElement(GroovyTokenTypes.mIDENT)).accepts(position);
}
public static void addModifiers(PsiElement position, CompletionResultSet result) {
PsiClass scope = PsiTreeUtil.getParentOfType(position, PsiClass.class);
PsiModifierList modifierList = ModifierChooser.findModifierList(position);
addKeywords(result, true, ModifierChooser.addMemberModifiers(modifierList, scope != null && scope.isInterface()));
}
private static void addTypeDefinitionKeywords(CompletionResultSet result, PsiElement position) {
if (suggestClassInterfaceEnum(position)) {
addKeywords(result, true, PsiKeyword.CLASS, PsiKeyword.INTERFACE, PsiKeyword.ENUM, GroovyTokenTypes.kTRAIT.toString());
}
}
@NotNull
private static String[] addExtendsImplements(PsiElement context) {
if (context.getParent() == null) {
return ArrayUtil.EMPTY_STRING_ARRAY;
}
PsiElement elem = context.getParent();
boolean ext = !(elem instanceof GrExtendsClause);
boolean impl = !(elem instanceof GrImplementsClause);
if (elem instanceof GrTypeDefinitionBody) { //inner class
elem = PsiUtil.skipWhitespacesAndComments(context.getPrevSibling(), false);
}
else {
if (elem instanceof GrReferenceExpression && PsiUtil.skipWhitespacesAndComments(elem.getPrevSibling(), false) instanceof GrTypeDefinition) {
elem = PsiUtil.skipWhitespacesAndComments(elem.getPrevSibling(), false);
}
else if (elem.getParent() != null) {
elem = PsiUtil.skipWhitespacesAndComments(elem.getParent().getPrevSibling(), false);
}
}
ext &= elem instanceof GrInterfaceDefinition || elem instanceof GrClassDefinition || elem instanceof GrTraitTypeDefinition;
impl &= elem instanceof GrEnumTypeDefinition || elem instanceof GrClassDefinition || elem instanceof GrTraitTypeDefinition;
if (!ext && !impl) return ArrayUtil.EMPTY_STRING_ARRAY;
PsiElement[] children = elem.getChildren();
for (PsiElement child : children) {
ext &= !(child instanceof GrExtendsClause && ((GrExtendsClause)child).getKeyword() != null);
if (child instanceof GrImplementsClause && ((GrImplementsClause)child).getKeyword() != null || child instanceof GrTypeDefinitionBody) {
return ArrayUtil.EMPTY_STRING_ARRAY;
}
}
if (ext && impl) {
return new String[]{PsiKeyword.EXTENDS, PsiKeyword.IMPLEMENTS};
}
return new String[]{ext ? PsiKeyword.EXTENDS : PsiKeyword.IMPLEMENTS};
}
public static void addKeywords(CompletionResultSet result, boolean space, String... keywords) {
for (String s : keywords) {
result.addElement(keyword(s, space ? TailType.HUMBLE_SPACE_BEFORE_WORD : TailType.NONE));
}
}
private static LookupElement keyword(final String keyword, @NotNull TailType tail) {
LookupElementBuilder element = LookupElementBuilder.create(keyword).bold();
return tail != TailType.NONE ? new JavaCompletionData.OverrideableSpace(element, tail) : element;
}
private static void registerControlCompletion(PsiElement context, CompletionResultSet result) {
if (isControlStructure(context)) {
result.addElement(keyword(PsiKeyword.TRY, TailTypes.TRY_LBRACE));
result.addElement(keyword(PsiKeyword.WHILE, TailTypes.WHILE_LPARENTH));
result.addElement(keyword(PsiKeyword.SWITCH, TailTypes.SWITCH_LPARENTH));
result.addElement(keyword(PsiKeyword.FOR, TailTypes.FOR_LPARENTH));
result.addElement(keyword(PsiKeyword.THROW, TailType.HUMBLE_SPACE_BEFORE_WORD));
result.addElement(keyword(PsiKeyword.ASSERT, TailType.HUMBLE_SPACE_BEFORE_WORD));
result.addElement(keyword(PsiKeyword.SYNCHRONIZED, TailTypes.SYNCHRONIZED_LPARENTH));
result.addElement(keyword(PsiKeyword.RETURN, hasReturnValue(context) ? TailType.HUMBLE_SPACE_BEFORE_WORD : TailType.NONE));
}
if (inCaseSection(context)) {
result.addElement(keyword("case", TailType.HUMBLE_SPACE_BEFORE_WORD));
result.addElement(keyword("default", TailType.CASE_COLON));
}
if (afterTry(context)) {
result.addElement(keyword(PsiKeyword.CATCH, TailTypes.CATCH_LPARENTH));
result.addElement(keyword(PsiKeyword.FINALLY, TailTypes.FINALLY_LBRACE));
}
if (afterIfOrElse(context)) {
result.addElement(keyword(PsiKeyword.ELSE, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
if (isCommandCallWithOneArg(context)) {
result.addElement(keyword(PsiKeyword.ASSERT, TailType.HUMBLE_SPACE_BEFORE_WORD));
if (hasReturnValue(context)) {
result.addElement(keyword(PsiKeyword.RETURN, TailType.HUMBLE_SPACE_BEFORE_WORD));
}
}
}
private static boolean isCommandCallWithOneArg(PsiElement context) {
return context.getParent() instanceof GrReferenceExpression &&
context.getParent().getParent() instanceof GrApplicationStatement &&
((GrApplicationStatement)context.getParent().getParent()).getExpressionArguments().length == 1 &&
!PsiImplUtil.hasNamedArguments(((GrApplicationStatement)context.getParent().getParent()).getArgumentList());
}
private static boolean hasReturnValue(PsiElement context) {
GrControlFlowOwner flowOwner = ControlFlowUtils.findControlFlowOwner(context);
if (flowOwner instanceof GrClosableBlock) return true;
if (flowOwner instanceof GroovyFile) return true;
if (flowOwner == null) return true;
PsiElement parent = flowOwner.getParent();
if (parent instanceof GrMethod) {
return ((GrMethod)parent).getReturnType() != PsiType.VOID;
}
else if (parent instanceof GrClassInitializer) {
return false;
}
return true;
}
public static void addGroovyDocKeywords(CompletionParameters parameters, CompletionResultSet result) {
PsiElement position = parameters.getPosition();
if (PlatformPatterns.psiElement(GroovyDocTokenTypes.mGDOC_TAG_NAME).andNot(PlatformPatterns.psiElement().afterLeaf(".")).accepts(
position)) {
String[] tags = position.getParent() instanceof GrDocInlinedTag ? INLINED_DOC_TAGS : DOC_TAGS;
for (String docTag : tags) {
result.addElement(TailTypeDecorator.withTail(LookupElementBuilder.create(docTag), TailType.HUMBLE_SPACE_BEFORE_WORD));
}
}
}
private static boolean suggestPackage(PsiElement context) {
if (context.getParent() != null &&
!(context.getParent() instanceof PsiErrorElement) &&
context.getParent().getParent() instanceof GroovyFile &&
((GroovyFile) context.getParent().getParent()).getPackageDefinition() == null) {
if (context.getParent() instanceof GrReferenceExpression) {
return true;
}
if (context.getParent() instanceof GrApplicationStatement &&
((GrApplicationStatement) context.getParent()).getExpressionArguments()[0] instanceof GrReferenceExpression) {
return true;
}
return false;
}
if (context.getTextRange().getStartOffset() == 0 && !(context instanceof OuterLanguageElement)) {
return true;
}
final PsiElement leaf = GroovyCompletionUtil.getLeafByOffset(context.getTextRange().getStartOffset() - 1, context);
if (leaf != null) {
PsiElement parent = leaf.getParent();
if (parent instanceof GroovyFile) {
GroovyFile groovyFile = (GroovyFile) parent;
if (groovyFile.getPackageDefinition() == null) {
return GroovyCompletionUtil.isNewStatement(context, false);
}
}
}
return false;
}
private static boolean suggestImport(PsiElement context) {
if (context.getParent() != null &&
!(context.getParent() instanceof PsiErrorElement) &&
GroovyCompletionUtil.isNewStatement(context, false) &&
context.getParent().getParent() instanceof GroovyFile) {
return true;
}
final PsiElement leaf = GroovyCompletionUtil.getLeafByOffset(context.getTextRange().getStartOffset() - 1, context);
if (leaf != null) {
PsiElement parent = leaf.getParent();
if (parent instanceof GroovyFile) {
return GroovyCompletionUtil.isNewStatement(context, false);
}
}
return context.getTextRange().getStartOffset() == 0 && !(context instanceof OuterLanguageElement);
}
public static boolean suggestClassInterfaceEnum(PsiElement context) {
PsiElement nextNonSpace = PsiUtil.getNextNonSpace(context);
if (nextNonSpace instanceof PsiErrorElement) nextNonSpace = PsiUtil.getNextNonSpace(nextNonSpace);
if (afterAbstractMethod(context, true, false) && nextNonSpace != null && nextNonSpace.getText().startsWith("{") || addExtendsImplements(context).length > 0) {
return false;
}
PsiElement parent = context.getParent();
if (parent instanceof GrTypeDefinitionBody) {
return true;
}
if (parent instanceof GrReferenceExpression) {
if (parent.getParent() instanceof GroovyFile) {
return true;
}
if ((parent.getParent() instanceof GrApplicationStatement ||
parent.getParent() instanceof GrCall) &&
parent.getParent().getParent() instanceof GroovyFile) {
return true;
}
}
/*
@Anno
cl<caret>
*/
if (parent instanceof GrVariable && context == ((GrVariable)parent).getNameIdentifierGroovy()) {
final PsiElement decl = parent.getParent();
if (decl instanceof GrVariableDeclaration &&
!((GrVariableDeclaration)decl).isTuple() &&
((GrVariableDeclaration)decl).getTypeElementGroovy() == null &&
(decl.getParent() instanceof GrTypeDefinitionBody || decl.getParent() instanceof GroovyFile)) {
return true;
}
}
final PsiElement leaf = GroovyCompletionUtil.getLeafByOffset(context.getTextRange().getStartOffset() - 1, context);
if (leaf != null) {
PsiElement prev = leaf;
prev = PsiImplUtil.realPrevious(prev);
if (prev instanceof GrModifierList &&
prev.getParent() != null &&
prev.getParent().getParent() instanceof GroovyFile) {
return true;
}
if (leaf.getParent() instanceof GroovyFile) {
return GroovyCompletionUtil.isNewStatement(context, false);
}
}
return false;
}
private static boolean afterAtInType(PsiElement context) {
PsiElement previous = PsiImplUtil.realPrevious(PsiTreeUtil.prevLeaf(context));
if (previous != null &&
GroovyTokenTypes.mAT.equals(previous.getNode().getElementType()) &&
(context.getParent() != null && context.getParent().getParent() instanceof GroovyFile ||
context.getParent() instanceof GrCodeReferenceElement && context.getParent().getParent() instanceof GrAnnotation)) {
return true;
}
return false;
}
private static boolean isControlStructure(PsiElement context) {
final int offset = context.getTextRange().getStartOffset();
PsiElement prevSibling = context.getPrevSibling();
if (context.getParent() instanceof GrReferenceElement && prevSibling != null && prevSibling.getNode() != null) {
ASTNode node = prevSibling.getNode();
return !TokenSets.DOTS.contains(node.getElementType());
}
if (GroovyCompletionUtil.isNewStatement(context, true)) {
final PsiElement leaf = GroovyCompletionUtil.getLeafByOffset(offset - 1, context);
if (leaf != null && (leaf.getParent() instanceof GrStatementOwner || leaf.getParent() instanceof GrLabeledStatement)) {
return true;
}
}
if (context.getParent() != null) {
PsiElement parent = context.getParent();
if (parent instanceof GrExpression &&
parent.getParent() instanceof GroovyFile) {
return true;
}
if (parent instanceof GrReferenceExpression) {
PsiElement superParent = parent.getParent();
if (superParent instanceof GrStatementOwner ||
superParent instanceof GrLabeledStatement ||
superParent instanceof GrControlStatement ||
superParent instanceof GrMethodCall) {
return true;
}
}
return false;
}
return false;
}
private static boolean inCaseSection(PsiElement context) {
if (context.getParent() instanceof GrReferenceExpression &&
context.getParent().getParent() instanceof GrCaseSection) {
return true;
}
final GrSwitchStatement switchStatement = PsiTreeUtil.getParentOfType(context, GrSwitchStatement.class, true, GrCodeBlock.class);
if (switchStatement == null) return false;
final GrExpression condition = switchStatement.getCondition();
return condition == null || !PsiTreeUtil.isAncestor(condition, context, false);
}
private static boolean afterTry(PsiElement context) {
if (context != null &&
GroovyCompletionUtil.nearestLeftSibling(context) instanceof GrTryCatchStatement) {
GrTryCatchStatement tryStatement = (GrTryCatchStatement) GroovyCompletionUtil.nearestLeftSibling(context);
if (tryStatement == null) return false;
if (tryStatement.getFinallyClause() == null) {
return true;
}
}
if (context != null &&
GroovyCompletionUtil.nearestLeftSibling(context) instanceof PsiErrorElement &&
GroovyCompletionUtil.nearestLeftSibling(context).getPrevSibling() instanceof GrTryCatchStatement) {
GrTryCatchStatement tryStatement = (GrTryCatchStatement) GroovyCompletionUtil.nearestLeftSibling(context).getPrevSibling();
if (tryStatement == null) return false;
if (tryStatement.getFinallyClause() == null) {
return true;
}
}
if (context != null &&
(context.getParent() instanceof GrReferenceExpression || context.getParent() instanceof PsiErrorElement) &&
GroovyCompletionUtil.nearestLeftSibling(context.getParent()) instanceof GrTryCatchStatement) {
GrTryCatchStatement tryStatement = (GrTryCatchStatement) GroovyCompletionUtil.nearestLeftSibling(context.getParent());
if (tryStatement == null) return false;
if (tryStatement.getFinallyClause() == null) {
return true;
}
}
if (context != null &&
(context.getParent() instanceof GrReferenceExpression) &&
(context.getParent().getParent() instanceof GrMethodCall) &&
GroovyCompletionUtil.nearestLeftSibling(context.getParent().getParent()) instanceof GrTryCatchStatement) {
GrTryCatchStatement tryStatement = (GrTryCatchStatement) GroovyCompletionUtil.nearestLeftSibling(context.getParent().getParent());
if (tryStatement == null) return false;
if (tryStatement.getFinallyClause() == null) {
return true;
}
}
return false;
}
private static boolean afterIfOrElse(PsiElement context) {
if (context.getParent() != null &&
GroovyCompletionUtil.nearestLeftSibling(context.getParent()) instanceof GrIfStatement) {
return true;
}
if (context.getParent() != null &&
GroovyCompletionUtil.nearestLeftSibling(context.getParent()) instanceof PsiErrorElement &&
GroovyCompletionUtil.nearestLeftSibling(GroovyCompletionUtil.nearestLeftSibling(context.getParent())) instanceof GrIfStatement) {
return true;
}
if (context.getParent() != null &&
GroovyCompletionUtil.nearestLeftSibling(context) != null &&
GroovyCompletionUtil.nearestLeftSibling(context).getPrevSibling() instanceof GrIfStatement) {
GrIfStatement statement = (GrIfStatement) GroovyCompletionUtil.nearestLeftSibling(context).getPrevSibling();
if (statement.getElseBranch() == null) {
return true;
}
}
if (context.getParent() != null &&
context.getParent().getParent() instanceof GrCommandArgumentList &&
context.getParent().getParent().getParent().getParent() instanceof GrIfStatement) {
GrIfStatement statement = (GrIfStatement) context.getParent().getParent().getParent().getParent();
if (statement.getElseBranch() == null) {
return true;
}
}
return false;
}
private static boolean afterAbstractMethod(PsiElement context, boolean acceptAnnotationMethods, boolean skipNLs) {
PsiElement candidate;
if (GroovyCompletionUtil.isInTypeDefinitionBody(context)) {
PsiElement run = context;
while(!(run.getParent() instanceof GrTypeDefinitionBody)) {
run = run.getParent();
assert run != null;
}
candidate = PsiUtil.skipWhitespacesAndComments(run.getPrevSibling(), false, skipNLs);
}
else {
candidate = PsiUtil.skipWhitespacesAndComments(PsiTreeUtil.prevLeaf(context), false);
}
if (candidate instanceof PsiErrorElement) candidate = candidate.getPrevSibling();
return candidate instanceof GrMethod &&
((GrMethod)candidate).getBlock() == null &&
(acceptAnnotationMethods || !(candidate instanceof GrAnnotationMethod));
}
private static boolean suggestPrimitiveTypes(PsiElement context) {
if (isInfixOperatorPosition(context)) return false;
if (isAfterForParameter(context)) return false;
final PsiElement parent = context.getParent();
if (parent == null) return false;
PsiElement previous = PsiImplUtil.realPrevious(parent.getPrevSibling());
if (parent instanceof GrReferenceElement && parent.getParent() instanceof GrArgumentList) {
PsiElement prevSibling = context.getPrevSibling();
if (prevSibling != null && prevSibling.getNode() != null) {
if (!TokenSets.DOTS.contains(prevSibling.getNode().getElementType())) {
return true;
}
} else if (!(previous != null && GroovyTokenTypes.mAT.equals(previous.getNode().getElementType()))) {
return true;
}
}
if (GroovyCompletionUtil.isTupleVarNameWithoutTypeDeclared(context)) return true;
if (previous != null && GroovyTokenTypes.mAT.equals(previous.getNode().getElementType())) {
return false;
}
if (GroovyCompletionUtil.asSimpleVariable(context) ||
GroovyCompletionUtil.asTypedMethod(context) ||
GroovyCompletionUtil.asVariableInBlock(context) ||
asVariableAfterModifiers(context)) {
return true;
}
if ((parent instanceof GrParameter &&
((GrParameter)parent).getTypeElementGroovy() == null) ||
parent instanceof GrReferenceElement &&
!(parent.getParent() instanceof GrImportStatement) &&
!(parent.getParent() instanceof GrPackageDefinition) &&
!(parent.getParent() instanceof GrArgumentList)) {
PsiElement prevSibling = context.getPrevSibling();
if (parent instanceof GrReferenceElement && prevSibling != null && prevSibling.getNode() != null) {
ASTNode node = prevSibling.getNode();
return !TokenSets.DOTS.contains(node.getElementType());
} else {
return true;
}
}
if (PsiImplUtil.realPrevious(parent.getPrevSibling()) instanceof GrModifierList) {
return true;
}
if (PsiImplUtil.realPrevious(context.getPrevSibling()) instanceof GrModifierList) {
return true;
}
return parent instanceof GrExpression &&
parent.getParent() instanceof GroovyFile &&
GroovyCompletionUtil.isNewStatement(context, false);
}
private static boolean asVariableAfterModifiers(PsiElement context) {
final PsiElement parent = context.getParent();
if (parent instanceof GrVariable && context == ((GrVariable)parent).getNameIdentifierGroovy()) {
final PsiElement decl = parent.getParent();
if (decl instanceof GrVariableDeclaration &&
!((GrVariableDeclaration)decl).isTuple() &&
((GrVariableDeclaration)decl).getTypeElementGroovy() == null) {
return true;
}
}
return false;
}
private static boolean isInfixOperatorPosition(PsiElement context) {
if (context.getParent() != null &&
context.getParent() instanceof GrReferenceExpression &&
context.getParent().getParent() != null &&
context.getParent().getParent() instanceof GrCommandArgumentList) {
return true;
}
if (GroovyCompletionUtil.nearestLeftSibling(context) instanceof PsiErrorElement &&
GroovyCompletionUtil.endsWithExpression(GroovyCompletionUtil.nearestLeftSibling(context).getPrevSibling())) {
return true;
}
if (context.getParent() instanceof GrReferenceExpression &&
GroovyCompletionUtil.nearestLeftLeaf(context) instanceof PsiErrorElement &&
GroovyCompletionUtil.endsWithExpression(GroovyCompletionUtil.nearestLeftLeaf(context).getPrevSibling())) {
return true;
}
if (context.getParent() instanceof PsiErrorElement &&
GroovyCompletionUtil.endsWithExpression(GroovyCompletionUtil.nearestLeftSibling(context.getParent()))) {
return true;
}
return false;
}
private static boolean suggestModifiers(PsiElement context) {
if (GroovyCompletionUtil.asSimpleVariable(context) ||
GroovyCompletionUtil.asTypedMethod(context) ||
GroovyCompletionUtil.isNewStatementInScript(context)) {
return true;
}
if (GroovyCompletionUtil.isFirstElementAfterPossibleModifiersInVariableDeclaration(context, false) &&
!PsiJavaPatterns.psiElement().afterLeaf("def").accepts(context)) {
return true;
}
if (PsiJavaPatterns.psiElement().afterLeaf(MODIFIERS).accepts(context) || PsiJavaPatterns.psiElement().afterLeaf("synchronized").accepts(context)) {
return true;
}
final PsiElement contextParent = context.getParent();
if (contextParent instanceof GrReferenceElement && contextParent.getParent() instanceof GrTypeElement) {
PsiElement parent = contextParent.getParent().getParent();
if (parent instanceof GrVariableDeclaration &&
(parent.getParent() instanceof GrTypeDefinitionBody || parent.getParent() instanceof GroovyFile) || parent instanceof GrMethod) {
return true;
}
}
if (contextParent instanceof GrField) {
final GrVariable variable = (GrVariable)contextParent;
if (variable.getTypeElementGroovy() == null) {
return true;
}
}
if (contextParent instanceof GrExpression &&
contextParent.getParent() instanceof GroovyFile &&
GroovyCompletionUtil.isNewStatement(context, false)) {
return true;
}
if (context.getTextRange().getStartOffset() == 0 && !(context instanceof OuterLanguageElement)) {
return true;
}
return contextParent instanceof GrExpression &&
contextParent.getParent() instanceof GrApplicationStatement &&
contextParent.getParent().getParent() instanceof GroovyFile &&
GroovyCompletionUtil.isNewStatement(context, false);
}
public static boolean suggestFinalDef(PsiElement context) {
if (GroovyCompletionUtil.asSimpleVariable(context) ||
GroovyCompletionUtil.asTypedMethod(context) ||
GroovyCompletionUtil.asVariableInBlock(context) ||
GroovyCompletionUtil.isNewStatementInScript(context) && !GroovyCompletionUtil.isReferenceElementInNewExpr(context) ||
GroovyCompletionUtil.isTypelessParameter(context) ||
GroovyCompletionUtil.isCodeReferenceElementApplicableToModifierCompletion(context)) {
return true;
}
if (PsiImplUtil.realPrevious(context.getParent().getPrevSibling()) instanceof GrModifierList) {
return true;
}
if (PsiImplUtil.realPrevious(context.getPrevSibling()) instanceof GrModifierList) {
return true;
}
return context.getParent() instanceof GrExpression &&
context.getParent().getParent() instanceof GroovyFile &&
GroovyCompletionUtil.isNewStatement(context, false);
}
}