Skip to content

Commit

Permalink
Merge pull request #55 from sourcegraph/nsc/analyzer-exception-catch
Browse files Browse the repository at this point in the history
catch exceptions instead of letting them hard fail builds
  • Loading branch information
Strum355 authored Apr 19, 2023
2 parents f1035f5 + 19dd6cd commit aa72546
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
package com.sourcegraph.semanticdb_kotlinc

import java.io.PrintWriter
import java.io.Writer
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.contracts.ExperimentalContracts
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.com.intellij.openapi.project.Project
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.utils.rethrow
import java.io.StringWriter

@ExperimentalContracts
class Analyzer(
Expand All @@ -19,24 +29,37 @@ class Analyzer(
) : AnalysisHandlerExtension {
private val globals = GlobalSymbolsCache()

private val messageCollector =
CompilerConfiguration()
.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false))

override fun analysisCompleted(
project: Project,
module: ModuleDescriptor,
bindingTrace: BindingTrace,
files: Collection<KtFile>
): AnalysisResult? {
val resolver = DescriptorResolver(bindingTrace).also { globals.resolver = it }
for (file in files) {
val lineMap = LineMap(project, file)
val document = SemanticdbVisitor(sourceroot, resolver, file, lineMap, globals).build()
semanticdbOutPathForFile(file)?.apply {
Files.write(this, TextDocuments { addDocuments(document) }.toByteArray())
): AnalysisResult? =
try {
val resolver = DescriptorResolver(bindingTrace).also { globals.resolver = it }
for (file in files) {
try {
val lineMap = LineMap(project, file)
val document =
SemanticdbVisitor(sourceroot, resolver, file, lineMap, globals).build()
semanticdbOutPathForFile(file)?.apply {
Files.write(this, TextDocuments { addDocuments(document) }.toByteArray())
}
callback(document)
} catch (e: Exception) {
handleException(e)
}
}
callback(document)
}

return super.analysisCompleted(project, module, bindingTrace, files)
}
super.analysisCompleted(project, module, bindingTrace, files)
} catch (e: Exception) {
handleException(e)
super.analysisCompleted(project, module, bindingTrace, files)
}

private fun semanticdbOutPathForFile(file: KtFile): Path? {
val normalizedPath = Paths.get(file.virtualFilePath).normalize()
Expand All @@ -57,4 +80,25 @@ class Analyzer(
"given file is not under the sourceroot.\n\tSourceroot: $sourceroot\n\tFile path: ${file.virtualFilePath}\n\tNormalized file path: $normalizedPath")
return null
}

private fun handleException(e: Exception) {
val writer =
PrintWriter(
object : Writer() {
val buf = StringBuffer()
override fun close() =
messageCollector.report(
CompilerMessageSeverity.EXCEPTION, buf.toString())
override fun flush() = Unit
override fun write(data: CharArray, offset: Int, len: Int) {
buf.append(data, offset, len)
}
},
false)
writer.println("Exception in semanticdb-kotlin compiler plugin:")
e.printStackTrace(writer)
writer.println(
"Please report a bug to https://github.com/sourcegraph/lsif-kotlin with the stack trace above.")
writer.close()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,27 @@ class AnalyzerTest {
assertSoftly(document.symbolsList) { withClue(this) { symbols.forEach(::shouldContain) } }
}

@Test
fun `exception test`(@TempDir path: Path) {
val buildPath = File(path.resolve("build").toString()).apply { mkdir() }
val result =
KotlinCompilation()
.apply {
sources = listOf(SourceFile.testKt(""))
compilerPlugins = listOf(AnalyzerRegistrar { throw Exception("sample text") })
verbose = false
pluginOptions =
listOf(
PluginOption("semanticdb-kotlinc", "sourceroot", path.toString()),
PluginOption("semanticdb-kotlinc", "targetroot", buildPath.toString()))
commandLineProcessors = listOf(AnalyzerCommandLineProcessor())
workingDir = path.toFile()
}
.compile()

result.exitCode shouldBe KotlinCompilation.ExitCode.OK
}

@Test
// shamelessly stolen code snippet from https://learnxinyminutes.com/docs/kotlin/
fun `learn x in y test`(@TempDir path: Path) {
Expand Down

0 comments on commit aa72546

Please sign in to comment.