From 3ba94d73528cebf697e0194418178c891d64e03f Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 21 Jan 2015 15:02:34 +0300 Subject: [PATCH] Parsing: secondary constructors --- .../org/jetbrains/kotlin/JetNodeTypes.java | 5 + .../org/jetbrains/kotlin/lexer/JetTokens.java | 5 +- .../jetbrains/kotlin/parsing/JetParsing.java | 89 +++++++- .../psi/JetConstructorDelegationCall.java | 76 +++++++ .../kotlin/psi/JetSecondaryConstructor.java | 172 +++++++++++++++ .../org/jetbrains/kotlin/psi/JetVisitor.java | 8 + .../jetbrains/kotlin/psi/JetVisitorVoid.java | 20 ++ .../psi/JetVisitorVoidWithParameter.java | 14 ++ .../stubs/elements/JetStubElementTypes.java | 6 +- .../anonymousInitializer.kt | 18 ++ .../anonymousInitializer.txt | 111 ++++++++++ .../psi/secondaryConstructors/basic.kt | 17 ++ .../psi/secondaryConstructors/basic.txt | 200 ++++++++++++++++++ .../psi/secondaryConstructors/enumParsing.kt | 15 ++ .../psi/secondaryConstructors/enumParsing.txt | 139 ++++++++++++ .../recoveryEmptyDelegationType.kt | 14 ++ .../recoveryEmptyDelegationType.txt | 124 +++++++++++ .../recoveryWithoutParameterList.kt | 8 + .../recoveryWithoutParameterList.txt | 83 ++++++++ .../recoveryWrongDelegationName.kt | 4 + .../recoveryWrongDelegationName.txt | 50 +++++ .../parsing/JetParsingTestGenerated.java | 46 ++++ grammar/src/class_members.grm | 11 + .../completion/keywords/AfterClassProperty.kt | 4 +- .../testData/completion/keywords/AfterFuns.kt | 4 +- .../completion/keywords/InClassBeforeFun.kt | 4 +- .../completion/keywords/InClassScope.kt | 4 +- .../completion/keywords/PropertyAccessors.kt | 4 +- .../completion/keywords/PropertyAccessors2.kt | 4 +- .../completion/keywords/PropertySetter.kt | 4 +- 30 files changed, 1249 insertions(+), 14 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java create mode 100644 compiler/testData/psi/secondaryConstructors/anonymousInitializer.kt create mode 100644 compiler/testData/psi/secondaryConstructors/anonymousInitializer.txt create mode 100644 compiler/testData/psi/secondaryConstructors/basic.kt create mode 100644 compiler/testData/psi/secondaryConstructors/basic.txt create mode 100644 compiler/testData/psi/secondaryConstructors/enumParsing.kt create mode 100644 compiler/testData/psi/secondaryConstructors/enumParsing.txt create mode 100644 compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.kt create mode 100644 compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.txt create mode 100644 compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.kt create mode 100644 compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.txt create mode 100644 compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.kt create mode 100644 compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java b/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java index a146cf53c11..830dbd53437 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/JetNodeTypes.java @@ -37,6 +37,7 @@ public interface JetNodeTypes { IElementType ENUM_ENTRY = JetStubElementTypes.ENUM_ENTRY; IElementType ANONYMOUS_INITIALIZER = JetStubElementTypes.ANONYMOUS_INITIALIZER; + IElementType SECONDARY_CONSTRUCTOR = JetStubElementTypes.SECONDARY_CONSTRUCTOR; IElementType TYPE_PARAMETER_LIST = JetStubElementTypes.TYPE_PARAMETER_LIST; IElementType TYPE_PARAMETER = JetStubElementTypes.TYPE_PARAMETER; @@ -79,6 +80,10 @@ public interface JetNodeTypes { IElementType TYPE_CONSTRAINT_LIST = JetStubElementTypes.TYPE_CONSTRAINT_LIST; IElementType TYPE_CONSTRAINT = JetStubElementTypes.TYPE_CONSTRAINT; + IElementType CONSTRUCTOR_DELEGATION_CALL = JetStubElementTypes.CONSTRUCTOR_DELEGATION_CALL; + JetNodeType CONSTRUCTOR_DELEGATION_REFERENCE = + new JetNodeType("CONSTRUCTOR_DELEGATION_REFERENCE", JetConstructorDelegationReferenceExpression.class); + // TODO: Not sure if we need separate NT for each kind of constants JetNodeType NULL = new JetNodeType("NULL", JetConstantExpression.class); JetNodeType BOOLEAN_CONSTANT = new JetNodeType("BOOLEAN_CONSTANT", JetConstantExpression.class); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java b/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java index 46dbd980bab..8dda77860f8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/lexer/JetTokens.java @@ -137,6 +137,9 @@ public interface JetTokens { JetKeywordToken BY_KEYWORD = JetKeywordToken.softKeyword("by"); JetKeywordToken GET_KEYWORD = JetKeywordToken.softKeyword("get"); JetKeywordToken SET_KEYWORD = JetKeywordToken.softKeyword("set"); + JetKeywordToken CONSTRUCTOR_KEYWORD = JetKeywordToken.softKeyword("constructor"); + JetKeywordToken INIT_KEYWORD = JetKeywordToken.softKeyword("init"); + JetModifierKeywordToken ABSTRACT_KEYWORD = JetModifierKeywordToken.softKeywordModifier("abstract"); JetModifierKeywordToken ENUM_KEYWORD = JetModifierKeywordToken.softKeywordModifier("enum"); JetModifierKeywordToken OPEN_KEYWORD = JetModifierKeywordToken.softKeywordModifier("open"); @@ -170,7 +173,7 @@ public interface JetTokens { SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, INNER_KEYWORD, ANNOTATION_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD, CATCH_KEYWORD, FINALLY_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD, - DYNAMIC_KEYWORD, DEFAULT_KEYWORD + DYNAMIC_KEYWORD, DEFAULT_KEYWORD, CONSTRUCTOR_KEYWORD, INIT_KEYWORD ); /* diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java index 61787bc2fad..1d405ce4bdf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParsing.java @@ -47,7 +47,7 @@ public class JetParsing extends AbstractJetParsing { private static final TokenSet TOPLEVEL_OBJECT_FIRST = TokenSet.create(TYPE_ALIAS_KEYWORD, TRAIT_KEYWORD, CLASS_KEYWORD, FUN_KEYWORD, VAL_KEYWORD, PACKAGE_KEYWORD); private static final TokenSet ENUM_MEMBER_FIRST = TokenSet.create(TYPE_ALIAS_KEYWORD, TRAIT_KEYWORD, CLASS_KEYWORD, - FUN_KEYWORD, VAL_KEYWORD, IDENTIFIER, OBJECT_KEYWORD); + FUN_KEYWORD, VAL_KEYWORD, LBRACE, IDENTIFIER, OBJECT_KEYWORD); private static final TokenSet CLASS_NAME_RECOVERY_SET = TokenSet.orSet(TokenSet.create(LT, LPAR, COLON, LBRACE), TOPLEVEL_OBJECT_FIRST); private static final TokenSet TYPE_PARAMETER_GT_RECOVERY_SET = TokenSet.create(WHERE_KEYWORD, LPAR, COLON, LBRACE, GT); @@ -60,6 +60,7 @@ public class JetParsing extends AbstractJetParsing { TokenSet.orSet(TokenSet.create(IDENTIFIER, LBRACKET, VAL_KEYWORD, VAR_KEYWORD), MODIFIER_KEYWORDS); private static final TokenSet LAMBDA_VALUE_PARAMETER_FIRST = TokenSet.orSet(TokenSet.create(IDENTIFIER, LBRACKET), MODIFIER_KEYWORDS); + private static final TokenSet SOFT_KEYWORDS_AT_MEMBER_START = TokenSet.create(CONSTRUCTOR_KEYWORD, INIT_KEYWORD); static JetParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) { JetParsing jetParsing = new JetParsing(builder); @@ -428,6 +429,9 @@ public class JetParsing extends AbstractJetParsing { PsiBuilder.Marker list = mark(); boolean empty = true; while (!eof()) { + if (annotationParsingMode.atMemberStart && atSet(SOFT_KEYWORDS_AT_MEMBER_START)) { + break; + } if (atSet(MODIFIER_KEYWORDS)) { if (tokenConsumer != null) tokenConsumer.consume(tt()); advance(); // MODIFIER @@ -702,7 +706,7 @@ public class JetParsing extends AbstractJetParsing { createTruncatedBuilder(lastId).parseModifierList(MODIFIER_LIST, detector, REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS); IElementType type; - if (at(IDENTIFIER)) { + if (!atSet(SOFT_KEYWORDS_AT_MEMBER_START) && at(IDENTIFIER)) { parseEnumEntry(); type = ENUM_ENTRY; } @@ -782,7 +786,7 @@ public class JetParsing extends AbstractJetParsing { * * memberDeclaration' * : defaultObject - * : constructor + * : secondaryConstructor * : function * : property * : class @@ -796,7 +800,7 @@ public class JetParsing extends AbstractJetParsing { PsiBuilder.Marker decl = mark(); ModifierDetector detector = new ModifierDetector(); - parseModifierList(MODIFIER_LIST, detector, REGULAR_ANNOTATIONS_ALLOW_SHORTS); + parseModifierList(MODIFIER_LIST, detector, REGULAR_ANNOTATIONS_ALLOW_SHORTS_AT_MEMBER_MODIFIER_LIST); IElementType declType = parseMemberDeclarationRest(detector.isEnumDetected(), detector.isDefaultDetected()); @@ -840,9 +844,77 @@ public class JetParsing extends AbstractJetParsing { parseBlock(); declType = ANONYMOUS_INITIALIZER; } + else if (at(INIT_KEYWORD)) { + advance(); // init + parseBlock(); + declType = ANONYMOUS_INITIALIZER; + } + else if (at(CONSTRUCTOR_KEYWORD)) { + parseSecondaryConstructor(); + declType = SECONDARY_CONSTRUCTOR; + } return declType; } + /* + * secondaryConstructor + * : modifiers "constructor" valueParameters (":" constructorDelegationCall)? block + * constructorDelegationCall + * : "this" valueArguments + * : "super" valueArguments + */ + private void parseSecondaryConstructor() { + assert _at(CONSTRUCTOR_KEYWORD); + + advance(); // CONSTRUCTOR_KEYWORD + + TokenSet valueArgsRecoverySet = TokenSet.create(COLON, LBRACE, SEMICOLON, RPAR); + if (at(LPAR)) { + parseValueParameterList(false, valueArgsRecoverySet); + } + else { + errorWithRecovery("Expecting '('", valueArgsRecoverySet); + } + + if (at(COLON)) { + advance(); // COLON + + PsiBuilder.Marker delegationCall = mark(); + + if (at(THIS_KEYWORD) || at(SUPER_KEYWORD)) { + parseThisOrSuper(); + } + else { + // if we're on LPAR it's probably start of value arguments list + if (!at(LPAR)) { + advance(); // wrong delegation call keyword? + } + error("Expecting a 'this' or 'super' constructor call"); + } + + myExpressionParsing.parseValueArgumentList(); + + delegationCall.done(CONSTRUCTOR_DELEGATION_CALL); + } + else { + // empty constructor delegation call + PsiBuilder.Marker emptyDelegationCall = mark(); + mark().done(CONSTRUCTOR_DELEGATION_REFERENCE); + emptyDelegationCall.done(CONSTRUCTOR_DELEGATION_CALL); + } + + parseBlock(); + } + + private void parseThisOrSuper() { + assert _at(THIS_KEYWORD) || _at(SUPER_KEYWORD); + PsiBuilder.Marker mark = mark(); + + advance(); // THIS_KEYWORD | SUPER_KEYWORD + + mark.done(CONSTRUCTOR_DELEGATION_REFERENCE); + } + /* * initializer{","} */ @@ -2026,14 +2098,21 @@ public class JetParsing extends AbstractJetParsing { FILE_ANNOTATIONS_BEFORE_PACKAGE(false, true), FILE_ANNOTATIONS_WHEN_PACKAGE_OMITTED(false, true), REGULAR_ANNOTATIONS_ONLY_WITH_BRACKETS(false, false), - REGULAR_ANNOTATIONS_ALLOW_SHORTS(true, false); + REGULAR_ANNOTATIONS_ALLOW_SHORTS(true, false), + REGULAR_ANNOTATIONS_ALLOW_SHORTS_AT_MEMBER_MODIFIER_LIST(true, false, true); boolean allowShortAnnotations; boolean isFileAnnotationParsingMode; + boolean atMemberStart = false; AnnotationParsingMode(boolean allowShortAnnotations, boolean onlyFileAnnotations) { this.allowShortAnnotations = allowShortAnnotations; this.isFileAnnotationParsingMode = onlyFileAnnotations; } + + AnnotationParsingMode(boolean allowShortAnnotations, boolean onlyFileAnnotations, boolean atMemberStart) { + this(allowShortAnnotations, onlyFileAnnotations); + this.atMemberStart = atMemberStart; + } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java new file mode 100644 index 00000000000..ead090e3274 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetConstructorDelegationCall.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2015 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.kotlin.psi; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.stubs.IStubElementType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.JetNodeTypes; +import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub; +import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; + +import java.util.Collections; +import java.util.List; + +public class JetConstructorDelegationCall extends JetElementImplStub> implements JetCallElement { + public JetConstructorDelegationCall( + @NotNull KotlinPlaceHolderStub stub + ) { + super(stub, JetStubElementTypes.CONSTRUCTOR_DELEGATION_CALL); + } + + public JetConstructorDelegationCall(@NotNull ASTNode node) { + super(node); + } + + @Override + @Nullable + public JetValueArgumentList getValueArgumentList() { + return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST); + } + + @Override + @NotNull + public List getValueArguments() { + JetValueArgumentList list = getValueArgumentList(); + return list != null ? list.getArguments() : Collections.emptyList(); + } + + @NotNull + @Override + public List getFunctionLiteralArguments() { + return Collections.emptyList(); + } + + @NotNull + @Override + public List getTypeArguments() { + return Collections.emptyList(); + } + + @Override + public JetTypeArgumentList getTypeArgumentList() { + return null; + } + + @Nullable + @Override + public JetExpression getCalleeExpression() { + return findChildByClass(JetExpression.class); + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java new file mode 100644 index 00000000000..b162c139ef5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetSecondaryConstructor.java @@ -0,0 +1,172 @@ +/* + * Copyright 2010-2015 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.kotlin.psi; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.name.FqName; +import org.jetbrains.kotlin.name.Name; +import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub; +import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; + +import java.util.Collections; +import java.util.List; + +public class JetSecondaryConstructor extends JetDeclarationStub> implements JetFunction { + public JetSecondaryConstructor(@NotNull ASTNode node) { + super(node); + } + + public JetSecondaryConstructor(@NotNull KotlinPlaceHolderStub stub) { + super(stub, JetStubElementTypes.SECONDARY_CONSTRUCTOR); + } + + @Override + public R accept(@NotNull JetVisitor visitor, D data) { + return visitor.visitSecondaryConstructor(this, data); + } + + @Override + public boolean isLocal() { + return false; + } + + @Override + @Nullable + public JetParameterList getValueParameterList() { + return getStubOrPsiChild(JetStubElementTypes.VALUE_PARAMETER_LIST); + } + + @Override + @NotNull + public List getValueParameters() { + JetParameterList list = getValueParameterList(); + return list != null ? list.getParameters() : Collections.emptyList(); + } + + @Nullable + @Override + public JetTypeReference getReceiverTypeReference() { + return null; + } + + @Nullable + @Override + public JetTypeReference getTypeReference() { + return null; + } + + @Nullable + @Override + public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) { + return null; + } + + @Nullable + @Override + public PsiElement getColon() { + return null; + } + + @Nullable + @Override + public JetExpression getBodyExpression() { + return findChildByClass(JetBlockExpression.class); + } + + @Nullable + @Override + public PsiElement getEqualsToken() { + return null; + } + + @Override + public boolean hasBlockBody() { + return true; + } + + @Override + public boolean hasBody() { + return true; + } + + @Override + public boolean hasDeclaredReturnType() { + return false; + } + + @Nullable + @Override + public JetTypeParameterList getTypeParameterList() { + return null; + } + + @Nullable + @Override + public JetTypeConstraintList getTypeConstraintList() { + return null; + } + + @NotNull + @Override + public List getTypeConstraints() { + return Collections.emptyList(); + } + + @NotNull + @Override + public List getTypeParameters() { + return Collections.emptyList(); + } + + @NotNull + @Override + public Name getNameAsSafeName() { + return Name.special(""); + } + + @Nullable + @Override + public FqName getFqName() { + return null; + } + + @Nullable + @Override + public Name getNameAsName() { + return getNameAsSafeName(); + } + + @Nullable + @Override + public PsiElement getNameIdentifier() { + return null; + } + + @Override + public PsiElement setName(@NotNull String name) throws IncorrectOperationException { + throw new IncorrectOperationException("setName to constructor"); + } + + @Nullable + public JetConstructorDelegationCall getDelegationCall() { + return getStubOrPsiChild(JetStubElementTypes.CONSTRUCTOR_DELEGATION_CALL); + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java index 8871aa27939..25208cc716b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitor.java @@ -33,6 +33,10 @@ public class JetVisitor extends PsiElementVisitor { return visitNamedDeclaration(klass, data); } + public R visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, D data) { + return visitJetElement(constructor, data); + } + public R visitNamedFunction(@NotNull JetNamedFunction function, D data) { return visitNamedDeclaration(function, data); } @@ -134,6 +138,10 @@ public class JetVisitor extends PsiElementVisitor { return visitDelegationSpecifier(specifier, data); } + public R visitConstructorDelegationCall(@NotNull JetConstructorDelegationCall call, D data) { + return visitJetElement(call, data); + } + public R visitPropertyDelegate(@NotNull JetPropertyDelegate delegate, D data) { return visitJetElement(delegate, data); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java index 2d1b8e7f80c..7d3f3ea0456 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoid.java @@ -33,6 +33,10 @@ public class JetVisitorVoid extends JetVisitor { super.visitClass(klass, null); } + public void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor) { + super.visitSecondaryConstructor(constructor, null); + } + public void visitNamedFunction(@NotNull JetNamedFunction function) { super.visitNamedFunction(function, null); } @@ -129,6 +133,10 @@ public class JetVisitorVoid extends JetVisitor { super.visitDelegationToSuperClassSpecifier(specifier, null); } + public void visitConstructorDelegationCall(@NotNull JetConstructorDelegationCall call) { + super.visitConstructorDelegationCall(call, null); + } + public void visitPropertyDelegate(@NotNull JetPropertyDelegate delegate) { super.visitPropertyDelegate(delegate, null); } @@ -436,6 +444,12 @@ public class JetVisitorVoid extends JetVisitor { return null; } + @Override + public final Void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, Void data) { + visitSecondaryConstructor(constructor); + return null; + } + @Override public final Void visitNamedFunction(@NotNull JetNamedFunction function, Void data) { visitNamedFunction(function); @@ -576,6 +590,12 @@ public class JetVisitorVoid extends JetVisitor { return null; } + @Override + public final Void visitConstructorDelegationCall(@NotNull JetConstructorDelegationCall call, Void data) { + visitConstructorDelegationCall(call); + return null; + } + @Override public final Void visitPropertyDelegate(@NotNull JetPropertyDelegate delegate, Void data) { visitPropertyDelegate(delegate); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java index 9bf4d606771..3ed1caf26ec 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetVisitorVoidWithParameter.java @@ -34,6 +34,10 @@ public class JetVisitorVoidWithParameter

extends JetVisitor { super.visitClass(klass, data); } + public void visitSecondaryConstructorVoid(@NotNull JetSecondaryConstructor constructor, P data) { + super.visitSecondaryConstructor(constructor, data); + } + public void visitNamedFunctionVoid(@NotNull JetNamedFunction function, P data) { super.visitNamedFunction(function, data); } @@ -130,6 +134,10 @@ public class JetVisitorVoidWithParameter

extends JetVisitor { super.visitDelegationToSuperClassSpecifier(specifier, data); } + public void visitDelegationCallVoid(@NotNull JetConstructorDelegationCall call, P data) { + super.visitConstructorDelegationCall(call, data); + } + public void visitPropertyDelegateVoid(@NotNull JetPropertyDelegate delegate, P data) { super.visitPropertyDelegate(delegate, data); } @@ -573,6 +581,12 @@ public class JetVisitorVoidWithParameter

extends JetVisitor { return null; } + @Override + public final Void visitConstructorDelegationCall(@NotNull JetConstructorDelegationCall call, P data) { + visitDelegationCallVoid(call, data); + return null; + } + @Override public final Void visitPropertyDelegate(@NotNull JetPropertyDelegate delegate, P data) { visitPropertyDelegateVoid(delegate, data); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetStubElementTypes.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetStubElementTypes.java index 0df6c64a308..f91f43f3082 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetStubElementTypes.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/JetStubElementTypes.java @@ -33,6 +33,8 @@ public interface JetStubElementTypes { JetObjectElementType OBJECT_DECLARATION = new JetObjectElementType("OBJECT_DECLARATION"); JetPlaceHolderStubElementType ANONYMOUS_INITIALIZER = new JetPlaceHolderStubElementType("ANONYMOUS_INITIALIZER", JetClassInitializer.class); + JetPlaceHolderStubElementType SECONDARY_CONSTRUCTOR = + new JetPlaceHolderStubElementType("SECONDARY_CONSTRUCTOR", JetSecondaryConstructor.class); JetParameterElementType VALUE_PARAMETER = new JetParameterElementType("VALUE_PARAMETER"); JetPlaceHolderStubElementType VALUE_PARAMETER_LIST = @@ -107,11 +109,13 @@ public interface JetStubElementTypes { new JetPlaceHolderStubElementType("DELEGATOR_SUPER_CALL", JetDelegatorToSuperCall.class); JetPlaceHolderStubElementType DELEGATOR_SUPER_CLASS = new JetPlaceHolderStubElementType("DELEGATOR_SUPER_CLASS", JetDelegatorToSuperClass.class); + JetPlaceHolderStubElementType CONSTRUCTOR_DELEGATION_CALL = + new JetPlaceHolderStubElementType("CONSTRUCTOR_DELEGATION_CALL", JetConstructorDelegationCall.class); JetPlaceHolderStubElementType CONSTRUCTOR_CALLEE = new JetPlaceHolderStubElementType("CONSTRUCTOR_CALLEE", JetConstructorCalleeExpression.class); TokenSet DECLARATION_TYPES = - TokenSet.create(CLASS, OBJECT_DECLARATION, FUNCTION, PROPERTY, ANONYMOUS_INITIALIZER, ENUM_ENTRY); + TokenSet.create(CLASS, OBJECT_DECLARATION, FUNCTION, PROPERTY, ANONYMOUS_INITIALIZER, SECONDARY_CONSTRUCTOR, ENUM_ENTRY); TokenSet DELEGATION_SPECIFIER_TYPES = TokenSet.create(DELEGATOR_BY, DELEGATOR_SUPER_CALL, DELEGATOR_SUPER_CLASS); diff --git a/compiler/testData/psi/secondaryConstructors/anonymousInitializer.kt b/compiler/testData/psi/secondaryConstructors/anonymousInitializer.kt new file mode 100644 index 00000000000..4fc48b41a3e --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/anonymousInitializer.kt @@ -0,0 +1,18 @@ +class A { + init {} + + private init {} + + val x = f() + init { + x = 1 + } + + val y = f() + { + x = 2 + } + { + x = 3 + } +} diff --git a/compiler/testData/psi/secondaryConstructors/anonymousInitializer.txt b/compiler/testData/psi/secondaryConstructors/anonymousInitializer.txt new file mode 100644 index 00000000000..2f0b92cf3d1 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/anonymousInitializer.txt @@ -0,0 +1,111 @@ +JetFile: anonymousInitializer.kt + PACKAGE_DIRECTIVE + + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + ANONYMOUS_INITIALIZER + PsiElement(init)('init') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + ANONYMOUS_INITIALIZER + MODIFIER_LIST + PsiElement(private)('private') + PsiWhiteSpace(' ') + PsiElement(init)('init') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + ANONYMOUS_INITIALIZER + PsiElement(init)('init') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('y') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('f') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + FUNCTION_LITERAL_ARGUMENT + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + FUNCTION_LITERAL_ARGUMENT + FUNCTION_LITERAL_EXPRESSION + FUNCTION_LITERAL + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BLOCK + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/secondaryConstructors/basic.kt b/compiler/testData/psi/secondaryConstructors/basic.kt new file mode 100644 index 00000000000..fa07a358a88 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/basic.kt @@ -0,0 +1,17 @@ +class A { + constructor() {} + + val x: Int + + private annot constructor(x: Int) {} + + [constructor] fun constructor() {} + + annot protected constructor(x: Int, y: Int) : this(1,2) {} + + [constructor] public constructor() : super() { + x = 1 + } +} + +constructor class B diff --git a/compiler/testData/psi/secondaryConstructors/basic.txt b/compiler/testData/psi/secondaryConstructors/basic.txt new file mode 100644 index 00000000000..613a07ebc53 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/basic.txt @@ -0,0 +1,200 @@ +JetFile: basic.kt + PACKAGE_DIRECTIVE + + 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)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiWhiteSpace('\n\n ') + SECONDARY_CONSTRUCTOR + MODIFIER_LIST + PsiElement(private)('private') + PsiWhiteSpace(' ') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('annot') + PsiWhiteSpace(' ') + PsiElement(constructor)('constructor') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + FUN + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('constructor') + PsiElement(RBRACKET)(']') + PsiWhiteSpace(' ') + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('constructor') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + SECONDARY_CONSTRUCTOR + MODIFIER_LIST + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('annot') + PsiWhiteSpace(' ') + PsiElement(protected)('protected') + PsiWhiteSpace(' ') + PsiElement(constructor)('constructor') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('y') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + PsiElement(this)('this') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(COMMA)(',') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + SECONDARY_CONSTRUCTOR + MODIFIER_LIST + ANNOTATION + PsiElement(LBRACKET)('[') + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('constructor') + PsiElement(RBRACKET)(']') + PsiWhiteSpace(' ') + PsiElement(public)('public') + PsiWhiteSpace(' ') + PsiElement(constructor)('constructor') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + PsiElement(super)('super') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + MODIFIER_LIST + ANNOTATION_ENTRY + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('constructor') + PsiWhiteSpace(' ') + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('B') \ No newline at end of file diff --git a/compiler/testData/psi/secondaryConstructors/enumParsing.kt b/compiler/testData/psi/secondaryConstructors/enumParsing.kt new file mode 100644 index 00000000000..445c76e93ad --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/enumParsing.kt @@ -0,0 +1,15 @@ +enum class A { + constructor(x: Int) {} + + abc1 : A(1,2,3) + abc2 : A(1,2,3) {} + + init {} + + abc3 + + constructor(x: Int): this() {} + { + + } +} diff --git a/compiler/testData/psi/secondaryConstructors/enumParsing.txt b/compiler/testData/psi/secondaryConstructors/enumParsing.txt new file mode 100644 index 00000000000..1a29e8f0c9d --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/enumParsing.txt @@ -0,0 +1,139 @@ +JetFile: enumParsing.kt + PACKAGE_DIRECTIVE + + CLASS + MODIFIER_LIST + PsiElement(enum)('enum') + PsiWhiteSpace(' ') + 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)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + ENUM_ENTRY + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('abc1') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + INITIALIZER_LIST + DELEGATOR_SUPER_CALL + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(COMMA)(',') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(COMMA)(',') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + ENUM_ENTRY + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('abc2') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + INITIALIZER_LIST + DELEGATOR_SUPER_CALL + CONSTRUCTOR_CALLEE + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('A') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(COMMA)(',') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(COMMA)(',') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + ANONYMOUS_INITIALIZER + PsiElement(init)('init') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n ') + ENUM_ENTRY + OBJECT_DECLARATION_NAME + PsiElement(IDENTIFIER)('abc3') + PsiWhiteSpace('\n\n ') + SECONDARY_CONSTRUCTOR + PsiElement(constructor)('constructor') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + PsiElement(this)('this') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + ANONYMOUS_INITIALIZER + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.kt b/compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.kt new file mode 100644 index 00000000000..db64890ccac --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.kt @@ -0,0 +1,14 @@ +class A { + constructor(x: Int) : () { + x = 1 + } + fun foo() = 2 +} + +class B { + constructor(x: Int) : () { + x = 3 + } +} + +fun foo() = 4 diff --git a/compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.txt b/compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.txt new file mode 100644 index 00000000000..b0a4793eb19 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.txt @@ -0,0 +1,124 @@ +JetFile: recoveryEmptyDelegationType.kt + PACKAGE_DIRECTIVE + + 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)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + PsiErrorElement:Expecting a 'this' or 'super' constructor call + + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('B') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + SECONDARY_CONSTRUCTOR + PsiElement(constructor)('constructor') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + VALUE_PARAMETER + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + PsiErrorElement:Expecting a 'this' or 'super' constructor call + + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + BINARY_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('x') + PsiWhiteSpace(' ') + OPERATION_REFERENCE + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('3') + PsiWhiteSpace('\n ') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('4') \ No newline at end of file diff --git a/compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.kt b/compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.kt new file mode 100644 index 00000000000..90be7e9def5 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.kt @@ -0,0 +1,8 @@ +class A { + constructor : this() {} + val x: Int +} +class B { + constructor : this() {} +} +fun foo(): Int diff --git a/compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.txt b/compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.txt new file mode 100644 index 00000000000..08707412cd0 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.txt @@ -0,0 +1,83 @@ +JetFile: recoveryWithoutParameterList.kt + PACKAGE_DIRECTIVE + + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('A') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + SECONDARY_CONSTRUCTOR + PsiElement(constructor)('constructor') + PsiErrorElement:Expecting '(' + + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + PsiElement(this)('this') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + CLASS + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('B') + PsiWhiteSpace(' ') + CLASS_BODY + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + SECONDARY_CONSTRUCTOR + PsiElement(constructor)('constructor') + PsiErrorElement:Expecting '(' + + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + CONSTRUCTOR_DELEGATION_REFERENCE + PsiElement(this)('this') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n') + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('foo') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') \ No newline at end of file diff --git a/compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.kt b/compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.kt new file mode 100644 index 00000000000..a49f0a6fa51 --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.kt @@ -0,0 +1,4 @@ +class A { + constructor() : superr(1,2) {} + val x: Int +} diff --git a/compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.txt b/compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.txt new file mode 100644 index 00000000000..53881731a1b --- /dev/null +++ b/compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.txt @@ -0,0 +1,50 @@ +JetFile: recoveryWrongDelegationName.kt + PACKAGE_DIRECTIVE + + 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)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + CONSTRUCTOR_DELEGATION_CALL + PsiElement(IDENTIFIER)('superr') + PsiErrorElement:Expecting a 'this' or 'super' constructor call + + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('1') + PsiElement(COMMA)(',') + VALUE_ARGUMENT + INTEGER_CONSTANT + PsiElement(INTEGER_LITERAL)('2') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiElement(RBRACE)('}') + PsiWhiteSpace('\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('x') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ 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 94d8313cf5f..e6745ccf648 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java @@ -48,6 +48,7 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { Psi.PropertyDelegate.class, Psi.Recovery.class, Psi.Script.class, + Psi.SecondaryConstructors.class, Psi.StringTemplates.class, }) @RunWith(JUnit3RunnerWithInners.class) @@ -1802,6 +1803,51 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { } } + @TestMetadata("compiler/testData/psi/secondaryConstructors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SecondaryConstructors extends AbstractJetParsingTest { + public void testAllFilesPresentInSecondaryConstructors() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/psi/secondaryConstructors"), Pattern.compile("^(.*)\\.kts?$"), true); + } + + @TestMetadata("anonymousInitializer.kt") + public void testAnonymousInitializer() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/secondaryConstructors/anonymousInitializer.kt"); + doParsingTest(fileName); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/secondaryConstructors/basic.kt"); + doParsingTest(fileName); + } + + @TestMetadata("enumParsing.kt") + public void testEnumParsing() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/secondaryConstructors/enumParsing.kt"); + doParsingTest(fileName); + } + + @TestMetadata("recoveryEmptyDelegationType.kt") + public void testRecoveryEmptyDelegationType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/secondaryConstructors/recoveryEmptyDelegationType.kt"); + doParsingTest(fileName); + } + + @TestMetadata("recoveryWithoutParameterList.kt") + public void testRecoveryWithoutParameterList() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/secondaryConstructors/recoveryWithoutParameterList.kt"); + doParsingTest(fileName); + } + + @TestMetadata("recoveryWrongDelegationName.kt") + public void testRecoveryWrongDelegationName() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/secondaryConstructors/recoveryWrongDelegationName.kt"); + doParsingTest(fileName); + } + } + @TestMetadata("compiler/testData/psi/stringTemplates") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/grammar/src/class_members.grm b/grammar/src/class_members.grm index 89975dc42c5..818607114da 100644 --- a/grammar/src/class_members.grm +++ b/grammar/src/class_members.grm @@ -34,9 +34,11 @@ memberDeclaration : class : typeAlias : anonymousInitializer + : secondaryConstructor ; anonymousInitializer + : "init" block : block ; @@ -110,6 +112,15 @@ parameter object : "object" SimpleName (":" delegationSpecifier{","})? classBody? // Class body can be optional: this is a declaration + +secondaryConstructor + : modifiers "constructor" valueParameters (":" constructorDelegationCall)? block + ; + +constructorDelegationCall + : "this" valueArguments + : "super" valueArguments + ; /** See [Object expressions and Declarations](object-declarations.html) */ diff --git a/idea/testData/completion/keywords/AfterClassProperty.kt b/idea/testData/completion/keywords/AfterClassProperty.kt index 6b7f6daf6e2..beda7535e60 100644 --- a/idea/testData/completion/keywords/AfterClassProperty.kt +++ b/idea/testData/completion/keywords/AfterClassProperty.kt @@ -29,5 +29,7 @@ class MouseMovedEventArgs // EXIST: val // EXIST: var // EXIST: vararg +// EXIST: constructor +// EXIST: init /*why?*/ -// NUMBER: 24 +// NUMBER: 26 diff --git a/idea/testData/completion/keywords/AfterFuns.kt b/idea/testData/completion/keywords/AfterFuns.kt index c22f29ed635..9bbc53e3082 100644 --- a/idea/testData/completion/keywords/AfterFuns.kt +++ b/idea/testData/completion/keywords/AfterFuns.kt @@ -32,5 +32,7 @@ class A { // EXIST: val // EXIST: var // EXIST: vararg +// EXIST: constructor +// EXIST: init /*why?*/ -// NUMBER: 21 +// NUMBER: 23 diff --git a/idea/testData/completion/keywords/InClassBeforeFun.kt b/idea/testData/completion/keywords/InClassBeforeFun.kt index 52c164d253c..63940445f75 100644 --- a/idea/testData/completion/keywords/InClassBeforeFun.kt +++ b/idea/testData/completion/keywords/InClassBeforeFun.kt @@ -30,5 +30,7 @@ public class Test { // EXIST: val // EXIST: var // EXIST: vararg +// EXIST: constructor +// EXIST: init /*why?*/ -// NUMBER: 21 \ No newline at end of file +// NUMBER: 23 diff --git a/idea/testData/completion/keywords/InClassScope.kt b/idea/testData/completion/keywords/InClassScope.kt index d29501a5ec6..53200a3b8a3 100644 --- a/idea/testData/completion/keywords/InClassScope.kt +++ b/idea/testData/completion/keywords/InClassScope.kt @@ -25,4 +25,6 @@ class TestClass { // EXIST: var // EXIST: vararg /*why?*/ -// NUMBER: 21 +// EXIST: constructor +// EXIST: init +// NUMBER: 23 diff --git a/idea/testData/completion/keywords/PropertyAccessors.kt b/idea/testData/completion/keywords/PropertyAccessors.kt index af0aad17280..2982518cb40 100644 --- a/idea/testData/completion/keywords/PropertyAccessors.kt +++ b/idea/testData/completion/keywords/PropertyAccessors.kt @@ -29,4 +29,6 @@ class Some { // EXIST: var // EXIST: vararg /*why?*/ -// NUMBER: 24 +// EXIST: constructor +// EXIST: init +// NUMBER: 26 diff --git a/idea/testData/completion/keywords/PropertyAccessors2.kt b/idea/testData/completion/keywords/PropertyAccessors2.kt index ad6c1f520ab..1a8f62d15ee 100644 --- a/idea/testData/completion/keywords/PropertyAccessors2.kt +++ b/idea/testData/completion/keywords/PropertyAccessors2.kt @@ -29,4 +29,6 @@ class Some { // EXIST: var // EXIST: vararg /*why?*/ -// NUMBER: 24 +// EXIST: constructor +// EXIST: init +// NUMBER: 26 diff --git a/idea/testData/completion/keywords/PropertySetter.kt b/idea/testData/completion/keywords/PropertySetter.kt index 20574902050..84b140907bc 100644 --- a/idea/testData/completion/keywords/PropertySetter.kt +++ b/idea/testData/completion/keywords/PropertySetter.kt @@ -31,4 +31,6 @@ class Some { // EXIST: var // EXIST: vararg /*why?*/ -// NUMBER: 24 +// EXIST: constructor +// EXIST: init +// NUMBER: 26