diff --git a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt index 446961c2f6e..a090c71d714 100644 --- a/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor2/src/main/kotlin/KotlinFileExtractor.kt @@ -1,7 +1,9 @@ package com.github.codeql import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.analysis.api.components.KaDiagnosticCheckerFilter +import org.jetbrains.kotlin.analysis.api.diagnostics.KaSeverity import org.jetbrains.kotlin.analysis.api.KaSession import org.jetbrains.kotlin.analysis.api.types.KaType import org.jetbrains.kotlin.KtNodeTypes @@ -207,43 +209,38 @@ open class KotlinFileExtractor( // TODO: Add comment private fun extractDiagnostics(file: KtFile) { - // TODO: Put this in the database - println("=== Diagnostics") val dcf = KaDiagnosticCheckerFilter.ONLY_COMMON_CHECKERS for (d in file.collectDiagnostics(dcf)) { - println("--- Diagnostic:") - println(d.factoryName) - println(d.severity) - println(d.defaultMessage) - // TODO: We could try to link diagnostics to d.psi, but we - // don't have labels for lots of things. We'd either have - // to cache the labels, or extract diagnostics from all the - // element extractors. - for (tr in d.textRanges) { - val loc = getLocationInfo(file, tr) - println(loc) + val diagLabel = tw.getFreshIdLabel() + val severity = when (d.severity) { + KaSeverity.ERROR -> Severity.Error.sev + KaSeverity.WARNING -> Severity.Warn.sev + KaSeverity.INFO -> null + } + if (severity != null) { + val location = if (d.textRanges.isEmpty()) { + tw.getWholeFileLocation() + } else { + // We just use a random location from the set + tw.getLocation(file, d.textRanges.first()) + } + tw.writeDiagnostics( + diagLabel, + "CodeQL Kotlin: Analysis API", + severity, + d.factoryName, + d.defaultMessage, + "", + location) + // TODO: We could try to link diagnostics to d.psi, but we + // don't have labels for lots of things. We'd either have + // to cache the labels, or extract diagnostics from all the + // element extractors. } } println("--- End diagnostics") } - // TODO: Common this up with TrapWriter's Location - private data class Location(val startLine: Int, val startColumn: Int, val endLine: Int, val endColumn: Int) - - // TODO: Common this up with TrapWriter's getLocationInfo - private fun getLocationInfo(file: KtFile, range: TextRange): Location { - val document = file.getViewProvider().getDocument() - val start = range.getStartOffset() - val startLine0 = document.getLineNumber(start) - val startCol0 = start - document.getLineStartOffset(startLine0) - val end = range.getEndOffset() - val endLine0 = document.getLineNumber(end) - val endCol1 = end - document.getLineStartOffset(endLine0) - // TODO: unknown/synthetic locations? - return Location(startLine0 + 1, startCol0 + 1, endLine0 + 1, endCol1) - } - - /* OLD: KE1 private fun javaBinaryDeclaresMethod(c: IrClass, name: String) = diff --git a/java/kotlin-extractor2/src/main/kotlin/TrapWriter.kt b/java/kotlin-extractor2/src/main/kotlin/TrapWriter.kt index afe475b774a..13838106f49 100644 --- a/java/kotlin-extractor2/src/main/kotlin/TrapWriter.kt +++ b/java/kotlin-extractor2/src/main/kotlin/TrapWriter.kt @@ -4,7 +4,9 @@ package com.github.codeql OLD: KE1 import com.github.codeql.KotlinUsesExtractor.LocallyVisibleFunctionLabels */ +import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.semmle.extractor.java.PopulateFile import com.semmle.util.unicode.UTF8Util import org.jetbrains.kotlin.analysis.api.symbols.KaVariableSymbol @@ -406,9 +408,8 @@ open class FileTrapWriter( private data class Location(val startLine: Int, val startColumn: Int, val endLine: Int, val endColumn: Int) - private fun getLocationInfo(e: PsiElement): Location { - val range = e.getTextRange() - val document = e.getContainingFile().getViewProvider().getDocument() + private fun getLocationInfo(file: PsiFile, range: TextRange): Location { + val document = file.getViewProvider().getDocument() val start = range.getStartOffset() val startLine0 = document.getLineNumber(start) val startCol0 = start - document.getLineStartOffset(startLine0) @@ -420,11 +421,18 @@ open class FileTrapWriter( } /** Gets a label for the location of `e`. */ - fun getLocation(e: PsiElement): Label { - val loc = getLocationInfo(e) + fun getLocation(file: PsiFile, range: TextRange): Label { + val loc = getLocationInfo(file, range) return getLocation(fileId, loc.startLine, loc.startColumn, loc.endLine, loc.endColumn) } + /** Gets a label for the location of `e`. */ + fun getLocation(e: PsiElement): Label { + val file = e.getContainingFile() + val range = e.getTextRange() + return getLocation(file, range) + } + /* OLD: KE1 /** Gets a label for the location of `e`. */ @@ -447,7 +455,9 @@ open class FileTrapWriter( * messages. */ /* TODO open */ fun getLocationString(e: PsiElement): String { - val loc = getLocationInfo(e) + val file = e.getContainingFile() + val range = e.getTextRange() + val loc = getLocationInfo(file, range) return "file://$filePath:${loc.startLine}:${loc.startColumn}:${loc.endLine}:${loc.endColumn}" /* diff --git a/java/kotlin-extractor2/src/main/kotlin/utils/Logger.kt b/java/kotlin-extractor2/src/main/kotlin/utils/Logger.kt index 655f1dbb200..04e63e6abab 100644 --- a/java/kotlin-extractor2/src/main/kotlin/utils/Logger.kt +++ b/java/kotlin-extractor2/src/main/kotlin/utils/Logger.kt @@ -226,7 +226,7 @@ class LoggerBase(val diagnosticCounter: DiagnosticCounter) : BasicLogger { val diagLabel = dtw.getFreshIdLabel() dtw.writeDiagnostics( diagLabel, - "CodeQL Kotlin extractor", + "CodeQL Kotlin: PSI extractor", severity.sev, "", msg, diff --git a/java/ql/lib/semmle/code/java/Diagnostics.qll b/java/ql/lib/semmle/code/java/Diagnostics.qll index 0134b32c5c0..d8c08a34d9b 100644 --- a/java/ql/lib/semmle/code/java/Diagnostics.qll +++ b/java/ql/lib/semmle/code/java/Diagnostics.qll @@ -35,7 +35,10 @@ class Diagnostic extends @diagnostic { */ int getSeverity() { diagnostics(this, _, result, _, _, _, _) } - /** Gets the error code for this compiler message. */ + /** + * Gets the error code for this compiler message. + * This is often the empty string. + */ string getTag() { diagnostics(this, _, _, result, _, _, _) } /** Holds if `s` is the error code for this compiler message. */