MeAmAnUsername / pie

Pipelines for Interactive Environments
Apache License 2.0
0 stars 0 forks source link

Annotation to suppress messages #293

Open MeAmAnUsername opened 2 years ago

MeAmAnUsername commented 2 years ago

Summary Add annotations to suppress messages

Todo

Reason Not every message can be fixed. In particular, notes may not be fixable. Having notes that have already been deemed unfixable is noise, so it would be good if these can be suppressed.

Description Annotations to suppress messages. This may make it possible to add notes when code does not follow language convention: if you don't want that, you can simply suppress them (possibly project wide, with suppress { PROJECT, conventionBreak }). Example of a convention: PROJECT suppressions should have their own file at the top level directory of the project, FILE suppressions should be before the module statement. Parameters: CaptureCount (optional, option name can be omitted): the number of messages that this suppression can capture. If the suppression matches outside the range of CaptureCount, there is a warning on suppress. The default is SINGLE, i.e. each suppression only captures a single message. Options: Name sugar for
SINGLE RANGE(1, 1)
OPT RANGE(0, 1)
ALL RANGE(1, inf)
ANY RANGE(0, inf)
MIN(x: int) RANGE(x, inf)
MAX(x: int\|inf) RANGE(1, x)
MAXOPT(x: int\|inf) RANGE(0, x)
EXACTLY(x: int) RANGE(x, x)
RANGE(min: int, max: int\|inf) -

MessageName (required, option name can be omitted): the name of the message to suppress. Message names form taxonomies, so you could e.g. use suppress { shadowing } to suppress all messages related to shadowing match (optional): a filter that is matched against the text of messages. This suppression only matches messages for which the text matches. Takes a string ("hello") or a regex (/he..o/). priority (optional): the priority of the suppression (any int). Higher priority suppressions capture messages earlier. scope (optional): can be either PROJECT, FILE, MODULE, TARGET (default) or a lexical scope created by adding a second set of brackets to the annotation. The second set can be either just { and }, or {x| and |x}, where x must be a non-negative integer (opening and closing bracket must use the same integer). PROJECT applies the suppression to the whole project. FILE applies the suppression to the whole file. MODULE applies the suppression to the whole module and its nested modules. It does not (?) apply to pseudo-modules. TARGET is the default and applies the suppression to the element that the annotation is put on. comment (optional, option name can be omitted): a comment describing why this message is suppressed. It is a string which does not require enclosing brackets.

If multiple suppressions with equal priorities match a message, it is captured by the suppression in the lexically closest (smallest) scope. If the outer suppression matches any messages not captured by another suppression, the inner suppression shows a warning (suppressed message is already captured in enclosing scope, see E15 below). If not, the outer suppression emits a warning (all matched messages are already captured by inner suppressions).

Warnings that are suppressed do not count for #158.

Example

module org:example:suppress_messages

// No notes unless specified in comment
data E1[E1] = foreign java Example {} // note on type parameter name E1.

data E2[suppress { shadowingTypeParameter, example to show how suppression on name works } E2] = foreign java Example {}

suppress { shadowingTypeParameter, example to show how suppression on data definition works } // annotation applies only to next definition, i.e. E3
data E3[E3] = foreign java Example {}

suppress { shadowingTypeParameter, example to show what happens if no message to suppress } // warning on `suppress`: "No shadowingTypeParameter messages to suppress. Remove this suppression or use option `OPT` to allow useless suppressions"
data E4[E] = foreign java Example {}

suppress { OPT, shadowingTypeParameter, example to show how optional suppression works }
data E5[E] = foreign java Example {}

suppress { shadowingTypeParameter, match: "E6", example to show how suppression with match works }
data E6[E6, E5] = foreign java Example {} // note on E5

suppress { shadowingTypeParameter, match: "E5", example to show how suppression with non-matching match works } // warning on `suppress`: "No messages to suppress. There were shadowingTypeParameter messages but they did not match "E5". Remove this suppression or use option `OPT` to allow useless suppressions"
data E7[E7, E6] = foreign java Example {} // note on type parameters E7, E6

suppress { shadowingTypeParameter, example to show what happens with multiple matching messages } // warning on `suppress`: "Multiple matching messages. Use option `ALL` to suppress them all, use a match to filter on the message text, or add a specific suppression for each message }
data E8[E8, E9] = foreign java Example {}

suppress { ALL, shadowingTypeParameter, example to show the ALL option }
data E9[E9, E8] = foreign java Example {}

suppress { shadowingTypeParameter } // no comment
data E10[E10] = foreign java Example {}

suppress { ALL, shadowingTypeParameter, example to show how suppression within a scope works}{
  data E11[E11] = foreign java Example {}
  data E12[E12] = foreign java Example {}
}

suppress { ALL, shadowingTypeParameter, example to show how custom brackets for annotation scope works}{1|
  data E13[E13] = foreign java Example {}
  data E14[E14] = foreign java Example {}
|1}

suppress { ALL, shadowingTypeParameter, example to show how suppression of something that was already suppressed works}{
  suppress { shadowingTypeParameter } // applies only to E15. warning on `suppress`: "Matching shadowingTypeParameter message "[message]" is already suppressed in surrounding scope. Add a priority higher than 0 to override suppression in surrounding scope. Alternatively, remove this annotation." Warnings like these are only emitted when this suppression captures nothing that is not already captured by suppressions in higher scopes.
  data E15[E15] = foreign java Example {}
  data E16[E16] = foreign java Example {}
}

suppress { ALL, shadowingTypeParameter, example to show how suppression of something that was already suppressed works}{
  suppress { shadowingTypeParameter, priority: 1 } // applies only to E17.
  data E17[E17] = foreign java Example {}
  data E18[E18] = foreign java Example {}
}

Implementation I don't think most of this is possible in Statix right now. For the lexical scoping, add lexical syntax AnnotationClosingBracket [}] and [|[INT]}] which can be added at a variety of positions

Extensions Create a way to view/filter all suppressions. Already possible by just searching for suppress, but that may turn up some false positives. Such a view could show the comments (i.e. reason) as well. Might be useful to find suppressions without comments.

Related issues

Fun fact You can upgrade a note to a warning by doing suppress { EXACT(0), ... }, which will show a warning on this suppression if such a note is found. That could be useful in combination with #158 to fail the build for certain notes.