diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt index 9ffa6e63ba2..09b72507419 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompilerFacility.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.analysis.api.fir.components import com.intellij.openapi.progress.ProgressManager +import com.intellij.psi.PsiErrorElement +import org.jetbrains.kotlin.KtRealPsiSourceElement import org.jetbrains.kotlin.analysis.api.compile.CodeFragmentCapturedValue import org.jetbrains.kotlin.analysis.api.components.KtCompilationResult import org.jetbrains.kotlin.analysis.api.components.KtCompilerFacility @@ -37,14 +39,12 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.constant.EvaluatedConstTracker import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticMarker -import org.jetbrains.kotlin.diagnostics.DiagnosticReporter -import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory -import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic -import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.diagnostics.* +import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.backend.jvm.* import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.diagnostics.ConeSyntaxDiagnostic import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.pipeline.applyIrGenerationExtensions import org.jetbrains.kotlin.fir.pipeline.signatureComposerForJvmFir2Ir @@ -102,6 +102,12 @@ internal class KtFirCompilerFacility( is KtCompilerTarget.Jvm -> target.classBuilderFactory } + val syntaxErrors = SyntaxErrorReportingVisitor().also(file::accept).diagnostics + + if (syntaxErrors.isNotEmpty()) { + return KtCompilationResult.Failure(syntaxErrors) + } + val mainFirFile = getFullyResolvedFirFile(file) val frontendDiagnostics = file.collectDiagnosticsForFile(firResolveSession, DiagnosticCheckerFilter.ONLY_COMMON_CHECKERS) @@ -685,4 +691,20 @@ private class DeclarationRegistrarVisitor(private val consumer: SymbolTable) : I val signature = symbol.signature ?: return registrar(signature, { symbol }, { declaration }) } +} + +context(KtFirAnalysisSessionComponent) +private class SyntaxErrorReportingVisitor : KtTreeVisitorVoid() { + private val collectedDiagnostics = mutableListOf() + + val diagnostics: List + get() = Collections.unmodifiableList(collectedDiagnostics) + + override fun visitErrorElement(element: PsiErrorElement) { + collectedDiagnostics += ConeSyntaxDiagnostic(element.errorDescription) + .toFirDiagnostics(analysisSession.useSiteSession, KtRealPsiSourceElement(element), callOrAssignmentSource = null) + .map { (it as KtPsiDiagnostic).asKtDiagnostic() } + + super.visitErrorElement(element) + } } \ No newline at end of file diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerated.java index ff743a0a285..27fc937b452 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerated.java @@ -133,6 +133,12 @@ public class FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerate runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/simple.kt"); } + @Test + @TestMetadata("syntaxError.kt") + public void testSyntaxError() throws Exception { + runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.kt"); + } + @Nested @TestMetadata("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java index 55b2a441269..cb5a00ff30b 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java @@ -133,6 +133,12 @@ public class FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated exten runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/simple.kt"); } + @Test + @TestMetadata("syntaxError.kt") + public void testSyntaxError() throws Exception { + runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.kt"); + } + @Nested @TestMetadata("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/capturing") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/compilerFacility/AbstractCompilerFacilityTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/compilerFacility/AbstractCompilerFacilityTest.kt index cec5eac30e8..a648b69dfb5 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/compilerFacility/AbstractCompilerFacilityTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/compilerFacility/AbstractCompilerFacilityTest.kt @@ -104,15 +104,19 @@ abstract class AbstractCompilerFacilityTest : AbstractAnalysisApiBasedTest() { val target = KtCompilerTarget.Jvm(ClassBuilderFactories.TEST) val allowedErrorFilter: (KtDiagnostic) -> Boolean = { it.factoryName in ALLOWED_ERRORS } - val actualText = when (val result = compile(ktTargetFile, compilerConfiguration, target, allowedErrorFilter)) { + val result = compile(ktTargetFile, compilerConfiguration, target, allowedErrorFilter) + + val actualText = when (result) { is KtCompilationResult.Failure -> result.errors.joinToString("\n") { dumpDiagnostic(it) } is KtCompilationResult.Success -> dumpClassFiles(result.output) } testServices.assertions.assertEqualsToTestDataFileSibling(actualText) - } - testServices.assertions.assertEqualsToTestDataFileSibling(irCollector.result, extension = ".ir.txt") + if (result is KtCompilationResult.Success) { + testServices.assertions.assertEqualsToTestDataFileSibling(irCollector.result, extension = ".ir.txt") + } + } } override fun configureTest(builder: TestConfigurationBuilder) { diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.fragment.kt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.fragment.kt new file mode 100644 index 00000000000..6d9a6ec11db --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.fragment.kt @@ -0,0 +1,3 @@ +fun foo() { + 1.toString() +}} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.kt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.kt new file mode 100644 index 00000000000..118d01da074 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.kt @@ -0,0 +1,3 @@ +fun test() { + val x = 0 +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.txt b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.txt new file mode 100644 index 00000000000..93c87a1ae93 --- /dev/null +++ b/analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/syntaxError.txt @@ -0,0 +1 @@ +(30,31) SYNTAX Syntax error: Unexpected symbol. \ No newline at end of file