[FIR] Support diagnostic SUPER_IS_NOT_AN_EXPRESSION

This commit is contained in:
Nick
2020-03-16 22:58:12 +03:00
committed by Mikhail Glukhikh
parent ca22e05acd
commit abcd6bd528
10 changed files with 93 additions and 20 deletions
@@ -0,0 +1,13 @@
class A
class B: A() {
fun act() {
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>()
<!UNRESOLVED_REFERENCE!>invoke<!>()
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!> {
println('weird')
}
}
}
@@ -0,0 +1,22 @@
FILE: superIsNotAnExpression.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public final class B : R|A| {
public constructor(): R|B| {
super<R|A|>()
}
public final fun act(): R|kotlin/Unit| {
<Super cannot be a callee>#()
<Unresolved name: invoke>#()
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <implicit>.<anonymous>(): <implicit> {
println#(ERROR_EXPR(Incorrect character: 'weird'))
}
)
}
}
@@ -739,6 +739,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
public void testInfixFunctions() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt");
}
@TestMetadata("superIsNotAnExpression.kt")
public void testSuperIsNotAnExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/expresssions")
@@ -739,6 +739,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
public void testInfixFunctions() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/infixFunctions.kt");
}
@TestMetadata("superIsNotAnExpression.kt")
public void testSuperIsNotAnExpression() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/superIsNotAnExpression.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/expresssions")
@@ -7,18 +7,17 @@ package org.jetbrains.kotlin.fir.analysis.collectors.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.onSource
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
@@ -62,6 +61,7 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
is FirVariableExpectedError -> Errors.VARIABLE_EXPECTED.onSource(source)
is FirTypeMismatchError -> FirErrors.TYPE_MISMATCH.onSource(source, diagnostic.expectedType, diagnostic.actualType)
is FirSimpleDiagnostic -> diagnostic.getFactory().onSource(source)
is FirDiagnosticWithParameters1<*> -> diagnostic.getFactory().tryOnSource(source, diagnostic.a)
is FirStubDiagnostic -> null
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${diagnostic.javaClass}")
}
@@ -85,6 +85,23 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
DiagnosticKind.RecursionInImplicitTypes -> FirErrors.RECURSION_IN_IMPLICIT_TYPES
DiagnosticKind.Java -> FirErrors.ERROR_FROM_JAVA_RESOLUTION
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
else -> throw IllegalArgumentException("Unsupported diagnostic kind: $kind at $javaClass")
} as DiagnosticFactory0<PsiElement>
}
private fun FirDiagnosticWithParameters1<*>.getFactory(): DiagnosticFactory1<PsiElement, Any?> {
@Suppress("UNCHECKED_CAST")
return when (kind) {
DiagnosticKind.SuperNotAllowed -> Errors.SUPER_IS_NOT_AN_EXPRESSION
else -> throw IllegalArgumentException("Unsupported diagnostic kind: $kind at $javaClass")
} as DiagnosticFactory1<PsiElement, Any?>
}
private inline fun <reified E : PsiElement, reified A> DiagnosticFactory1<E, A>.tryOnSource(
source: FirSourceElement,
a: Any?
): ConeDiagnostic? {
val aa = a as? A ?: throw IllegalArgumentException("Parameter passed to the factory is of incompatible type!")
return onSource(source, aa)
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticWithParameters1
import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
@@ -465,12 +466,16 @@ class ExpressionsConverter(
val valueArguments = mutableListOf<LighterASTNode>()
var additionalArgument: FirExpression? = null
var hasArguments = false
var superNode: LighterASTNode? = null
callSuffix.forEachChildren { child ->
fun process(node: LighterASTNode) {
when (node.tokenType) {
REFERENCE_EXPRESSION -> {
name = node.asText
}
SUPER_EXPRESSION -> {
superNode = node
}
PARENTHESIZED -> node.getExpressionInParentheses()?.let { process(it) } ?: run {
additionalArgument = getAsFirExpression(node, "Incorrect invoke receiver")
}
@@ -495,7 +500,16 @@ class ExpressionsConverter(
additionalArgument != null -> {
buildSimpleNamedReference { this.name = OperatorNameConventions.INVOKE } to additionalArgument!!
}
else -> buildErrorNamedReference {diagnostic = FirSimpleDiagnostic("Call has no callee", DiagnosticKind.Syntax) } to null
superNode != null -> {
buildErrorNamedReference {
val node = superNode!!
source = node.toFirSourceElement()
diagnostic = FirDiagnosticWithParameters1("Super cannot be a callee", node.asText, DiagnosticKind.SuperNotAllowed)
} to null
}
else -> buildErrorNamedReference {
diagnostic = FirSimpleDiagnostic("Call has no callee", DiagnosticKind.Syntax)
} to null
}
val builder: FirQualifiedAccessBuilder = if (hasArguments) {
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticWithParameters1
import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
@@ -1489,6 +1490,13 @@ class RawFirBuilder(
buildErrorNamedReference { diagnostic = FirSimpleDiagnostic("Call has no callee", DiagnosticKind.Syntax) } to null
}
is KtSuperExpression -> {
buildErrorNamedReference {
source = calleeExpression.toFirSourceElement()
diagnostic = FirDiagnosticWithParameters1("Super cannot be a callee", calleeExpression.text, DiagnosticKind.SuperNotAllowed)
} to null
}
else -> {
buildSimpleNamedReference {
source = defaultSource
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.diagnostics
class FirSimpleDiagnostic(override val reason: String, val kind: DiagnosticKind = DiagnosticKind.Other) : FirDiagnostic()
class FirDiagnosticWithParameters1<A>(override val reason: String, val a: A, val kind: DiagnosticKind = DiagnosticKind.Other) : FirDiagnostic()
enum class DiagnosticKind {
Syntax,
ReturnNotAllowed,
@@ -21,5 +23,6 @@ enum class DiagnosticKind {
RecursionInSupertypes,
RecursionInImplicitTypes,
Java,
SuperNotAllowed,
Other
}
@@ -1,15 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class A {
operator fun invoke() {}
operator fun invoke(f: () -> Unit) {}
}
class B : A() {
fun bar() {
super()
(super)()
super {}
(super) {}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class A {