[FIR] Add KtBackingField (see: KT-CR-4119, KT-14663)

This commit is contained in:
Nikolay Lunyak
2021-08-04 17:02:46 +03:00
committed by TeamCityServer
parent 654ed3caf6
commit 37f832bc2f
13 changed files with 289 additions and 42 deletions
@@ -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}"
@@ -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)
@@ -319,4 +319,9 @@ object SourceElementPositioningStrategies {
LightTreePositioningStrategies.ENUM_MODIFIER,
PositioningStrategies.ENUM_MODIFIER
)
val FIELD_KEYWORD = SourceElementPositioningStrategy(
LightTreePositioningStrategies.FIELD_KEYWORD,
PositioningStrategies.FIELD_KEYWORD
)
}
@@ -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
@@ -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);
}
}