diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java index ade86b34f06..23b80eb3fe8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java @@ -1277,9 +1277,11 @@ public class JetParsing extends AbstractJetParsing { consumeIf(SEMICOLON); } - if (parsePropertyGetterOrSetter()) { - parsePropertyGetterOrSetter(); + AccessorKind accessorKind = parsePropertyGetterOrSetter(null); + if (accessorKind != null) { + parsePropertyGetterOrSetter(accessorKind); } + if (!atSet(EOL_OR_SEMICOLON, RBRACE)) { if (getLastToken() != SEMICOLON) { errorUntil("Property getter or setter expected", TokenSet.create(EOL_OR_SEMICOLON, LBRACE, RBRACE)); @@ -1346,6 +1348,8 @@ public class JetParsing extends AbstractJetParsing { myBuilder.restoreNewlinesState(); } + private enum AccessorKind { GET, SET} + /* * getterOrSetter * : modifiers ("get" | "set") @@ -1356,17 +1360,29 @@ public class JetParsing extends AbstractJetParsing { * ) functionBody * ; */ - private boolean parsePropertyGetterOrSetter() { + @Nullable + private AccessorKind parsePropertyGetterOrSetter(@Nullable AccessorKind notAllowedKind) { PsiBuilder.Marker getterOrSetter = mark(); parseModifierList(DEFAULT, TokenSet.EMPTY); - if (!at(GET_KEYWORD) && !at(SET_KEYWORD)) { + AccessorKind accessorKind; + if (at(GET_KEYWORD)) { + accessorKind = AccessorKind.GET; + } + else if (at(SET_KEYWORD)) { + accessorKind = AccessorKind.SET; + } + else { getterOrSetter.rollbackTo(); - return false; + return null; + } + + if (accessorKind == notAllowedKind) { + getterOrSetter.rollbackTo(); + return null; } - boolean setter = at(SET_KEYWORD); advance(); // GET_KEYWORD or SET_KEYWORD if (!at(LPAR)) { @@ -1377,13 +1393,13 @@ public class JetParsing extends AbstractJetParsing { } else { closeDeclarationWithCommentBinders(getterOrSetter, PROPERTY_ACCESSOR, false); - return true; + return accessorKind; } } myBuilder.disableNewlines(); expect(LPAR, "Expecting '('", TokenSet.create(RPAR, IDENTIFIER, COLON, LBRACE, EQ)); - if (setter) { + if (accessorKind == AccessorKind.SET) { PsiBuilder.Marker parameterList = mark(); PsiBuilder.Marker setterParameter = mark(); parseModifierList(DEFAULT, TokenSet.create(COMMA, COLON, RPAR)); @@ -1414,7 +1430,7 @@ public class JetParsing extends AbstractJetParsing { closeDeclarationWithCommentBinders(getterOrSetter, PROPERTY_ACCESSOR, false); - return true; + return accessorKind; } /* diff --git a/compiler/testData/psi/DuplicateAccessor.kt b/compiler/testData/psi/DuplicateAccessor.kt new file mode 100644 index 00000000000..f544b5183b6 --- /dev/null +++ b/compiler/testData/psi/DuplicateAccessor.kt @@ -0,0 +1,3 @@ +val a : Int + get() = 0 + get() = 0 diff --git a/compiler/testData/psi/DuplicateAccessor.txt b/compiler/testData/psi/DuplicateAccessor.txt new file mode 100644 index 00000000000..1a5c0fc4889 --- /dev/null +++ b/compiler/testData/psi/DuplicateAccessor.txt @@ -0,0 +1,39 @@ +JetFile: DuplicateAccessor.kt + PACKAGE_DIRECTIVE + + IMPORT_LIST + + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('a') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiWhiteSpace('\n ') + PROPERTY_ACCESSOR + PsiElement(get)('get') + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('0') + PsiWhiteSpace('\n ') + PsiErrorElement:Expecting a top level declaration + PsiElement(get)('get') + PsiErrorElement:Expecting a top level declaration + PsiElement(LPAR)('(') + PsiErrorElement:Expecting a top level declaration + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiErrorElement:Expecting a top level declaration + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + PsiErrorElement:Expecting a top level declaration + PsiElement(INTEGER_LITERAL)('0') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java index 78acac82a8e..2d765b18b8a 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java @@ -169,6 +169,12 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { doParsingTest(fileName); } + @TestMetadata("DuplicateAccessor.kt") + public void testDuplicateAccessor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/DuplicateAccessor.kt"); + doParsingTest(fileName); + } + @TestMetadata("DynamicReceiver.kt") public void testDynamicReceiver() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/DynamicReceiver.kt"); diff --git a/idea/idea-completion/testData/keywords/PropertySetter.kt b/idea/idea-completion/testData/keywords/PropertySetter.kt index 5a6da8bf797..ee8d6b8076e 100644 --- a/idea/idea-completion/testData/keywords/PropertySetter.kt +++ b/idea/idea-completion/testData/keywords/PropertySetter.kt @@ -10,12 +10,6 @@ class Some { // EXIST: enum class // EXIST: final // EXIST: fun - -/*TODO*/ -// EXIST: get -// EXIST: "get() = " -// EXIST: "get() {}" - // EXIST: inner // EXIST: internal // EXIST: object