KT-1630 Do not select automatically completion proposal in definition of lambda parameters

#KT-1630 fixed
This commit is contained in:
Nikolay Krasko
2012-04-19 16:05:39 +04:00
parent 414966b27e
commit aa4e4623d4
12 changed files with 257 additions and 73 deletions
@@ -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, }
}
+63 -4
View File
@@ -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>
+1
View File
@@ -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"/>
@@ -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);
}
}