Skip to main content

yara_x/compiler/
warnings.rs

1#![cfg_attr(any(), rustfmt::skip)]
2#![allow(clippy::duplicated_attributes)]
3
4use std::fmt::{Debug, Display, Formatter};
5
6use serde::Serialize;
7use thiserror::Error;
8
9use yara_x_macros::ErrorEnum;
10use yara_x_macros::ErrorStruct;
11
12pub(crate) use crate::compiler::report::{Level, Patch, Report, ReportBuilder, CodeLoc, Label, Footer};
13
14/// A warning raised while compiling YARA rules.
15#[allow(missing_docs)]
16#[non_exhaustive]
17#[derive(ErrorEnum, Error, PartialEq, Eq)]
18#[derive(Serialize)]
19#[serde(tag = "type")]
20pub enum Warning {
21    AmbiguousExpression(Box<AmbiguousExpression>),
22    BooleanIntegerComparison(Box<BooleanIntegerComparison>),
23    ConsecutiveJumps(Box<ConsecutiveJumps>),
24    DeprecatedField(Box<DeprecatedField>),
25    DuplicateImport(Box<DuplicateImport>),
26    GlobalRuleMisuse(Box<GlobalRuleMisuse>),
27    IgnoredModule(Box<IgnoredModule>),
28    IgnoredRule(Box<IgnoredRule>),
29    InvalidMetadata(Box<InvalidMetadata>),
30    InvalidRuleName(Box<InvalidRuleName>),
31    InvalidTag(Box<InvalidTag>),
32    InvariantBooleanExpression(Box<InvariantBooleanExpression>),
33    MissingMetadata(Box<MissingMetadata>),
34    NonBooleanAsBoolean(Box<NonBooleanAsBoolean>),
35    PotentiallySlowLoop(Box<PotentiallySlowLoop>),
36    PotentiallyUnsatisfiableExpression(Box<PotentiallyUnsatisfiableExpression>),
37    RedundantCaseModifier(Box<RedundantCaseModifier>),
38    SlowPattern(Box<SlowPattern>),
39    TextPatternAsHex(Box<TextPatternAsHex>),
40    TooManyIterations(Box<TooManyIterations>),
41    UnknownTag(Box<UnknownTag>),
42    UnsatisfiableExpression(Box<UnsatisfiableExpression>),
43    UnusedIdentifier(Box<UnusedIdentifier>),
44}
45
46/// A hex pattern contains two or more consecutive jumps.
47///
48/// For instance, in `{01 02 [0-2] [1-3] 03 04 }` the jumps `[0-2]` and `[1-3]`
49/// appear one after the other. Consecutive jumps are useless, and they can be
50/// folded into a single one. In this case they can be replaced by `[1-5]`.
51///
52/// ## Example
53///
54/// ```text
55/// warning[consecutive_jumps]: consecutive jumps in hex pattern `$a`
56/// --> line:3:18
57///   |
58/// 3 |     $a = { 0F 84 [4] [0-7] 8D }
59///   |                  --------- these consecutive jumps will be treated as [4-11]
60///   |
61/// ```
62#[derive(ErrorStruct, Debug, PartialEq, Eq)]
63#[associated_enum(Warning)]
64#[warning(
65    code = "consecutive_jumps",
66    title = "consecutive jumps in hex pattern `{pattern_ident}`",
67)]
68#[label(
69    "these consecutive jumps will be treated as {coalesced_jump}",
70    coalesced_jump_loc
71)]
72pub struct ConsecutiveJumps {
73    report: Report,
74    pattern_ident: String,
75    coalesced_jump: String,
76    coalesced_jump_loc: CodeLoc,
77}
78
79impl ConsecutiveJumps {
80    /// Identifier of the pattern containing the consecutive jumps.
81    #[inline]
82    pub fn pattern(&self) -> &str {
83        self.pattern_ident.as_str()
84    }
85}
86
87/// A rule contains a loop that could be very slow.
88///
89/// This warning indicates that a rule contains a `for` loop that may be very
90/// slow because it iterates over a range with an upper bound that depends on
91/// `filesize`. For very large files this may mean hundreds of millions of
92/// iterations.
93///
94/// # Example
95///
96/// ```text
97/// warning[potentially_slow_loop]: potentially slow loop
98///  --> test.yar:1:34
99///   |
100/// 1 | rule t { condition: for any i in (0..filesize-1) : ( int32(i) == 0xcafebabe ) }
101///   |                                  --------------- this range can be very large
102///   |
103/// ```
104#[derive(ErrorStruct, Debug, PartialEq, Eq)]
105#[associated_enum(Warning)]
106#[warning(
107    code = "potentially_slow_loop",
108    title = "potentially slow loop",
109)]
110#[label(
111    "this range can be very large",
112    loc
113)]
114pub struct PotentiallySlowLoop {
115    report: Report,
116    loc: CodeLoc,
117}
118
119/// A boolean expression may be impossible to match.
120///
121/// For instance, the condition `2 of ($a, $b) at 0` is impossible
122/// to match, unless that both `$a` and `$b` are the same pattern,
123/// or one is a prefix of the other. In most cases this expression
124/// is unsatisfiable because two different matches can match at the
125/// same file offset.
126///
127/// ## Example
128///
129/// ```text
130/// warning[unsatisfiable_expr]: potentially unsatisfiable expression
131/// --> line:6:5
132///   |
133/// 6 |     2 of ($*) at 0
134///   |     - this implies that multiple patterns must match
135///   |               ---- but they must match at the same offset
136///   |
137/// ```
138#[derive(ErrorStruct, Debug, PartialEq, Eq)]
139#[associated_enum(Warning)]
140#[warning(
141    code = "unsatisfiable_expr",
142    title = "potentially unsatisfiable expression"
143)]
144#[label(
145    "this implies that multiple patterns must match",
146    quantifier_loc
147)]
148#[label(
149    "but they must match at the same offset",
150    at_loc
151)]
152pub struct PotentiallyUnsatisfiableExpression {
153    report: Report,
154    quantifier_loc: CodeLoc,
155    at_loc: CodeLoc,
156}
157
158/// A boolean expression can't be satisfied.
159///
160/// ## Example
161///
162/// ```text
163/// warning[unsatisfiable_expr]: unsatisfiable expression
164/// --> test.yar:6:34
165/// |
166/// 6 | rule x { condition: "AD" == hash.sha256(0,filesize) }
167/// |                     ----         ------------------ this is a lowercase string
168/// |                     |
169/// |                     this contains uppercase characters
170/// |
171/// = note: a lowercase strings can't be equal to a string containing uppercase characters
172#[derive(ErrorStruct, Debug, PartialEq, Eq)]
173#[associated_enum(Warning)]
174#[warning(
175    code = "unsatisfiable_expr",
176    title = "unsatisfiable expression"
177)]
178#[label(
179    "{label_1}",
180    loc_1
181)]
182#[label(
183    "{label_2}",
184    loc_2
185)]
186#[footer(note)]
187pub struct UnsatisfiableExpression {
188    report: Report,
189    label_1: String,
190    label_2: String,
191    loc_1: CodeLoc,
192    loc_2: CodeLoc,
193    note: Option<String>,
194}
195
196
197/// A boolean expression always has the same value.
198///
199/// This warning indicates that some boolean expression is always true or false,
200/// regardless of the data being scanned.
201///
202/// ## Example
203///
204/// ```text
205/// warning[invariant_expr]: invariant boolean expression
206///  --> line:6:5
207///   |
208/// 6 |     3 of them
209///   |     --------- this expression is always false
210///   |
211///   = note: the expression requires 3 matching patterns out of 2
212/// ```
213#[derive(ErrorStruct, Debug, PartialEq, Eq)]
214#[associated_enum(Warning)]
215#[warning(
216    code = "invariant_expr",
217    title = "invariant boolean expression"
218)]
219#[label(
220    "this expression is always {expr_value}",
221    expr_loc
222)]
223#[footer(note)]
224pub struct InvariantBooleanExpression {
225    report: Report,
226    expr_value: bool,
227    expr_loc: CodeLoc,
228    note: Option<String>,
229}
230
231/// A non-boolean expression is being used as a boolean.
232///
233/// ## Example
234///
235/// ```text
236/// warning[non_bool_expr]: non-boolean expression used as boolean
237/// --> line:3:14
238///   |
239/// 3 |   condition: 2 and 3
240///   |              - this expression is `integer` but is being used as `bool`
241///   |
242///   = note: non-zero integers are considered `true`, while zero is `false`
243/// ```
244#[derive(ErrorStruct, Debug, PartialEq, Eq)]
245#[associated_enum(Warning)]
246#[warning(
247    code = "non_bool_expr",
248    title = "non-boolean expression used as boolean"
249)]
250#[label(
251    "this expression is `{expr_type}` but is being used as `bool`",
252    expr_loc
253)]
254#[footer(note)]
255pub struct NonBooleanAsBoolean {
256    report: Report,
257    expr_type: String,
258    expr_loc: CodeLoc,
259    note: Option<String>,
260}
261
262/// Comparison between boolean and integer.
263///
264/// This warning indicates that some expression is a comparison between
265/// boolean and integer values.
266///
267/// ## Example
268///
269/// ```text
270/// warning[bool_int_comparison]: comparison between boolean and integer
271/// --> line:4:13
272///   |
273/// 4 |  condition: test_proto2.array_bool[0] == 1
274///   |             ------------------------------ this comparison can be replaced with: `test_proto2.array_bool[0]`
275///   |
276/// ```
277#[derive(ErrorStruct, Debug, PartialEq, Eq)]
278#[associated_enum(Warning)]
279#[warning(
280    code = "bool_int_comparison",
281    title = "comparison between boolean and integer"
282)]
283#[label(
284    "this is comparing an integer and a boolean",
285    expr_loc
286)]
287pub struct BooleanIntegerComparison {
288    report: Report,
289    expr_loc: CodeLoc,
290}
291
292/// Duplicate import statement.
293///
294/// This warning indicates that some module has been imported multiple times.
295///
296/// ## Example
297///
298/// ```text
299/// warning[duplicate_import]: duplicate import statement
300/// --> line:1:21
301///   |
302/// 1 | import "test_proto2"
303///   | -------------------- note: `test_proto2` imported here for the first time
304/// 2 | import "test_proto2"
305///   | -------------------- duplicate import
306///   |
307/// ```
308#[derive(ErrorStruct, Debug, PartialEq, Eq)]
309#[associated_enum(Warning)]
310#[warning(
311    code = "duplicate_import",
312    title = "duplicate import statement"
313)]
314#[label(
315    "duplicate import",
316    new_import_loc
317)]
318#[label(
319    "`{module_name}` imported here for the first time",
320    existing_import_loc,
321    Level::NOTE
322)]
323pub struct DuplicateImport {
324    report: Report,
325    module_name: String,
326    new_import_loc: CodeLoc,
327    existing_import_loc: CodeLoc,
328}
329
330
331/// Redundant case-insensitive modifier for a regular expression.
332///
333/// A regular expression can be made case-insensitive in two ways: by using the
334/// `nocase` modifier or by appending the `i` suffix to the pattern. Both
335/// methods achieve the same result, making it redundant to use them
336/// simultaneously.
337///
338/// For example, the following patterns are equivalent:
339///
340/// ```text
341/// $re = /some regexp/i
342/// $re = /some regexp/ nocase
343/// ```
344///
345/// ## Example
346///
347/// ```text
348/// warning[redundant_modifier]: redundant case-insensitive modifier
349/// --> line:3:15
350///   |
351/// 3 |     $a = /foo/i nocase
352///   |               - the `i` suffix indicates that the pattern is case-insensitive
353///   |                 ------ the `nocase` modifier does the same
354///   |
355/// ```
356#[derive(ErrorStruct, Debug, PartialEq, Eq)]
357#[associated_enum(Warning)]
358#[warning(
359    code = "redundant_modifier",
360    title = "redundant case-insensitive modifier"
361)]
362#[label(
363    "the `i` suffix indicates that the pattern is case-insensitive",
364    i_loc
365)]
366#[label(
367    "the `nocase` modifier does the same",
368    nocase_loc
369)]
370pub struct RedundantCaseModifier {
371    report: Report,
372    nocase_loc: CodeLoc,
373    i_loc: CodeLoc,
374}
375
376/// Some pattern may be potentially slow.
377///
378/// This warning indicates that a pattern may be very slow to match, and can
379/// degrade rule's the performance. In most cases this is caused by patterns
380/// that doesn't contain any large fixed sub-pattern that be used for speeding
381/// up the scan. For example, `{00 [1-10] 01}` is very slow because the only
382/// fixed sub-patterns (`00` and `01`) are only one byte long.
383///
384/// ## Example
385///
386/// ```text
387/// warning[slow_pattern]: slow pattern
388/// --> line:3:5
389///   |
390/// 3 |     $a = {00 [1-10] 01}
391///   |     ------------------ this pattern may slow down the scan
392///   |
393/// ```
394#[derive(ErrorStruct, Debug, PartialEq, Eq)]
395#[associated_enum(Warning)]
396#[warning(
397    code = "slow_pattern",
398    title = "slow pattern"
399)]
400#[label(
401    "this pattern may slow down the scan",
402    pattern_loc
403)]
404#[footer(note)]
405pub struct SlowPattern {
406    report: Report,
407    pattern_loc: CodeLoc,
408    note: Option<String>,
409}
410
411/// An unsupported module has been used.
412///
413/// If you use [`crate::Compiler::ignore_module`] for telling the compiler
414/// that some module is not supported, the compiler will raise this warning
415/// when the module is used in some of your rules.
416///
417/// ## Example
418///
419/// ```text
420/// warning[unsupported_module]: module `magic` is not supported
421/// --> line:4:5
422///   |
423/// 4 |     magic.type()
424///   |     ----- module `magic` used here
425///   |
426/// = note: the whole rule `foo` will be ignored
427/// ```
428#[derive(ErrorStruct, Debug, PartialEq, Eq)]
429#[associated_enum(Warning)]
430#[warning(
431    code = "unsupported_module",
432    title = "module `{module_name}` is not supported"
433)]
434#[label(
435    "module `{module_name}` used here",
436    module_name_loc
437)]
438#[footer(note)]
439pub struct IgnoredModule {
440    report: Report,
441    module_name: String,
442    module_name_loc: CodeLoc,
443    note: Option<String>,
444}
445
446/// A rule indirectly depends on some unsupported module.
447///
448/// If you use [`crate::Compiler::ignore_module`] for telling the compiler
449/// that some module is not supported, the compiler will raise this warning
450/// when a rule `A` uses some rule `B` that uses the module.
451///
452/// ## Example
453///
454/// ```text
455/// warning[ignored_rule]: rule `foo` will be ignored due to an indirect dependency on module `magic`
456/// --> line:9:5
457///   |
458/// 9 |     bar
459///   |     --- this other rule depends on module `magic`, which is unsupported
460///   |
461/// ```
462#[derive(ErrorStruct, Debug, PartialEq, Eq)]
463#[associated_enum(Warning)]
464#[warning(
465    code = "ignored_rule",
466    title = "rule `{ignored_rule}` will be ignored due to an indirect dependency on module `{module_name}`"
467)]
468#[label(
469    "this other rule depends on module `{module_name}`, which is unsupported",
470    ignored_rule_loc
471)]
472pub struct IgnoredRule {
473    report: Report,
474    module_name: String,
475    ignored_rule: String,
476    ignored_rule_loc: CodeLoc,
477}
478
479/// Some hex pattern can be written as a text literal.
480///
481/// For instance `{61 62 63}` can be written as "abc". Text literals are
482/// preferred over hex patterns because they are more legible.
483///
484/// ## Example
485///
486/// ```text
487/// warning[text_as_hex]: hex pattern could be written as text literal
488///  --> test.yar:6:4
489///   |
490/// 6 |    $d = { 61 61 61 }
491///   |    --------------- this pattern can be written as a text literal
492///   |    --------------- help: replace with "aaa"
493/// ```
494#[derive(ErrorStruct, Debug, PartialEq, Eq)]
495#[associated_enum(Warning)]
496#[warning(
497    code = "text_as_hex",
498    title = "hex pattern could be written as text literal"
499)]
500#[label(
501    "this pattern can be written as a text literal",
502    pattern_loc
503)]
504pub struct TextPatternAsHex {
505    report: Report,
506    pattern_loc: CodeLoc,
507}
508
509/// Some metadata entry is invalid. This is only used if the compiler is
510/// configured to check for valid metadata (see: [`crate::linters::Metadata`]).
511///
512/// ## Example
513///
514/// ```text
515/// warning[invalid_metadata]: metadata `author` is not valid
516/// --> test.yar:4:5
517///   |
518/// 4 |     author = 1234
519///   |              ---- `author` must be a string
520///   |
521/// ```
522#[derive(ErrorStruct, Debug, PartialEq, Eq)]
523#[associated_enum(Warning)]
524#[warning(
525    code = "invalid_metadata",
526    title = "metadata `{name}` is not valid"
527)]
528#[label(
529    "{label}",
530    label_loc
531)]
532pub struct InvalidMetadata {
533    report: Report,
534    name: String,
535    label_loc: CodeLoc,
536    label: String,
537}
538
539/// Missing metadata. This is only used if the compiler is configured to check
540/// for required metadata (see:  [`crate::linters::Metadata`]).
541///
542/// ## Example
543///
544/// ```text
545/// warning[missing_metadata]: required metadata is missing
546///  --> test.yar:12:6
547///    |
548/// 12 | rule pants {
549///    |      ----- required metadata "date" not found
550///    |
551/// ```
552#[derive(ErrorStruct, Debug, PartialEq, Eq)]
553#[associated_enum(Warning)]
554#[warning(
555    code = "missing_metadata",
556    title = "required metadata is missing"
557)]
558#[label(
559    "required metadata `{name}` not found",
560    rule_loc
561)]
562#[footer(note)]
563pub struct MissingMetadata {
564    report: Report,
565    rule_loc: CodeLoc,
566    name: String,
567    note: Option<String>,
568}
569
570/// Rule name does not match regex. This is only used if the compiler is
571/// configured to check for it (see: [`crate::linters::RuleName`]).
572///
573/// ## Example
574///
575/// ```text
576/// warning[invalid_rule_name]: rule name does not match regex `APT_.*`
577///  --> test.yar:13:6
578///    |
579/// 13 | rule pants {
580///    |      ----- this rule name does not match regex `APT_.*`
581///    |
582/// ```
583#[derive(ErrorStruct, Debug, PartialEq, Eq)]
584#[associated_enum(Warning)]
585#[warning(
586    code = "invalid_rule_name",
587    title = "rule name does not match regex `{regex}`"
588)]
589#[label(
590    "this rule name does not match regex `{regex}`",
591    rule_loc
592)]
593pub struct InvalidRuleName {
594    report: Report,
595    rule_loc: CodeLoc,
596    regex: String,
597}
598
599/// A loop or nested loops have a total number of iterations exceeding a
600/// predefined threshold.
601///
602/// This warning indicates that a rule contains a `for` loop, or a set of nested
603/// `for` loops, that may be very slow because the total number of iterations
604/// is very large.
605///
606/// # Example
607///
608/// ```text
609/// warning[too_many_iterations]: loop has too many iterations
610///  --> test.yar:1:20
611///   |
612/// 1 | rule t { condition: for any i in (0..1000) : ( for any j in (0..1000) : ( true ) ) }
613///   |                    -------------------------------------------------------------- this loop iterates 1000000 times, which may be slow
614///   |
615/// ```
616#[derive(ErrorStruct, Debug, PartialEq, Eq)]
617#[associated_enum(Warning)]
618#[warning(
619    code = "too_many_iterations",
620    title = "loop has too many iterations",
621)]
622#[label(
623    "this loop iterates {iterations} times, which may be slow",
624    loc
625)]
626pub struct TooManyIterations {
627    report: Report,
628    iterations: i64,
629    loc: CodeLoc,
630}
631
632/// Unknown tag. This is only used if the compiler is configured to check
633/// for required tags (see: [`crate::linters::Tags`]).
634///
635/// ## Example
636///
637/// ```text
638/// warning[unknown_tag]: tag not in allowed list
639///  --> rules/test.yara:1:10
640///   |
641/// 1 | rule a : foo {
642///   |          --- tag `foo` not in allowed list
643///   |
644///   = note: allowed tags: test, bar
645/// ```
646#[derive(ErrorStruct, Clone, Debug, PartialEq, Eq)]
647#[associated_enum(Warning)]
648#[warning(
649    code = "unknown_tag",
650    title = "tag not in allowed list"
651)]
652#[label(
653    "tag `{name}` not in allowed list",
654    tag_loc
655)]
656#[footer(note)]
657pub struct UnknownTag {
658    report: Report,
659    tag_loc: CodeLoc,
660    name: String,
661    note: Option<String>,
662}
663
664/// Tag does not match regex. This is only used if the compiler is configured to
665/// check for it (see: [`crate::linters::Tags`]).
666///
667/// ## Example
668///
669/// ```text
670/// warning[invalid_tag]: tag `foo` does not match regex `bar`
671///  --> rules/test.yara:1:10
672///   |
673/// 1 | rule a : foo {
674///   |          --- tag `foo` does not match regex `bar`
675///   |
676/// ```
677#[derive(ErrorStruct, Debug, PartialEq, Eq)]
678#[associated_enum(Warning)]
679#[warning(
680    code = "invalid_tag",
681    title = "tag `{name}` does not match regex `{regex}`"
682)]
683#[label(
684    "tag `{name}` does not match regex `{regex}`",
685    tag_loc
686)]
687pub struct InvalidTag {
688    report: Report,
689    tag_loc: CodeLoc,
690    name: String,
691    regex: String,
692}
693
694/// A deprecated field was used in a YARA rule.
695///
696/// ## Example
697///
698/// ```text
699/// warning[deprecated_field]: field `foo` is deprecated
700///  --> rules/test.yara:1:10
701///   |
702/// 3 | vt.metadata.foo
703///   |             --- `foo` is deprecated, use `bar` instead
704///   |
705/// ```
706#[derive(ErrorStruct, Debug, PartialEq, Eq)]
707#[associated_enum(Warning)]
708#[warning(
709    code = "deprecated_field",
710    title = "field `{name}` is deprecated"
711)]
712#[label(
713    "{msg}",
714    loc
715)]
716pub struct DeprecatedField {
717    report: Report,
718    name: String,
719    loc: CodeLoc,
720    msg: String,
721}
722
723/// An ambiguous expression is used in a condition.
724///
725/// ## Example
726///
727/// ```text
728/// warning[ambiguous_expr]: ambiguous expression
729///  --> line:6:5
730///   |
731/// 6 |     0 of them
732///   |     --------- this expression is ambiguous
733///   |
734/// help: consider using `none` instead of `0`
735///   |
736/// 6 - 0 of them
737/// 6 + none of them
738///   |
739/// ```
740#[derive(ErrorStruct, Debug, PartialEq, Eq)]
741#[associated_enum(Warning)]
742#[warning(
743    code = "ambiguous_expr",
744    title = "ambiguous expression"
745)]
746#[label(
747    "this expression is ambiguous",
748    loc
749)]
750pub struct AmbiguousExpression {
751    report: Report,
752    loc: CodeLoc,
753}
754
755/// An identifier was declared but not used.
756///
757/// ## Example
758///
759/// ```text
760/// warning[unused_identifier]: unused identifier
761///  --> test.yar:6:32
762///   |
763/// 6 |             with a = 1, b = 2, c = 3 : (
764///   |                                - this identifier is unused
765/// ```
766#[derive(ErrorStruct, Debug, PartialEq, Eq)]
767#[associated_enum(Warning)]
768#[warning(
769    code = "unused_identifier",
770    title = "unused identifier",
771)]
772#[label(
773    "this identifier declared but not used",
774    loc
775)]
776pub struct UnusedIdentifier {
777    report: Report,
778    loc: CodeLoc,
779}
780
781
782/// A global rule has been used as part of a rule condition.
783///
784/// Referencing a global rule within a condition is redundant and may create
785/// logical contradictions. Global rules are implicit prerequisites for all
786/// non-global rules. Therefore, explicitly checking a global rule in a 
787/// condition is unnecessary. Furthermore, negating a global rule renders the
788/// condition unsatisfiable: the condition requires the global rule to be false,
789/// but a false global rule prevents all non-global rules from being true.
790///
791/// ## Example
792///
793/// ```text
794/// warning[global_rule_misuse]: global rule used in condition
795///  --> line:7:5
796///   |
797/// 7 |     test_1
798///   |     ------ a global rule is being used as part of an condition
799///   |
800///   = note: referencing a global rule in a condition is redundant, and may result in an unsatisfiable condition
801/// ```
802#[derive(ErrorStruct, Debug, PartialEq, Eq)]
803#[associated_enum(Warning)]
804#[warning(
805    code = "global_rule_misuse",
806    title = "global rule used in condition",
807)]
808#[label(
809    "a global rule is being used as part of an condition",
810    loc
811)]
812#[footer(note)]
813pub struct GlobalRuleMisuse {
814    report: Report,
815    loc: CodeLoc,
816    note: Option<String>,
817}