From 3dec848c0377086fd9534d37a87c02948619b1d9 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 17 Nov 2020 16:17:01 +0300 Subject: [PATCH] [FIR] Implement light tree DECLARATION_NAME & SIGNATURE strategies --- .../fir/analysis/diagnostics/FirErrors.kt | 10 +- .../LightTreePositioningStrategies.kt | 126 +++++++++++++++++- .../funInterfaceDeclarationCheck.fir.kt | 4 +- .../diagnostics/tests/localInterfaces.fir.kt | 8 +- .../unqualifiedSuperWithLocalClass.fir.kt | 21 --- .../unqualifiedSuperWithLocalClass.kt | 1 + 6 files changed, 132 insertions(+), 38 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.fir.kt diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 4303a48e8eb..be48b7a8102 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -66,8 +66,8 @@ object FirErrors { val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error0() // Constructor problems - val CONSTRUCTOR_IN_OBJECT by existing0() - val CONSTRUCTOR_IN_INTERFACE by existing0() + val CONSTRUCTOR_IN_OBJECT by error0(LightTreePositioningStrategies.DECLARATION_SIGNATURE) + val CONSTRUCTOR_IN_INTERFACE by error0(LightTreePositioningStrategies.DECLARATION_SIGNATURE) val NON_PRIVATE_CONSTRUCTOR_IN_ENUM by existing0() val NON_PRIVATE_CONSTRUCTOR_IN_SEALED by existing0() val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by warning0() @@ -144,11 +144,11 @@ object FirErrors { val ANY_METHOD_IMPLEMENTED_IN_INTERFACE by error0() // Invalid local declarations - val LOCAL_OBJECT_NOT_ALLOWED by error1() - val LOCAL_INTERFACE_NOT_ALLOWED by error1() + val LOCAL_OBJECT_NOT_ALLOWED by error1(LightTreePositioningStrategies.DECLARATION_NAME) + val LOCAL_INTERFACE_NOT_ALLOWED by error1(LightTreePositioningStrategies.DECLARATION_NAME) // Control flow diagnostics - val UNINITIALIZED_VARIABLE by error1() + val UNINITIALIZED_VARIABLE by error1(LightTreePositioningStrategies.DECLARATION_SIGNATURE) val WRONG_INVOCATION_KIND by warning3, EventOccurrencesRange, EventOccurrencesRange>() val LEAKED_IN_PLACE_LAMBDA by error1>() val WRONG_IMPLIES_CONDITION by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index c2c9a105958..6e15910de74 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -20,10 +20,10 @@ object LightTreePositioningStrategies { override fun mark(node: LighterASTNode, tree: FlyweightCapableTreeStructure): List { when (node.tokenType) { KtNodeTypes.OBJECT_DECLARATION -> { - val objectKeyword = tree.findChildByType(node, KtTokens.OBJECT_KEYWORD)!! + val objectKeyword = tree.objectKeyword(node)!! return markRange( from = objectKeyword, - to = tree.findChildByType(node, KtTokens.IDENTIFIER) ?: objectKeyword, + to = tree.nameIdentifier(node) ?: objectKeyword, tree ) } @@ -46,9 +46,9 @@ object LightTreePositioningStrategies { override fun mark(node: LighterASTNode, tree: FlyweightCapableTreeStructure): List { when (node.tokenType) { KtNodeTypes.SECONDARY_CONSTRUCTOR -> { - val valueParameterList = tree.findChildByType(node, KtNodeTypes.VALUE_PARAMETER_LIST) ?: return markElement(node, tree) + val valueParameterList = tree.valueParameterList(node) ?: return markElement(node, tree) return markRange( - tree.findChildByType(node, KtTokens.CONSTRUCTOR_KEYWORD)!!, + tree.constructorKeyword(node)!!, tree.lastChild(valueParameterList)!!, tree ) } @@ -56,10 +56,10 @@ object LightTreePositioningStrategies { val delegationReference = tree.findChildByType(node, KtNodeTypes.CONSTRUCTOR_DELEGATION_REFERENCE) if (delegationReference != null && tree.firstChild(delegationReference) == null) { val constructor = tree.findParentOfType(node, KtNodeTypes.SECONDARY_CONSTRUCTOR)!! - val valueParameterList = tree.findChildByType(constructor, KtNodeTypes.VALUE_PARAMETER_LIST) + val valueParameterList = tree.valueParameterList(constructor) ?: return markElement(constructor, tree) return markRange( - tree.findChildByType(constructor, KtTokens.CONSTRUCTOR_KEYWORD)!!, + tree.constructorKeyword(constructor)!!, tree.lastChild(valueParameterList)!!, tree ) } @@ -69,6 +69,120 @@ object LightTreePositioningStrategies { } } } + + val DECLARATION_NAME: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { + override fun mark(node: LighterASTNode, tree: FlyweightCapableTreeStructure): List { + val nameIdentifier = tree.nameIdentifier(node) + if (nameIdentifier != null) { + if (node.tokenType == KtNodeTypes.CLASS || node.tokenType == KtNodeTypes.OBJECT_DECLARATION) { + val startElement = + tree.modifierList(node)?.let { modifierList -> tree.findChildByType(modifierList, KtTokens.ENUM_KEYWORD) } + ?: tree.findChildByType(node, TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD)) + ?: node + + return markRange(startElement, nameIdentifier, tree) + } + return markElement(nameIdentifier, tree) + } + if (node.tokenType == KtNodeTypes.FUN) { + return DECLARATION_SIGNATURE.mark(node, tree) + } + return DEFAULT.mark(node, tree) + } + } + + val DECLARATION_SIGNATURE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { + override fun mark(node: LighterASTNode, tree: FlyweightCapableTreeStructure): List { + when (node.tokenType) { + KtNodeTypes.PRIMARY_CONSTRUCTOR, KtNodeTypes.SECONDARY_CONSTRUCTOR -> { + val begin = tree.constructorKeyword(node) ?: tree.valueParameterList(node) ?: return markElement(node, tree) + val end = tree.valueParameterList(node) ?: tree.constructorKeyword(node) ?: return markElement(node, tree) + return markRange(begin, end, tree) + } + KtNodeTypes.FUN, KtNodeTypes.FUNCTION_LITERAL -> { + val endOfSignatureElement = + tree.typeReference(node) + ?: tree.valueParameterList(node) + ?: tree.nameIdentifier(node) + ?: node + val startElement = if (node.tokenType == KtNodeTypes.FUNCTION_LITERAL) { + tree.receiverTypeReference(node) + ?: tree.valueParameterList(node) + ?: node + } else node + return markRange(startElement, endOfSignatureElement, tree) + } + KtNodeTypes.PROPERTY -> { + val endOfSignatureElement = tree.typeReference(node) ?: tree.nameIdentifier(node) ?: node + return markRange(node, endOfSignatureElement, tree) + } + KtNodeTypes.PROPERTY_ACCESSOR -> { + val endOfSignatureElement = + tree.typeReference(node) + ?: tree.rightParenthesis(node) + ?: tree.accessorNamePlaceholder(node) + + return markRange(node, endOfSignatureElement, tree) + } + KtNodeTypes.CLASS -> { + val nameAsDeclaration = tree.nameIdentifier(node) ?: return markElement(node, tree) + val primaryConstructorParameterList = tree.primaryConstructor(node)?.let { constructor -> + tree.valueParameterList(constructor) + } ?: return markElement(nameAsDeclaration, tree) + return markRange(nameAsDeclaration, primaryConstructorParameterList, tree) + } + KtNodeTypes.OBJECT_DECLARATION -> { + return DECLARATION_NAME.mark(node, tree) + } + KtNodeTypes.CLASS_INITIALIZER -> { + return markElement(tree.initKeyword(node)!!, tree) + } + } + return super.mark(node, tree) + } + } +} + +private fun FlyweightCapableTreeStructure.constructorKeyword(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtTokens.CONSTRUCTOR_KEYWORD) + +private fun FlyweightCapableTreeStructure.initKeyword(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtTokens.INIT_KEYWORD) + +private fun FlyweightCapableTreeStructure.nameIdentifier(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtTokens.IDENTIFIER) + +private fun FlyweightCapableTreeStructure.rightParenthesis(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtTokens.RPAR) + +private fun FlyweightCapableTreeStructure.objectKeyword(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtTokens.OBJECT_KEYWORD) + +private fun FlyweightCapableTreeStructure.accessorNamePlaceholder(node: LighterASTNode): LighterASTNode = + findChildByType(node, KtTokens.GET_KEYWORD) ?: findChildByType(node, KtTokens.SET_KEYWORD)!! + +private fun FlyweightCapableTreeStructure.modifierList(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtNodeTypes.MODIFIER_LIST) + +private fun FlyweightCapableTreeStructure.primaryConstructor(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtNodeTypes.PRIMARY_CONSTRUCTOR) + +private fun FlyweightCapableTreeStructure.valueParameterList(node: LighterASTNode): LighterASTNode? = + findChildByType(node, KtNodeTypes.VALUE_PARAMETER_LIST) + +private fun FlyweightCapableTreeStructure.typeReference(node: LighterASTNode): LighterASTNode? { + val childrenRef = Ref>() + getChildren(node, childrenRef) + return childrenRef.get()?.dropWhile { it.tokenType != KtTokens.COLON }?.firstOrNull { it.tokenType == KtNodeTypes.TYPE_REFERENCE } +} + +private fun FlyweightCapableTreeStructure.receiverTypeReference(node: LighterASTNode): LighterASTNode? { + val childrenRef = Ref>() + getChildren(node, childrenRef) + return childrenRef.get()?.firstOrNull { + if (it.tokenType == KtTokens.COLON || it.tokenType == KtTokens.LPAR) return null + it.tokenType == KtNodeTypes.TYPE_REFERENCE + } } private fun FlyweightCapableTreeStructure.findChildByType(node: LighterASTNode, type: IElementType): LighterASTNode? { diff --git a/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt b/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt index ae051437cf0..ea025258bfd 100644 --- a/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt +++ b/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt @@ -87,9 +87,9 @@ class WithNestedFun { } fun local() { - fun interface LocalFun { + fun interface LocalFun { fun invoke(element: T) - } + } } fun interface WithDefaultValue { diff --git a/compiler/testData/diagnostics/tests/localInterfaces.fir.kt b/compiler/testData/diagnostics/tests/localInterfaces.fir.kt index 85615bc8335..d02f565bcfb 100644 --- a/compiler/testData/diagnostics/tests/localInterfaces.fir.kt +++ b/compiler/testData/diagnostics/tests/localInterfaces.fir.kt @@ -1,14 +1,14 @@ // !DIAGNOSTICS: -UNUSED_VARIABLE fun foo() { - interface a {} + interface a {} val b = object { - interface c {} + interface c {} } class A { - interface d {} + interface d {} } val f = { - interface e {} + interface e {} } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.fir.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.fir.kt deleted file mode 100644 index 7045253537b..00000000000 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -interface Interface { - fun foo(x: Int): Int -} - -fun withLocalClasses(param: Int): Interface { - open class LocalBase { - open val param: Int - get() = 100 - } - - interface LocalInterface : Interface { - override fun foo(x: Int): Int = - x + param - } - - return object : LocalBase(), LocalInterface { - override fun foo(x: Int): Int = - x + super.param - } - -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.kt index 1fa5cf4008c..ceb904b403e 100644 --- a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.kt +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/unqualifiedSuperWithLocalClass.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL interface Interface { fun foo(x: Int): Int }