KT-1630 Do not select automatically completion proposal in definition of lambda parameters
#KT-1630 fixed
This commit is contained in:
@@ -1128,27 +1128,20 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
// {(a, b) -> ...}
|
||||
|
||||
{
|
||||
PsiBuilder.Marker rollbackMarker = mark();
|
||||
boolean preferParamsToExpressions = isConfirmedParametersByComma();
|
||||
|
||||
PsiBuilder.Marker rollbackMarker = mark();
|
||||
parseFunctionLiteralParametersAndType();
|
||||
|
||||
paramsFound = rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
paramsFound = preferParamsToExpressions ?
|
||||
rollbackOrDrop(rollbackMarker, ARROW, "An -> is expected", RBRACE) :
|
||||
rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
}
|
||||
|
||||
if (!paramsFound) {
|
||||
// If not found, try a typeRef DOT and then LPAR .. RPAR ARROW
|
||||
// {((A) -> B).(x) -> ... }
|
||||
PsiBuilder.Marker rollbackMarker = mark();
|
||||
int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtSet(ARROW, RPAR)));
|
||||
if (lastDot >= 0) {
|
||||
createTruncatedBuilder(lastDot).parseTypeRef();
|
||||
if (at(DOT)) {
|
||||
advance(); // DOT
|
||||
parseFunctionLiteralParametersAndType();
|
||||
}
|
||||
}
|
||||
|
||||
paramsFound = rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
paramsFound = parseFunctionTypeDotParametersAndType();
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1157,69 +1150,21 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
// {a -> ...}
|
||||
// {a, b -> ...}
|
||||
PsiBuilder.Marker rollbackMarker = mark();
|
||||
boolean preferParamsToExpressions = (lookahead(1) == COMMA);
|
||||
parseFunctionLiteralShorthandParameterList();
|
||||
parseOptionalFunctionLiteralType();
|
||||
paramsFound = rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
|
||||
paramsFound = preferParamsToExpressions ?
|
||||
rollbackOrDrop(rollbackMarker, ARROW, "An -> is expected", RBRACE) :
|
||||
rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
}
|
||||
if (!paramsFound && atSet(JetParsing.TYPE_REF_FIRST)) {
|
||||
// Try to parse a type DOT valueParameterList ARROW
|
||||
// {A.(b) -> ...}
|
||||
PsiBuilder.Marker rollbackMarker = mark();
|
||||
int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtSet(ARROW, RBRACE)));
|
||||
if (lastDot >= 0) { // There is a receiver type
|
||||
createTruncatedBuilder(lastDot).parseTypeRef();
|
||||
}
|
||||
|
||||
if (at(DOT)) {
|
||||
advance(); // DOT
|
||||
parseFunctionLiteralParametersAndType();
|
||||
paramsFound = rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
}
|
||||
else {
|
||||
rollbackMarker.rollbackTo();
|
||||
}
|
||||
paramsFound = parseFunctionTypeDotParametersAndType();
|
||||
}
|
||||
// int doubleArrowPos = matchTokenStreamPredicate(new FirstBefore(new At(ARROW), new At(RBRACE)) {
|
||||
// @Override
|
||||
// public boolean isTopLevel(int openAngleBrackets, int openBrackets, int openBraces, int openParentheses) {
|
||||
// return openBraces == 0;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// boolean doubleArrowPresent = doubleArrowPos >= 0;
|
||||
// if (doubleArrowPresent) {
|
||||
// boolean dontExpectParameters = false;
|
||||
//
|
||||
// int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtOffset(doubleArrowPos)));
|
||||
// if (lastDot >= 0) { // There is a receiver type
|
||||
// createTruncatedBuilder(lastDot).parseTypeRef();
|
||||
//
|
||||
// expect(DOT, "Expecting '.'");
|
||||
//
|
||||
// if (!at(LPAR)) {
|
||||
// int firstLParPos = matchTokenStreamPredicate(new FirstBefore(new At(LPAR), new AtOffset(doubleArrowPos)));
|
||||
//
|
||||
// if (firstLParPos >= 0) {
|
||||
// errorUntilOffset("Expecting '('", firstLParPos);
|
||||
// } else {
|
||||
// errorUntilOffset("To specify a receiver type, use the full notation: {ReceiverType.(parameters) [: ReturnType] -> ...}",
|
||||
// doubleArrowPos);
|
||||
// dontExpectParameters = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// if (at(LPAR)) {
|
||||
// parseFunctionLiteralParametersAndType();
|
||||
// }
|
||||
// else if (!dontExpectParameters) {
|
||||
// parseFunctionLiteralShorthandParameterList();
|
||||
// }
|
||||
//
|
||||
// expectNoAdvance(ARROW, "Expecting '->'");
|
||||
// }
|
||||
}
|
||||
|
||||
if (!paramsFound) {
|
||||
if (preferBlock) {
|
||||
literal.drop();
|
||||
@@ -1231,6 +1176,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PsiBuilder.Marker body = mark();
|
||||
parseStatements();
|
||||
body.done(BLOCK);
|
||||
@@ -1252,6 +1198,25 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean rollbackOrDrop(PsiBuilder.Marker rollbackMarker,
|
||||
JetToken expected, String expectMessage,
|
||||
IElementType validForDrop) {
|
||||
if (at(expected)) {
|
||||
advance(); // dropAt
|
||||
rollbackMarker.drop();
|
||||
return true;
|
||||
}
|
||||
else if (at(validForDrop)) {
|
||||
rollbackMarker.drop();
|
||||
expect(expected, expectMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
rollbackMarker.rollbackTo();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SimpleName{,}
|
||||
*/
|
||||
@@ -1289,9 +1254,45 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
parameterList.done(VALUE_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
// Check that position is followed by top level comma. It can't be expression and we want it be
|
||||
// parsed as parameters in function literal
|
||||
private boolean isConfirmedParametersByComma() {
|
||||
assert _at(LPAR);
|
||||
PsiBuilder.Marker lparMarker = mark();
|
||||
advance(); // LPAR
|
||||
int comma = matchTokenStreamPredicate(new FirstBefore(new At(COMMA), new AtSet(ARROW, RPAR)));
|
||||
lparMarker.rollbackTo();
|
||||
return comma > 0;
|
||||
}
|
||||
|
||||
private boolean parseFunctionTypeDotParametersAndType() {
|
||||
PsiBuilder.Marker rollbackMarker = mark();
|
||||
|
||||
// True when it's confirmed that body of literal can't be simple expressions and we prefer to parse
|
||||
// it to function params if possible.
|
||||
boolean preferParamsToExpressions = false;
|
||||
|
||||
int lastDot = matchTokenStreamPredicate(new LastBefore(new At(DOT), new AtSet(ARROW, RPAR)));
|
||||
if (lastDot >= 0) {
|
||||
createTruncatedBuilder(lastDot).parseTypeRef();
|
||||
if (at(DOT)) {
|
||||
advance(); // DOT
|
||||
|
||||
if (at(LPAR)) {
|
||||
preferParamsToExpressions = isConfirmedParametersByComma();
|
||||
}
|
||||
|
||||
parseFunctionLiteralParametersAndType();
|
||||
}
|
||||
}
|
||||
|
||||
return preferParamsToExpressions ?
|
||||
rollbackOrDrop(rollbackMarker, ARROW, "An -> is expected", RBRACE) :
|
||||
rollbackOrDropAt(rollbackMarker, ARROW);
|
||||
}
|
||||
|
||||
private void parseFunctionLiteralParametersAndType() {
|
||||
parseFunctionLiteralParameterList();
|
||||
|
||||
parseOptionalFunctionLiteralType();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,4 +15,8 @@ fun foo() {
|
||||
|
||||
{a : b -> f}
|
||||
{T.a : b -> f}
|
||||
|
||||
{(a, b) }
|
||||
{T.(a, b) }
|
||||
{a, }
|
||||
}
|
||||
@@ -326,7 +326,66 @@ JetFile: FunctionLiterals_ERR.jet
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('f')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiErrorElement:Expecting '}'
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n\n ')
|
||||
FUNCTION_LITERAL_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
VALUE_PARAMETER
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
VALUE_PARAMETER
|
||||
PsiElement(IDENTIFIER)('b')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiErrorElement:An -> is expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
<empty list>
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n ')
|
||||
FUNCTION_LITERAL_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('T')
|
||||
PsiElement(DOT)('.')
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
VALUE_PARAMETER
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
VALUE_PARAMETER
|
||||
PsiElement(IDENTIFIER)('b')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiErrorElement:An -> is expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
<empty list>
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n ')
|
||||
FUNCTION_LITERAL_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
VALUE_PARAMETER_LIST
|
||||
VALUE_PARAMETER
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
PsiElement(COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
VALUE_PARAMETER
|
||||
PsiErrorElement:Expecting parameter name
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiErrorElement:Expecting '->' or ','
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
BLOCK
|
||||
<empty list>
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiErrorElement:Expecting '}'
|
||||
<empty list>
|
||||
@@ -109,6 +109,7 @@
|
||||
<completion.contributor language="jet" implementationClass="org.jetbrains.jet.plugin.liveTemplates.JetLiveTemplateCompletionContributor" id="liveTemplates" order="first"/>
|
||||
|
||||
<completion.confidence language="jet" implementationClass="com.intellij.codeInsight.completion.UnfocusedNameIdentifier"/>
|
||||
<completion.confidence language="jet" implementationClass="org.jetbrains.jet.plugin.completion.confidence.UnfocusedPossibleFunctionParameter"/>
|
||||
<completion.confidence language="jet" implementationClass="com.intellij.codeInsight.completion.AlwaysFocusLookup" order="last"/>
|
||||
|
||||
<completion.skip implementation="org.jetbrains.jet.plugin.liveTemplates.JetLiveTemplateCompletionContributor$Skipper" id="skipLiveTemplate"/>
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010-2012 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.jet.plugin.completion.confidence;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionConfidence;
|
||||
import com.intellij.codeInsight.completion.CompletionParameters;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ThreeState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
/**
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
public class UnfocusedPossibleFunctionParameter extends CompletionConfidence {
|
||||
@NotNull
|
||||
@Override
|
||||
public ThreeState shouldFocusLookup(@NotNull CompletionParameters parameters) {
|
||||
// 1. Do not automatically insert completion for first reference expression in block inside
|
||||
// function literal if it has no parameters yet.
|
||||
|
||||
// 2. The same but for the case when first expression is additionally surrounded with brackets
|
||||
|
||||
PsiElement position = parameters.getPosition();
|
||||
JetFunctionLiteralExpression functionLiteral = PsiTreeUtil.getParentOfType(
|
||||
position, JetFunctionLiteralExpression.class);
|
||||
|
||||
if (functionLiteral != null) {
|
||||
PsiElement expectedReference = position.getParent();
|
||||
if (expectedReference instanceof JetSimpleNameExpression) {
|
||||
if (PsiTreeUtil.findChildOfType(functionLiteral, JetParameterList.class) == null) {
|
||||
{
|
||||
// 1.
|
||||
PsiElement expectedBlock = expectedReference.getParent();
|
||||
if (expectedBlock instanceof JetBlockExpression) {
|
||||
if (expectedReference.getPrevSibling() == null) {
|
||||
return ThreeState.NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// 2.
|
||||
PsiElement expectedParenthesized = expectedReference.getParent();
|
||||
if (expectedParenthesized instanceof JetParenthesizedExpression) {
|
||||
PsiElement expectedBlock = expectedParenthesized.getParent();
|
||||
if (expectedBlock instanceof JetBlockExpression) {
|
||||
if (expectedParenthesized.getPrevSibling() == null) {
|
||||
return ThreeState.NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ThreeState.UNSURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args : Array<String>) {
|
||||
val mmm = 12
|
||||
val t = { <caret>}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args : Array<String>) {
|
||||
val mmm = 12
|
||||
val t = { mm }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args : Array<String>) {
|
||||
val mmm = 12
|
||||
val t = { (<caret>) }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args : Array<String>) {
|
||||
val mmm = 12
|
||||
val t = { (mm ) }
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args : Array<String>) {
|
||||
val mmm = 12
|
||||
val t = { i -> <caret>}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args : Array<String>) {
|
||||
val mmm = 12
|
||||
val t = { i -> mmm }
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.jet.completion.confidence;
|
||||
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.LightCompletionTestCase;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
@@ -37,6 +39,18 @@ public class JetConfidenceTest extends LightCompletionTestCase {
|
||||
doTest("pub");
|
||||
}
|
||||
|
||||
public void testInBeginningOfFunctionLiteral() {
|
||||
doTest("mm");
|
||||
}
|
||||
|
||||
public void testInBeginningOfFunctionLiteralInBrackets() {
|
||||
doTest("mm");
|
||||
}
|
||||
|
||||
public void testInBlockOfFunctionLiteral() {
|
||||
doTest("mm");
|
||||
}
|
||||
|
||||
protected void doTest(String completionActivateType) {
|
||||
configureByFile(getBeforeFileName());
|
||||
type(completionActivateType + " ");
|
||||
@@ -60,4 +74,9 @@ public class JetConfidenceTest extends LightCompletionTestCase {
|
||||
protected Sdk getProjectJDK() {
|
||||
return JavaSdk.getInstance().createJdk("JDK", SystemUtils.getJavaHome().getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void complete() {
|
||||
new CodeCompletionHandlerBase(CompletionType.BASIC, false, true, true).invokeCompletion(getProject(), getEditor(), 0, false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user