[FIR JS] Report CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION
This commit is contained in:
committed by
Space Team
parent
4cf8d9ffb9
commit
56285bb2d6
+2
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy
|
||||
@@ -38,6 +39,7 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") {
|
||||
val OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<FirNamedFunctionSymbol>("function")
|
||||
}
|
||||
val CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION by error<PsiElement>()
|
||||
}
|
||||
|
||||
val DYNAMICS by object : DiagnosticGroup("Dynamics") {
|
||||
|
||||
+2
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.diagnostics.js
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||
@@ -35,6 +36,7 @@ object FirJsErrors {
|
||||
// External
|
||||
val OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS by error0<KtElement>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE by error1<KtElement, FirNamedFunctionSymbol>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION by error0<PsiElement>()
|
||||
|
||||
// Dynamics
|
||||
val DELEGATION_BY_DYNAMIC by error0<KtElement>()
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.checkMissingMessages
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.DELEGATION_BY_DYNAMIC
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.IMPLEMENTING_FUNCTION_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_MODULE_PROHIBITED_ON_NON_NATIVE
|
||||
@@ -42,6 +43,7 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"Overriding `external` function with optional parameters by declaration from superclass: {0}",
|
||||
FirDiagnosticRenderers.SYMBOL
|
||||
)
|
||||
map.put(CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION, "This property can only be used from external declarations")
|
||||
|
||||
map.checkMissingMessages(FirJsErrors)
|
||||
}
|
||||
|
||||
+30
-1
@@ -14,12 +14,14 @@ import org.jetbrains.kotlin.fir.analysis.checkers.directOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.hasAnnotationOrInsideAnnotatedClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
|
||||
private val FirBasedSymbol<*>.isExternal
|
||||
@@ -46,6 +48,10 @@ fun FirBasedSymbol<*>.isEffectivelyExternal(session: FirSession): Boolean {
|
||||
return getContainingClassSymbol(session)?.isEffectivelyExternal(session) == true
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isEffectivelyExternalMember(session: FirSession): Boolean {
|
||||
return fir is FirMemberDeclaration && isEffectivelyExternal(session)
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isEffectivelyExternal(context: CheckerContext) = isEffectivelyExternal(context.session)
|
||||
|
||||
fun FirFunctionSymbol<*>.isOverridingExternalWithOptionalParams(context: CheckerContext): Boolean {
|
||||
@@ -66,10 +72,33 @@ fun FirBasedSymbol<*>.isNativeObject(session: FirSession): Boolean {
|
||||
}
|
||||
|
||||
if (this is FirPropertyAccessorSymbol) {
|
||||
return propertySymbol.hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsNative, session)
|
||||
val property = propertySymbol
|
||||
return property.hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsNative, session)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private val FirBasedSymbol<*>.isExpect
|
||||
get() = when (this) {
|
||||
is FirCallableSymbol<*> -> isExpect
|
||||
is FirClassSymbol<*> -> isExpect
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isPredefinedObject(session: FirSession): Boolean {
|
||||
if (fir is FirMemberDeclaration && isExpect) return true
|
||||
if (isEffectivelyExternalMember(session)) return true
|
||||
|
||||
for (annotation in PredefinedAnnotation.values()) {
|
||||
if (hasAnnotationOrInsideAnnotatedClass(annotation.classId, session)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isNativeObject(context: CheckerContext) = isNativeObject(context.session)
|
||||
|
||||
fun FirBasedSymbol<*>.isPredefinedObject(context: CheckerContext) = isPredefinedObject(context.session)
|
||||
|
||||
+6
-1
@@ -6,11 +6,16 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.js.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.expression.FirJsQualifierChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.expression.*
|
||||
|
||||
object JsExpressionCheckers : ExpressionCheckers() {
|
||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||
get() = setOf(
|
||||
FirJsQualifierChecker,
|
||||
)
|
||||
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
get() = setOf(
|
||||
FirJsDefinedExternallyCallChecker,
|
||||
)
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.js.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.closestNonLocal
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isNativeObject
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isPredefinedObject
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
|
||||
object FirJsDefinedExternallyCallChecker : FirQualifiedAccessChecker() {
|
||||
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val symbol = expression.calleeReference.toResolvedCallableSymbol() ?: return
|
||||
|
||||
if (symbol.callableId !in JsStandardClassIds.Callables.definedExternallyPropertyNames) {
|
||||
return
|
||||
}
|
||||
|
||||
val container = context.closestNonLocal?.symbol ?: return
|
||||
|
||||
if (!container.isNativeObject(context) && !container.isPredefinedObject(context)) {
|
||||
reporter.reportOn(expression.source, FirJsErrors.CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -713,6 +713,8 @@ fun FirNamedFunctionSymbol.directOverriddenFunctions(session: FirSession, scopeS
|
||||
fun FirNamedFunctionSymbol.directOverriddenFunctions(context: CheckerContext) =
|
||||
directOverriddenFunctions(context.session, context.sessionHolder.scopeSession)
|
||||
|
||||
val CheckerContext.closestNonLocal get() = containingDeclarations.takeWhile { it.isNonLocal }.lastOrNull()
|
||||
|
||||
fun CheckerContext.closestNonLocalWith(declaration: FirDeclaration) =
|
||||
(containingDeclarations + declaration).takeWhile { it.isNonLocal }.lastOrNull()
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER -UNUSED_PARAMETER, -UNREACHABLE_CODE
|
||||
|
||||
val prop: String = definedExternally
|
||||
|
||||
val prop2: String
|
||||
get() = definedExternally
|
||||
|
||||
fun foo(x: Int, y: String = definedExternally) {
|
||||
println("Hello")
|
||||
println("world")
|
||||
|
||||
object {
|
||||
fun bar(): Any = definedExternally
|
||||
}
|
||||
|
||||
listOf<String>()
|
||||
.map<String, String> { definedExternally }
|
||||
.filter(fun(x: String): Boolean { definedExternally })
|
||||
|
||||
definedExternally
|
||||
}
|
||||
|
||||
open class A(val x: Int)
|
||||
|
||||
open class B() : A(definedExternally) {
|
||||
constructor(y: String) : this()
|
||||
|
||||
constructor(y: String, z: String) : this(y + z + definedExternally)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER -UNUSED_PARAMETER, -UNREACHABLE_CODE
|
||||
|
||||
val prop: String = <!CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION!>definedExternally<!>
|
||||
@@ -27,3 +28,12 @@ open class B() : A(<!CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION!>d
|
||||
|
||||
constructor(y: String, z: String) : this(y + z + <!CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION!>definedExternally<!>)
|
||||
}
|
||||
|
||||
private fun exposeClassS() = run {
|
||||
class S {
|
||||
inner class W {
|
||||
val v: String = <!CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION!>definedExternally<!>
|
||||
}
|
||||
}
|
||||
S()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package
|
||||
|
||||
public val prop: kotlin.String
|
||||
public val prop2: kotlin.String
|
||||
private fun exposeClassS(): exposeClassS.`<anonymous>`.S
|
||||
public fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String = ...): kotlin.Unit
|
||||
|
||||
public open class A {
|
||||
@@ -21,3 +22,4 @@ public open class B : A {
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user