diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.kt index 014b17a2021..c5fabaecd67 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/classifierAccessFromCompanion.kt @@ -4,7 +4,7 @@ class Factory { } companion object { - val f = Function + val f = Function val x = Function.Default } } diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.kt index 4a642b8b735..4caed8f2d41 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/innerQualifier.kt @@ -2,5 +2,5 @@ class Outer { inner class Inner } -val x = Outer.Inner +val x = Outer.Inner val klass = Outer.Inner::class diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt index 6186a1623a0..be82ea3493a 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/qualifierPriority.kt @@ -23,7 +23,8 @@ object D { val D.E get() = "" val def = D.E.F // object -val de = D.E // extension +// See KT-46409 +val de = D.E // Should be: extension & no error, in fact: qualifier enum class G { H; diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index b28746bf47f..fc14480eeb6 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -38,6 +38,7 @@ fun main(args: Array) { alias("EqualityOperatorCallChecker") alias("AnonymousFunctionAsExpressionChecker") alias("StringConcatenationCallChecker") + alias("ResolvedQualifierChecker") } val declarationPackage = "org.jetbrains.kotlin.fir.analysis.checkers.declaration" diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 9d2c6ef1bb0..f28f7d1df45 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -669,6 +669,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val TYPE_PARAMETER_ON_LHS_OF_DOT by error { parameter("typeParameter") } + val NO_COMPANION_OBJECT by error(PositioningStrategy.SELECTOR_BY_QUALIFIED) { + parameter("klass") + } + val EXPRESSION_EXPECTED_PACKAGE_FOUND by error(PositioningStrategy.SELECTOR_BY_QUALIFIED) } val FUNCTION_CONTRACTS by object : DiagnosticGroup("Function contracts") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt index 2b93bf86606..17fbfb51bd1 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt @@ -45,6 +45,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() { get() = _anonymousFunctionAsExpressionCheckers override val stringConcatenationCallCheckers: Set get() = _stringConcatenationCallCheckers + override val resolvedQualifierCheckers: Set + get() = _resolvedQualifierCheckers private val _basicExpressionCheckers: MutableSet = mutableSetOf() private val _qualifiedAccessCheckers: MutableSet = mutableSetOf() @@ -62,6 +64,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() { private val _equalityOperatorCallCheckers: MutableSet = mutableSetOf() private val _anonymousFunctionAsExpressionCheckers: MutableSet = mutableSetOf() private val _stringConcatenationCallCheckers: MutableSet = mutableSetOf() + private val _resolvedQualifierCheckers: MutableSet = mutableSetOf() @CheckersComponentInternal fun register(checkers: ExpressionCheckers) { @@ -81,5 +84,6 @@ class ComposedExpressionCheckers : ExpressionCheckers() { _equalityOperatorCallCheckers += checkers.equalityOperatorCallCheckers _anonymousFunctionAsExpressionCheckers += checkers.anonymousFunctionAsExpressionCheckers _stringConcatenationCallCheckers += checkers.stringConcatenationCallCheckers + _resolvedQualifierCheckers += checkers.resolvedQualifierCheckers } } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt index e9d753c490a..788334c72b0 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt @@ -33,6 +33,7 @@ abstract class ExpressionCheckers { open val equalityOperatorCallCheckers: Set = emptySet() open val anonymousFunctionAsExpressionCheckers: Set = emptySet() open val stringConcatenationCallCheckers: Set = emptySet() + open val resolvedQualifierCheckers: Set = emptySet() @CheckersComponentInternal internal val allBasicExpressionCheckers: Set get() = basicExpressionCheckers @CheckersComponentInternal internal val allQualifiedAccessCheckers: Set get() = qualifiedAccessCheckers + basicExpressionCheckers @@ -50,4 +51,5 @@ abstract class ExpressionCheckers { @CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set get() = equalityOperatorCallCheckers + basicExpressionCheckers @CheckersComponentInternal internal val allAnonymousFunctionAsExpressionCheckers: Set get() = anonymousFunctionAsExpressionCheckers + basicExpressionCheckers @CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set get() = stringConcatenationCallCheckers + basicExpressionCheckers + @CheckersComponentInternal internal val allResolvedQualifierCheckers: Set get() = resolvedQualifierCheckers + basicExpressionCheckers } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt index 13edf801b17..b2bc160ba0f 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression +import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression import org.jetbrains.kotlin.fir.expressions.FirStatement @@ -43,3 +44,4 @@ typealias FirSafeCallExpressionChecker = FirExpressionChecker typealias FirAnonymousFunctionAsExpressionChecker = FirExpressionChecker typealias FirStringConcatenationCallChecker = FirExpressionChecker +typealias FirResolvedQualifierChecker = FirExpressionChecker diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 67678f07df0..fee616ca0f8 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -398,6 +398,8 @@ object FirErrors { // Context tracking val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1() val TYPE_PARAMETER_ON_LHS_OF_DOT by error1() + val NO_COMPANION_OBJECT by error1(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) + val EXPRESSION_EXPECTED_PACKAGE_FOUND by error0(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) // Function contracts val ERROR_IN_CONTRACT_DESCRIPTION by error1(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt new file mode 100644 index 00000000000..41ba73f0bd0 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt @@ -0,0 +1,36 @@ +/* + * 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.expression + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.types.isUnit + +object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() { + override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { + val lastQualifiedAccess = context.qualifiedAccesses.lastOrNull() + if (lastQualifiedAccess?.explicitReceiver === expression) return + val lastGetClass = context.getClassCalls.lastOrNull() + if (lastGetClass?.argument === expression) return + // Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below + if (!expression.typeRef.isUnit) return + + when (val symbol = expression.symbol) { + is FirRegularClassSymbol -> { + if (symbol.fir.classKind == ClassKind.OBJECT) return + reporter.reportOn(expression.source, FirErrors.NO_COMPANION_OBJECT, symbol, context) + } + null -> { + reporter.reportOn(expression.source, FirErrors.EXPRESSION_EXPECTED_PACKAGE_FOUND, context) + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollectorVisitor.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollectorVisitor.kt index f9135075c3f..192f28894bf 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollectorVisitor.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollectorVisitor.kt @@ -182,6 +182,10 @@ abstract class AbstractDiagnosticCollectorVisitor( visitWithQualifiedAccess(qualifiedAccessExpression) } + override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Nothing?) { + visitWithQualifiedAccess(variableAssignment) + } + override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Nothing?) { visitWithGetClassCall(getClassCall) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt index 123d62c5a21..18e5b84144d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt @@ -56,7 +56,7 @@ class ExpressionCheckersDiagnosticComponent( } override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: CheckerContext) { - checkers.allBasicExpressionCheckers.check(resolvedQualifier, data, reporter) + checkers.allResolvedQualifierCheckers.check(resolvedQualifier, data, reporter) } override fun visitWhenExpression(whenExpression: FirWhenExpression, data: CheckerContext) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 93f85b28dbc..0a18d0c888d 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -106,6 +106,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_SUPER_CLA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_SUPER_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPE_PARAMETER_BOUND +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPRESSION_EXPECTED_PACKAGE_FOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT @@ -183,6 +184,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_SET_METHOD @@ -879,6 +881,12 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { "Type parameter ''{0}'' cannot have or inherit a companion object, so it cannot be on the left hand side of dot", SYMBOL ) + map.put( + NO_COMPANION_OBJECT, + "Classifier ''{0}'' does not have a companion object, and thus must be initialized here", + SYMBOL + ) + map.put(EXPRESSION_EXPECTED_PACKAGE_FOUND, "Expression expected, but a package name found") // Function contracts map.put(ERROR_IN_CONTRACT_DESCRIPTION, "Error in contract description", TO_STRING) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index ecbbcad94d2..2a9902efd7c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -441,6 +441,13 @@ object LightTreePositioningStrategies { endOffset: Int, tree: FlyweightCapableTreeStructure ): List { + if (node.tokenType == KtNodeTypes.BINARY_EXPRESSION && + tree.findDescendantByTypes(node, KtTokens.ALL_ASSIGNMENTS) != null + ) { + tree.findExpressionDeep(node)?.let { + return markElement(it, startOffset, endOffset, tree, node) + } + } if (node.tokenType != KtNodeTypes.DOT_QUALIFIED_EXPRESSION && node.tokenType != KtNodeTypes.SAFE_ACCESS_EXPRESSION) { return super.mark(node, startOffset, endOffset, tree) } @@ -492,7 +499,7 @@ object LightTreePositioningStrategies { return markElement(tree.referenceExpression(node, locateReferencedName) ?: node, startOffset, endOffset, tree, node) } if (node.tokenType == KtNodeTypes.PROPERTY_DELEGATE) { - return markElement(tree.findReferenceExpressionDeep(node) ?: node, startOffset, endOffset, tree, node) + return markElement(tree.findExpressionDeep(node) ?: node, startOffset, endOffset, tree, node) } if (node.tokenType in nodeTypesWithOperation) { return markElement(tree.operationReference(node) ?: node, startOffset, endOffset, tree, node) @@ -661,7 +668,7 @@ object LightTreePositioningStrategies { } val descendants = - tree.collectDescendantsOfType(node, KtTokens.IDENTIFIER) { descendant -> descendant.toString().all { it == '_' } }; + tree.collectDescendantsOfType(node, KtTokens.IDENTIFIER) { descendant -> descendant.toString().all { it == '_' } } if (descendants.isNotEmpty()) return descendants.map { markSingleElement(it, it, startOffset, endOffset, tree, node) } return super.mark(node, startOffset, endOffset, tree) @@ -756,7 +763,7 @@ private fun FlyweightCapableTreeStructure.referenceExpression( return result } -private fun FlyweightCapableTreeStructure.findReferenceExpressionDeep(node: LighterASTNode): LighterASTNode? = +private fun FlyweightCapableTreeStructure.findExpressionDeep(node: LighterASTNode): LighterASTNode? = findFirstDescendant(node) { it.isExpression() } private fun FlyweightCapableTreeStructure.rightParenthesis(node: LighterASTNode): LighterASTNode? = @@ -863,7 +870,7 @@ fun FlyweightCapableTreeStructure.findDescendantByType(node: Lig ?.firstNotNullResult { child -> child?.let { findDescendantByType(it, type) } } } -fun FlyweightCapableTreeStructure.findDescendantByTypes(node: LighterASTNode, types: Set): LighterASTNode? { +fun FlyweightCapableTreeStructure.findDescendantByTypes(node: LighterASTNode, types: TokenSet): LighterASTNode? { val childrenRef = Ref>() getChildren(node, childrenRef) return childrenRef.get()?.firstOrNull { types.contains(it?.tokenType) } ?: childrenRef.get() diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt index ebbdc213351..36382fad35e 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt @@ -93,4 +93,9 @@ object CommonExpressionCheckers : ExpressionCheckers() { get() = setOf( FirAnonymousFunctionChecker, ) + + override val resolvedQualifierCheckers: Set + get() = setOf( + FirStandaloneQualifierChecker, + ) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt index f3effe58dc1..d11bef39459 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/Utils.kt @@ -66,10 +66,24 @@ fun R.copyWithNewSourceKind(newKind: FirFakeSourceElementKind): * @param stepsToWholeQualifier distance between the original psi and the whole qualifier psi */ fun FirSourceElement.getWholeQualifierSourceIfPossible(stepsToWholeQualifier: Int): FirSourceElement { - if (this !is FirRealPsiSourceElement<*>) return this - - val qualifiersChain = generateSequence(psi) { it.parent } - val wholeQualifier = qualifiersChain.drop(stepsToWholeQualifier).first() - - return wholeQualifier.toFirPsiSourceElement() as FirRealPsiSourceElement + if (stepsToWholeQualifier == 0) return this + return when (this) { + is FirRealPsiSourceElement<*> -> { + val qualifiersChain = generateSequence(psi) { it.parent } + val wholeQualifier = qualifiersChain.drop(stepsToWholeQualifier).first() + wholeQualifier.toFirPsiSourceElement() as FirRealPsiSourceElement + } + is FirLightSourceElement -> { + val qualifiersChain = generateSequence(lighterASTNode) { treeStructure.getParent(it) } + val wholeQualifier = qualifiersChain.drop(stepsToWholeQualifier).first() + wholeQualifier.toFirLightSourceElement( + treeStructure, + startOffset = this.startOffset, + endOffset = wholeQualifier.endOffset + (this.endOffset - this.lighterASTNode.endOffset) + ) + } + is FirFakeSourceElement<*> -> { + this + } + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 3eaf31eedd4..e630b8c671e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -776,6 +776,9 @@ object PositioningStrategies { val SELECTOR_BY_QUALIFIED: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: PsiElement): List { + if (element is KtBinaryExpression && element.operationToken in KtTokens.ALL_ASSIGNMENTS) { + element.left?.let { return mark(it) } + } if (element is KtQualifiedExpression) { when (val selectorExpression = element.selectorExpression) { is KtElement -> return mark(selectorExpression) diff --git a/compiler/testData/codegen/box/package/privateMembersInImportList.kt b/compiler/testData/codegen/box/package/privateMembersInImportList.kt index e7009753efa..260602bfe57 100644 --- a/compiler/testData/codegen/box/package/privateMembersInImportList.kt +++ b/compiler/testData/codegen/box/package/privateMembersInImportList.kt @@ -1,3 +1,4 @@ +// IGNORE_BACKEND_FIR: JVM_IR package test import test.C.E1 @@ -16,6 +17,7 @@ class A { } fun test() { + // Note: FIR resolve this to test/C instead of test/A.B.C C D() } diff --git a/compiler/testData/diagnostics/tests/PackageInExpressionPosition.fir.kt b/compiler/testData/diagnostics/tests/PackageInExpressionPosition.fir.kt index f0d8cb2a71f..9e55bb3f6a0 100644 --- a/compiler/testData/diagnostics/tests/PackageInExpressionPosition.fir.kt +++ b/compiler/testData/diagnostics/tests/PackageInExpressionPosition.fir.kt @@ -2,25 +2,25 @@ package foo class X {} -val s = java -val ss = System -val sss = X -val x = "${System}" -val xs = java.lang -val xss = java.lang.System -val xsss = foo.X -val xssss = foo -val f = { System } +val s = java +val ss = System +val sss = X +val x = "${System}" +val xs = java.lang +val xss = java.lang.System +val xsss = foo.X +val xssss = foo +val f = { System } fun main() { - java = null - System = null - System!! - java.lang.System = null - java.lang.System!! - System is Int + java = null + System = null + System!! + java.lang.System = null + java.lang.System!! + System is Int System() - (System) - foo@ System + (System) + foo@ System null in System } diff --git a/compiler/testData/diagnostics/tests/ResolveToJava.fir.kt b/compiler/testData/diagnostics/tests/ResolveToJava.fir.kt index 29fce207662..5f606da6594 100644 --- a/compiler/testData/diagnostics/tests/ResolveToJava.fir.kt +++ b/compiler/testData/diagnostics/tests/ResolveToJava.fir.kt @@ -30,7 +30,7 @@ fun test(l : java.util.List) { checkSubtype?>(Collections.singleton(1)) Collections.singleton(1.0) - List + List val o = "sdf" as Object diff --git a/compiler/testData/diagnostics/tests/SafeCallOnFakePackage.fir.kt b/compiler/testData/diagnostics/tests/SafeCallOnFakePackage.fir.kt index dd371a01999..bb6402ecbb8 100644 --- a/compiler/testData/diagnostics/tests/SafeCallOnFakePackage.fir.kt +++ b/compiler/testData/diagnostics/tests/SafeCallOnFakePackage.fir.kt @@ -10,7 +10,7 @@ val s: String = "test" // FILE: test.kt fun ff() { - val a = Test?.FOO - val b = foo?.s - System?.out.println(a + b) + val a = Test?.FOO + val b = foo?.s + System?.out.println(a + b) } diff --git a/compiler/testData/diagnostics/tests/classObjects/ClassObjects.fir.kt b/compiler/testData/diagnostics/tests/classObjects/ClassObjects.fir.kt index 4e8baccdef8..0928188e162 100644 --- a/compiler/testData/diagnostics/tests/classObjects/ClassObjects.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/ClassObjects.fir.kt @@ -36,7 +36,7 @@ val a = A.x val c = B.x val d = b.x -val s = System // error +val s = System // error fun test() { System.out.println() java.lang.System.out.println() diff --git a/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughClassObject.fir.kt b/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughClassObject.fir.kt index b9a6940b154..82d0b3d64c6 100644 --- a/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughClassObject.fir.kt +++ b/compiler/testData/diagnostics/tests/classObjects/InnerClassAccessThroughClassObject.fir.kt @@ -33,7 +33,7 @@ fun f() { A().Inner() A.Companion.Nested A.Companion.Inner - A.Inner + A.Inner A.Companion.c A.Companion.Obj2 A.Companion.Obj2.c diff --git a/compiler/testData/diagnostics/tests/regressions/kt2956.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt2956.fir.kt index bfe423f976e..7e4964a960f 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt2956.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt2956.fir.kt @@ -1 +1 @@ -val a: String = Nothing +val a: String = Nothing diff --git a/compiler/testData/diagnostics/tests/resolve/constructorVsCompanion.fir.kt b/compiler/testData/diagnostics/tests/resolve/constructorVsCompanion.fir.kt index 4e5e8b3754d..a5e60aa0f3c 100644 --- a/compiler/testData/diagnostics/tests/resolve/constructorVsCompanion.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/constructorVsCompanion.fir.kt @@ -16,8 +16,8 @@ class E private constructor() { } } -val a = A +val a = A val b = B -val c = C +val c = C val d = D val e = E(42) diff --git a/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifier.fir.kt b/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifier.fir.kt index 2a51b0dbcf0..66eca0d07d2 100644 --- a/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifier.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifier.fir.kt @@ -7,10 +7,10 @@ class C fun test() { val interface_as_fun = A() - val interface_as_val = A + val interface_as_val = A val object_as_fun = B() - val class_as_val = C + val class_as_val = C } fun bar() { diff --git a/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifierWithReceiver.fir.kt b/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifierWithReceiver.fir.kt index cc9714a6c9e..d14d0265f70 100644 --- a/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifierWithReceiver.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/noCandidates/resolvedToClassifierWithReceiver.fir.kt @@ -9,10 +9,10 @@ object X { fun testX() { val interface_as_fun = X.A() - val interface_as_val = X.A + val interface_as_val = X.A val object_as_fun = X.B() - val class_as_val = X.C + val class_as_val = X.C } class Y { @@ -24,10 +24,10 @@ class Y { fun testY() { val interface_as_fun = Y.A() - val interface_as_val = Y.A + val interface_as_val = Y.A val object_as_fun = Y.B() - val class_as_val = Y.C + val class_as_val = Y.C } fun test(x: X) { diff --git a/compiler/testData/diagnostics/tests/resolve/wrongReceiver.fir.kt b/compiler/testData/diagnostics/tests/resolve/wrongReceiver.fir.kt index e160c818aca..ad2ea727ea5 100644 --- a/compiler/testData/diagnostics/tests/resolve/wrongReceiver.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/wrongReceiver.fir.kt @@ -9,7 +9,7 @@ val Int.foo: Int get() = 4 fun Int.extFun() = 4 fun String.test() { - some + some some.A() "".some diff --git a/compiler/testData/diagnostics/tests/sealed/TreeWhenFunctionalNoIs.fir.kt b/compiler/testData/diagnostics/tests/sealed/TreeWhenFunctionalNoIs.fir.kt index 9aabfe0ddb5..3e2555f93fd 100644 --- a/compiler/testData/diagnostics/tests/sealed/TreeWhenFunctionalNoIs.fir.kt +++ b/compiler/testData/diagnostics/tests/sealed/TreeWhenFunctionalNoIs.fir.kt @@ -11,7 +11,7 @@ sealed class Tree { fun maxIsClass(): Int = when(this) { Empty -> -1 - Leaf -> 0 + Leaf -> 0 is Node -> this.left.max() } diff --git a/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt b/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt index 8de3f1bbecb..950a76595ee 100644 --- a/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/privateInFile.fir.kt @@ -6,14 +6,14 @@ private class C { private typealias TA = C private val test1: C = C() -private val test1co: C.Companion = C +private val test1co: C.Companion = C private val test2: TA = TA() private val test2co = TA // FILE: file2.kt private val test1: C = C() -private val test1co: C.Companion = C +private val test1co: C.Companion = C private val test2: TA = TA() private val test2co = TA diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmPackageName/incorrectJvmPackageName.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmPackageName/incorrectJvmPackageName.fir.kt index 12ce9ee1123..b9e41cdcdd9 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmPackageName/incorrectJvmPackageName.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmPackageName/incorrectJvmPackageName.fir.kt @@ -22,6 +22,6 @@ package e fun e() {} // FILE: f.kt -@file:JvmPackageName(f) +@file:JvmPackageName(f) package f const val name = "f" diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/suspendCallsWithErrors.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/suspendCallsWithErrors.fir.kt index bfb426348a6..db4a9dd6775 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/suspendCallsWithErrors.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/suspendCallsWithErrors.fir.kt @@ -16,7 +16,7 @@ fun generate(@BuilderInference g: suspend Controller.() -> Unit): S = TOD class A val test1 = generate { - yield(A) + yield(A) } val test2: Int = generate { diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt1558.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt1558.fir.kt index 0a2061564ac..b9c0dab49af 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/kt1558.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt1558.fir.kt @@ -10,7 +10,7 @@ fun T?.sure() : T = this!! fun List<*>.toArray(ar: Array): Array = ar fun testArrays(ci: List, cii: List?) { - val c1: Array = cii.sure().toArray(Array) + val c1: Array = cii.sure().toArray(Array) val c2: Array = ci.toArray(Array()) diff --git a/compiler/testData/diagnostics/testsWithStdLib/resolve/javaStaticMembers.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/resolve/javaStaticMembers.fir.kt index 52e50757c2a..3bfaa40a735 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/resolve/javaStaticMembers.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/resolve/javaStaticMembers.fir.kt @@ -6,7 +6,7 @@ public class Test { // FILE: test.kt fun ff() { val a = Test.FOO - val b = Test?.FOO + val b = Test?.FOO System.out.println(a + b) - System?.out.println(a + b) + System?.out.println(a + b) } diff --git a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/neg/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/neg/1.1.fir.kt index 196a7e2a659..8234e962ff6 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/neg/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/expressions/when-expression/p-6/neg/1.1.fir.kt @@ -3,7 +3,7 @@ // TESTCASE NUMBER: 1 fun case_1(value_1: Any): String { when (value_1) { - EmptyClass -> return "" + EmptyClass -> return "" } return "" @@ -12,7 +12,7 @@ fun case_1(value_1: Any): String { // TESTCASE NUMBER: 2 fun case_2(value_1: Any): String { when (value_1) { - Any -> return "" + Any -> return "" } return "" @@ -21,7 +21,7 @@ fun case_2(value_1: Any): String { // TESTCASE NUMBER: 3 fun case_3(value_1: Any): String { when (value_1) { - Nothing -> return "" + Nothing -> return "" } return "" diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index c47d19c20f2..79603e2d5c9 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -1888,6 +1888,19 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NO_COMPANION_OBJECT) { firDiagnostic -> + NoCompanionObjectImpl( + firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a.fir), + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.EXPRESSION_EXPECTED_PACKAGE_FOUND) { firDiagnostic -> + ExpressionExpectedPackageFoundImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.ERROR_IN_CONTRACT_DESCRIPTION) { firDiagnostic -> ErrorInContractDescriptionImpl( firDiagnostic.a, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index e7f6849aba5..acd55a481e5 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1325,6 +1325,15 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val typeParameter: KtTypeParameterSymbol } + abstract class NoCompanionObject : KtFirDiagnostic() { + override val diagnosticClass get() = NoCompanionObject::class + abstract val klass: KtClassLikeSymbol + } + + abstract class ExpressionExpectedPackageFound : KtFirDiagnostic() { + override val diagnosticClass get() = ExpressionExpectedPackageFound::class + } + abstract class ErrorInContractDescription : KtFirDiagnostic() { override val diagnosticClass get() = ErrorInContractDescription::class abstract val reason: String diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index d732ed33b3a..bf81b8ebb32 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -2151,6 +2151,21 @@ internal class TypeParameterOnLhsOfDotImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class NoCompanionObjectImpl( + override val klass: KtClassLikeSymbol, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.NoCompanionObject(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class ExpressionExpectedPackageFoundImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpressionExpectedPackageFound(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class ErrorInContractDescriptionImpl( override val reason: String, firDiagnostic: FirPsiDiagnostic<*>,