[FE] Commonize positioning strategies and move them to :frontend-psi module
This commit is contained in:
committed by
TeamCityServer
parent
7536dadb65
commit
850ca1916f
+1
-1
@@ -284,7 +284,7 @@ object SourceElementPositioningStrategies {
|
||||
|
||||
val ACTUAL_DECLARATION_NAME = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.ACTUAL_DECLARATION_NAME,
|
||||
PositioningStrategies.ACTUAL_DECLARATION_NAME
|
||||
PositioningStrategies.DEFAULT // TODO
|
||||
)
|
||||
|
||||
val LABEL = SourceElementPositioningStrategy(
|
||||
|
||||
+4
-103
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -9,22 +9,16 @@ import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.cfg.UnreachableCode
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.ACTUAL_WITHOUT_EXPECT
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.NO_ACTUAL_FOR_EXPECT
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.MODALITY_MODIFIERS
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.VISIBILITY_MODIFIERS
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible.*
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
|
||||
object PositioningStrategies {
|
||||
private open class DeclarationHeader<T : KtDeclaration> : PositioningStrategy<T>() {
|
||||
open class DeclarationHeader<T : KtDeclaration> : PositioningStrategy<T>() {
|
||||
override fun isValid(element: T): Boolean {
|
||||
if (element is KtNamedDeclaration &&
|
||||
element !is KtObjectDeclaration &&
|
||||
@@ -102,93 +96,8 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val ACTUAL_DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
||||
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
||||
val nameIdentifier = element.nameIdentifier
|
||||
return when {
|
||||
nameIdentifier != null -> markElement(nameIdentifier)
|
||||
element is KtNamedFunction -> DECLARATION_SIGNATURE.mark(element)
|
||||
else -> DEFAULT.mark(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val ParametrizedDiagnostic<out KtNamedDeclaration>.firstIncompatibility: Incompatible<MemberDescriptor>?
|
||||
get() {
|
||||
val map = when (factory) {
|
||||
NO_ACTUAL_FOR_EXPECT ->
|
||||
NO_ACTUAL_FOR_EXPECT.cast(this).c
|
||||
ACTUAL_WITHOUT_EXPECT ->
|
||||
ACTUAL_WITHOUT_EXPECT.cast(this).b
|
||||
else ->
|
||||
return null
|
||||
}
|
||||
return map.keys.firstOrNull()
|
||||
}
|
||||
|
||||
private val propertyKindTokens = TokenSet.create(KtTokens.VAL_KEYWORD, KtTokens.VAR_KEYWORD)
|
||||
|
||||
private val classKindTokens = TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD, KtTokens.INTERFACE_KEYWORD)
|
||||
|
||||
@JvmField
|
||||
val INCOMPATIBLE_DECLARATION: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
||||
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out KtNamedDeclaration>): List<TextRange> {
|
||||
val element = diagnostic.psiElement
|
||||
val callableDeclaration = element as? KtCallableDeclaration
|
||||
val incompatibility = diagnostic.firstIncompatibility
|
||||
return when (incompatibility) {
|
||||
null, Unknown, is ClassScopes, EnumEntries -> null
|
||||
ClassKind -> {
|
||||
val startElement =
|
||||
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||
val endElement =
|
||||
element.node.findChildByType(classKindTokens)?.psi
|
||||
?: element.nameIdentifier
|
||||
if (startElement != null && endElement != null) {
|
||||
return markRange(startElement, endElement)
|
||||
} else {
|
||||
endElement
|
||||
}
|
||||
}
|
||||
TypeParameterNames, TypeParameterCount,
|
||||
TypeParameterUpperBounds, TypeParameterVariance, TypeParameterReified -> {
|
||||
(element as? KtTypeParameterListOwner)?.typeParameterList
|
||||
}
|
||||
CallableKind -> {
|
||||
(callableDeclaration as? KtNamedFunction)?.funKeyword
|
||||
?: (callableDeclaration as? KtProperty)?.valOrVarKeyword
|
||||
}
|
||||
ParameterShape -> {
|
||||
callableDeclaration?.let { it.receiverTypeReference ?: it.valueParameterList }
|
||||
}
|
||||
ParameterCount, ParameterTypes, ParameterNames,
|
||||
ValueParameterVararg, ValueParameterNoinline, ValueParameterCrossinline -> {
|
||||
callableDeclaration?.valueParameterList
|
||||
}
|
||||
ReturnType -> {
|
||||
callableDeclaration?.typeReference
|
||||
}
|
||||
FunctionModifiersDifferent, FunctionModifiersNotSubset,
|
||||
PropertyModifiers, ClassModifiers -> {
|
||||
element.modifierList
|
||||
}
|
||||
PropertyKind -> {
|
||||
element.node.findChildByType(propertyKindTokens)?.psi
|
||||
}
|
||||
Supertypes -> {
|
||||
(element as? KtClassOrObject)?.getSuperTypeList()
|
||||
}
|
||||
Modality -> {
|
||||
element.modalityModifier()
|
||||
}
|
||||
Visibility -> {
|
||||
element.visibilityModifier()
|
||||
}
|
||||
}?.let { markElement(it) } ?: ACTUAL_DECLARATION_NAME.mark(element)
|
||||
}
|
||||
}
|
||||
val propertyKindTokens = TokenSet.create(KtTokens.VAL_KEYWORD, KtTokens.VAR_KEYWORD)
|
||||
val classKindTokens = TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD, KtTokens.INTERFACE_KEYWORD)
|
||||
|
||||
@JvmField
|
||||
val DECLARATION_START_TO_NAME: PositioningStrategy<KtDeclaration> = object : DeclarationHeader<KtDeclaration>() {
|
||||
@@ -693,14 +602,6 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val UNREACHABLE_CODE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out PsiElement>): List<TextRange> {
|
||||
val unreachableCode = Errors.UNREACHABLE_CODE.cast(diagnostic)
|
||||
return UnreachableCode.getUnreachableTextRanges(unreachableCode.psiElement, unreachableCode.a, unreachableCode.b)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val AS_TYPE: PositioningStrategy<KtBinaryExpressionWithTypeRHS> = object : PositioningStrategy<KtBinaryExpressionWithTypeRHS>() {
|
||||
override fun mark(element: KtBinaryExpressionWithTypeRHS): List<TextRange> {
|
||||
+5
-15
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.diagnostics
|
||||
@@ -26,8 +15,9 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
open class PositioningStrategy<in E : PsiElement> {
|
||||
open fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out E>): List<TextRange> {
|
||||
return mark(diagnostic.psiElement)
|
||||
open fun markDiagnostic(diagnostic: DiagnosticMarker): List<TextRange> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return mark(diagnostic.psiElement as E)
|
||||
}
|
||||
|
||||
open fun mark(element: E): List<TextRange> {
|
||||
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.Named;
|
||||
import org.jetbrains.kotlin.diagnostics.*;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.diagnostics
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.cfg.UnreachableCode
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
|
||||
object ClassicPositioningStrategies {
|
||||
@JvmField
|
||||
val ACTUAL_DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> =
|
||||
object : PositioningStrategies.DeclarationHeader<KtNamedDeclaration>() {
|
||||
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
||||
val nameIdentifier = element.nameIdentifier
|
||||
return when {
|
||||
nameIdentifier != null -> markElement(nameIdentifier)
|
||||
element is KtNamedFunction -> PositioningStrategies.DECLARATION_SIGNATURE.mark(element)
|
||||
else -> PositioningStrategies.DEFAULT.mark(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move to specific strategies
|
||||
private val DiagnosticMarker.firstIncompatibility: ExpectActualCompatibility.Incompatible<MemberDescriptor>?
|
||||
get() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val map = when (factoryName) {
|
||||
Errors.NO_ACTUAL_FOR_EXPECT.name -> (this as DiagnosticWithParameters3Marker<*, *, *>).c
|
||||
Errors.ACTUAL_WITHOUT_EXPECT.name -> (this as DiagnosticWithParameters2Marker<*, *>).b
|
||||
else -> null
|
||||
} as? Map<ExpectActualCompatibility.Incompatible<MemberDescriptor>, Collection<MemberDescriptor>> ?: return null
|
||||
return map.keys.firstOrNull()
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val INCOMPATIBLE_DECLARATION: PositioningStrategy<KtNamedDeclaration> =
|
||||
object : PositioningStrategies.DeclarationHeader<KtNamedDeclaration>() {
|
||||
override fun markDiagnostic(diagnostic: DiagnosticMarker): List<TextRange> {
|
||||
val element = diagnostic.psiElement as KtNamedDeclaration
|
||||
val callableDeclaration = element as? KtCallableDeclaration
|
||||
val incompatibility = diagnostic.firstIncompatibility
|
||||
return when (incompatibility) {
|
||||
null, ExpectActualCompatibility.Incompatible.Unknown, is ExpectActualCompatibility.Incompatible.ClassScopes, ExpectActualCompatibility.Incompatible.EnumEntries -> null
|
||||
ExpectActualCompatibility.Incompatible.ClassKind -> {
|
||||
val startElement =
|
||||
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||
val endElement =
|
||||
element.node.findChildByType(PositioningStrategies.classKindTokens)?.psi
|
||||
?: element.nameIdentifier
|
||||
if (startElement != null && endElement != null) {
|
||||
return markRange(startElement, endElement)
|
||||
} else {
|
||||
endElement
|
||||
}
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.TypeParameterNames, ExpectActualCompatibility.Incompatible.TypeParameterCount,
|
||||
ExpectActualCompatibility.Incompatible.TypeParameterUpperBounds, ExpectActualCompatibility.Incompatible.TypeParameterVariance, ExpectActualCompatibility.Incompatible.TypeParameterReified -> {
|
||||
(element as? KtTypeParameterListOwner)?.typeParameterList
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.CallableKind -> {
|
||||
(callableDeclaration as? KtNamedFunction)?.funKeyword
|
||||
?: (callableDeclaration as? KtProperty)?.valOrVarKeyword
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.ParameterShape -> {
|
||||
callableDeclaration?.let { it.receiverTypeReference ?: it.valueParameterList }
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.ParameterCount, ExpectActualCompatibility.Incompatible.ParameterTypes, ExpectActualCompatibility.Incompatible.ParameterNames,
|
||||
ExpectActualCompatibility.Incompatible.ValueParameterVararg, ExpectActualCompatibility.Incompatible.ValueParameterNoinline, ExpectActualCompatibility.Incompatible.ValueParameterCrossinline -> {
|
||||
callableDeclaration?.valueParameterList
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.ReturnType -> {
|
||||
callableDeclaration?.typeReference
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.FunctionModifiersDifferent, ExpectActualCompatibility.Incompatible.FunctionModifiersNotSubset,
|
||||
ExpectActualCompatibility.Incompatible.PropertyModifiers, ExpectActualCompatibility.Incompatible.ClassModifiers -> {
|
||||
element.modifierList
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.PropertyKind -> {
|
||||
element.node.findChildByType(PositioningStrategies.propertyKindTokens)?.psi
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.Supertypes -> {
|
||||
(element as? KtClassOrObject)?.getSuperTypeList()
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.Modality -> {
|
||||
element.modalityModifier()
|
||||
}
|
||||
ExpectActualCompatibility.Incompatible.Visibility -> {
|
||||
element.visibilityModifier()
|
||||
}
|
||||
}?.let { markElement(it) } ?: ACTUAL_DECLARATION_NAME.mark(element)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val UNREACHABLE_CODE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun markDiagnostic(diagnostic: DiagnosticMarker): List<TextRange> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val unreachableCode = diagnostic as DiagnosticWithParameters2Marker<Set<KtElement>, Set<KtElement>>
|
||||
return UnreachableCode.getUnreachableTextRanges(unreachableCode.psiElement as KtElement, unreachableCode.a, unreachableCode.b)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -31,7 +31,8 @@ public abstract class DiagnosticFactoryWithPsiElement<E extends PsiElement, D ex
|
||||
}
|
||||
|
||||
protected List<TextRange> getTextRanges(ParametrizedDiagnostic<E> diagnostic) {
|
||||
return positioningStrategy.markDiagnostic(diagnostic);
|
||||
// TODO: it's strange that java requires cast here, because ParametrizedDiagnostic<E> inherits DiagnosticMarker
|
||||
return positioningStrategy.markDiagnostic((DiagnosticMarker) diagnostic);
|
||||
}
|
||||
|
||||
protected boolean isValid(ParametrizedDiagnostic<E> diagnostic) {
|
||||
|
||||
@@ -41,6 +41,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.ACTUAL_DECLARATION_NAME;
|
||||
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.INCOMPATIBLE_DECLARATION;
|
||||
import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
|
||||
import static org.jetbrains.kotlin.diagnostics.Severity.*;
|
||||
|
||||
@@ -953,7 +955,7 @@ public interface Errors {
|
||||
// Control flow / Data flow
|
||||
|
||||
DiagnosticFactory2<KtElement, Set<KtElement>, Set<KtElement>> UNREACHABLE_CODE = DiagnosticFactory2.create(
|
||||
WARNING, PositioningStrategies.UNREACHABLE_CODE);
|
||||
WARNING, ClassicPositioningStrategies.UNREACHABLE_CODE);
|
||||
|
||||
DiagnosticFactory0<KtVariableDeclaration> VARIABLE_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_NAME);
|
||||
|
||||
|
||||
+2
-6
@@ -18,16 +18,12 @@ package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.PositioningStrategy
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters3
|
||||
import org.jetbrains.kotlin.diagnostics.ParametrizedDiagnostic
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallData
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters1
|
||||
|
||||
object JsCodePositioningStrategy : PositioningStrategy<PsiElement>() {
|
||||
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out PsiElement>): List<TextRange> {
|
||||
override fun markDiagnostic(diagnostic: DiagnosticMarker): List<TextRange> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val diagnosticWithParameters = diagnostic as DiagnosticWithParameters1<KtExpression, JsCallData>
|
||||
val textRange = diagnosticWithParameters.a.reportRange
|
||||
|
||||
Reference in New Issue
Block a user