Parser: Recovery for parameter with missing name

This commit is contained in:
Alexey Sedunov
2015-04-03 15:51:50 +03:00
parent 7d4d3e537c
commit 4af608ef84
26 changed files with 501 additions and 9 deletions
@@ -1040,7 +1040,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
}
}
else {
if (at(IDENTIFIER)) {
if (at(IDENTIFIER) || at(COLON)) {
// Try to parse a simple name list followed by an ARROW
// {a -> ...}
// {a, b -> ...}
@@ -1123,7 +1123,12 @@ public class JetExpressionParsing extends AbstractJetParsing {
// int parameterNamePos = matchTokenStreamPredicate(new LastBefore(new At(IDENTIFIER), new AtOffset(doubleArrowPos)));
// createTruncatedBuilder(parameterNamePos).parseModifierList(MODIFIER_LIST, false);
expect(IDENTIFIER, "Expecting parameter name", TokenSet.create(ARROW));
if (at(COLON)) {
error("Expecting parameter name");
}
else {
expect(IDENTIFIER, "Expecting parameter name", TokenSet.create(ARROW));
}
if (at(COLON)) {
advance(); // COLON
@@ -638,7 +638,7 @@ public class JetParsing extends AbstractJetParsing {
beforeConstructorModifiers.drop();
if (at(LPAR)) {
parseValueParameterList(false, /* typeRequired = */ true, TokenSet.create(COLON, LBRACE));
parseValueParameterList(false, /* typeRequired = */ true, TokenSet.create(LBRACE));
primaryConstructorMarker.done(PRIMARY_CONSTRUCTOR);
}
else if (hasConstructorModifiers) {
@@ -877,12 +877,12 @@ public class JetParsing extends AbstractJetParsing {
advance(); // CONSTRUCTOR_KEYWORD
TokenSet valueArgsRecoverySet = TokenSet.create(COLON, LBRACE, SEMICOLON, RPAR, EOL_OR_SEMICOLON, RBRACE);
TokenSet valueArgsRecoverySet = TokenSet.create(LBRACE, SEMICOLON, RPAR, EOL_OR_SEMICOLON, RBRACE);
if (at(LPAR)) {
parseValueParameterList(false, /*typeRequired = */ true, valueArgsRecoverySet);
}
else {
errorWithRecovery("Expecting '('", valueArgsRecoverySet);
errorWithRecovery("Expecting '('", TokenSet.orSet(valueArgsRecoverySet, TokenSet.create(COLON)));
}
if (at(COLON)) {
@@ -1264,7 +1264,7 @@ public class JetParsing extends AbstractJetParsing {
myBuilder.restoreJoiningComplexTokensState();
TokenSet valueParametersFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON, RPAR);
TokenSet valueParametersFollow = TokenSet.create(EQ, LBRACE, SEMICOLON, RPAR);
if (at(LT)) {
PsiBuilder.Marker error = mark();
@@ -2056,10 +2056,17 @@ public class JetParsing extends AbstractJetParsing {
boolean noErrors = true;
// Recovery for the case 'fun foo(Array<String>) {}'
if (at(IDENTIFIER) && lookahead(1) == LT) {
// Recovery for the case 'fun foo(: Int) {}'
if ((at(IDENTIFIER) && lookahead(1) == LT) || at(COLON)) {
error("Parameter name expected");
if (at(COLON)) {
// We keep noErrors == true so that unnamed parameters starting with ":" are not rolled back during parsing of functional types
advance(); // COLON
}
else {
noErrors = false;
}
parseTypeRef();
noErrors = false;
}
else {
expect(IDENTIFIER, "Parameter name expected", PARAMETER_NAME_RECOVERY_SET);
@@ -0,0 +1,3 @@
fun foo(: Int) {
}
@@ -0,0 +1,24 @@
JetFile: firstInFunction.kt
PACKAGE_DIRECTIVE
<empty list>
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n')
PsiElement(RBRACE)('}')
@@ -0,0 +1 @@
val foo: (: Int) -> Int
@@ -0,0 +1,30 @@
JetFile: firstInFunctionalType.kt
PACKAGE_DIRECTIVE
<empty list>
PROPERTY
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
FUNCTION_TYPE
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(ARROW)('->')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
@@ -0,0 +1 @@
val foo = { : Int -> 0 }
@@ -0,0 +1,32 @@
JetFile: firstInLambda.kt
PACKAGE_DIRECTIVE
<empty list>
PROPERTY
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
PsiWhiteSpace(' ')
FUNCTION_LITERAL_EXPRESSION
FUNCTION_LITERAL
PsiElement(LBRACE)('{')
PsiWhiteSpace(' ')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiErrorElement:Expecting parameter name
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiWhiteSpace(' ')
PsiElement(ARROW)('->')
PsiWhiteSpace(' ')
BLOCK
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('0')
PsiWhiteSpace(' ')
PsiElement(RBRACE)('}')
@@ -0,0 +1,3 @@
class A(: Int) {
}
@@ -0,0 +1,25 @@
JetFile: firstInPrimaryConstructor.kt
PACKAGE_DIRECTIVE
<empty list>
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A')
PRIMARY_CONSTRUCTOR
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
CLASS_BODY
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n')
PsiElement(RBRACE)('}')
@@ -0,0 +1,5 @@
class A {
constructor(: Int) {
}
}
@@ -0,0 +1,35 @@
JetFile: firstInSecondaryConstructor.kt
PACKAGE_DIRECTIVE
<empty list>
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A')
PsiWhiteSpace(' ')
CLASS_BODY
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
SECONDARY_CONSTRUCTOR
PsiElement(constructor)('constructor')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
CONSTRUCTOR_DELEGATION_CALL
CONSTRUCTOR_DELEGATION_REFERENCE
<empty list>
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n ')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
@@ -0,0 +1,4 @@
val foo: Int
set(: Int) {
}
@@ -0,0 +1,33 @@
JetFile: firstInSetter.kt
PACKAGE_DIRECTIVE
<empty list>
PROPERTY
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiWhiteSpace('\n ')
PROPERTY_ACCESSOR
PsiElement(set)('set')
PsiElement(LPAR)('(')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiErrorElement:Expecting parameter name
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n ')
PsiElement(RBRACE)('}')
@@ -0,0 +1,3 @@
fun foo(s: String, : Int) {
}
@@ -0,0 +1,34 @@
JetFile: secondInFunction.kt
PACKAGE_DIRECTIVE
<empty list>
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('s')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('String')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n')
PsiElement(RBRACE)('}')
@@ -0,0 +1 @@
val foo: (s: String, : Int) -> Int
@@ -0,0 +1,40 @@
JetFile: secondInFunctionalType.kt
PACKAGE_DIRECTIVE
<empty list>
PROPERTY
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
FUNCTION_TYPE
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('s')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('String')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
PsiElement(ARROW)('->')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
@@ -0,0 +1 @@
val foo = { s: String, : Int -> 0 }
@@ -0,0 +1,42 @@
JetFile: secondInLambda.kt
PACKAGE_DIRECTIVE
<empty list>
PROPERTY
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('foo')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
PsiWhiteSpace(' ')
FUNCTION_LITERAL_EXPRESSION
FUNCTION_LITERAL
PsiElement(LBRACE)('{')
PsiWhiteSpace(' ')
VALUE_PARAMETER_LIST
VALUE_PARAMETER
PsiElement(IDENTIFIER)('s')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('String')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
VALUE_PARAMETER
PsiErrorElement:Expecting parameter name
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiWhiteSpace(' ')
PsiElement(ARROW)('->')
PsiWhiteSpace(' ')
BLOCK
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('0')
PsiWhiteSpace(' ')
PsiElement(RBRACE)('}')
@@ -0,0 +1,3 @@
class A(s: String, : Int) {
}
@@ -0,0 +1,35 @@
JetFile: secondInPrimaryConstructor.kt
PACKAGE_DIRECTIVE
<empty list>
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A')
PRIMARY_CONSTRUCTOR
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('s')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('String')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
CLASS_BODY
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n')
PsiElement(RBRACE)('}')
@@ -0,0 +1,5 @@
class A {
constructor(s: String, : Int) {
}
}
@@ -0,0 +1,45 @@
JetFile: secondInSecondaryConstructor.kt
PACKAGE_DIRECTIVE
<empty list>
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('A')
PsiWhiteSpace(' ')
CLASS_BODY
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
SECONDARY_CONSTRUCTOR
PsiElement(constructor)('constructor')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('s')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('String')
PsiElement(COMMA)(',')
PsiWhiteSpace(' ')
VALUE_PARAMETER
PsiErrorElement:Parameter name expected
<empty list>
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
CONSTRUCTOR_DELEGATION_CALL
CONSTRUCTOR_DELEGATION_REFERENCE
<empty list>
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n\n ')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
@@ -1450,6 +1450,7 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest {
@InnerTestClasses({
Recovery.Objects.class,
Recovery.QualifiedExpression.class,
Recovery.UnnamedParameter.class,
})
@RunWith(JUnit3RunnerWithInners.class)
public static class Recovery extends AbstractJetParsingTest {
@@ -1838,6 +1839,81 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest {
doParsingTest(fileName);
}
}
@TestMetadata("compiler/testData/psi/recovery/unnamedParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class UnnamedParameter extends AbstractJetParsingTest {
public void testAllFilesPresentInUnnamedParameter() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/psi/recovery/unnamedParameter"), Pattern.compile("^(.*)\\.kts?$"), true);
}
@TestMetadata("firstInFunction.kt")
public void testFirstInFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/firstInFunction.kt");
doParsingTest(fileName);
}
@TestMetadata("firstInFunctionalType.kt")
public void testFirstInFunctionalType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/firstInFunctionalType.kt");
doParsingTest(fileName);
}
@TestMetadata("firstInLambda.kt")
public void testFirstInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/firstInLambda.kt");
doParsingTest(fileName);
}
@TestMetadata("firstInPrimaryConstructor.kt")
public void testFirstInPrimaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/firstInPrimaryConstructor.kt");
doParsingTest(fileName);
}
@TestMetadata("firstInSecondaryConstructor.kt")
public void testFirstInSecondaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/firstInSecondaryConstructor.kt");
doParsingTest(fileName);
}
@TestMetadata("firstInSetter.kt")
public void testFirstInSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/firstInSetter.kt");
doParsingTest(fileName);
}
@TestMetadata("secondInFunction.kt")
public void testSecondInFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/secondInFunction.kt");
doParsingTest(fileName);
}
@TestMetadata("secondInFunctionalType.kt")
public void testSecondInFunctionalType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/secondInFunctionalType.kt");
doParsingTest(fileName);
}
@TestMetadata("secondInLambda.kt")
public void testSecondInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/secondInLambda.kt");
doParsingTest(fileName);
}
@TestMetadata("secondInPrimaryConstructor.kt")
public void testSecondInPrimaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/secondInPrimaryConstructor.kt");
doParsingTest(fileName);
}
@TestMetadata("secondInSecondaryConstructor.kt")
public void testSecondInSecondaryConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/recovery/unnamedParameter/secondInSecondaryConstructor.kt");
doParsingTest(fileName);
}
}
}
@TestMetadata("compiler/testData/psi/script")
@@ -1,5 +1,4 @@
// "class com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFixBase" "false"
// ERROR: Function 'f' must have a body
// ERROR: Unresolved reference: TTT
fun f(: Int) {