diff --git a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractorPSI.kt b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractorPSI.kt index 3ca5dc45554..d63a470d79f 100644 --- a/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractorPSI.kt +++ b/java/kotlin-extractor/src/main/kotlin/comments/CommentExtractorPSI.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtVisitor +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset @@ -95,8 +96,21 @@ class CommentExtractorPSI( } } - // Only storing the owner of doc comments: - val ownerPsi = getKDocOwner(comment) ?: return + val ownerPsi = getKDocOwner(comment) + if (ownerPsi == null) { + // A file-level KDoc (one written before the file's package + // directive) has no declaration owner. The K2/FIR extractor + // attributes such a comment to the compilation unit (the KDOC + // is a direct child of the FILE node there), so we do the same + // here to keep the two frontends in agreement. + if (comment.parent is KtFile) { + val fileOwnerLabel = getLabel(file) + if (fileOwnerLabel != null) { + tw.writeKtCommentOwners(commentLabel, fileOwnerLabel) + } + } + return + } val owners = mutableListOf() file.accept(IrVisitorLookup(psi2Ir, ownerPsi, file), owners) @@ -111,7 +125,7 @@ class CommentExtractorPSI( private fun getKDocOwner(comment: KDoc): PsiElement? { val owner = comment.owner - if (owner == null) { + if (owner == null && comment.parent !is KtFile) { logger.warn( "Couldn't get owner of KDoc. The comment is extracted without an owner." ) diff --git a/java/ql/test-kotlin1/library-tests/comments/comments.expected b/java/ql/test-kotlin1/library-tests/comments/comments.expected index 955400b7c19..3ffdeea37dd 100644 --- a/java/ql/test-kotlin1/library-tests/comments/comments.expected +++ b/java/ql/test-kotlin1/library-tests/comments/comments.expected @@ -1,5 +1,5 @@ comments -| comments.kt:1:1:1:25 | /** Kdoc with no owner */ | /** Kdoc with no owner */ | +| comments.kt:1:1:1:36 | /** Kdoc owned by CompilationUnit */ | /** Kdoc owned by CompilationUnit */ | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | | comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | /**\n * Members of this group.\n */ | | comments.kt:19:5:22:7 | /**\n * Adds a [member] to this group.\n * @return the new size of the group.\n */ | /**\n * Adds a [member] to this group.\n * @return the new size of the group.\n */ | @@ -15,8 +15,8 @@ comments | comments.kt:71:9:73:11 | /**\n * An anonymous function comment\n */ | /**\n * An anonymous function comment\n */ | | comments.kt:79:9:81:11 | /**\n * A local function comment\n */ | /**\n * A local function comment\n */ | | comments.kt:88:10:90:11 | /**\n * An anonymous object comment\n */ | /**\n * An anonymous object comment\n */ | -| comments.kt:95:1:95:163 | // Diagnostic Matches: % Couldn't get owner of KDoc. The comment is extracted without an owner. ...while extracting a file (comments.kt) at %comments.kt:1:1:96:0% | // Diagnostic Matches: % Couldn't get owner of KDoc. The comment is extracted without an owner. ...while extracting a file (comments.kt) at %comments.kt:1:1:96:0% | commentOwners +| comments.kt:1:1:1:36 | /** Kdoc owned by CompilationUnit */ | comments.kt:0:0:0:0 | comments | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | comments.kt:12:1:31:1 | Group | | comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | comments.kt:17:13:17:23 | getMembers$private | | comments.kt:14:5:16:7 | /**\n * Members of this group.\n */ | comments.kt:17:13:17:46 | members | @@ -35,13 +35,11 @@ commentOwners | comments.kt:88:10:90:11 | /**\n * An anonymous object comment\n */ | comments.kt:87:15:92:5 | | | comments.kt:88:10:90:11 | /**\n * An anonymous object comment\n */ | comments.kt:87:15:92:5 | new X(...) { ... } | commentNoOwners -| comments.kt:1:1:1:25 | /** Kdoc with no owner */ | | comments.kt:24:9:24:25 | // A line comment | | comments.kt:28:5:30:6 | /*\n A block comment\n */ | | comments.kt:42:5:44:7 | /**\n * A variable.\n */ | -| comments.kt:95:1:95:163 | // Diagnostic Matches: % Couldn't get owner of KDoc. The comment is extracted without an owner. ...while extracting a file (comments.kt) at %comments.kt:1:1:96:0% | commentSections -| comments.kt:1:1:1:25 | /** Kdoc with no owner */ | Kdoc with no owner | +| comments.kt:1:1:1:36 | /** Kdoc owned by CompilationUnit */ | Kdoc owned by CompilationUnit | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | A group of *members*.\n\nThis class has no useful logic; it's just a documentation example.\n\n | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | Creates an empty group. | | comments.kt:4:1:11:3 | /**\n * A group of *members*.\n *\n * This class has no useful logic; it's just a documentation example.\n *\n * @property name the name of this group.\n * @constructor Creates an empty group.\n */ | the name of this group. | @@ -69,7 +67,7 @@ commentSectionContents | An anonymous object comment | An anonymous object comment | | An init block comment | An init block comment | | Creates an empty group. | Creates an empty group. | -| Kdoc with no owner | Kdoc with no owner | +| Kdoc owned by CompilationUnit | Kdoc owned by CompilationUnit | | Medium is in the middle | Medium is in the middle | | Members of this group. | Members of this group. | | This is high | This is high | diff --git a/java/ql/test-kotlin1/library-tests/comments/comments.kt b/java/ql/test-kotlin1/library-tests/comments/comments.kt index 4552254fa22..fb79677cbc0 100644 --- a/java/ql/test-kotlin1/library-tests/comments/comments.kt +++ b/java/ql/test-kotlin1/library-tests/comments/comments.kt @@ -1,4 +1,4 @@ -/** Kdoc with no owner */ +/** Kdoc owned by CompilationUnit */ package foo.bar /** @@ -91,5 +91,3 @@ class XX { X() { } } - -// Diagnostic Matches: % Couldn't get owner of KDoc. The comment is extracted without an owner. ...while extracting a file (comments.kt) at %comments.kt:1:1:96:0% diff --git a/java/ql/test-kotlin1/library-tests/dataflow/func/kotlinx_coroutines_stubs.kt b/java/ql/test-kotlin1/library-tests/dataflow/func/kotlinx_coroutines_stubs.kt index 3ef2c70d363..8cb4c31fb25 100644 --- a/java/ql/test-kotlin1/library-tests/dataflow/func/kotlinx_coroutines_stubs.kt +++ b/java/ql/test-kotlin1/library-tests/dataflow/func/kotlinx_coroutines_stubs.kt @@ -31,5 +31,3 @@ public fun CoroutineScope.async( ): Deferred { return null!! } - -// Diagnostic Matches: % Couldn't get owner of KDoc. The comment is extracted without an owner. ...while extracting a file (kotlinx_coroutines_stubs.kt) at %kotlinx_coroutines_stubs.kt:1:1:36:0%