mirror of
https://github.com/github/codeql.git
synced 2026-07-27 05:51:56 +02:00
Kotlin: attribute file-level KDoc to the compilation unit (K1/PSI)
A KDoc written before a file's `package` directive documents the file itself and has no declaration owner: the PSI extractor's `comment.owner` is null for it. The extractor previously emitted a "Couldn't get owner of KDoc" diagnostic and recorded no owner in that case. The K2/FIR extractor, by contrast, already attributes such a comment to the compilation unit, because the KDOC node is a direct child of the FILE node in the FIR lighter AST and the enclosing `IrFile` is discovered as its owner. The two frontends therefore disagreed on file-level KDoc ownership. Align the PSI extractor with the FIR one: when a KDoc has no declaration owner but is a direct child of the `KtFile`, attribute it to the file (`getLabel(file)` yields the compilation-unit label, the same target the FIR extractor reaches). The now-spurious "Couldn't get owner" diagnostic is suppressed for file-level KDoc (it remains for any genuinely ownerless KDoc elsewhere). This removes the last owner-attribution divergence for file-level KDoc. The `comments` and `dataflow/func` test sources, which previously carried frontend-specific text and a `// Diagnostic Matches` line asserting the old warning, are unified with their K2 counterparts; the K1 expectations lose the diagnostic and gain the compilation-unit owner row, matching K2. Remaining `comments` divergence (owners of enum entries, init blocks and an anonymous function) stems from those IR nodes carrying no FIR source metadata under K2 and is addressed separately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -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<IrElement>()
|
||||
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."
|
||||
)
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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%
|
||||
|
||||
@@ -31,5 +31,3 @@ public fun <T> CoroutineScope.async(
|
||||
): Deferred<T> {
|
||||
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%
|
||||
|
||||
Reference in New Issue
Block a user