Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,23 @@ class DocscribeAnnotator : ExternalAnnotator<AnnotatorFileInfo, DocscribeOutput>
if (annotationResult != null) {
val projectDir = file.project.basePath ?: ""
val useRbs = RbsDetector.shouldUseRbs(projectDir)
val warnInvalidYard =
try {
DocscribeSettings.getInstance().warnOnInvalidYardTypes
} catch (_: Exception) {
true
}
for (parsedFile in annotationResult.files) {
for (offense in parsedFile.offenses) {
val isRbsTypeUpdateRaw = offense.copName == "Docscribe/UpdatedParam" || offense.copName == "Docscribe/UpdatedReturn"
val isInvalidYardRaw = offense.copName == "Docscribe/InvalidType"
val isError = offense.copName == "Docscribe/Error"
val isRbsSource = offense.source == "rbs" || offense.message.contains("RBS")
// Warn toggle OFF hides syntax-driven InvalidType; RBS ones stay.
if (isInvalidYardHidden(offense.copName, offense.source, offense.message, warnInvalidYard)) {
log.info("DocScribe apply skipping InvalidType for $filePath (warnOnInvalidYardTypes=false)")
continue
}
val baseLine = (offense.location.startLine - 1).coerceIn(0, document.lineCount - 1)
// For RBS updates and invalid YARD, highlight the YARD comment, not the def. Errors stay on line 1.
val line =
Expand Down Expand Up @@ -409,8 +420,8 @@ class DocscribeAnnotator : ExternalAnnotator<AnnotatorFileInfo, DocscribeOutput>
}
}
}
// YARD syntax validation without RBS is now handled by the gem via --validate-types
// (Yard::Validator + TypeMismatchValidator) and appears as Docscribe/InvalidType above
// Syntax-driven InvalidType is filtered above when the warn setting is
// off (see isInvalidYardHidden); RBS-sourced InvalidType always shows.
}

private fun showGemNotInstalledBalloon(
Expand Down Expand Up @@ -552,6 +563,28 @@ class DocscribeAnnotator : ExternalAnnotator<AnnotatorFileInfo, DocscribeOutput>
nowMs: Long = System.currentTimeMillis(),
): Boolean = lastShownMs == null || nowMs - lastShownMs >= BALLOON_THROTTLE_MS

/**
* Whether a `Docscribe/InvalidType` offense should be hidden because the
* "Warn on invalid YARD types" setting is off. RBS-sourced offenses always
* stay visible — the toggle only gates syntax-driven ones.
*
* @param copName Cop name of the offense.
* @param source `source` field of the offense (`rbs`, `infer`, `syntax`, or `null`).
* @param message Offense message (legacy RBS marker fallback).
* @param warnInvalidYardTypes Current value of the setting.
* @return `true` when the offense must be skipped in [apply].
*/
@JvmStatic
fun isInvalidYardHidden(
copName: String,
source: String?,
message: String,
warnInvalidYardTypes: Boolean,
): Boolean {
if (copName != "Docscribe/InvalidType" || warnInvalidYardTypes) return false
return !(source == "rbs" || message.contains("RBS"))
}

/**
* Generation counter per file path.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.florexlabs.docscribe.annotator

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class DocscribeAnnotatorWarnToggleTest {
@Test
fun `warn on shows syntax invalid type`() {
assertFalse(
DocscribeAnnotator.isInvalidYardHidden(
"Docscribe/InvalidType",
"syntax",
"invalid YARD type [Symbкol] for @param x",
warnInvalidYardTypes = true,
),
)
}

@Test
fun `warn off hides syntax invalid type`() {
assertTrue(
DocscribeAnnotator.isInvalidYardHidden(
"Docscribe/InvalidType",
"syntax",
"invalid YARD type [Symbкol] for @param x",
warnInvalidYardTypes = false,
),
)
}

@Test
fun `warn off hides invalid type with null source`() {
assertTrue(
DocscribeAnnotator.isInvalidYardHidden(
"Docscribe/InvalidType",
null,
"invalid YARD type [Array<] for @return",
warnInvalidYardTypes = false,
),
)
}

@Test
fun `warn off keeps rbs sourced invalid type`() {
assertFalse(
DocscribeAnnotator.isInvalidYardHidden(
"Docscribe/InvalidType",
"rbs",
"invalid YARD type [String] for @param x",
warnInvalidYardTypes = false,
),
)
}

@Test
fun `warn off keeps other cops`() {
assertFalse(
DocscribeAnnotator.isInvalidYardHidden(
"Docscribe/MissingDocBlock",
"infer",
"missing docs for Calc#add",
warnInvalidYardTypes = false,
),
)
assertFalse(
DocscribeAnnotator.isInvalidYardHidden(
"Docscribe/UpdatedParam",
"rbs",
"updated @param x from String to Integer",
warnInvalidYardTypes = false,
),
)
}
}
21 changes: 11 additions & 10 deletions tools/gui-qa/cases/3h5.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#!/bin/zsh
# 3H.5 Warn toggle live: bad.rb with [Symbкol] (CYRILLIC к, U+043A) and NO
# RBS (sig/ moved away). Settings ON -> annotator flags (offenses=1) +
# intention fix row without restart. OFF leg: DRIFT (proven 2026-09-18) —
# the gem ALWAYS emits invalid_type for syntax-broken YARD
# (handle_existing_param -> invalid_yard_type? is unconditional; the
# --validate-types flag only gates *mismatch-vs-inferred* reporting, and
# the plugin's toggle is not even wired into RunOptions for CHECK). So OFF
# still yields offenses=1. Assert ON (count + fix row); record OFF=1 as
# drift in the note.
# intention fix row without restart. OFF -> plugin filters the
# syntax-driven InvalidType in apply() (log: "skipping InvalidType ..."),
# RBS-sourced ones would stay. The gem still emits the offense (its
# --validate-types flag only gates mismatch-vs-inferred reporting), so the
# "apply ... offenses=1" line is pre-filter and CANNOT be the OFF oracle —
# assert the skip line instead.
cd "$(dirname "$0")/.." || exit 2
source ./lib.sh || exit 2
source ./menu.sh || exit 2
Expand Down Expand Up @@ -89,8 +88,10 @@ M1="$(log_mark)"
rewrite_run '~/qa-stand/bad.rb'
sleep 20
A2="$(gssh "awk 'NR>$M1' ~/Library/Logs/JetBrains/RubyMine2026.2/idea.log" | grep -F 'DocScribe apply file=/Users/admin/qa-stand/bad.rb' | tail -n 1)"
print -r -- "OFF apply (drift, still flagged): [$A2]" >&2
SKIP2="$(gssh "awk 'NR>$M1' ~/Library/Logs/JetBrains/RubyMine2026.2/idea.log" | grep -F 'skipping InvalidType for /Users/admin/qa-stand/bad.rb' | tail -n 1)"
[[ -n "$SKIP2" ]] || RC=2
print -r -- "OFF skip line: [$SKIP2]" >&2
cleanup
if [[ $RC -eq 1 ]]; then fail "3h5" "no highlight when ON"; exit 1; fi
fail "3h5" "OFF still flags InvalidType (gem always emits; toggle unwired for CHECK)"
exit 1
if [[ $RC -eq 2 ]]; then echo "--- log tail ---" >&2; echo "$A2" >&2; fail "3h5" "no skip line when OFF"; exit 1; fi
pass "3h5"
Loading