FIR checker: introduce top-level function checker
This commit is contained in:
committed by
Mikhail Glukhikh
parent
df68f319bc
commit
9341ca3004
+2
-1
@@ -19,7 +19,8 @@ FILE: operatorsOverLiterals.kt
|
||||
}
|
||||
public final fun R|kotlin/Int|.bar(): R|kotlin/Int| {
|
||||
}
|
||||
public final fun R|kotlin/Int|.baz(): R|kotlin/Int|
|
||||
public final fun R|kotlin/Int|.baz(): R|kotlin/Int| {
|
||||
}
|
||||
public final fun R|kotlin/Byte|.baz(): R|kotlin/Byte| {
|
||||
}
|
||||
public final fun test_3(): R|kotlin/Unit| {
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ fun test_2(n: Int) {
|
||||
|
||||
fun Int.bar(): Int {}
|
||||
|
||||
fun Int.baz(): Int
|
||||
fun Int.baz(): Int {}
|
||||
fun Byte.baz(): Byte {}
|
||||
|
||||
fun test_3() {
|
||||
|
||||
+2
-1
@@ -111,7 +111,8 @@ FILE: conflictingOverloads.kt
|
||||
}
|
||||
|
||||
}
|
||||
public final fun mest(): R|kotlin/Unit|
|
||||
public final fun mest(): R|kotlin/Unit| {
|
||||
}
|
||||
public final class mest : R|kotlin/Any| {
|
||||
public constructor(): R|mest| {
|
||||
super<R|kotlin/Any|>()
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ class L {
|
||||
fun B.foo() {}
|
||||
}
|
||||
|
||||
fun mest()
|
||||
fun mest() {}
|
||||
|
||||
class mest
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ interface B
|
||||
class Clazz1 : A, B
|
||||
class Clazz2 : A, B
|
||||
|
||||
fun <K> select(x: K, y: K): K
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>fun <K> select(x: K, y: K): K<!>
|
||||
|
||||
fun test() = select(Clazz1(), Clazz2())
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ package a.d
|
||||
|
||||
import b.d.*
|
||||
|
||||
fun foo(arg: Other): Another
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>fun foo(arg: Other): Another<!>
|
||||
|
||||
fun bar() {
|
||||
baz()
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
|
||||
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.lexer.KtTokens
|
||||
|
||||
// See old FE's [DeclarationsChecker]
|
||||
object FirTopLevelFunctionChecker : FirFileChecker() {
|
||||
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
for (topLevelDeclaration in declaration.declarations) {
|
||||
if (topLevelDeclaration is FirSimpleFunction) {
|
||||
checkFunction(topLevelDeclaration, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFunction(function: FirSimpleFunction, reporter: DiagnosticReporter) {
|
||||
val source = function.source ?: return
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
val hasAbstractModifier = modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
|
||||
val isExternal = function.isExternal || modifierList?.modifiers?.any { it.token == KtTokens.EXTERNAL_KEYWORD } == true
|
||||
val isExpect = function.isExpect || modifierList?.modifiers?.any { it.token == KtTokens.EXPECT_KEYWORD } == true
|
||||
if (!function.hasBody && !hasAbstractModifier && !isExternal && !isExpect) {
|
||||
reporter.report(FirErrors.NON_MEMBER_FUNCTION_NO_BODY.on(source, function))
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -80,6 +80,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OB
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_MEMBER_FUNCTION_NO_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_SEALED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_AN_ANNOTATION_CLASS
|
||||
@@ -359,6 +360,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(ABSTRACT_FUNCTION_WITH_BODY, "A function ''{0}'' with body cannot be abstract", DECLARATION_NAME)
|
||||
map.put(NON_ABSTRACT_FUNCTION_WITH_NO_BODY, "Function ''{0}'' without a body must be abstract", DECLARATION_NAME)
|
||||
map.put(PRIVATE_FUNCTION_WITH_NO_BODY, "Function ''{0}'' without body cannot be private", DECLARATION_NAME)
|
||||
map.put(NON_MEMBER_FUNCTION_NO_BODY, "Function ''{0}'' must have a body", DECLARATION_NAME)
|
||||
|
||||
map.put(FUNCTION_DECLARATION_WITH_NO_NAME, "Function declaration must have a name")
|
||||
|
||||
|
||||
@@ -155,6 +155,7 @@ object FirErrors {
|
||||
val ABSTRACT_FUNCTION_WITH_BODY by error1<FirSourceElement, KtFunction, FirMemberDeclaration>(SourceElementPositioningStrategies.MODALITY_MODIFIER)
|
||||
val NON_ABSTRACT_FUNCTION_WITH_NO_BODY by error1<FirSourceElement, KtFunction, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val PRIVATE_FUNCTION_WITH_NO_BODY by error1<FirSourceElement, KtFunction, FirMemberDeclaration>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
||||
val NON_MEMBER_FUNCTION_NO_BODY by error1<FirSourceElement, KtFunction, FirMemberDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
val FUNCTION_DECLARATION_WITH_NO_NAME by error0<FirSourceElement, KtFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
|
||||
+4
@@ -59,6 +59,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirConstructorAllowedChecker,
|
||||
)
|
||||
|
||||
override val fileCheckers: Set<FirFileChecker> = setOf(
|
||||
FirTopLevelFunctionChecker,
|
||||
)
|
||||
|
||||
override val controlFlowAnalyserCheckers: Set<FirControlFlowChecker> = setOf(
|
||||
FirCallsEffectAnalyzer,
|
||||
FirReturnsImpliesAnalyzer,
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ package MyPackage
|
||||
abstract val e3: Int = 0; get() = a
|
||||
|
||||
//methods
|
||||
fun f()
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>fun f()<!>
|
||||
fun g() {}
|
||||
abstract fun h()
|
||||
abstract fun j() {}
|
||||
|
||||
@@ -6,4 +6,4 @@ abstract class Abst {
|
||||
abstract fun foo(x: Int = <!UNRESOLVED_REFERENCE!>y<!>, y: Int = x)
|
||||
}
|
||||
|
||||
fun extraDiagnostics(x: Int = <!UNRESOLVED_REFERENCE!>y<!>, y: Int)
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>fun extraDiagnostics(x: Int = <!UNRESOLVED_REFERENCE!>y<!>, y: Int)<!>
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
fun bar()
|
||||
+1
@@ -1 +1,2 @@
|
||||
// FIR_IDENTICAL
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>fun bar()<!>
|
||||
|
||||
Vendored
+2
-2
@@ -7,6 +7,6 @@ expect fun foo()
|
||||
// MODULE: m2-jvm(m1-common)
|
||||
// FILE: jvm.kt
|
||||
|
||||
actual fun foo()
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>actual fun foo()<!>
|
||||
|
||||
actual fun bar()
|
||||
<!NON_MEMBER_FUNCTION_NO_BODY!>actual fun bar()<!>
|
||||
|
||||
Reference in New Issue
Block a user