[FIR] Move all checkers and theirs infrastructure to separate module

This commit is contained in:
Dmitriy Novozhilov
2020-03-18 15:29:51 +03:00
parent cc07ae96b3
commit 39372c06cf
32 changed files with 134 additions and 90 deletions
+16
View File
@@ -0,0 +1,16 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:fir:resolve"))
compileOnly(project(":kotlin-reflect-api"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
}
@@ -0,0 +1,14 @@
/*
* 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.call
import org.jetbrains.kotlin.fir.expressions.FirExpression
object CallCheckers {
val EXPRESSIONS: List<FirExpressionChecker<FirExpression>> = listOf()
val QUALIFIED_ACCESS: List<FirQualifiedAccessChecker> = listOf<FirQualifiedAccessChecker>() + EXPRESSIONS
val FUNCTION_CALLS: List<FirFunctionCallChecker> = listOf<FirFunctionCallChecker>() + QUALIFIED_ACCESS
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2019 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.call
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
abstract class FirExpressionChecker<in E : FirExpression> {
abstract fun check(functionCall: E, reporter: DiagnosticReporter)
}
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccessExpression>
@@ -0,0 +1,16 @@
/*
* 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.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
object DeclarationCheckers {
val DECLARATIONS: List<FirDeclarationChecker<FirDeclaration>> = listOf()
val MEMBER_DECLARATIONS: List<FirDeclarationChecker<FirMemberDeclaration>> = DECLARATIONS + listOf(
FirInfixFunctionDeclarationChecker
)
}
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 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.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
abstract class FirDeclarationChecker<in D : FirDeclaration> {
abstract fun check(declaration: D, reporter: DiagnosticReporter)
}
@@ -0,0 +1,32 @@
/*
* 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.diagnostics.Errors
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.onSource
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.isInfix
object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDeclaration>() {
override fun check(declaration: FirMemberDeclaration, reporter: DiagnosticReporter) {
if (declaration is FirSimpleFunction && declaration.isInfix) {
if (declaration.valueParameters.size != 1 || declaration.receiverTypeRef == null) {
reporter.report(declaration.source)
}
return
}
if (declaration.isInfix) {
reporter.report(declaration.source)
}
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(Errors.INAPPLICABLE_INFIX_MODIFIER.onSource(it, "Inapplicable infix modifier")) }
}
}
@@ -0,0 +1,64 @@
/*
* 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.collectors
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.analysis.collectors.components.DeclarationCheckersDiagnosticComponent
import org.jetbrains.kotlin.fir.analysis.collectors.components.ErrorNodeDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.analysis.collectors.components.ExpressionCheckersDiagnosticComponent
import org.jetbrains.kotlin.fir.analysis.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
abstract class AbstractDiagnosticCollector {
fun collectDiagnostics(firFile: FirFile): Iterable<ConeDiagnostic> {
if (!componentsInitialized) {
throw IllegalStateException("Components are not initialized")
}
initializeCollector()
firFile.accept(visitor)
return getCollectedDiagnostics()
}
protected abstract fun initializeCollector()
protected abstract fun getCollectedDiagnostics(): Iterable<ConeDiagnostic>
abstract fun runCheck(block: (DiagnosticReporter) -> Unit)
private val components: MutableList<AbstractDiagnosticCollectorComponent> = mutableListOf()
private var componentsInitialized = false
private val visitor = Visitor()
fun initializeComponents(vararg components: AbstractDiagnosticCollectorComponent) {
if (componentsInitialized) {
throw IllegalStateException()
}
this.components += components
componentsInitialized = true
}
private inner class Visitor : FirVisitorVoid() {
private fun <T : FirElement> T.runComponents() {
components.forEach {
this.accept(it)
}
}
override fun visitElement(element: FirElement) {
element.runComponents()
element.acceptChildren(this)
}
}
}
fun AbstractDiagnosticCollector.registerAllComponents() {
initializeComponents(
DeclarationCheckersDiagnosticComponent(this),
ExpressionCheckersDiagnosticComponent(this),
ErrorNodeDiagnosticCollectorComponent(this),
)
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2019 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.collectors
object FirDiagnosticsCollector {
fun create(): AbstractDiagnosticCollector {
val collector = SimpleDiagnosticsCollector()
collector.registerAllComponents()
return collector
}
// Use in CLI compiler
@Suppress("unused")
fun createParallel(): AbstractDiagnosticCollector {
val collector = ParallelDiagnosticsCollector(4)
collector.registerAllComponents()
return collector
}
}
@@ -0,0 +1,76 @@
/*
* 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.collectors
import org.jetbrains.kotlin.fir.analysis.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.SimpleDiagnosticReporter
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.Future
import java.util.concurrent.atomic.AtomicInteger
class ParallelDiagnosticsCollector(private val numberOfThreads: Int) : AbstractDiagnosticCollector() {
init {
require(numberOfThreads >= 1) {
"Number of threads should be at least 1"
}
}
private var reporters = initializeReporters()
private val collectorLocalIndex = ThreadLocal<Int>()
private val collectorIndexCounter = AtomicInteger()
private val futures = LinkedList<Future<*>>()
private val pool = Executors.newFixedThreadPool(numberOfThreads) { runnable ->
Thread {
collectorLocalIndex.set(collectorIndexCounter.getAndIncrement())
runnable.run()
}
}
private fun initializeReporters(): List<SimpleDiagnosticReporter> {
return (1..numberOfThreads).map { SimpleDiagnosticReporter() }
}
override fun initializeCollector() {
reporters = initializeReporters()
futures.clear()
}
override fun getCollectedDiagnostics(): Iterable<ConeDiagnostic> {
futures.forEach { it.get() }
return Iterable {
object : Iterator<ConeDiagnostic> {
private val globalIterator = reporters.iterator()
private var localIterator = globalIterator.next().diagnostics.iterator()
private fun update() {
while (!localIterator.hasNext() && globalIterator.hasNext()) {
localIterator = globalIterator.next().diagnostics.iterator()
}
}
override fun hasNext(): Boolean {
update()
return localIterator.hasNext()
}
override fun next(): ConeDiagnostic {
update()
return localIterator.next()
}
}
}
}
override fun runCheck(block: (DiagnosticReporter) -> Unit) {
futures += pool.submit {
val reporter = reporters[collectorLocalIndex.get()]
block(reporter)
}
}
}
@@ -0,0 +1,27 @@
/*
* 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.collectors
import org.jetbrains.kotlin.fir.analysis.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.SimpleDiagnosticReporter
class SimpleDiagnosticsCollector : AbstractDiagnosticCollector() {
private var reporter = SimpleDiagnosticReporter()
override fun initializeCollector() {
reporter = SimpleDiagnosticReporter()
}
override fun getCollectedDiagnostics(): Iterable<ConeDiagnostic> {
return reporter.diagnostics
}
override fun runCheck(block: (DiagnosticReporter) -> Unit) {
block(reporter)
}
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2019 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.collectors.components
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
abstract class AbstractDiagnosticCollectorComponent(private val collector: AbstractDiagnosticCollector) : FirVisitorVoid() {
override fun visitElement(element: FirElement) {}
protected fun runCheck(block: (DiagnosticReporter) -> Unit) {
collector.runCheck(block)
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2019 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.collectors.components
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.*
class DeclarationCheckersDiagnosticComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitProperty(property: FirProperty) {
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(property, it) }
}
override fun visitRegularClass(regularClass: FirRegularClass) {
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(regularClass, it) }
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(simpleFunction, it) }
}
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(typeAlias, it) }
}
override fun visitConstructor(constructor: FirConstructor) {
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(constructor, it) }
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction) {
runCheck { DeclarationCheckers.DECLARATIONS.check(anonymousFunction, it) }
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor) {
runCheck { DeclarationCheckers.DECLARATIONS.check(propertyAccessor, it) }
}
override fun visitValueParameter(valueParameter: FirValueParameter) {
runCheck { DeclarationCheckers.DECLARATIONS.check(valueParameter, it) }
}
override fun visitEnumEntry(enumEntry: FirEnumEntry) {
runCheck { DeclarationCheckers.DECLARATIONS.check(enumEntry, it) }
}
private fun <D : FirDeclaration> List<FirDeclarationChecker<D>>.check(declaration: D, reporter: DiagnosticReporter) {
for (checker in this) {
checker.check(declaration, reporter)
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2019 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.collectors.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
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.FirStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitErrorLoop(errorLoop: FirErrorLoop) {
val source = errorLoop.source ?: return
runCheck { reportFirDiagnostic(errorLoop.diagnostic, source, it) }
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef) {
val source = errorTypeRef.source ?: return
runCheck { reportFirDiagnostic(errorTypeRef.diagnostic, source, it) }
}
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference) {
val source = errorNamedReference.source ?: return
runCheck { reportFirDiagnostic(errorNamedReference.diagnostic, source, it) }
}
override fun visitErrorExpression(errorExpression: FirErrorExpression) {
val source = errorExpression.source ?: return
runCheck { reportFirDiagnostic(errorExpression.diagnostic, source, it) }
}
override fun visitErrorFunction(errorFunction: FirErrorFunction) {
val source = errorFunction.source ?: return
runCheck { reportFirDiagnostic(errorFunction.diagnostic, source, it) }
}
private fun reportFirDiagnostic(diagnostic: FirDiagnostic, source: FirSourceElement, reporter: DiagnosticReporter) {
val coneDiagnostic = when (diagnostic) {
is FirUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.onSource(source, diagnostic.name?.asString())
is FirUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.onSource(source, diagnostic.classId.asString())
is FirUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.onSource(source, diagnostic.name.asString())
is FirInapplicableCandidateError -> FirErrors.INAPPLICABLE_CANDIDATE.onSource(source, diagnostic.candidates.map { it.symbol })
is FirAmbiguityError -> FirErrors.AMBIGUITY.onSource(source, diagnostic.candidates)
is FirOperatorAmbiguityError -> FirErrors.ASSIGN_OPERATOR_AMBIGUITY.onSource(source, diagnostic.candidates)
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 FirStubDiagnostic -> null
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${diagnostic.javaClass}")
}
reporter.report(coneDiagnostic)
}
private fun FirSimpleDiagnostic.getFactory(): DiagnosticFactory0<PsiElement> {
@Suppress("UNCHECKED_CAST")
return when (kind) {
DiagnosticKind.Syntax -> FirErrors.SYNTAX_ERROR
DiagnosticKind.ReturnNotAllowed -> Errors.RETURN_NOT_ALLOWED
DiagnosticKind.UnresolvedLabel -> FirErrors.UNRESOLVED_LABEL
DiagnosticKind.IllegalConstExpression -> FirErrors.ILLEGAL_CONST_EXPRESSION
DiagnosticKind.ConstructorInObject -> Errors.CONSTRUCTOR_IN_OBJECT
DiagnosticKind.DeserializationError -> FirErrors.DESERIALIZATION_ERROR
DiagnosticKind.InferenceError -> FirErrors.INFERENCE_ERROR
DiagnosticKind.NoSupertype -> FirErrors.NO_SUPERTYPE
DiagnosticKind.TypeParameterAsSupertype -> FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
DiagnosticKind.EnumAsSupertype -> FirErrors.ENUM_AS_SUPERTYPE
DiagnosticKind.RecursionInSupertypes -> FirErrors.RECURSION_IN_SUPERTYPES
DiagnosticKind.RecursionInImplicitTypes -> FirErrors.RECURSION_IN_IMPLICIT_TYPES
DiagnosticKind.Java -> FirErrors.ERROR_FROM_JAVA_RESOLUTION
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
} as DiagnosticFactory0<PsiElement>
}
}
@@ -0,0 +1,84 @@
/*
* 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.collectors.components
import org.jetbrains.kotlin.fir.analysis.checkers.call.CallCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.call.FirExpressionChecker
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.expressions.*
class ExpressionCheckersDiagnosticComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall) {
runCheck { CallCheckers.EXPRESSIONS.check(typeOperatorCall, it) }
}
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>) {
runCheck { CallCheckers.EXPRESSIONS.check(constExpression, it) }
}
override fun visitAnnotationCall(annotationCall: FirAnnotationCall) {
runCheck { CallCheckers.EXPRESSIONS.check(annotationCall, it) }
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) {
runCheck { CallCheckers.QUALIFIED_ACCESS.check(qualifiedAccessExpression, it) }
}
override fun visitFunctionCall(functionCall: FirFunctionCall) {
runCheck { CallCheckers.FUNCTION_CALLS.check(functionCall, it) }
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
runCheck { CallCheckers.QUALIFIED_ACCESS.check(callableReferenceAccess, it) }
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression) {
runCheck { CallCheckers.EXPRESSIONS.check(thisReceiverExpression, it) }
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
runCheck { CallCheckers.EXPRESSIONS.check(resolvedQualifier, it) }
}
override fun visitWhenExpression(whenExpression: FirWhenExpression) {
runCheck { CallCheckers.EXPRESSIONS.check(whenExpression, it) }
}
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression) {
runCheck { CallCheckers.EXPRESSIONS.check(binaryLogicExpression, it) }
}
override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall) {
runCheck { CallCheckers.EXPRESSIONS.check(arrayOfCall, it) }
}
override fun visitStringConcatenationCall(stringConcatenationCall: FirStringConcatenationCall) {
runCheck { CallCheckers.EXPRESSIONS.check(stringConcatenationCall, it) }
}
override fun visitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall) {
runCheck { CallCheckers.EXPRESSIONS.check(checkNotNullCall, it) }
}
override fun visitTryExpression(tryExpression: FirTryExpression) {
runCheck { CallCheckers.EXPRESSIONS.check(tryExpression, it) }
}
override fun visitClassReferenceExpression(classReferenceExpression: FirClassReferenceExpression) {
runCheck { CallCheckers.EXPRESSIONS.check(classReferenceExpression, it) }
}
override fun visitGetClassCall(getClassCall: FirGetClassCall) {
runCheck { CallCheckers.EXPRESSIONS.check(getClassCall, it) }
}
private fun <E : FirExpression> List<FirExpressionChecker<E>>.check(expression: E, reporter: DiagnosticReporter) {
for (checker in this) {
checker.check(expression, reporter)
}
}
}
@@ -0,0 +1,36 @@
/*
* 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.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.psi
class ConeDiagnostic(
val diagnostic: Diagnostic,
val source: FirSourceElement
)
inline fun <reified E : PsiElement> DiagnosticFactory0<E>.onSource(source: FirSourceElement): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi), source)
}
inline fun <reified E : PsiElement, A> DiagnosticFactory1<E, A>.onSource(source: FirSourceElement, a: A): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi, a), source)
}
inline fun <reified E : PsiElement, A, B> DiagnosticFactory2<E, A, B>.onSource(source: FirSourceElement, a: A, b: B): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi, a, b), source)
}
inline fun <reified E : PsiElement, A, B, C> DiagnosticFactory3<E, A, B, C>.onSource(source: FirSourceElement, a: A, b: B, c: C): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi, a, b, c), source)
}
@@ -0,0 +1,69 @@
/*
* 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.diagnostics
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.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.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.SYNTAX_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.rendering.Renderer
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
@Suppress("unused")
class DefaultErrorMessagesFir : DefaultErrorMessages.Extension {
override fun getMap(): DiagnosticFactoryToRendererMap {
return MAP
}
companion object {
private val SYMBOL_COLLECTION_RENDERER = Renderer { symbols: Collection<AbstractFirBasedSymbol<*>> ->
symbols.joinToString(prefix = "[", postfix = "]", separator = ",", limit = 3, truncated = "...") { symbol ->
when (symbol) {
is FirClassLikeSymbol<*> -> symbol.classId.asString()
is FirCallableSymbol<*> -> symbol.callableId.toString()
else -> "???"
}
}
}
private val MAP = DiagnosticFactoryToRendererMap("FIR").also { map ->
map.put(UNRESOLVED_REFERENCE, "Unresolved reference: {0}", Renderer { it })
map.put(INAPPLICABLE_CANDIDATE, "Inapplicable candidate(s): {0}", SYMBOL_COLLECTION_RENDERER)
map.put(AMBIGUITY, "Ambiguity between candidates: {0}", SYMBOL_COLLECTION_RENDERER)
map.put(ASSIGN_OPERATOR_AMBIGUITY, "Ambiguity between assign operator candidates: {0}", SYMBOL_COLLECTION_RENDERER)
map.put(SYNTAX_ERROR, "Syntax error")
map.put(UNRESOLVED_LABEL, "Unresolved label")
map.put(ILLEGAL_CONST_EXPRESSION, "Illegal const expression")
map.put(DESERIALIZATION_ERROR, "Deserialization error")
map.put(INFERENCE_ERROR, "Inference error")
map.put(NO_SUPERTYPE, "No supertype")
map.put(TYPE_PARAMETER_AS_SUPERTYPE, "Type parameter as supertype")
map.put(ENUM_AS_SUPERTYPE, "Enum as supertype")
map.put(RECURSION_IN_SUPERTYPES, "Recursion in supertypes")
map.put(RECURSION_IN_IMPLICIT_TYPES, "Recursion in implicit types")
map.put(ERROR_FROM_JAVA_RESOLUTION, "Java resolution error")
map.put(OTHER_ERROR, "Unknown (other) error")
}
}
}
@@ -0,0 +1,19 @@
/*
* 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.diagnostics
abstract class DiagnosticReporter {
abstract fun report(diagnostic: ConeDiagnostic?)
}
class SimpleDiagnosticReporter : DiagnosticReporter() {
val diagnostics: MutableList<ConeDiagnostic> = mutableListOf()
override fun report(diagnostic: ConeDiagnostic?) {
if (diagnostic == null) return
diagnostics += diagnostic
}
}
@@ -0,0 +1,19 @@
/*
* 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.
*/
@file:Suppress("PackageDirectoryMismatch")
package org.jetbrains.kotlin.diagnostics
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import kotlin.reflect.full.memberProperties
fun FirErrors.registerExternalFactories() {
val klass = FirErrors::class
for (property in klass.memberProperties) {
val factory = property.get(this) as? DiagnosticFactory<*> ?: continue
factory.name = property.name
}
}
@@ -0,0 +1,36 @@
/*
* 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.diagnostics
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.diagnostics.Severity.ERROR
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.psi.KtElement
object FirErrors {
val UNRESOLVED_REFERENCE = DiagnosticFactory1.create<KtElement, String?>(ERROR)
val INAPPLICABLE_CANDIDATE = DiagnosticFactory1.create<KtElement, Collection<AbstractFirBasedSymbol<*>>>(ERROR)
val AMBIGUITY = DiagnosticFactory1.create<KtElement, Collection<AbstractFirBasedSymbol<*>>>(ERROR)
val ASSIGN_OPERATOR_AMBIGUITY = DiagnosticFactory1.create<KtElement, Collection<AbstractFirBasedSymbol<*>>>(ERROR)
val SYNTAX_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val UNRESOLVED_LABEL = DiagnosticFactory0.create<KtElement>(ERROR)
val ILLEGAL_CONST_EXPRESSION = DiagnosticFactory0.create<KtElement>(ERROR)
val DESERIALIZATION_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val INFERENCE_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val NO_SUPERTYPE = DiagnosticFactory0.create<KtElement>(ERROR)
val TYPE_PARAMETER_AS_SUPERTYPE = DiagnosticFactory0.create<KtElement>(ERROR)
val ENUM_AS_SUPERTYPE = DiagnosticFactory0.create<KtElement>(ERROR)
val RECURSION_IN_SUPERTYPES = DiagnosticFactory0.create<KtElement>(ERROR)
val RECURSION_IN_IMPLICIT_TYPES = DiagnosticFactory0.create<KtElement>(ERROR)
val ERROR_FROM_JAVA_RESOLUTION = DiagnosticFactory0.create<KtElement>(ERROR)
val OTHER_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val TYPE_MISMATCH = DiagnosticFactory2.create<KtElement, ConeKotlinType, ConeKotlinType>(ERROR)
init {
registerExternalFactories()
}
}