[FIR] Add KtBackingField (see: KT-CR-4119, KT-14663)
This commit is contained in:
committed by
TeamCityServer
parent
654ed3caf6
commit
37f832bc2f
+2
@@ -106,6 +106,8 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
OPERATOR_MODIFIER,
|
||||
NON_FINAL_MODIFIER_OR_NAME,
|
||||
ENUM_MODIFIER,
|
||||
FIELD_KEYWORD,
|
||||
|
||||
;
|
||||
|
||||
val expressionToCreate get() = "SourceElementPositioningStrategies.${strategy ?: name}"
|
||||
|
||||
+22
@@ -379,6 +379,25 @@ object LightTreePositioningStrategies {
|
||||
val ENUM_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.ENUM_KEYWORD))
|
||||
|
||||
val FIELD_KEYWORD: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val fieldKeyword = tree.fieldKeyword(node)
|
||||
if (fieldKeyword != null) {
|
||||
return markElement(fieldKeyword, startOffset, endOffset, tree, node)
|
||||
}
|
||||
return DEFAULT.mark(node, startOffset, endOffset, tree)
|
||||
}
|
||||
|
||||
override fun isValid(node: LighterASTNode, tree: FlyweightCapableTreeStructure<LighterASTNode>): Boolean {
|
||||
return tree.fieldKeyword(node) != null
|
||||
}
|
||||
}
|
||||
|
||||
val INLINE_PARAMETER_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.NOINLINE_KEYWORD, KtTokens.CROSSINLINE_KEYWORD))
|
||||
|
||||
@@ -992,6 +1011,9 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.elseKeyword(node: Ligh
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.returnKeyword(node: LighterASTNode): LighterASTNode? =
|
||||
findChildByType(node, KtTokens.RETURN_KEYWORD)
|
||||
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.fieldKeyword(node: LighterASTNode): LighterASTNode? =
|
||||
findChildByType(node, KtTokens.FIELD_KEYWORD)
|
||||
|
||||
internal fun FlyweightCapableTreeStructure<LighterASTNode>.nameIdentifier(node: LighterASTNode): LighterASTNode? =
|
||||
findChildByType(node, KtTokens.IDENTIFIER)
|
||||
|
||||
|
||||
+5
@@ -319,4 +319,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.ENUM_MODIFIER,
|
||||
PositioningStrategies.ENUM_MODIFIER
|
||||
)
|
||||
|
||||
val FIELD_KEYWORD = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.FIELD_KEYWORD,
|
||||
PositioningStrategies.FIELD_KEYWORD
|
||||
)
|
||||
}
|
||||
|
||||
+7
@@ -292,6 +292,13 @@ object PositioningStrategies {
|
||||
@JvmField
|
||||
val ENUM_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ENUM_KEYWORD)
|
||||
|
||||
@JvmField
|
||||
val FIELD_KEYWORD: PositioningStrategy<KtBackingField> = object : DeclarationHeader<KtBackingField>() {
|
||||
override fun mark(element: KtBackingField): List<TextRange> {
|
||||
return markElement(element.fieldKeyword)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun mark(element: PsiElement): List<TextRange> {
|
||||
|
||||
@@ -79,6 +79,7 @@ public interface KtNodeTypes {
|
||||
IElementType TYPE_PROJECTION = KtStubElementTypes.TYPE_PROJECTION;
|
||||
|
||||
IElementType PROPERTY_ACCESSOR = KtStubElementTypes.PROPERTY_ACCESSOR;
|
||||
IElementType BACKING_FIELD = KtStubElementTypes.BACKING_FIELD;
|
||||
IElementType INITIALIZER_LIST = KtStubElementTypes.INITIALIZER_LIST;
|
||||
IElementType TYPE_CONSTRAINT_LIST = KtStubElementTypes.TYPE_CONSTRAINT_LIST;
|
||||
IElementType TYPE_CONSTRAINT = KtStubElementTypes.TYPE_CONSTRAINT;
|
||||
|
||||
@@ -1415,9 +1415,12 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
myBuilder.restoreNewlinesState();
|
||||
|
||||
if (!hasNewLineWithSemicolon) {
|
||||
AccessorKind accessorKind = parsePropertyGetterOrSetter(null);
|
||||
if (accessorKind != null) {
|
||||
parsePropertyGetterOrSetter(accessorKind);
|
||||
PropertyComponentKind.Collector alreadyRead = new PropertyComponentKind.Collector();
|
||||
PropertyComponentKind propertyComponentKind = parsePropertyComponent(alreadyRead);
|
||||
|
||||
while (propertyComponentKind != null) {
|
||||
alreadyRead.collect(propertyComponentKind);
|
||||
propertyComponentKind = parsePropertyComponent(alreadyRead);
|
||||
}
|
||||
|
||||
if (!atSet(EOL_OR_SEMICOLON, RBRACE)) {
|
||||
@@ -1504,78 +1507,102 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
myBuilder.restoreNewlinesState();
|
||||
}
|
||||
|
||||
private enum AccessorKind { GET, SET}
|
||||
private enum PropertyComponentKind {
|
||||
GET,
|
||||
SET,
|
||||
FIELD;
|
||||
|
||||
static class Collector {
|
||||
private final boolean[] collected = { false, false, false };
|
||||
|
||||
public void collect(PropertyComponentKind kind) {
|
||||
collected[kind.ordinal()] = true;
|
||||
}
|
||||
|
||||
public boolean contains(PropertyComponentKind kind) {
|
||||
return collected[kind.ordinal()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* getterOrSetter
|
||||
* propertyComponent
|
||||
* : modifiers ("get" | "set")
|
||||
* :
|
||||
* ( "get" "(" ")"
|
||||
* |
|
||||
* "set" "(" modifiers parameter ")"
|
||||
* |
|
||||
* "field"
|
||||
* ) functionBody
|
||||
* ;
|
||||
*/
|
||||
@Nullable
|
||||
private AccessorKind parsePropertyGetterOrSetter(@Nullable AccessorKind notAllowedKind) {
|
||||
PsiBuilder.Marker getterOrSetter = mark();
|
||||
private PropertyComponentKind parsePropertyComponent(PropertyComponentKind.Collector notAllowedKind) {
|
||||
PsiBuilder.Marker propertyComponent = mark();
|
||||
|
||||
parseModifierList(DEFAULT, TokenSet.EMPTY);
|
||||
|
||||
AccessorKind accessorKind;
|
||||
PropertyComponentKind propertyComponentKind;
|
||||
if (at(GET_KEYWORD)) {
|
||||
accessorKind = AccessorKind.GET;
|
||||
propertyComponentKind = PropertyComponentKind.GET;
|
||||
}
|
||||
else if (at(SET_KEYWORD)) {
|
||||
accessorKind = AccessorKind.SET;
|
||||
propertyComponentKind = PropertyComponentKind.SET;
|
||||
}
|
||||
else if (at(FIELD_KEYWORD)) {
|
||||
propertyComponentKind = PropertyComponentKind.FIELD;
|
||||
}
|
||||
else {
|
||||
getterOrSetter.rollbackTo();
|
||||
propertyComponent.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (accessorKind == notAllowedKind) {
|
||||
getterOrSetter.rollbackTo();
|
||||
if (notAllowedKind.contains(propertyComponentKind)) {
|
||||
propertyComponent.rollbackTo();
|
||||
return null;
|
||||
}
|
||||
|
||||
advance(); // GET_KEYWORD or SET_KEYWORD
|
||||
advance(); // GET_KEYWORD, SET_KEYWORD or FIELD_KEYWORD
|
||||
|
||||
if (!at(LPAR)) {
|
||||
if (!at(LPAR) && propertyComponentKind != PropertyComponentKind.FIELD) {
|
||||
// Account for Jet-114 (val a : int get {...})
|
||||
TokenSet ACCESSOR_FIRST_OR_PROPERTY_END = TokenSet.orSet(MODIFIER_KEYWORDS, TokenSet.create(AT, GET_KEYWORD, SET_KEYWORD, EOL_OR_SEMICOLON, RBRACE));
|
||||
TokenSet ACCESSOR_FIRST_OR_PROPERTY_END = TokenSet.orSet(MODIFIER_KEYWORDS, TokenSet.create(AT, GET_KEYWORD, SET_KEYWORD, FIELD_KEYWORD, EOL_OR_SEMICOLON, RBRACE));
|
||||
if (!atSet(ACCESSOR_FIRST_OR_PROPERTY_END)) {
|
||||
errorUntil("Accessor body expected", TokenSet.orSet(ACCESSOR_FIRST_OR_PROPERTY_END, TokenSet.create(LBRACE, LPAR, EQ)));
|
||||
}
|
||||
else {
|
||||
closeDeclarationWithCommentBinders(getterOrSetter, PROPERTY_ACCESSOR, true);
|
||||
return accessorKind;
|
||||
closeDeclarationWithCommentBinders(propertyComponent, PROPERTY_ACCESSOR, true);
|
||||
return propertyComponentKind;
|
||||
}
|
||||
}
|
||||
|
||||
myBuilder.disableNewlines();
|
||||
expect(LPAR, "Expecting '('", TokenSet.create(RPAR, IDENTIFIER, COLON, LBRACE, EQ));
|
||||
if (accessorKind == AccessorKind.SET) {
|
||||
PsiBuilder.Marker parameterList = mark();
|
||||
PsiBuilder.Marker setterParameter = mark();
|
||||
parseModifierList(DEFAULT, TokenSet.create(COMMA, COLON, RPAR));
|
||||
expect(IDENTIFIER, "Expecting parameter name", TokenSet.create(RPAR, COLON, LBRACE, EQ));
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
parseTypeRef();
|
||||
if (propertyComponentKind != PropertyComponentKind.FIELD) {
|
||||
expect(LPAR, "Expecting '('", TokenSet.create(RPAR, IDENTIFIER, COLON, LBRACE, EQ));
|
||||
if (propertyComponentKind == PropertyComponentKind.SET) {
|
||||
PsiBuilder.Marker parameterList = mark();
|
||||
PsiBuilder.Marker setterParameter = mark();
|
||||
parseModifierList(DEFAULT, TokenSet.create(COMMA, COLON, RPAR));
|
||||
expect(IDENTIFIER, "Expecting parameter name", TokenSet.create(RPAR, COLON, LBRACE, EQ));
|
||||
|
||||
if (at(COLON)) {
|
||||
advance(); // COLON
|
||||
parseTypeRef();
|
||||
}
|
||||
setterParameter.done(VALUE_PARAMETER);
|
||||
if (at(COMMA)) {
|
||||
advance(); // COMMA
|
||||
}
|
||||
parameterList.done(VALUE_PARAMETER_LIST);
|
||||
}
|
||||
setterParameter.done(VALUE_PARAMETER);
|
||||
if (at(COMMA)) {
|
||||
advance(); // COMMA
|
||||
if (!at(RPAR)) {
|
||||
errorUntil("Expecting ')'", TokenSet.create(RPAR, COLON, LBRACE, RBRACE, EQ, EOL_OR_SEMICOLON));
|
||||
}
|
||||
if (at(RPAR)) {
|
||||
advance();
|
||||
}
|
||||
parameterList.done(VALUE_PARAMETER_LIST);
|
||||
}
|
||||
if (!at(RPAR)) {
|
||||
errorUntil("Expecting ')'", TokenSet.create(RPAR, COLON, LBRACE, RBRACE, EQ, EOL_OR_SEMICOLON));
|
||||
}
|
||||
if (at(RPAR)) {
|
||||
advance();
|
||||
}
|
||||
myBuilder.restoreNewlinesState();
|
||||
|
||||
@@ -1585,13 +1612,22 @@ public class KotlinParsing extends AbstractKotlinParsing {
|
||||
parseTypeRef();
|
||||
}
|
||||
|
||||
parseFunctionContract();
|
||||
if (propertyComponentKind != PropertyComponentKind.FIELD) {
|
||||
parseFunctionContract();
|
||||
parseFunctionBody();
|
||||
} else if (at(EQ)) {
|
||||
advance();
|
||||
myExpressionParsing.parseExpression();
|
||||
consumeIf(SEMICOLON);
|
||||
}
|
||||
|
||||
parseFunctionBody();
|
||||
if (propertyComponentKind == PropertyComponentKind.FIELD) {
|
||||
closeDeclarationWithCommentBinders(propertyComponent, BACKING_FIELD, true);
|
||||
} else {
|
||||
closeDeclarationWithCommentBinders(propertyComponent, PROPERTY_ACCESSOR, true);
|
||||
}
|
||||
|
||||
closeDeclarationWithCommentBinders(getterOrSetter, PROPERTY_ACCESSOR, true);
|
||||
|
||||
return accessorKind;
|
||||
return propertyComponentKind;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinBackingFieldStub;
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||
|
||||
public class KtBackingField extends KtDeclarationStub<KotlinBackingFieldStub>
|
||||
implements KtModifierListOwner, KtDeclarationWithInitializer {
|
||||
public KtBackingField(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public KtBackingField(@NotNull KotlinBackingFieldStub stub) {
|
||||
super(stub, KtStubElementTypes.BACKING_FIELD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitBackingField(this, data);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getEqualsToken() {
|
||||
return findChildByType(KtTokens.EQ);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KtTypeReference getReturnTypeReference() {
|
||||
return getStubOrPsiChild(KtStubElementTypes.TYPE_REFERENCE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement getNamePlaceholder() {
|
||||
PsiElement it = getFieldKeyword();
|
||||
if (it != null) {
|
||||
return it;
|
||||
}
|
||||
return getNode().getPsi();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public KtExpression getInitializer() {
|
||||
return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), KtExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasInitializer() {
|
||||
return getInitializer() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTextOffset() {
|
||||
return getNamePlaceholder().getTextRange().getStartOffset();
|
||||
}
|
||||
|
||||
public PsiElement getFieldKeyword() {
|
||||
return findChildByType(KtTokens.FIELD_KEYWORD);
|
||||
}
|
||||
}
|
||||
@@ -191,6 +191,15 @@ public class KtProperty extends KtTypeParameterListOwnerStub<KotlinPropertyStub>
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KtBackingField getFieldDeclaration() {
|
||||
for (KtBackingField field : getStubOrPsiChildrenAsList(KtStubElementTypes.BACKING_FIELD)) {
|
||||
return field;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasDelegate() {
|
||||
KotlinPropertyStub stub = getStub();
|
||||
if (stub != null) {
|
||||
|
||||
@@ -358,6 +358,10 @@ public class KtVisitor<R, D> extends PsiElementVisitor {
|
||||
return visitDeclaration(accessor, data);
|
||||
}
|
||||
|
||||
public R visitBackingField(@NotNull KtBackingField accessor, D data) {
|
||||
return visitDeclaration(accessor, data);
|
||||
}
|
||||
|
||||
public R visitTypeConstraintList(@NotNull KtTypeConstraintList list, D data) {
|
||||
return visitKtElement(list, data);
|
||||
}
|
||||
|
||||
@@ -121,6 +121,8 @@ interface KotlinPropertyAccessorStub : StubElement<KtPropertyAccessor> {
|
||||
fun hasBlockBody(): Boolean
|
||||
}
|
||||
|
||||
interface KotlinBackingFieldStub : StubElement<KtBackingField>
|
||||
|
||||
interface KotlinPropertyStub : KotlinCallableStubBase<KtProperty> {
|
||||
fun isVar(): Boolean
|
||||
fun hasDelegate(): Boolean
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.stubs.elements;
|
||||
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.stubs.StubInputStream;
|
||||
import com.intellij.psi.stubs.StubOutputStream;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.psi.KtBackingField;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinBackingFieldStub;
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinBackingFieldStubImpl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class KtBackingFieldElementType extends KtStubElementType<KotlinBackingFieldStub, KtBackingField> {
|
||||
public KtBackingFieldElementType(@NotNull @NonNls String debugName) {
|
||||
super(debugName, KtBackingField.class, KotlinBackingFieldStub.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KotlinBackingFieldStub createStub(@NotNull KtBackingField psi, StubElement parentStub) {
|
||||
return new KotlinBackingFieldStubImpl(parentStub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(@NotNull KotlinBackingFieldStub stub, @NotNull StubOutputStream dataStream) throws IOException {}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KotlinBackingFieldStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
|
||||
return new KotlinBackingFieldStubImpl(parentStub);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public interface KtStubElementTypes {
|
||||
KtFunctionElementType FUNCTION = new KtFunctionElementType("FUN");
|
||||
KtPropertyElementType PROPERTY = new KtPropertyElementType("PROPERTY");
|
||||
KtPropertyAccessorElementType PROPERTY_ACCESSOR = new KtPropertyAccessorElementType("PROPERTY_ACCESSOR");
|
||||
KtBackingFieldElementType BACKING_FIELD = new KtBackingFieldElementType("BACKING_FIELD");
|
||||
KtTypeAliasElementType TYPEALIAS = new KtTypeAliasElementType("TYPEALIAS");
|
||||
|
||||
KtClassElementType ENUM_ENTRY = new KtClassElementType("ENUM_ENTRY");
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.stubs.impl;
|
||||
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import org.jetbrains.kotlin.psi.KtBackingField;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinBackingFieldStub;
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
|
||||
|
||||
public class KotlinBackingFieldStubImpl extends KotlinStubBaseImpl<KtBackingField>
|
||||
implements KotlinBackingFieldStub {
|
||||
public KotlinBackingFieldStubImpl(StubElement parent) {
|
||||
super(parent, KtStubElementTypes.PROPERTY_ACCESSOR);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user