From 2a1d4a42ae7531bc7e46a535fb6d346897c31b54 Mon Sep 17 00:00:00 2001 From: Andrei Klunnyi Date: Tue, 9 May 2023 15:28:14 +0200 Subject: [PATCH] [KT-58817] Implicit import issues cannot be reported To be reported with [1] imports require source. It was missing for implicit script imports. `FirScriptConfiguratorExtensionImpl` was extended and now adds fake source elements (users don't see imports in the source code). Since diagnostics for implicit import statements are meaningless for IDE, they are suppressed in `LLFirDiagnosticReporter`. ---------------------------------------------------------------------- [1]: DiagnosticReporter.reportOn() --- .../api/fir/diagnostics/LLFirDiagnosticReporter.kt | 10 ++++++++++ .../analysis/checkers/declaration/FirImportsChecker.kt | 3 +-- .../src/org/jetbrains/kotlin/KtSourceElement.kt | 3 +++ .../services/FirScriptConfigurationExtensionImpl.kt | 8 ++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/LLFirDiagnosticReporter.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/LLFirDiagnosticReporter.kt index 73c39385dfa..6bae9cb9dea 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/LLFirDiagnosticReporter.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/LLFirDiagnosticReporter.kt @@ -7,6 +7,8 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics import com.intellij.psi.PsiElement import org.jetbrains.kotlin.AbstractKtSourceElement +import org.jetbrains.kotlin.KtFakeSourceElement +import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor import org.jetbrains.kotlin.diagnostics.* @@ -18,6 +20,10 @@ internal class LLFirDiagnosticReporter : DiagnosticReporter() { if (diagnostic == null) return if (context.isDiagnosticSuppressed(diagnostic)) return + // Implicit imports for scripts are currently implemented via FIR-tree mutation (they do not exist in default importing scopes). + // So as a temporary solution we filter out related diagnostics here. + if (diagnostic.isAboutImplicitImport()) return + val psiDiagnostic = when (diagnostic) { is KtPsiDiagnostic -> diagnostic is KtLightDiagnostic -> diagnostic.toPsiDiagnostic() @@ -51,6 +57,10 @@ internal class LLFirDiagnosticReporter : DiagnosticReporter() { } } +private fun KtDiagnostic.isAboutImplicitImport() = + (element is KtFakeSourceElement && (element as KtFakeSourceElement).kind == KtFakeSourceElementKind.ImplicitImport) + + private fun KtLightDiagnostic.toPsiDiagnostic(): KtPsiDiagnostic { val psiSourceElement = element.unwrapToKtPsiSourceElement() ?: error("Diagnostic should be created from PSI in IDE") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt index 3547bb295b2..b6a4f025867 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationChecker -import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.getSourceForImportSegment @@ -128,7 +127,7 @@ object FirImportsChecker : FirFileChecker() { } resolvedDeclaration?.let { - val source = import.getSourceForImportSegment(0) + val source = import.getSourceForImportSegment(0) ?: import.source reporter.reportOn(source, FirErrors.INVISIBLE_REFERENCE, it.symbol, context) return } diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt index 5064e86d674..a20e395afd0 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt @@ -272,6 +272,9 @@ sealed class KtFakeSourceElementKind(final override val shouldSkipErrorTypeRepor // When property doesn't have an initializer and explicit return type, but its getter's return type is specified object PropertyTypeFromGetterReturnType : KtFakeSourceElementKind() + + // Scripts get implicit imports from their configurations + object ImplicitImport : KtFakeSourceElementKind() } sealed class AbstractKtSourceElement { diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt index 8dc5e5c8b73..86d30e1721f 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/services/FirScriptConfigurationExtensionImpl.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.scripting.compiler.plugin.services +import com.intellij.openapi.project.Project import org.jetbrains.kotlin.* import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities @@ -27,6 +28,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.scripting.definitions.annotationsForSamWithReceivers import org.jetbrains.kotlin.scripting.resolve.KtFileScriptSource import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource @@ -61,6 +63,10 @@ class FirScriptConfiguratorExtensionImpl( val stripped = if (endsWithStar) trimmed.substring(0, trimmed.length - 2) else trimmed val fqName = FqName.fromSegments(stripped.split(".")) fileBuilder.imports += buildImport { + fileBuilder.sourceFile?.project()?.let { + val dummyElement = KtPsiFactory(it, markGenerated = true).createColon() + source = KtFakeSourceElement(dummyElement, KtFakeSourceElementKind.ImplicitImport) + } importedFqName = fqName isAllUnder = endsWithStar } @@ -148,6 +154,8 @@ class FirScriptConfiguratorExtensionImpl( } } +private fun KtSourceFile.project(): Project? = (toSourceCode() as? KtFileScriptSource)?.ktFile?.project + fun KtSourceFile.toSourceCode(): SourceCode? = when (this) { is KtPsiSourceFile -> (psiFile as? KtFile)?.let(::KtFileScriptSource) ?: VirtualFileScriptSource(psiFile.virtualFile) is KtVirtualFileSourceFile -> VirtualFileScriptSource(virtualFile)