FIR checker: introduce top-level function checker

This commit is contained in:
Jinseong Jeon
2021-01-19 15:09:00 -08:00
committed by Mikhail Glukhikh
parent df68f319bc
commit 9341ca3004
15 changed files with 59 additions and 11 deletions
@@ -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| {
@@ -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() {
@@ -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|>()
@@ -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()
@@ -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))
}
}
}
@@ -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)
@@ -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
View File
@@ -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)<!>
@@ -1 +1,2 @@
// FIR_IDENTICAL
<!NON_MEMBER_FUNCTION_NO_BODY!>fun bar()<!>
@@ -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()<!>