[FIR] Support 4 diagnostics for pairs of modifiers
In particular, this commit includes: * Attempt to abstract access to FirSourceElement via FirModifier * Add more visit functions to DeclarationCheckersDiagnosticComponent * Add messages+factories for 4 modifier-related errors and warnings * Introduce FirModifierChecker
This commit is contained in:
committed by
Mikhail Glukhikh
parent
311a91af79
commit
b7d8e879a6
+31
@@ -0,0 +1,31 @@
|
||||
class A<<!INCOMPATIBLE_MODIFIERS!>in<!> <!INCOMPATIBLE_MODIFIERS!>out<!> T> { }
|
||||
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>public<!> class B
|
||||
<!INCOMPATIBLE_MODIFIERS!>protected<!> <!INCOMPATIBLE_MODIFIERS!>internal<!> class C
|
||||
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> class D
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>open<!> class E
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>sealed<!> class F
|
||||
<!INCOMPATIBLE_MODIFIERS!>open<!> <!INCOMPATIBLE_MODIFIERS!>sealed<!> class G
|
||||
|
||||
inline fun foo(
|
||||
<!INCOMPATIBLE_MODIFIERS!>crossinline<!> <!INCOMPATIBLE_MODIFIERS!>noinline<!> first: () -> Unit,
|
||||
second: () -> Unit
|
||||
) { }
|
||||
|
||||
<!INCOMPATIBLE_MODIFIERS, REDUNDANT_MODIFIER!>open<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class H(val i: Int)
|
||||
<!INCOMPATIBLE_MODIFIERS!>sealed<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class I(val i: Int)
|
||||
<!INCOMPATIBLE_MODIFIERS!>inline<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class J(val i: Int)
|
||||
|
||||
abstract class K {
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>open<!> val i1: Int = 0
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> val i2: Int
|
||||
}
|
||||
|
||||
private open class L : K()
|
||||
private abstract class M : K()
|
||||
|
||||
class X {
|
||||
<!INCOMPATIBLE_MODIFIERS!>inner<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class Y(val i: Int)
|
||||
<!INCOMPATIBLE_MODIFIERS!>sealed<!> <!INCOMPATIBLE_MODIFIERS!>inner<!> class Z
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
FILE: incompatibleModifiers.kt
|
||||
public final class A<out T> : R|kotlin/Any| {
|
||||
public constructor<out T>(): R|A<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
private final class B : R|kotlin/Any| {
|
||||
public[private] constructor(): R|B| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
protected final class C : R|kotlin/Any| {
|
||||
public[protected] constructor(): R|C| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class D : R|kotlin/Any| {
|
||||
public constructor(): R|D| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class E : R|kotlin/Any| {
|
||||
public constructor(): R|E| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class F : R|kotlin/Any| {
|
||||
private constructor(): R|F| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public sealed class G : R|kotlin/Any| {
|
||||
private constructor(): R|G| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final inline fun foo(crossinline noinline first: R|() -> kotlin/Unit|, second: R|() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||
}
|
||||
public abstract data class H : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|H| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
public final fun component1(): R|kotlin/Int| {
|
||||
^component1 this@R|/H|.R|/H.i|
|
||||
}
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|/H|.R|/H.i|): R|H| {
|
||||
}
|
||||
|
||||
}
|
||||
public sealed data class I : R|kotlin/Any| {
|
||||
private constructor(i: R|kotlin/Int|): R|I| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
public final fun component1(): R|kotlin/Int| {
|
||||
^component1 this@R|/I|.R|/I.i|
|
||||
}
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|/I|.R|/I.i|): R|I| {
|
||||
}
|
||||
|
||||
}
|
||||
public final data inline class J : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|J| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
public final fun component1(): R|kotlin/Int| {
|
||||
^component1 this@R|/J|.R|/J.i|
|
||||
}
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|/J|.R|/J.i|): R|J| {
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class K : R|kotlin/Any| {
|
||||
public constructor(): R|K| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private open val i1: R|kotlin/Int| = Int(0)
|
||||
private get(): R|kotlin/Int|
|
||||
|
||||
private abstract val i2: R|kotlin/Int|
|
||||
private get(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
private open class L : R|K| {
|
||||
public[private] constructor(): R|L| {
|
||||
super<R|K|>()
|
||||
}
|
||||
|
||||
}
|
||||
private abstract class M : R|K| {
|
||||
public[private] constructor(): R|M| {
|
||||
super<R|K|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class X : R|kotlin/Any| {
|
||||
public constructor(): R|X| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner data class Y : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|X.Y| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
public final fun component1(): R|kotlin/Int| {
|
||||
^component1 this@R|/X.Y|.R|/X.Y.i|
|
||||
}
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|/X.Y|.R|/X.Y.i|): R|X.Y| {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed inner class Z : R|kotlin/Any| {
|
||||
private constructor(): R|X.Z| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<!REDUNDANT_MODIFIER!>open<!> abstract class A
|
||||
<!REDUNDANT_MODIFIER!>abstract<!> sealed class B
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
FILE: redundantModifier.kt
|
||||
public abstract class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public sealed class B : R|kotlin/Any| {
|
||||
private constructor(): R|B| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
open <!REPEATED_MODIFIER!>open<!> class A
|
||||
|
||||
internal <!REPEATED_MODIFIER!>internal<!> object B
|
||||
|
||||
enum <!REPEATED_MODIFIER!>enum<!> class C {
|
||||
VALUE1, VALUE2;
|
||||
|
||||
protected <!REPEATED_MODIFIER!>protected<!> companion object {
|
||||
private <!REPEATED_MODIFIER!>private<!> val D = 5
|
||||
}
|
||||
|
||||
inline <!REPEATED_MODIFIER!>inline<!> fun foo(f: (Int) -> Int) = f(8)
|
||||
}
|
||||
|
||||
open class E(private <!REPEATED_MODIFIER!>private<!> val int: Int = 5) {
|
||||
protected <!REPEATED_MODIFIER!>protected<!> var double = int + 8.0
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
FILE: repeatedModifier.kt
|
||||
public open class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
internal final object B : R|kotlin/Any| {
|
||||
private constructor(): R|B| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final enum class C : R|kotlin/Enum<C>| {
|
||||
private constructor(): R|C| {
|
||||
super<R|kotlin/Enum<C>|>()
|
||||
}
|
||||
|
||||
public final static enum entry VALUE1: R|C|
|
||||
public final static enum entry VALUE2: R|C|
|
||||
protected final companion object Companion : R|kotlin/Any| {
|
||||
private constructor(): R|C.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val D: R|kotlin/Int| = Int(5)
|
||||
private get(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
|
||||
public final inline fun foo(f: R|(kotlin/Int) -> kotlin/Int|): R|kotlin/Int| {
|
||||
^foo R|<local>/f|.R|FakeOverride<kotlin/Function1.invoke: R|kotlin/Int|>|(Int(8))
|
||||
}
|
||||
|
||||
public final static fun values(): R|kotlin/Array<C>| {
|
||||
}
|
||||
|
||||
public final static fun valueOf(value: R|kotlin/String|): R|C| {
|
||||
}
|
||||
|
||||
}
|
||||
public open class E : R|kotlin/Any| {
|
||||
public constructor(int: R|kotlin/Int| = Int(5)): R|E| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val int: R|kotlin/Int| = R|<local>/int|
|
||||
private get(): R|kotlin/Int|
|
||||
|
||||
protected final var double: R|kotlin/Double| = R|<local>/int|.R|kotlin/Int.plus|(Double(8.0))
|
||||
protected get(): R|kotlin/Double|
|
||||
protected set(value: R|kotlin/Double|): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
Generated
+15
@@ -740,11 +740,26 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("incompatibleModifiers.kt")
|
||||
public void testIncompatibleModifiers() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("infixFunctions.kt")
|
||||
public void testInfixFunctions() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("redundantModifier.kt")
|
||||
public void testRedundantModifier() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/redundantModifier.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("repeatedModifier.kt")
|
||||
public void testRepeatedModifier() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/repeatedModifier.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("superIsNotAnExpression.kt")
|
||||
public void testSuperIsNotAnExpression() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
|
||||
|
||||
+15
@@ -740,11 +740,26 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("incompatibleModifiers.kt")
|
||||
public void testIncompatibleModifiers() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("infixFunctions.kt")
|
||||
public void testInfixFunctions() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("redundantModifier.kt")
|
||||
public void testRedundantModifier() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/redundantModifier.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("repeatedModifier.kt")
|
||||
public void testRepeatedModifier() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/repeatedModifier.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("superIsNotAnExpression.kt")
|
||||
public void testSuperIsNotAnExpression() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
|
||||
|
||||
+3
-1
@@ -9,7 +9,9 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
|
||||
object DeclarationCheckers {
|
||||
val DECLARATIONS: List<FirDeclarationChecker<FirDeclaration>> = listOf()
|
||||
val DECLARATIONS: List<FirDeclarationChecker<FirDeclaration>> = listOf(
|
||||
FirModifierChecker
|
||||
)
|
||||
val MEMBER_DECLARATIONS: List<FirDeclarationChecker<FirMemberDeclaration>> = DECLARATIONS + listOf(
|
||||
FirInfixFunctionDeclarationChecker
|
||||
)
|
||||
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
|
||||
object FirModifierChecker : FirDeclarationChecker<FirDeclaration>() {
|
||||
|
||||
private enum class CompatibilityType {
|
||||
COMPATIBLE,
|
||||
COMPATIBLE_FOR_CLASSES, // for functions and properties: error
|
||||
REDUNDANT_1_TO_2, // first is redundant to second: warning
|
||||
REDUNDANT_2_TO_1, // second is redundant to first: warning
|
||||
DEPRECATED, // pair is deprecated and will soon become incompatible: warning
|
||||
REPEATED, // first and second are the same: error
|
||||
INCOMPATIBLE, // pair is incompatible: error
|
||||
}
|
||||
|
||||
// first modifier in pair should also be first in spelling order and declaration's modifier list
|
||||
private val compatibilityTypeMap = hashMapOf<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, CompatibilityType>()
|
||||
|
||||
private fun recordCompatibilityType(compatibilityType: CompatibilityType, vararg list: KtModifierKeywordToken) {
|
||||
for (firstKeyword in list) {
|
||||
for (secondKeyword in list) {
|
||||
if (firstKeyword != secondKeyword) {
|
||||
compatibilityTypeMap[Pair(firstKeyword, secondKeyword)] = compatibilityType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordPairsCompatibleForClasses(vararg list: KtModifierKeywordToken) {
|
||||
recordCompatibilityType(CompatibilityType.COMPATIBLE_FOR_CLASSES, *list)
|
||||
}
|
||||
|
||||
private fun recordDeprecatedPairs(vararg list: KtModifierKeywordToken) {
|
||||
recordCompatibilityType(CompatibilityType.DEPRECATED, *list)
|
||||
}
|
||||
|
||||
private fun recordIncompatiblePairs(vararg list: KtModifierKeywordToken) {
|
||||
recordCompatibilityType(CompatibilityType.INCOMPATIBLE, *list)
|
||||
}
|
||||
|
||||
// note that order matters: the first argument is redundant to the second, not the other way around
|
||||
private fun recordRedundantPairs(redundantKeyword: KtModifierKeywordToken, sufficientKeyword: KtModifierKeywordToken) {
|
||||
compatibilityTypeMap[Pair(redundantKeyword, sufficientKeyword)] = CompatibilityType.REDUNDANT_1_TO_2
|
||||
compatibilityTypeMap[Pair(sufficientKeyword, redundantKeyword)] = CompatibilityType.REDUNDANT_2_TO_1
|
||||
}
|
||||
|
||||
// building the compatibility type mapping
|
||||
init {
|
||||
recordIncompatiblePairs(IN_KEYWORD, OUT_KEYWORD) // Variance
|
||||
recordIncompatiblePairs(PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD) // Visibilities
|
||||
recordIncompatiblePairs(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD, ACTUAL_KEYWORD)
|
||||
recordIncompatiblePairs(FINAL_KEYWORD, ABSTRACT_KEYWORD)
|
||||
recordIncompatiblePairs(FINAL_KEYWORD, OPEN_KEYWORD, SEALED_KEYWORD)
|
||||
recordIncompatiblePairs(CROSSINLINE_KEYWORD, NOINLINE_KEYWORD)
|
||||
|
||||
recordIncompatiblePairs(DATA_KEYWORD, OPEN_KEYWORD)
|
||||
recordIncompatiblePairs(DATA_KEYWORD, INNER_KEYWORD)
|
||||
recordIncompatiblePairs(DATA_KEYWORD, ABSTRACT_KEYWORD)
|
||||
recordIncompatiblePairs(DATA_KEYWORD, SEALED_KEYWORD)
|
||||
recordIncompatiblePairs(DATA_KEYWORD, INLINE_KEYWORD)
|
||||
|
||||
recordIncompatiblePairs(CONST_KEYWORD, ABSTRACT_KEYWORD)
|
||||
recordIncompatiblePairs(CONST_KEYWORD, OPEN_KEYWORD)
|
||||
recordIncompatiblePairs(CONST_KEYWORD, OVERRIDE_KEYWORD)
|
||||
|
||||
recordIncompatiblePairs(PRIVATE_KEYWORD, OVERRIDE_KEYWORD)
|
||||
recordPairsCompatibleForClasses(PRIVATE_KEYWORD, OPEN_KEYWORD)
|
||||
recordPairsCompatibleForClasses(PRIVATE_KEYWORD, ABSTRACT_KEYWORD)
|
||||
|
||||
// 1. subclasses contained inside a sealed class can not be instantiated, because their constructors needs
|
||||
// an instance of an outer sealed (effectively abstract) class
|
||||
// 2. subclasses of a non-top-level sealed class must be declared inside the class
|
||||
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
|
||||
recordIncompatiblePairs(SEALED_KEYWORD, INNER_KEYWORD)
|
||||
|
||||
recordRedundantPairs(OPEN_KEYWORD, ABSTRACT_KEYWORD)
|
||||
recordRedundantPairs(ABSTRACT_KEYWORD, SEALED_KEYWORD)
|
||||
}
|
||||
|
||||
private fun deduceCompatibilityType(firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken): CompatibilityType =
|
||||
if (firstKeyword == secondKeyword) {
|
||||
CompatibilityType.REPEATED
|
||||
} else {
|
||||
compatibilityTypeMap[Pair(firstKeyword, secondKeyword)] ?: CompatibilityType.COMPATIBLE
|
||||
}
|
||||
|
||||
private fun checkCompatibilityType(
|
||||
firstModifier: FirModifier<*>,
|
||||
secondModifier: FirModifier<*>,
|
||||
reporter: DiagnosticReporter,
|
||||
reportedNodes: MutableSet<FirModifier<*>>,
|
||||
owner: FirDeclaration?
|
||||
) {
|
||||
val firstToken = firstModifier.token
|
||||
val secondToken = secondModifier.token
|
||||
when (val compatibilityType = deduceCompatibilityType(firstToken, secondToken)) {
|
||||
CompatibilityType.COMPATIBLE -> {}
|
||||
CompatibilityType.REPEATED ->
|
||||
if (reportedNodes.add(secondModifier)) reporter.reportRepeatedModifier(secondModifier, secondToken)
|
||||
CompatibilityType.REDUNDANT_2_TO_1 ->
|
||||
reporter.reportRedundantModifier(secondModifier, secondToken, firstToken)
|
||||
CompatibilityType.REDUNDANT_1_TO_2 ->
|
||||
reporter.reportRedundantModifier(firstModifier, firstToken, secondToken)
|
||||
CompatibilityType.DEPRECATED -> {
|
||||
reporter.reportDeprecatedModifierPair(firstModifier, firstToken, secondToken)
|
||||
reporter.reportDeprecatedModifierPair(secondModifier, secondToken, firstToken)
|
||||
}
|
||||
CompatibilityType.INCOMPATIBLE, CompatibilityType.COMPATIBLE_FOR_CLASSES -> {
|
||||
if (compatibilityType == CompatibilityType.COMPATIBLE_FOR_CLASSES && owner is FirClass<*>) {
|
||||
return
|
||||
}
|
||||
if (reportedNodes.add(firstModifier)) reporter.reportIncompatibleModifiers(firstModifier, firstToken, secondToken)
|
||||
if (reportedNodes.add(secondModifier)) reporter.reportIncompatibleModifiers(secondModifier, secondToken, firstToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkModifiers(
|
||||
list: FirModifierList,
|
||||
owner: FirDeclaration,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
// general strategy: report no more than one error and any number of warnings
|
||||
// therefore, a track of nodes with already reported errors should be kept
|
||||
val reportedNodes = hashSetOf<FirModifier<*>>()
|
||||
|
||||
val modifiers = list.modifiers
|
||||
for (secondModifier in modifiers) {
|
||||
for (firstModifier in modifiers) {
|
||||
if (firstModifier == secondModifier) {
|
||||
break
|
||||
}
|
||||
checkCompatibilityType(firstModifier, secondModifier, reporter, reportedNodes, owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDeclarationMappedToSourceCorrectly(declaration: FirDeclaration, source: FirSourceElement): Boolean =
|
||||
when (source.elementType) {
|
||||
KtNodeTypes.CLASS -> declaration is FirClass<*>
|
||||
KtNodeTypes.OBJECT_DECLARATION -> declaration is FirClass<*>
|
||||
KtNodeTypes.PROPERTY -> declaration is FirProperty
|
||||
KtNodeTypes.VALUE_PARAMETER -> declaration is FirValueParameter
|
||||
// TODO more FIR-PSI relations possibly have to be added
|
||||
else -> true
|
||||
}
|
||||
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = declaration.source ?: return
|
||||
if (!isDeclarationMappedToSourceCorrectly(declaration, source)) return
|
||||
if (context.containingDeclarations.last() is FirDefaultPropertyAccessor) return
|
||||
|
||||
val modifierList = source.getModifierList()
|
||||
modifierList?.let { checkModifiers(it, declaration, reporter) }
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportRepeatedModifier(
|
||||
modifier: FirModifier<*>, keyword: KtModifierKeywordToken
|
||||
) {
|
||||
val source = modifier.source
|
||||
source?.let { report(FirErrors.REPEATED_MODIFIER.on(it, keyword)) }
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportRedundantModifier(
|
||||
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken
|
||||
) {
|
||||
val source = modifier.source
|
||||
source?.let { report(FirErrors.REDUNDANT_MODIFIER.on(it, firstKeyword, secondKeyword)) }
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportDeprecatedModifierPair(
|
||||
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken
|
||||
) {
|
||||
val source = modifier.source
|
||||
source?.let { report(FirErrors.DEPRECATED_MODIFIER_PAIR.on(it, firstKeyword, secondKeyword)) }
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportIncompatibleModifiers(
|
||||
modifier: FirModifier<*>, firstKeyword: KtModifierKeywordToken, secondKeyword: KtModifierKeywordToken
|
||||
) {
|
||||
val source = modifier.source
|
||||
source?.let { report(FirErrors.INCOMPATIBLE_MODIFIERS.on(it, firstKeyword, secondKeyword)) }
|
||||
}
|
||||
|
||||
}
|
||||
+13
-1
@@ -21,6 +21,10 @@ class DeclarationCheckersDiagnosticComponent(collector: AbstractDiagnosticCollec
|
||||
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(regularClass, data, it) }
|
||||
}
|
||||
|
||||
override fun visitSealedClass(sealedClass: FirSealedClass, data: CheckerContext) {
|
||||
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(sealedClass, data, it) }
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: CheckerContext) {
|
||||
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(simpleFunction, data, it) }
|
||||
}
|
||||
@@ -45,11 +49,19 @@ class DeclarationCheckersDiagnosticComponent(collector: AbstractDiagnosticCollec
|
||||
runCheck { DeclarationCheckers.DECLARATIONS.check(valueParameter, data, it) }
|
||||
}
|
||||
|
||||
override fun visitTypeParameter(typeParameter: FirTypeParameter, data: CheckerContext) {
|
||||
runCheck { DeclarationCheckers.DECLARATIONS.check(typeParameter, data, it) }
|
||||
}
|
||||
|
||||
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: CheckerContext) {
|
||||
runCheck { DeclarationCheckers.DECLARATIONS.check(enumEntry, data, it) }
|
||||
}
|
||||
|
||||
private fun <D : FirDeclaration> List<FirDeclarationChecker<D>>.check(declaration: D, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
private fun <D : FirDeclaration> List<FirDeclarationChecker<D>>.check(
|
||||
declaration: D,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
for (checker in this) {
|
||||
checker.check(declaration, context, reporter)
|
||||
}
|
||||
|
||||
+10
@@ -9,18 +9,23 @@ import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.TO_STRING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_MODIFIER_PAIR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ENUM_AS_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_MODIFIERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OTHER_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_IMPLICIT_TYPES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_SUPERTYPES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_IS_NOT_AN_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
|
||||
@@ -52,6 +57,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(ERROR_FROM_JAVA_RESOLUTION, "Java resolution error")
|
||||
map.put(OTHER_ERROR, "Unknown (other) error")
|
||||
map.put(SUPER_IS_NOT_AN_EXPRESSION, "Super cannot be a callee")
|
||||
|
||||
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING)
|
||||
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING)
|
||||
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING)
|
||||
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -22,4 +22,6 @@ object FirDiagnosticRenderers {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val TO_STRING = Renderer<Any> { it.toString() }
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
|
||||
object FirErrors {
|
||||
val UNRESOLVED_REFERENCE by error1<FirSourceElement, String?>()
|
||||
@@ -34,4 +35,9 @@ object FirErrors {
|
||||
val SUPER_IS_NOT_AN_EXPRESSION by error0<FirSourceElement>()
|
||||
|
||||
val INAPPLICABLE_INFIX_MODIFIER by existing<FirSourceElement, String>(Errors.INAPPLICABLE_INFIX_MODIFIER)
|
||||
|
||||
val REPEATED_MODIFIER by error1<FirSourceElement, KtModifierKeywordToken>()
|
||||
val REDUNDANT_MODIFIER by error2<FirSourceElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val INCOMPATIBLE_MODIFIERS by error2<FirSourceElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
}
|
||||
|
||||
@@ -37,14 +37,34 @@ class FirLightModifierList(val modifierList: LighterASTNode, val tree: Flyweight
|
||||
val modifierNodes = kidsRef.get()
|
||||
return modifierNodes.filterNotNull()
|
||||
.filter { it.tokenType is KtModifierKeywordToken }
|
||||
.map { FirLightModifier(it, it.tokenType as KtModifierKeywordToken) }
|
||||
.map { FirLightModifier(it, it.tokenType as KtModifierKeywordToken, tree) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class FirModifier<Node : Any>(val node: Node, val token: KtModifierKeywordToken)
|
||||
|
||||
class FirPsiModifier(node: ASTNode, token: KtModifierKeywordToken) : FirModifier<ASTNode>(node, token)
|
||||
class FirPsiModifier(
|
||||
node: ASTNode,
|
||||
token: KtModifierKeywordToken
|
||||
) : FirModifier<ASTNode>(node, token)
|
||||
|
||||
class FirLightModifier(node: LighterASTNode, token: KtModifierKeywordToken) : FirModifier<LighterASTNode>(node, token)
|
||||
class FirLightModifier(
|
||||
node: LighterASTNode,
|
||||
token: KtModifierKeywordToken,
|
||||
val tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
) : FirModifier<LighterASTNode>(node, token)
|
||||
|
||||
val FirModifier<*>.psi: PsiElement? get() = (this as? FirPsiModifier)?.node?.psi
|
||||
val FirModifier<*>.psi: PsiElement? get() = (this as? FirPsiModifier)?.node?.psi
|
||||
|
||||
val FirModifier<*>.lightNode: LighterASTNode? get() = (this as? FirLightModifier)?.node
|
||||
|
||||
val FirModifier<*>.source: FirSourceElement?
|
||||
get() = when (this) {
|
||||
is FirPsiModifier -> this.psi?.toFirSourceElement()
|
||||
is FirLightModifier -> {
|
||||
// TODO pretty sure I got offsets wrong here
|
||||
val startOffset = tree.getStartOffset(node)
|
||||
val endOffset = tree.getEndOffset(node)
|
||||
FirLightSourceElement(node, startOffset, endOffset, tree)
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
@@ -7,7 +7,7 @@ annotation class A
|
||||
@A
|
||||
open class B1 {
|
||||
@A
|
||||
private open fun foo() {}
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>open<!> fun foo() {}
|
||||
}
|
||||
|
||||
class D1 : B1() {
|
||||
|
||||
@@ -2,7 +2,7 @@ interface SuperInterface
|
||||
|
||||
open class SuperClass
|
||||
|
||||
abstract data class Base(val x: Int)
|
||||
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class Base(val x: Int)
|
||||
|
||||
class Derived: Base(42)
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
class Outer {
|
||||
inner data class Inner(val x: Int)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class Outer {
|
||||
<!INCOMPATIBLE_MODIFIERS!>inner<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class Inner(val x: Int)
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
inner data class Outer(val x: Int)
|
||||
<!INCOMPATIBLE_MODIFIERS!>inner<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class Outer(val x: Int)
|
||||
@@ -1,4 +0,0 @@
|
||||
sealed data class My(val x: Int) {
|
||||
object Your: My(1)
|
||||
class His(y: Int): My(y)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
<!INCOMPATIBLE_MODIFIERS!>sealed<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class My(val x: Int) {
|
||||
object Your: My(1)
|
||||
class His(y: Int): My(y)
|
||||
|
||||
+1
-1
@@ -30,4 +30,4 @@ open inline class D1(val x: Int)
|
||||
abstract inline class D2(val x: Int)
|
||||
sealed inline class D3(val x: Int)
|
||||
|
||||
inline data class D4(val x: String)
|
||||
<!INCOMPATIBLE_MODIFIERS!>inline<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class D4(val x: String)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package illegal_modifiers
|
||||
|
||||
abstract class A() {
|
||||
abstract final fun f()
|
||||
abstract open fun g()
|
||||
final open fun h() {}
|
||||
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>final<!> fun f()
|
||||
abstract <!REDUNDANT_MODIFIER!>open<!> fun g()
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>open<!> fun h() {}
|
||||
|
||||
open var r: String
|
||||
get
|
||||
@@ -21,8 +21,8 @@ class FinalClass() {
|
||||
open set(v: Int) {}
|
||||
}
|
||||
|
||||
private public class C
|
||||
private public object D
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>public<!> class C
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>public<!> object D
|
||||
|
||||
//A sample annotation to check annotation usage in parameters.
|
||||
annotation class annotated(val text: String = "not given")
|
||||
@@ -32,8 +32,8 @@ class LegalModifier(val a: Int, @annotated private var b: String, @annotated var
|
||||
|
||||
//Check illegal modifier in constructor parameters
|
||||
class IllegalModifiers1(
|
||||
in
|
||||
out
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
reified
|
||||
enum
|
||||
private
|
||||
@@ -41,7 +41,7 @@ class IllegalModifiers1(
|
||||
a: Int)
|
||||
|
||||
//Check multiple illegal modifiers in constructor
|
||||
class IllegalModifiers2(private abstract a: Int)
|
||||
class IllegalModifiers2(<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> a: Int)
|
||||
|
||||
|
||||
//Check annotations with illegal modifiers in constructor
|
||||
@@ -65,10 +65,10 @@ abstract class IllegalModifiers5() {
|
||||
private fun qux() {
|
||||
|
||||
//Check illegal modifier in catch block
|
||||
try {} catch (in out reified enum public e: Exception) {}
|
||||
try {} catch (<!INCOMPATIBLE_MODIFIERS!>in<!> <!INCOMPATIBLE_MODIFIERS!>out<!> reified enum public e: Exception) {}
|
||||
|
||||
//Check multiple illegal modifiers in catch block
|
||||
try {} catch (in out reified enum abstract public e: Exception) {}
|
||||
try {} catch (<!INCOMPATIBLE_MODIFIERS!>in<!> <!INCOMPATIBLE_MODIFIERS!>out<!> reified enum abstract public e: Exception) {}
|
||||
|
||||
//Check annotations with illegal modifiers
|
||||
try {} catch (@annotated("a text") abstract public e: Exception) {}
|
||||
@@ -92,24 +92,24 @@ abstract class IllegalModifiers6() {
|
||||
|
||||
// strange inappropriate modifiers usages
|
||||
override
|
||||
out
|
||||
in
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
vararg
|
||||
reified
|
||||
class IllegalModifiers7() {
|
||||
enum
|
||||
inner
|
||||
annotation
|
||||
out
|
||||
in
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
vararg
|
||||
reified
|
||||
val x = 1
|
||||
enum
|
||||
inner
|
||||
annotation
|
||||
out
|
||||
in
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
vararg
|
||||
reified
|
||||
const
|
||||
@@ -118,46 +118,46 @@ class IllegalModifiers7() {
|
||||
|
||||
// Secondary constructors
|
||||
class IllegalModifiers8 {
|
||||
abstract
|
||||
<!INCOMPATIBLE_MODIFIERS!>abstract<!>
|
||||
enum
|
||||
open
|
||||
<!INCOMPATIBLE_MODIFIERS, REDUNDANT_MODIFIER!>open<!>
|
||||
inner
|
||||
annotation
|
||||
override
|
||||
out
|
||||
in
|
||||
final
|
||||
<!INCOMPATIBLE_MODIFIERS!>override<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!>
|
||||
vararg
|
||||
reified
|
||||
const<!SYNTAX!><!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>const<!><!SYNTAX!><!>
|
||||
constructor() {}
|
||||
|
||||
constructor(private enum abstract x: Int) {}
|
||||
constructor(<!INCOMPATIBLE_MODIFIERS!>private<!> enum <!INCOMPATIBLE_MODIFIERS!>abstract<!> x: Int) {}
|
||||
}
|
||||
|
||||
class IllegalModifiers9 {
|
||||
private protected constructor() {}
|
||||
private internal constructor(x: Int) {}
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>protected<!> constructor() {}
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>internal<!> constructor(x: Int) {}
|
||||
}
|
||||
|
||||
// Illegal modifiers on primary constructor
|
||||
|
||||
class IllegalModifiers10
|
||||
abstract
|
||||
<!INCOMPATIBLE_MODIFIERS!>abstract<!>
|
||||
enum
|
||||
open
|
||||
<!INCOMPATIBLE_MODIFIERS, REDUNDANT_MODIFIER!>open<!>
|
||||
inner
|
||||
annotation
|
||||
override
|
||||
out
|
||||
in
|
||||
final
|
||||
<!INCOMPATIBLE_MODIFIERS!>override<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!>
|
||||
vararg
|
||||
reified
|
||||
const constructor()
|
||||
<!INCOMPATIBLE_MODIFIERS!>const<!> constructor()
|
||||
|
||||
class IllegalModifiers11 private protected constructor()
|
||||
class IllegalModifiers11 <!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>protected<!> constructor()
|
||||
|
||||
class Outer {
|
||||
inner sealed class Inner
|
||||
<!INCOMPATIBLE_MODIFIERS!>inner<!> <!INCOMPATIBLE_MODIFIERS!>sealed<!> class Inner
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ object A {
|
||||
class B(const val constructor: Int = 5)
|
||||
|
||||
abstract class C {
|
||||
open const val x: Int = 6
|
||||
<!INCOMPATIBLE_MODIFIERS!>open<!> <!INCOMPATIBLE_MODIFIERS!>const<!> val x: Int = 6
|
||||
|
||||
abstract const val y: Int = 7
|
||||
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>const<!> val y: Int = 7
|
||||
|
||||
companion object {
|
||||
const val inCompaionObject = 8
|
||||
@@ -25,7 +25,7 @@ abstract class C {
|
||||
}
|
||||
|
||||
object D : C() {
|
||||
override const val x: Int = 9
|
||||
<!INCOMPATIBLE_MODIFIERS!>override<!> <!INCOMPATIBLE_MODIFIERS!>const<!> val x: Int = 9
|
||||
|
||||
const val inObject = 10
|
||||
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
interface Foo<T>
|
||||
interface Foo1<in out T>
|
||||
interface Foo2<in in T>
|
||||
interface Foo1<<!INCOMPATIBLE_MODIFIERS!>in<!> <!INCOMPATIBLE_MODIFIERS!>out<!> T>
|
||||
interface Foo2<in <!REPEATED_MODIFIER!>in<!> T>
|
||||
|
||||
fun test1(foo: Foo<in out Int>) = foo
|
||||
fun test2(): Foo<in in Int> = throw Exception()
|
||||
@@ -10,11 +10,11 @@ fun test2(): Foo<in in Int> = throw Exception()
|
||||
fun test3() {
|
||||
val f: Foo<out out out out Int>
|
||||
|
||||
class Bzz<in in T>
|
||||
class Bzz<in <!REPEATED_MODIFIER!>in<!> T>
|
||||
}
|
||||
|
||||
class A {
|
||||
fun <out out T> bar() {
|
||||
fun <out <!REPEATED_MODIFIER!>out<!> T> bar() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ fun gav(noinline x: (Int) -> Unit, crossinline y: (String) -> Int) {}
|
||||
|
||||
inline fun correct(noinline x: (Int) -> Unit, crossinline y: (String) -> Int) {}
|
||||
|
||||
inline fun incompatible(noinline crossinline x: () -> String) {}
|
||||
inline fun incompatible(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: () -> String) {}
|
||||
|
||||
class FunctionSubtype : () -> Unit {
|
||||
override fun invoke() {}
|
||||
}
|
||||
|
||||
inline fun functionSubtype(
|
||||
noinline f: FunctionSubtype,
|
||||
crossinline g: FunctionSubtype
|
||||
noinline f: FunctionSubtype,
|
||||
crossinline g: FunctionSubtype
|
||||
) { }
|
||||
|
||||
+17
-17
@@ -19,30 +19,30 @@ class A : (vararg Int)->Unit {
|
||||
get(): (vararg x: Int)->Unit = {}
|
||||
}
|
||||
|
||||
val allProhibited: (abstract
|
||||
val allProhibited: (<!INCOMPATIBLE_MODIFIERS, REDUNDANT_MODIFIER!>abstract<!>
|
||||
annotation
|
||||
companion
|
||||
const
|
||||
crossinline
|
||||
data
|
||||
<!INCOMPATIBLE_MODIFIERS!>const<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>crossinline<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>data<!>
|
||||
enum
|
||||
external
|
||||
final
|
||||
in
|
||||
inline
|
||||
inner
|
||||
internal
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>in<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>inline<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>inner<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>internal<!>
|
||||
lateinit
|
||||
noinline
|
||||
open
|
||||
<!INCOMPATIBLE_MODIFIERS!>noinline<!>
|
||||
<!INCOMPATIBLE_MODIFIERS, REDUNDANT_MODIFIER!>open<!>
|
||||
operator
|
||||
out
|
||||
override
|
||||
private
|
||||
protected
|
||||
public
|
||||
<!INCOMPATIBLE_MODIFIERS!>out<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>override<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>protected<!>
|
||||
<!INCOMPATIBLE_MODIFIERS!>public<!>
|
||||
reified
|
||||
sealed
|
||||
<!INCOMPATIBLE_MODIFIERS!>sealed<!>
|
||||
tailrec
|
||||
vararg
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
interface My {
|
||||
open fun foo()
|
||||
open fun bar() {}
|
||||
open abstract fun baz(): Int
|
||||
<!REDUNDANT_MODIFIER!>open<!> abstract fun baz(): Int
|
||||
|
||||
open val x: Int
|
||||
open val y: String
|
||||
get() = ""
|
||||
open abstract val z: Double
|
||||
<!REDUNDANT_MODIFIER!>open<!> abstract val z: Double
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
interface My {
|
||||
private val x: Int
|
||||
private abstract val xx: Int
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> val xx: Int
|
||||
private val xxx: Int
|
||||
get() = 0
|
||||
final val y: Int
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
abstract abstract class Foo
|
||||
public public class Bar
|
||||
open open final class Baz {
|
||||
private private fun foo() {}
|
||||
abstract <!REPEATED_MODIFIER!>abstract<!> class Foo
|
||||
public <!REPEATED_MODIFIER!>public<!> class Bar
|
||||
<!INCOMPATIBLE_MODIFIERS!>open<!> <!REPEATED_MODIFIER!>open<!> <!INCOMPATIBLE_MODIFIERS!>final<!> class Baz {
|
||||
private <!REPEATED_MODIFIER!>private<!> fun foo() {}
|
||||
}
|
||||
|
||||
class Bzz(public public val q: Int = 1) {
|
||||
public public val x: Int = 2
|
||||
class Bzz(public <!REPEATED_MODIFIER!>public<!> val q: Int = 1) {
|
||||
public <!REPEATED_MODIFIER!>public<!> val x: Int = 2
|
||||
|
||||
public val y: Int
|
||||
public public get() = 3
|
||||
public <!REPEATED_MODIFIER!>public<!> get() = 3
|
||||
|
||||
val z: Int
|
||||
open final get() = 4
|
||||
<!INCOMPATIBLE_MODIFIERS!>open<!> <!INCOMPATIBLE_MODIFIERS!>final<!> get() = 4
|
||||
|
||||
public public class B(public public val z: Int = 1) {
|
||||
public public val y: Int = 2
|
||||
public <!REPEATED_MODIFIER!>public<!> class B(public <!REPEATED_MODIFIER!>public<!> val z: Int = 1) {
|
||||
public <!REPEATED_MODIFIER!>public<!> val y: Int = 2
|
||||
|
||||
public val x: Int
|
||||
public public get() = 3
|
||||
public <!REPEATED_MODIFIER!>public<!> get() = 3
|
||||
}
|
||||
|
||||
public public object C {
|
||||
public public val y: Int = 1
|
||||
public public fun z(): Int = 1
|
||||
public <!REPEATED_MODIFIER!>public<!> object C {
|
||||
public <!REPEATED_MODIFIER!>public<!> val y: Int = 1
|
||||
public <!REPEATED_MODIFIER!>public<!> fun z(): Int = 1
|
||||
}
|
||||
}
|
||||
|
||||
public public val bar: Int = 1
|
||||
public <!REPEATED_MODIFIER!>public<!> val bar: Int = 1
|
||||
|
||||
public public fun foo(): Int = 1
|
||||
public <!REPEATED_MODIFIER!>public<!> fun foo(): Int = 1
|
||||
|
||||
fun test() {
|
||||
public public class B(public public val z: Int = 1) {
|
||||
public public val y: Int = 2
|
||||
public <!REPEATED_MODIFIER!>public<!> class B(public <!REPEATED_MODIFIER!>public<!> val z: Int = 1) {
|
||||
public <!REPEATED_MODIFIER!>public<!> val y: Int = 2
|
||||
|
||||
public val x: Int
|
||||
public public get() = 3
|
||||
public <!REPEATED_MODIFIER!>public<!> get() = 3
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
|
||||
header impl class First
|
||||
<!INCOMPATIBLE_MODIFIERS!>header<!> <!INCOMPATIBLE_MODIFIERS!>impl<!> class First
|
||||
|
||||
header expect class Second
|
||||
<!INCOMPATIBLE_MODIFIERS!>header<!> <!INCOMPATIBLE_MODIFIERS!>expect<!> class Second
|
||||
|
||||
header actual class Third
|
||||
<!INCOMPATIBLE_MODIFIERS!>header<!> <!INCOMPATIBLE_MODIFIERS!>actual<!> class Third
|
||||
|
||||
impl expect class Fourth
|
||||
<!INCOMPATIBLE_MODIFIERS!>impl<!> <!INCOMPATIBLE_MODIFIERS!>expect<!> class Fourth
|
||||
|
||||
impl actual class Fifth
|
||||
<!INCOMPATIBLE_MODIFIERS!>impl<!> <!INCOMPATIBLE_MODIFIERS!>actual<!> class Fifth
|
||||
|
||||
expect actual class Sixth
|
||||
<!INCOMPATIBLE_MODIFIERS!>expect<!> <!INCOMPATIBLE_MODIFIERS!>actual<!> class Sixth
|
||||
Vendored
+3
-3
@@ -11,7 +11,7 @@ public abstract class TestBug1() {
|
||||
position(m1().second)
|
||||
}
|
||||
|
||||
private abstract fun m1(): Pair<Int, Int>
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> fun m1(): Pair<Int, Int>
|
||||
|
||||
private fun position(p: Int) {}
|
||||
|
||||
@@ -19,6 +19,6 @@ public abstract class TestBug1() {
|
||||
|
||||
//from library
|
||||
public class Pair<out A, out B> (
|
||||
public val first: A,
|
||||
public val second: B
|
||||
public val first: A,
|
||||
public val second: B
|
||||
)
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ class C : A() {
|
||||
|
||||
//------------
|
||||
open class D {
|
||||
private open fun self() : D = this
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>open<!> fun self() : D = this
|
||||
}
|
||||
|
||||
class E : D() {
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class E : C(), T {
|
||||
}
|
||||
|
||||
class F : C(), T {
|
||||
private override fun foo() {}
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>override<!> fun foo() {}
|
||||
}
|
||||
|
||||
class G : C(), T {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
final sealed class Base {
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>sealed<!> class Base {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
open sealed class Base {
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
<!INCOMPATIBLE_MODIFIERS!>open<!> <!INCOMPATIBLE_MODIFIERS!>sealed<!> class Base {
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
abstract sealed class Base {
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
<!REDUNDANT_MODIFIER!>abstract<!> sealed class Base {
|
||||
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ interface Allowed
|
||||
|
||||
open class NotAllowed
|
||||
|
||||
abstract data class Base(val x: Int)
|
||||
<!INCOMPATIBLE_MODIFIERS!>abstract<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class Base(val x: Int)
|
||||
|
||||
class Derived: Base(42)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user