[PATCH 2/6] dtc: dt-check-style: Sort rule functions by name
From: Krzysztof Kozlowski
Date: Sat Aug 29 2026 - 15:54:42 EST
Sort all the functions implementing style rules by name, so managing
this will be at bit easier and simultaneous addons of new rules less
conflict-prone. No functional changes, except adding underscore to
_detect_indent_unit() to match other helpers used by the rules.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@xxxxxxxxxxxxxxxx>
---
scripts/dtc/dt-check-style | 607 +++++++++++++++++++++++----------------------
1 file changed, 304 insertions(+), 303 deletions(-)
diff --git a/scripts/dtc/dt-check-style b/scripts/dtc/dt-check-style
index 49b5c28563eb..5385a03f377e 100755
--- a/scripts/dtc/dt-check-style
+++ b/scripts/dtc/dt-check-style
@@ -343,88 +343,8 @@ class Rule:
# --- individual rule check functions --------------------------------------
-def check_trailing_whitespace(ctx):
- for dl in ctx.lines:
- if dl.raw != dl.raw.rstrip():
- yield (dl.lineno, 'trailing whitespace')
-
-def _check_redundant_whitespace(dl):
- if dl.linetype in (LineType.COMMENT, LineType.COMMENT_BODY,
- LineType.COMMENT_END, LineType.COMMENT_START,
- LineType.PREPROCESSOR):
- return
- if re.search(r'(\s\s+|\t)\{', dl.code):
- yield (dl.lineno, 'extra whitespace before {')
- if re.search(r':(\s\s+|\t)', dl.code):
- yield (dl.lineno, 'extra whitespace after :')
- if re.search(r'\s+;', dl.code):
- yield (dl.lineno, 'extra whitespace before ;')
-
-
-def check_redundant_whitespace(ctx):
- """No whitespace between brackets or other code elements.
- See also check_value_whitespace() for more checks."""
- for dl in ctx.lines:
- yield from _check_redundant_whitespace(dl)
- for cont in dl.continuations:
- yield from _check_redundant_whitespace(cont)
-
-
-def check_redundant_whitespace_strict(ctx):
- """No whitespace between brackets or other code elements.
- See also check_value_whitespace() for more checks."""
- for dl in ctx.lines:
- if dl.linetype in (LineType.COMMENT, LineType.COMMENT_BODY,
- LineType.COMMENT_END, LineType.COMMENT_START,
- LineType.PREPROCESSOR):
- continue
- if re.search(r'(\s\s+|\t)=', dl.code):
- yield (dl.lineno, 'extra whitespace before =')
- if re.search(r'=(\s\s+|\t)', dl.code):
- yield (dl.lineno, 'extra whitespace after =')
-
-
-def check_tab_in_yaml_example(ctx):
- """Reject literal tabs in DTS lines when input is YAML.
-
- For YAML examples, indent and content must use spaces. Tabs inside
- a #define value are tolerated (those are CPP macros, not DTS).
- For .dts files, this rule does not apply -- tabs are required.
- """
- if ctx.file_type != 'yaml':
- return
- for dl in ctx.lines:
- if dl.linetype == LineType.PREPROCESSOR:
- continue
- if dl.linetype == LineType.BLANK:
- continue
- if '\t' in dl.raw:
- yield (dl.lineno, 'tab character not allowed in DTS example')
-
-
-def check_mixed_indent_chars(ctx):
- """Indent must be all-tabs, except for aligning indentation (comments
- or continued lines)."""
- for dl in ctx.lines:
- if not dl.indent_str:
- continue
- if dl.linetype == LineType.PREPROCESSOR:
- continue
- if re.search(r' \t', dl.indent_str):
- yield (dl.lineno, 'mixed tabs and spaces in indent')
- if dl.indent_str.count(' ') > 7:
- yield (dl.lineno, 'too many space characters in indent (more than 7)')
- for cont in dl.continuations:
- if not cont.indent_str:
- continue
- if cont.linetype == LineType.PREPROCESSOR:
- continue
- if re.search(r' \t', cont.indent_str):
- yield (cont.lineno, 'mixed tabs and spaces in indent')
-
-
-def detect_indent_unit(ctx):
+def _detect_indent_unit(ctx):
"""Find the indent unit used at depth 1 in this block.
Returns tuple of string (one of: ' ' (2 spaces), ' ' (4 spaces),
@@ -450,85 +370,42 @@ def detect_indent_unit(ctx):
return (None, None)
-def check_indent_unit_relaxed(ctx):
- """YAML examples: 2 or 4 spaces. Never tabs or other widths."""
- (unit, lineno) = detect_indent_unit(ctx)
- if unit is None:
- return
- if unit not in (' ', ' '):
- yield (lineno, 'indent unit must be 2 or 4 spaces, got %r' % unit)
+def _display_col(text):
+ """Visual column width of text, with tabs expanded to the next
+ 8-column stop, matching how printf and most editors render a
+ line and the kernel-wide line length convention."""
+ col = 0
+ for ch in text:
+ if ch == '\t':
+ col = (col // 8 + 1) * 8
+ else:
+ col += 1
+ return col
-def check_indent_unit_dts(ctx):
- """DTS files: 1 tab per level. Always required."""
- (unit, lineno) = detect_indent_unit(ctx)
- if unit is None:
- return
- if unit != '\t':
- yield (lineno, 'indent unit must be 1 tab in DTS, got %r' % unit)
+def _natural_sort_key(s):
+ """Split a string into a tuple of (kind, value) pairs that compares
+ numeric runs as ints, so 'foo10' sorts after 'foo2'."""
+ parts = []
+ for part in re.split(r'(\d+)', s):
+ if part.isdigit():
+ parts.append((0, int(part)))
+ else:
+ parts.append((1, part))
+ return tuple(parts)
-def check_indent_unit_strict(ctx):
- """YAML: must be exactly 4 spaces. DTS: 1 tab (same as relaxed)."""
- (unit, lineno) = detect_indent_unit(ctx)
- if unit is None:
- return
- if ctx.file_type == 'yaml':
- if unit != ' ':
- yield (lineno, 'indent unit must be 4 spaces in strict mode, '
- 'got %r' % unit)
-
-
-def check_indent_consistent(ctx):
- """All indented lines must be a multiple of the detected unit."""
- (unit, lineno) = detect_indent_unit(ctx)
- if unit is None:
- return
- if ctx.file_type == 'yaml':
- if unit not in (' ', ' '):
- return # let check_indent_unit_* report this
- else:
- if unit != '\t':
- return
-
- for dl in ctx.lines:
- if dl.linetype in (LineType.BLANK, LineType.PREPROCESSOR):
- continue
- if dl.linetype == LineType.CONTINUATION:
- continue # continuations align to <, not to indent unit
- if dl.linetype in (LineType.COMMENT_BODY, LineType.COMMENT_END):
- continue
- if not dl.indent_str:
- continue
- # The indent must be 'unit' repeated dl.depth times, exactly.
- # NODE_CLOSE lines have depth equal to the post-decrement value,
- # which matches the indent expected.
- expected = unit * dl.depth
- if dl.indent_str != expected:
- yield (dl.lineno,
- 'indent mismatch (expected depth %d * %r)' %
- (dl.depth, unit))
-
-
-def check_blank_lines(ctx):
- """No two consecutive blank lines, no leading/trailing blank lines
- in any node body."""
- lines = ctx.lines
- # Consecutive blanks
- for i in range(1, len(lines)):
- if lines[i].linetype == LineType.BLANK and \
- lines[i - 1].linetype == LineType.BLANK:
- yield (lines[i].lineno, 'consecutive blank lines')
- # Blank right after { or right before }
- for i, dl in enumerate(lines):
- if dl.linetype != LineType.BLANK:
- continue
- prev = lines[i - 1] if i > 0 else None
- nxt = lines[i + 1] if i + 1 < len(lines) else None
- if prev is not None and prev.linetype == LineType.NODE_OPEN:
- yield (dl.lineno, 'blank line at start of node body')
- if nxt is not None and nxt.linetype == LineType.NODE_CLOSE:
- yield (dl.lineno, 'blank line at end of node body')
+def _strip_strings_and_comments(text):
+ """Remove string literals and /* */ + // comments from a single
+ line, replacing them with empty strings. Used so syntactic checks
+ (whitespace, hex case, etc.) don't false-positive on contents of
+ quoted strings or comments. An unclosed /* on the line is treated
+ as a comment running to end of line."""
+ text = re.sub(r'"(?:[^"\\]|\\.)*"', '""', text)
+ text = re.sub(r'/\*.*?\*/', '', text)
+ text = re.sub(r'/\*.*$', '', text)
+ text = re.sub(r'//.*$', '', text)
+ return text
def _walk_bodies(lines):
@@ -559,16 +436,25 @@ def _walk_bodies(lines):
yield body_stack.pop()
-def _natural_sort_key(s):
- """Split a string into a tuple of (kind, value) pairs that compares
- numeric runs as ints, so 'foo10' sorts after 'foo2'."""
- parts = []
- for part in re.split(r'(\d+)', s):
- if part.isdigit():
- parts.append((0, int(part)))
- else:
- parts.append((1, part))
- return tuple(parts)
+def check_blank_lines(ctx):
+ """No two consecutive blank lines, no leading/trailing blank lines
+ in any node body."""
+ lines = ctx.lines
+ # Consecutive blanks
+ for i in range(1, len(lines)):
+ if lines[i].linetype == LineType.BLANK and \
+ lines[i - 1].linetype == LineType.BLANK:
+ yield (lines[i].lineno, 'consecutive blank lines')
+ # Blank right after { or right before }
+ for i, dl in enumerate(lines):
+ if dl.linetype != LineType.BLANK:
+ continue
+ prev = lines[i - 1] if i > 0 else None
+ nxt = lines[i + 1] if i + 1 < len(lines) else None
+ if prev is not None and prev.linetype == LineType.NODE_OPEN:
+ yield (dl.lineno, 'blank line at start of node body')
+ if nxt is not None and nxt.linetype == LineType.NODE_CLOSE:
+ yield (dl.lineno, 'blank line at end of node body')
def check_child_address_order(ctx):
@@ -624,6 +510,172 @@ def check_child_name_order(ctx):
'child node %r out of name order' % dl.node_name)
+def check_continuation_alignment(ctx):
+ """A multi-line property's continuation lines must align their
+ first non-whitespace character to the display column of:
+ 1. the first '<' or '"' after the '=' in the leading line, if continuation is with '<' or '"'
+ 2. the first value, if the continuation is still the same phandle.
+ Display columns are used so tab-indented .dts files (where a continuation
+ aligns with tabs plus spaces) are compared correctly."""
+ for dl in ctx.lines:
+ if dl.linetype != LineType.PROPERTY:
+ continue
+ if not dl.continuations:
+ continue
+ eq = dl.raw.find('=')
+ if eq < 0:
+ continue
+ # First '<' or '"' after '=', but ignore comments and strip trailing
+ # whitespace (e.g. remaining after removing the comment)
+ rest = _strip_strings_and_comments(dl.raw[eq + 1:]).rstrip()
+ m = re.search(r'\s*([<"])', rest)
+ if not m:
+ continue
+ dl_value_complete = rest.endswith('",') or rest.endswith('>,')
+ target_col = _display_col(_strip_strings_and_comments(dl.raw[:eq + 1 + m.start(1)]))
+ for cont in dl.continuations:
+ target_offset = 0
+ err_msg_explanation = 'to < or "'
+ if not dl_value_complete:
+ target_offset = 1
+ err_msg_explanation = 'to the value under <'
+ if _display_col(cont.indent_str) != target_col + target_offset:
+ yield (cont.lineno,
+ 'continuation should align to column %d '
+ '(%s)' % (target_col + target_offset + 1, err_msg_explanation))
+ # Align to the value within <> or "" of continuation (so the previous line)
+ dl_value_complete = cont.stripped.endswith('",') or cont.stripped.endswith('>,')
+
+
+def check_hex_case(ctx):
+ """Hex literals (0xN) must use lowercase digits and prefix."""
+ for dl in ctx.lines:
+ if dl.linetype in (LineType.BLANK, LineType.COMMENT,
+ LineType.COMMENT_START, LineType.COMMENT_BODY,
+ LineType.COMMENT_END, LineType.PREPROCESSOR):
+ continue
+ for m in re.finditer(r'\b0[xX][0-9a-fA-F]+\b', dl.code):
+ lit = m.group(0)
+ if any(c.isupper() for c in lit[2:]) or lit[1] == 'X':
+ yield (dl.lineno,
+ 'hex literal %r must be lowercase' % lit)
+
+
+def check_indent_consistent(ctx):
+ """All indented lines must be a multiple of the detected unit."""
+ (unit, lineno) = _detect_indent_unit(ctx)
+ if unit is None:
+ return
+ if ctx.file_type == 'yaml':
+ if unit not in (' ', ' '):
+ return # let check_indent_unit_* report this
+ else:
+ if unit != '\t':
+ return
+
+ for dl in ctx.lines:
+ if dl.linetype in (LineType.BLANK, LineType.PREPROCESSOR):
+ continue
+ if dl.linetype == LineType.CONTINUATION:
+ continue # continuations align to <, not to indent unit
+ if dl.linetype in (LineType.COMMENT_BODY, LineType.COMMENT_END):
+ continue
+ if not dl.indent_str:
+ continue
+ # The indent must be 'unit' repeated dl.depth times, exactly.
+ # NODE_CLOSE lines have depth equal to the post-decrement value,
+ # which matches the indent expected.
+ expected = unit * dl.depth
+ if dl.indent_str != expected:
+ yield (dl.lineno,
+ 'indent mismatch (expected depth %d * %r)' %
+ (dl.depth, unit))
+
+
+def check_indent_unit_dts(ctx):
+ """DTS files: 1 tab per level. Always required."""
+ (unit, lineno) = _detect_indent_unit(ctx)
+ if unit is None:
+ return
+ if unit != '\t':
+ yield (lineno, 'indent unit must be 1 tab in DTS, got %r' % unit)
+
+
+def check_indent_unit_relaxed(ctx):
+ """YAML examples: 2 or 4 spaces. Never tabs or other widths."""
+ (unit, lineno) = _detect_indent_unit(ctx)
+ if unit is None:
+ return
+ if unit not in (' ', ' '):
+ yield (lineno, 'indent unit must be 2 or 4 spaces, got %r' % unit)
+
+
+def check_indent_unit_strict(ctx):
+ """YAML: must be exactly 4 spaces. DTS: 1 tab (same as relaxed)."""
+ (unit, lineno) = _detect_indent_unit(ctx)
+ if unit is None:
+ return
+ if ctx.file_type == 'yaml':
+ if unit != ' ':
+ yield (lineno, 'indent unit must be 4 spaces in strict mode, '
+ 'got %r' % unit)
+
+
+def check_line_length(ctx):
+ """Lines must not exceed 80 columns; tabs count as 8 (see
+ _display_col)."""
+ for dl in ctx.lines:
+ if dl.linetype == LineType.BLANK:
+ continue
+ cols = _display_col(dl.raw)
+ if cols > 80:
+ yield (dl.lineno,
+ 'line exceeds 80 columns (%d)' % cols)
+
+
+def check_mixed_indent_chars(ctx):
+ """Indent must be all-tabs, except for aligning indentation (comments
+ or continued lines)."""
+ for dl in ctx.lines:
+ if not dl.indent_str:
+ continue
+ if dl.linetype == LineType.PREPROCESSOR:
+ continue
+ if re.search(r' \t', dl.indent_str):
+ yield (dl.lineno, 'mixed tabs and spaces in indent')
+ if dl.indent_str.count(' ') > 7:
+ yield (dl.lineno, 'too many space characters in indent (more than 7)')
+ for cont in dl.continuations:
+ if not cont.indent_str:
+ continue
+ if cont.linetype == LineType.PREPROCESSOR:
+ continue
+ if re.search(r' \t', cont.indent_str):
+ yield (cont.lineno, 'mixed tabs and spaces in indent')
+
+
+def check_node_close_alone(ctx):
+ """The closing '};' of a node must be on its own line. The
+ classifier accepts a canonical "}" or "};" as NODE_CLOSE; a line
+ that is all closures (e.g. "}; };") is still NODE_CLOSE for depth
+ tracking but is flagged here via dl.closures. Any other line that
+ still contains '};' (in code, not in strings or comments) is
+ mixing a node close with something else."""
+ for dl in ctx.lines:
+ if dl.linetype == LineType.NODE_CLOSE:
+ if dl.closures > 1:
+ yield (dl.lineno,
+ 'closing brace must be on its own line')
+ continue
+ if dl.linetype in (LineType.BLANK, LineType.COMMENT,
+ LineType.COMMENT_START, LineType.COMMENT_BODY,
+ LineType.COMMENT_END, LineType.PREPROCESSOR):
+ continue
+ if '};' in dl.code:
+ yield (dl.lineno,
+ 'closing brace must be on its own line')
+
+
def _property_bucket(name):
"""Return the canonical bucket index for a property:
0 device_type
@@ -769,17 +821,40 @@ def check_property_order(ctx):
(p.prop_name, prev.prop_name))
-def _strip_strings_and_comments(text):
- """Remove string literals and /* */ + // comments from a single
- line, replacing them with empty strings. Used so syntactic checks
- (whitespace, hex case, etc.) don't false-positive on contents of
- quoted strings or comments. An unclosed /* on the line is treated
- as a comment running to end of line."""
- text = re.sub(r'"(?:[^"\\]|\\.)*"', '""', text)
- text = re.sub(r'/\*.*?\*/', '', text)
- text = re.sub(r'/\*.*$', '', text)
- text = re.sub(r'//.*$', '', text)
- return text
+def _check_redundant_whitespace(dl):
+ if dl.linetype in (LineType.COMMENT, LineType.COMMENT_BODY,
+ LineType.COMMENT_END, LineType.COMMENT_START,
+ LineType.PREPROCESSOR):
+ return
+ if re.search(r'(\s\s+|\t)\{', dl.code):
+ yield (dl.lineno, 'extra whitespace before {')
+ if re.search(r':(\s\s+|\t)', dl.code):
+ yield (dl.lineno, 'extra whitespace after :')
+ if re.search(r'\s+;', dl.code):
+ yield (dl.lineno, 'extra whitespace before ;')
+
+
+def check_redundant_whitespace(ctx):
+ """No whitespace between brackets or other code elements.
+ See also check_value_whitespace() for more checks."""
+ for dl in ctx.lines:
+ yield from _check_redundant_whitespace(dl)
+ for cont in dl.continuations:
+ yield from _check_redundant_whitespace(cont)
+
+
+def check_redundant_whitespace_strict(ctx):
+ """No whitespace between brackets or other code elements.
+ See also check_value_whitespace() for more checks."""
+ for dl in ctx.lines:
+ if dl.linetype in (LineType.COMMENT, LineType.COMMENT_BODY,
+ LineType.COMMENT_END, LineType.COMMENT_START,
+ LineType.PREPROCESSOR):
+ continue
+ if re.search(r'(\s\s+|\t)=', dl.code):
+ yield (dl.lineno, 'extra whitespace before =')
+ if re.search(r'=(\s\s+|\t)', dl.code):
+ yield (dl.lineno, 'extra whitespace after =')
def check_required_blank_lines(ctx):
@@ -841,18 +916,49 @@ def check_required_blank_lines(ctx):
between_blanks = 0
-def check_hex_case(ctx):
- """Hex literals (0xN) must use lowercase digits and prefix."""
+def check_tab_in_yaml_example(ctx):
+ """Reject literal tabs in DTS lines when input is YAML.
+
+ For YAML examples, indent and content must use spaces. Tabs inside
+ a #define value are tolerated (those are CPP macros, not DTS).
+ For .dts files, this rule does not apply -- tabs are required.
+ """
+ if ctx.file_type != 'yaml':
+ return
for dl in ctx.lines:
- if dl.linetype in (LineType.BLANK, LineType.COMMENT,
- LineType.COMMENT_START, LineType.COMMENT_BODY,
- LineType.COMMENT_END, LineType.PREPROCESSOR):
+ if dl.linetype == LineType.PREPROCESSOR:
continue
- for m in re.finditer(r'\b0[xX][0-9a-fA-F]+\b', dl.code):
- lit = m.group(0)
- if any(c.isupper() for c in lit[2:]) or lit[1] == 'X':
- yield (dl.lineno,
- 'hex literal %r must be lowercase' % lit)
+ if dl.linetype == LineType.BLANK:
+ continue
+ if '\t' in dl.raw:
+ yield (dl.lineno, 'tab character not allowed in DTS example')
+
+
+def check_trailing_whitespace(ctx):
+ for dl in ctx.lines:
+ if dl.raw != dl.raw.rstrip():
+ yield (dl.lineno, 'trailing whitespace')
+
+
+def check_unclosed_block_comment(ctx):
+ """Every /* must have a matching */ in the same block. Catches both
+ a comment opened on its own line (COMMENT_START) and a tail comment
+ opened on a PROPERTY or other code line (where in_block_comment is
+ set by _split_code so the next line becomes COMMENT_BODY without a
+ preceding COMMENT_START)."""
+ open_lineno = None
+ for dl in ctx.lines:
+ if dl.linetype == LineType.COMMENT_START:
+ open_lineno = dl.lineno
+ elif dl.linetype == LineType.COMMENT_END:
+ open_lineno = None
+ elif dl.linetype == LineType.COMMENT_BODY and open_lineno is None:
+ # Block was opened by a /* tail on a code line; report at
+ # the first orphan body line since the originating line is
+ # already classified as something else.
+ open_lineno = dl.lineno
+ if open_lineno is not None:
+ yield (open_lineno, 'unclosed /* block comment')
def check_unit_address_format(ctx):
@@ -886,6 +992,17 @@ def check_unit_address_format(ctx):
break
+def check_unused_labels(ctx):
+ """Labels defined but never referenced are clutter."""
+ defined, referenced = collect_labels_and_refs(ctx.text)
+ for label in sorted(defined - referenced):
+ # Find the line where this label is defined for line-number
+ # reporting.
+ m = re.search(r'(?m)^.*\b' + re.escape(label) + r'\s*:', ctx.text)
+ lineno = ctx.text[:m.start()].count('\n') + 1 if m else 1
+ yield (lineno, 'label %r defined but never &-referenced' % label)
+
+
def check_value_whitespace(ctx):
"""A <...> cell list must have no whitespace directly after '<'
or directly before '>'. Continuation lines are joined onto the
@@ -914,122 +1031,6 @@ def check_value_whitespace(ctx):
break
-def check_node_close_alone(ctx):
- """The closing '};' of a node must be on its own line. The
- classifier accepts a canonical "}" or "};" as NODE_CLOSE; a line
- that is all closures (e.g. "}; };") is still NODE_CLOSE for depth
- tracking but is flagged here via dl.closures. Any other line that
- still contains '};' (in code, not in strings or comments) is
- mixing a node close with something else."""
- for dl in ctx.lines:
- if dl.linetype == LineType.NODE_CLOSE:
- if dl.closures > 1:
- yield (dl.lineno,
- 'closing brace must be on its own line')
- continue
- if dl.linetype in (LineType.BLANK, LineType.COMMENT,
- LineType.COMMENT_START, LineType.COMMENT_BODY,
- LineType.COMMENT_END, LineType.PREPROCESSOR):
- continue
- if '};' in dl.code:
- yield (dl.lineno,
- 'closing brace must be on its own line')
-
-
-def _display_col(text):
- """Visual column width of text, with tabs expanded to the next
- 8-column stop, matching how printf and most editors render a
- line and the kernel-wide line length convention."""
- col = 0
- for ch in text:
- if ch == '\t':
- col = (col // 8 + 1) * 8
- else:
- col += 1
- return col
-
-
-def check_line_length(ctx):
- """Lines must not exceed 80 columns; tabs count as 8 (see
- _display_col)."""
- for dl in ctx.lines:
- if dl.linetype == LineType.BLANK:
- continue
- cols = _display_col(dl.raw)
- if cols > 80:
- yield (dl.lineno,
- 'line exceeds 80 columns (%d)' % cols)
-
-
-def check_continuation_alignment(ctx):
- """A multi-line property's continuation lines must align their
- first non-whitespace character to the display column of:
- 1. the first '<' or '"' after the '=' in the leading line, if continuation is with '<' or '"'
- 2. the first value, if the continuation is still the same phandle.
- Display columns are used so tab-indented .dts files (where a continuation
- aligns with tabs plus spaces) are compared correctly."""
- for dl in ctx.lines:
- if dl.linetype != LineType.PROPERTY:
- continue
- if not dl.continuations:
- continue
- eq = dl.raw.find('=')
- if eq < 0:
- continue
- # First '<' or '"' after '=', but ignore comments and strip trailing
- # whitespace (e.g. remaining after removing the comment)
- rest = _strip_strings_and_comments(dl.raw[eq + 1:]).rstrip()
- m = re.search(r'\s*([<"])', rest)
- if not m:
- continue
- dl_value_complete = rest.endswith('",') or rest.endswith('>,')
- target_col = _display_col(_strip_strings_and_comments(dl.raw[:eq + 1 + m.start(1)]))
- for cont in dl.continuations:
- target_offset = 0
- err_msg_explanation = 'to < or "'
- if not dl_value_complete:
- target_offset = 1
- err_msg_explanation = 'to the value under <'
- if _display_col(cont.indent_str) != target_col + target_offset:
- yield (cont.lineno,
- 'continuation should align to column %d '
- '(%s)' % (target_col + target_offset + 1, err_msg_explanation))
- # Align to the value within <> or "" of continuation (so the previous line)
- dl_value_complete = cont.stripped.endswith('",') or cont.stripped.endswith('>,')
-
-
-def check_unclosed_block_comment(ctx):
- """Every /* must have a matching */ in the same block. Catches both
- a comment opened on its own line (COMMENT_START) and a tail comment
- opened on a PROPERTY or other code line (where in_block_comment is
- set by _split_code so the next line becomes COMMENT_BODY without a
- preceding COMMENT_START)."""
- open_lineno = None
- for dl in ctx.lines:
- if dl.linetype == LineType.COMMENT_START:
- open_lineno = dl.lineno
- elif dl.linetype == LineType.COMMENT_END:
- open_lineno = None
- elif dl.linetype == LineType.COMMENT_BODY and open_lineno is None:
- # Block was opened by a /* tail on a code line; report at
- # the first orphan body line since the originating line is
- # already classified as something else.
- open_lineno = dl.lineno
- if open_lineno is not None:
- yield (open_lineno, 'unclosed /* block comment')
-
-
-def check_unused_labels(ctx):
- """Labels defined but never referenced are clutter."""
- defined, referenced = collect_labels_and_refs(ctx.text)
- for label in sorted(defined - referenced):
- # Find the line where this label is defined for line-number
- # reporting.
- m = re.search(r'(?m)^.*\b' + re.escape(label) + r'\s*:', ctx.text)
- lineno = ctx.text[:m.start()].count('\n') + 1 if m else 1
- yield (lineno, 'label %r defined but never &-referenced' % label)
-
-
# --- registry --------------------------------------------------------------
RULES = [
--
2.53.0