From d292b6bcfe2a6053e35a71700070d4e2c9e86124 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 7 Nov 2011 19:16:40 +0300 Subject: [PATCH] KT-193: Guard primary constructor modifier list with a lookahead for LPAR --- .../jet/lang/parsing/JetParsing.java | 24 +++-- .../psi/PrimaryConstructorModifiers_ERR.jet | 13 +++ .../psi/PrimaryConstructorModifiers_ERR.txt | 87 +++++++++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet create mode 100644 compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 57471dc7120..9a97153ce8d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -419,13 +419,27 @@ public class JetParsing extends AbstractJetParsing { expect(IDENTIFIER, "Class name expected", CLASS_NAME_RECOVERY_SET); boolean typeParametersDeclared = parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); - if (parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, false)) { + PsiBuilder.Marker beforeConstructorModifiers = mark(); + boolean hasConstructorModifiers = parseModifierList(PRIMARY_CONSTRUCTOR_MODIFIER_LIST, false); + + // Some modifiers found, but no parentheses following: class has already ended, and we are looking at something else + if (hasConstructorModifiers && !atSet(LPAR, LBRACE, COLON) ) { + beforeConstructorModifiers.rollbackTo(); + return CLASS; + } + + // We are still inside a class declaration + beforeConstructorModifiers.drop(); + + if (at(LPAR)) { parseValueParameterList(false, TokenSet.create(COLON, LBRACE)); } - else { - if (at(LPAR)) { - parseValueParameterList(false, TokenSet.create(COLON, LBRACE)); - } + else if (hasConstructorModifiers) { + // A comprehensive error message for cases like: + // class A private : Foo + // or + // class A private { + error("Expecting primary constructor parameter list"); } if (at(COLON)) { diff --git a/compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet new file mode 100644 index 00000000000..d24a9e56ab5 --- /dev/null +++ b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.jet @@ -0,0 +1,13 @@ +open class A + +open class AB private { + fun foo() {} +} + +class A1 { + +} + +open class B private () { + +} diff --git a/compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt new file mode 100644 index 00000000000..090d5cf7366 --- /dev/null +++ b/compiler/testData/psi/PrimaryConstructorModifiers_ERR.txt @@ -0,0 +1,87 @@ +JetFile: PrimaryConstructorModifiers_ERR.jet + NAMESPACE + CLASS + MODIFIER_LIST + PsiElement(open)('open') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace('\n\n') + TYPE_PARAMETER_LIST + + CLASS + MODIFIER_LIST + PsiElement(open)('open') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('AB') + PsiWhiteSpace(' ') + TYPE_PARAMETER_LIST + + PRIMARY_CONSTRUCTOR_MODIFIER_LIST + PsiElement(private)('private') + PsiErrorElement:Expecting primary constructor parameter list + + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A1') + PsiWhiteSpace(' ') + TYPE_PARAMETER_LIST + + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + PsiElement(open)('open') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('B') + TYPE_PARAMETER_LIST + PsiElement(LT)('<') + TYPE_PARAMETER + PsiElement(IDENTIFIER)('T') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + PsiElement(GT)('>') + PsiWhiteSpace(' ') + PRIMARY_CONSTRUCTOR_MODIFIER_LIST + PsiElement(private)('private') + PsiWhiteSpace(' ') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n\n') + PsiElement(RBRACE)('}') \ No newline at end of file