mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-93662 Groovy: complete type in tuple declarations
This commit is contained in:
@@ -59,6 +59,7 @@ lcurly.expected='{' expected
|
||||
comma.expected=',' expected
|
||||
rcurly.expected='}' expected
|
||||
rparen.expected=')' expected
|
||||
comma.or.rparen.expected=',' or ')' expected
|
||||
semi.expected=';' expected
|
||||
gt.expected='>' expected
|
||||
else.without.if='else' without 'if'
|
||||
|
||||
+7
-2
@@ -358,8 +358,9 @@ public class GroovyCompletionContributor extends CompletionContributor {
|
||||
|
||||
private static boolean couldContainReference(PsiElement position) {
|
||||
return IN_CATCH_TYPE.accepts(position) ||
|
||||
AFTER_AT.accepts(position) ||
|
||||
GroovyCompletionUtil.isFirstElementAfterPossibleModifiersInVariableDeclaration(position, true);
|
||||
AFTER_AT.accepts(position) ||
|
||||
GroovyCompletionUtil.isFirstElementAfterPossibleModifiersInVariableDeclaration(position, true) ||
|
||||
GroovyCompletionUtil.isTupleVarNameWithoutTypeDeclared(position);
|
||||
}
|
||||
|
||||
public static boolean isClassNamePossible(PsiElement position) {
|
||||
@@ -734,6 +735,10 @@ public class GroovyCompletionContributor extends CompletionContributor {
|
||||
iterator.advance();
|
||||
}
|
||||
|
||||
while (!iterator.atEnd() && WHITE_SPACES_OR_COMMENTS.contains(iterator.getTokenType())) {
|
||||
iterator.advance();
|
||||
}
|
||||
|
||||
if (!iterator.atEnd() && iterator.getTokenType() == mLPAREN) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+4
-2
@@ -106,7 +106,7 @@ public class GroovyCompletionData {
|
||||
for (String keyword : addExtendsImplements(position)) {
|
||||
result.addElement(keyword(keyword, TailType.HUMBLE_SPACE_BEFORE_WORD));
|
||||
}
|
||||
|
||||
|
||||
addExtendsForTypeParams(position, result);
|
||||
|
||||
registerControlCompletion(position, result);
|
||||
@@ -216,7 +216,7 @@ public class GroovyCompletionData {
|
||||
if (ext && impl) {
|
||||
return new String[]{PsiKeyword.EXTENDS, PsiKeyword.IMPLEMENTS};
|
||||
}
|
||||
|
||||
|
||||
return new String[]{ext ? PsiKeyword.EXTENDS : PsiKeyword.IMPLEMENTS};
|
||||
}
|
||||
|
||||
@@ -541,6 +541,8 @@ public class GroovyCompletionData {
|
||||
|
||||
}
|
||||
|
||||
if (isTupleVarNameWithoutTypeDeclared(context)) return true;
|
||||
|
||||
if (previous != null && GroovyTokenTypes.mAT.equals(previous.getNode().getElementType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+23
-8
@@ -186,10 +186,11 @@ public class GroovyCompletionUtil {
|
||||
return ((GrParameter)parent).getTypeElementGroovy() == null;
|
||||
}
|
||||
|
||||
final PsiElement parent1 = parent.getParent();
|
||||
if (!(parent1 instanceof GrVariableDeclaration)) return false;
|
||||
final PsiElement pparent = parent.getParent();
|
||||
if (!(pparent instanceof GrVariableDeclaration)) return false;
|
||||
if (((GrVariableDeclaration)pparent).isTuple()) return false;
|
||||
|
||||
final GrVariableDeclaration variableDeclaration = (GrVariableDeclaration)parent1;
|
||||
final GrVariableDeclaration variableDeclaration = (GrVariableDeclaration)pparent;
|
||||
if (variableDeclaration.getTypeElementGroovy() != null) return false;
|
||||
|
||||
return variableDeclaration.getVariables()[0] == parent;
|
||||
@@ -232,7 +233,6 @@ public class GroovyCompletionUtil {
|
||||
context.getParent().getParent().getParent().getParent() instanceof GrTypeDefinitionBody &&
|
||||
context.getTextRange().getStartOffset() ==
|
||||
context.getParent().getParent().getParent().getParent().getTextRange().getStartOffset();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -307,8 +307,8 @@ public class GroovyCompletionUtil {
|
||||
|
||||
private static boolean getterMatches(PrefixMatcher matcher, PsiMethod element, String importedName) {
|
||||
return isSimplePropertyGetter(element) &&
|
||||
(matcher.prefixMatches(getGetterNameNonBoolean(importedName)) ||
|
||||
element.getReturnType() == PsiType.BOOLEAN && matcher.prefixMatches(getGetterNameBoolean(importedName)));
|
||||
(matcher.prefixMatches(getGetterNameNonBoolean(importedName)) ||
|
||||
element.getReturnType() == PsiType.BOOLEAN && matcher.prefixMatches(getGetterNameBoolean(importedName)));
|
||||
}
|
||||
|
||||
public static LookupElement createClassLookupItem(PsiClass psiClass) {
|
||||
@@ -316,7 +316,9 @@ public class GroovyCompletionUtil {
|
||||
return AllClassesGetter.createLookupItem(psiClass, new GroovyClassNameInsertHandler());
|
||||
}
|
||||
|
||||
private static List<? extends LookupElement> generateLookupForImportedElement(GroovyResolveResult resolveResult, String importedName, boolean alias) {
|
||||
private static List<? extends LookupElement> generateLookupForImportedElement(GroovyResolveResult resolveResult,
|
||||
String importedName,
|
||||
boolean alias) {
|
||||
final PsiElement element = resolveResult.getElement();
|
||||
assert element != null;
|
||||
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
@@ -380,7 +382,10 @@ public class GroovyCompletionUtil {
|
||||
}
|
||||
|
||||
|
||||
private static LookupElementBuilder setTypeText(PsiElement element, LookupElementBuilder builder, PsiSubstitutor substitutor, @Nullable PsiElement position) {
|
||||
private static LookupElementBuilder setTypeText(PsiElement element,
|
||||
LookupElementBuilder builder,
|
||||
PsiSubstitutor substitutor,
|
||||
@Nullable PsiElement position) {
|
||||
PsiType type = null;
|
||||
if (element instanceof GrVariable) {
|
||||
if (position != null && GroovyRefactoringUtil.isLocalVariable(element)) {
|
||||
@@ -599,4 +604,14 @@ public class GroovyCompletionUtil {
|
||||
static boolean isTypelessParameter(PsiElement context) {
|
||||
return (context.getParent() instanceof GrParameter && ((GrParameter)context.getParent()).getTypeElementGroovy() == null);
|
||||
}
|
||||
|
||||
public static boolean isTupleVarNameWithoutTypeDeclared(PsiElement position) {
|
||||
PsiElement parent = position.getParent();
|
||||
PsiElement pparent = parent.getParent();
|
||||
return parent instanceof GrVariable &&
|
||||
((GrVariable)parent).getNameIdentifierGroovy() == position &&
|
||||
((GrVariable)parent).getTypeElementGroovy() == null &&
|
||||
pparent instanceof GrVariableDeclaration &&
|
||||
((GrVariableDeclaration)pparent).isTuple();
|
||||
}
|
||||
}
|
||||
|
||||
+43
-23
@@ -17,60 +17,80 @@ package org.jetbrains.plugins.groovy.lang.parser.parsing.statements;
|
||||
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyBundle;
|
||||
import org.jetbrains.plugins.groovy.lang.parser.parsing.types.TypeSpec;
|
||||
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
|
||||
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mCOMMA;
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mIDENT;
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mLPAREN;
|
||||
import static org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes.*;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
*/
|
||||
public class TupleParse {
|
||||
public static boolean parseTuple(PsiBuilder builder, @Nullable IElementType tupleType, IElementType componentType) {
|
||||
if (builder.getTokenType() != mLPAREN) return false;
|
||||
public static boolean parseTupleForAssignment(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = parseTuple(builder, REFERENCE_EXPRESSION, false);
|
||||
if (marker == null) return false;
|
||||
marker.done(TUPLE_EXPRESSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean parseTupleForVariableDeclaration(PsiBuilder builder) {
|
||||
PsiBuilder.Marker marker = parseTuple(builder, VARIABLE, true);
|
||||
if (marker == null) return false;
|
||||
marker.drop();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static PsiBuilder.Marker parseTuple(PsiBuilder builder, IElementType componentType, boolean acceptType) {
|
||||
if (builder.getTokenType() != mLPAREN) return null;
|
||||
|
||||
final PsiBuilder.Marker marker = builder.mark();
|
||||
builder.advanceLexer();
|
||||
int count = 0;
|
||||
do {
|
||||
//skip unnecessary commas
|
||||
while (ParserUtils.getToken(builder, mCOMMA)) {
|
||||
count++;
|
||||
builder.error(GroovyBundle.message("identifier.expected"));
|
||||
}
|
||||
|
||||
//parse modifiers for definitions
|
||||
PsiBuilder.Marker typeMarker = builder.mark();
|
||||
TypeSpec.parse(builder);
|
||||
if (builder.getTokenType() != mIDENT) {
|
||||
typeMarker.rollbackTo();
|
||||
if (acceptType) {
|
||||
//parse modifiers for definitions
|
||||
PsiBuilder.Marker typeMarker = builder.mark();
|
||||
TypeSpec.parse(builder);
|
||||
if (builder.getTokenType() != mIDENT) {
|
||||
typeMarker.rollbackTo();
|
||||
}
|
||||
else {
|
||||
typeMarker.drop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeMarker.drop();
|
||||
}
|
||||
PsiBuilder.Marker varMarker = builder.mark();
|
||||
|
||||
PsiBuilder.Marker componentMarker = builder.mark();
|
||||
if (!ParserUtils.getToken(builder, mIDENT)) {
|
||||
builder.error(GroovyBundle.message("identifier.expected"));
|
||||
varMarker.drop();
|
||||
componentMarker.drop();
|
||||
}
|
||||
else {
|
||||
varMarker.done(componentType);
|
||||
componentMarker.done(componentType);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
while (ParserUtils.getToken(builder, mCOMMA));
|
||||
|
||||
if (ParserUtils.getToken(builder, mRPAREN)) {
|
||||
if (tupleType != null) {
|
||||
marker.done(tupleType);
|
||||
}
|
||||
else {
|
||||
marker.drop();
|
||||
}
|
||||
return true;
|
||||
return marker;
|
||||
}
|
||||
else if (count > 0) { //accept tuple if there was at least one comma or parsed tuple element inside it
|
||||
builder.error(GroovyBundle.message("comma.or.rparen.expected"));
|
||||
return marker;
|
||||
}
|
||||
else {
|
||||
marker.rollbackTo();
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-9
@@ -203,16 +203,11 @@ public class VariableDefinitions implements GroovyElementTypes {
|
||||
}
|
||||
|
||||
private static IElementType parseDeclarator(PsiBuilder builder, boolean isTuple) {
|
||||
if (!isTuple) {
|
||||
if (builder.getTokenType() == mIDENT) {
|
||||
ParserUtils.getToken(builder, mIDENT);
|
||||
return mIDENT;
|
||||
}
|
||||
if (isTuple && builder.getTokenType() == mLPAREN && TupleParse.parseTupleForVariableDeclaration(builder)) {
|
||||
return TUPLE_DECLARATION;
|
||||
}
|
||||
else if (builder.getTokenType() == mLPAREN && isTuple) {
|
||||
if (TupleParse.parseTuple(builder, null, VARIABLE)) {
|
||||
return TUPLE_DECLARATION;
|
||||
}
|
||||
if (!isTuple && ParserUtils.getToken(builder, mIDENT)) {
|
||||
return mIDENT;
|
||||
}
|
||||
return WRONGWAY;
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class AssignmentExpression implements GroovyElementTypes {
|
||||
|
||||
private static boolean parseSide(PsiBuilder builder, GroovyParser parser, boolean tuple, boolean comExprAllowed) {
|
||||
if (tuple) {
|
||||
return TupleParse.parseTuple(builder, TUPLE_EXPRESSION, REFERENCE_EXPRESSION);
|
||||
return TupleParse.parseTupleForAssignment(builder);
|
||||
}
|
||||
|
||||
if (comExprAllowed) {
|
||||
|
||||
+1
@@ -95,6 +95,7 @@ public class KeywordCompletionTest extends CompletionTestBase {
|
||||
void testAssertInClosure() { doTest() }
|
||||
void testAfterLabel() { doTest() }
|
||||
void testKeywordsInParentheses() { doTest() }
|
||||
void testCompletionInTupleVar(){ doTest() }
|
||||
|
||||
String basePath = TestUtils.testDataPath + 'groovy/oldCompletion/keyword'
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
def (<caret>a, b) = [1, 2]
|
||||
-----
|
||||
boolean
|
||||
byte
|
||||
char
|
||||
double
|
||||
float
|
||||
i
|
||||
int
|
||||
integer
|
||||
long
|
||||
short
|
||||
void
|
||||
Reference in New Issue
Block a user