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
6 changes: 5 additions & 1 deletion docs/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ rules run on the JuliaSyntax tree of a single file alone
| `detached_docstring` | A string that looks like a docstring but is not attached to anything, because a comment or a blank line sits between it and the expression it documents. The text is evaluated and discarded. |

All of these are `"off"` outside the `strict` preset, except `detached_docstring`,
which reports as an error in every preset but `minimal`: a severed docstring
which reports as a warning in every preset but `minimal`: a severed docstring
discards its text outright rather than expressing a style preference.

### Severities
Expand Down Expand Up @@ -320,6 +320,10 @@ A preset name **floats**: it tracks the tool rather than pinning a frozen rule
set, so upgrading the tooling can change what a preset reports. To keep that
from breaking projects on upgrade, a rule that did not exist before enters
existing presets as `"off"`; promoting it is a deliberate, changelogged change.
The one exception so far is `detached_docstring`, which found its way into
`default` directly because its finding is outright discarded program text — and
even that class of rule enters at `"warning"` at most, never `"error"`, so an
upgrade can never change `julialint`'s exit status.
Version-pinning syntax (`preset = "default@2"`) may be added later — bare names
will keep floating, so nothing written today changes meaning.

Expand Down
11 changes: 8 additions & 3 deletions src/lint_rules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ const LINT_RULES = LintRule[
# ── Purely syntactic rules (see lint_syntax_rules.jl) ────────────────────
# New rules ship `:off` outside `strict` so an upgrade never switches them
# on for existing projects; promotion to default-on is a deliberate,
# sweep-validated release decision.
# sweep-validated release decision. The one exception is
# `detached_docstring`, and even it caps at `:warning`: no new rule may
# enter `default` at `:error`, so an upgrade never flips `julialint`'s
# exit code.
LintRule(id = :nan_comparison, tier = TierSyntax,
severity_default = :off, severity_strict = :warning,
doc_link = URI("https://docs.julialang.org/en/v1/base/numbers/#Base.isnan")),
Expand All @@ -209,9 +212,11 @@ const LINT_RULES = LintRule[
LintRule(id = :async_task, tier = TierSyntax,
severity_default = :off, severity_strict = :warning),
# The text is discarded outright rather than a style opinion, so it does not
# follow the `:off`-by-default convention for a new rule.
# follow the `:off`-by-default convention for a new rule. `:warning`, not
# `:error`: the detector is a heuristic, and only the definitional
# breakage rules below may fail CI out of the box.
LintRule(id = :detached_docstring, tier = TierSyntax,
severity_default = :error, severity_strict = :error),
severity_default = :warning, severity_strict = :warning),

# ── Rules backed by analyses other than StaticLint ───────────────────────
LintRule(id = :syntax_errors, tier = TierSyntax,
Expand Down
2 changes: 1 addition & 1 deletion test/test_config.jl
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ end
:bare_using => :off,
:debug_statement => :off,
:async_task => :off,
:detached_docstring => :error,
:detached_docstring => :warning,
)
@test JuliaWorkspaces.LINT_PRESETS["default"] == expected_default

Expand Down
4 changes: 2 additions & 2 deletions test/test_lint_syntax_rules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -290,10 +290,10 @@ end
# One finding per detached docstring.
@test length(dd_diags("$D\n# c\n$X\n$D\n# c\ng(x) = 2\n")) == 2

# Reported as an error in the default preset.
# Reported as a warning in the default preset.
src = "$D\n# c\n$X\n"
d = only(dd_diags(src))
@test d.severity === :error
@test d.severity === :warning
@test occursin("immediately followed", d.message)
# The range is exactly the string, not the enclosing container.
@test src[first(d.range):last(d.range)-1] == D
Expand Down
Loading