From 1004b9262c83024152e9276edaaa17c5b21b037c Mon Sep 17 00:00:00 2001 From: reniers-tiobe Date: Fri, 23 Jan 2026 14:15:21 +0100 Subject: [PATCH] Fix FP for `document-constants` Fixed false positive on `const` declaration for a generic type, such as `const AnyTree = Union{SyntaxNode, GreenNode}` We do this by checking whether right-hand side of assignment node is of kind `curly`, which seem to denote generic (parameterized) types. We do still generate violations on expressions such `Vector{Float64}(undef, 3)`, which are `call`s. --- checks/DocumentConstants.jl | 37 +++++++++++++++------------------- test/res/DocumentConstants.jl | 6 ++++++ test/res/DocumentConstants.val | 19 +++++++++++++---- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/checks/DocumentConstants.jl b/checks/DocumentConstants.jl index ed5a51a..93057e1 100644 --- a/checks/DocumentConstants.jl +++ b/checks/DocumentConstants.jl @@ -1,6 +1,7 @@ module DocumentConstants using ...Properties: find_lhs_of_kind, haschildren, is_constant +using ...SyntaxNodeHelpers: find_descendants include("_common.jl") @@ -10,31 +11,25 @@ severity(::Check) = 7 synopsis(::Check) = "Constants must have a docstring" function init(this::Check, ctxt::AnalysisContext) - register_syntaxnode_action(ctxt, is_constant, n -> check(this, ctxt, n)) + register_syntaxnode_action(ctxt, n -> kind(n) == K"const", n -> check(this, ctxt, n)) end function check(this::Check, ctxt::AnalysisContext, const_node::SyntaxNode) - if kind(const_node) == K"global" - if haschildren(const_node) - const_node = children(const_node)[1] - else - @debug "A global node without children:" const_node - return nothing - end - end @assert kind(const_node) == K"const" "Expected a [const] const_node, got $(kind(const_node))." - if haschildren(const_node) && kind(children(const_node)[1]) == K"=" - # This is a constant value declaration. - assignment = children(const_node)[1] - if haschildren(assignment) - if kind(const_node.parent) != K"doc" - const_id = find_lhs_of_kind(K"Identifier", const_node) - report_violation(ctxt, this, const_node, - "Const value $(string(const_id)) has no docstring." - ) - end - else - @debug "An assignment without children:" assignment + + if kind(const_node.parent) == K"doc" + return nothing # Nothing to report: there is a docstring already + end + + # Find first (typically only) assignment underneath [const] node + assignment = first(find_descendants(n -> kind(n) == K"=", const_node, true)) + if ! isnothing(assignment) && length(children(assignment)) >= 2 + rhs = children(assignment)[2] + if kind(rhs) != K"curly" # RM-37765: ignore Union and other parameterized type + const_id = find_lhs_of_kind(K"Identifier", const_node) + report_violation(ctxt, this, const_node, + "Const value '$(string(const_id))' has no docstring" + ) end end end diff --git a/test/res/DocumentConstants.jl b/test/res/DocumentConstants.jl index 4aaabed..e867288 100644 --- a/test/res/DocumentConstants.jl +++ b/test/res/DocumentConstants.jl @@ -7,6 +7,8 @@ struct MyType x::Int end const UNDOCUMENTED_GLOBAL_ITEM = MyType(3) +const myvar = {} +const MyVector = Vector{Float64}(undef, 3) # Good "MAG_THRESHOLD is dimensionless. A value of 0 means no expansion." @@ -17,3 +19,7 @@ const THE_ANSWER = 42 "Cierto!" const E_VERO = true + +# RM-37765: No docstring needed for 'type aliases' +const AnyTree = Union{SyntaxNode, GreenNode} +const MyTuple = Tuple{SyntaxNode, GreenNode} diff --git a/test/res/DocumentConstants.val b/test/res/DocumentConstants.val index df66a1e..7b5719c 100644 --- a/test/res/DocumentConstants.val +++ b/test/res/DocumentConstants.val @@ -1,20 +1,31 @@ - >> Processing file 'DocumentConstants.jl'... DocumentConstants.jl(3, 1): const MAGTHRESHOLD::Float64 = 3.00 # In ppm -└────────────────────────────────┘ ── Const value MAGTHRESHOLD has no docstring. +└────────────────────────────────┘ ── Const value 'MAGTHRESHOLD' has no docstring. Constants must have a docstring. Rule: document-constants. Severity: 7 DocumentConstants.jl(4, 1): const THEANSWER = 42 -└──────────────────┘ ── Const value THEANSWER has no docstring. +└──────────────────┘ ── Const value 'THEANSWER' has no docstring. Constants must have a docstring. Rule: document-constants. Severity: 7 DocumentConstants.jl(9, 1): const UNDOCUMENTED_GLOBAL_ITEM = MyType(3) -└────────────────────────────────────────┘ ── Const value UNDOCUMENTED_GLOBAL_ITEM has no docstring. +└────────────────────────────────────────┘ ── Const value 'UNDOCUMENTED_GLOBAL_ITEM' has no docstring. +Constants must have a docstring. +Rule: document-constants. Severity: 7 + +DocumentConstants.jl(10, 1): +const myvar = {} +└──────────────┘ ── Const value 'myvar' has no docstring. +Constants must have a docstring. +Rule: document-constants. Severity: 7 + +DocumentConstants.jl(11, 1): +const MyVector = Vector{Float64}(undef, 3) +└────────────────────────────────────────┘ ── Const value 'MyVector' has no docstring. Constants must have a docstring. Rule: document-constants. Severity: 7