#398 Various CIF check violation reporting improvements

I opted to create a new merge request, rather than updating !350 (closed), as due to renaming all checks, there were heavy conflicts.

While implementing the design discussed at !350 (comment 959716), it quickly became more complicated than expected. The messages may depend on whether the violation is reported on the object itself, or an ancestor of that object. For instance, for a named location, it will report on the object itself, and it 'is urgent', while for a nameless location, it will be reported on the parent automaton, which 'has an urgent location'. I then added a second replacement pattern, allowing for conditional replacement, explained it in the JavaDoc, etc. This became a monster, and was completely non-extensible. I therefore opted for a more extensive design, allowing for arbitrary trees of messages, and which is easily extensible.

Summary of the changes:

  • CifViolation and CifViolations now allow reporting violations on both 'Specification' objects and 'null' values. This allows checks to just report violations on components, and not have to worry about whether they happen to be a Specification.
  • CifViolations normalizes Specification objects to null, to have a single unique representation for specifications. This simplifies some of the other changes.
  • CifViolation and CifViolations now allow reporting on non-named object. If the object is not named, they will automatically find the closest named ancestor and use that instead. The checks no longer have to find that closest named ancestor themselves anymore.
  • Improved the JavaDoc with violation reporting instructions.
  • Introduced message trees (type CifCheckViolationMessage) to build up more complex messages. LiteralMessage is for literal text. ReportObjectTypeDescriptionMessage implements the {type-of-reported-object} placeholder that we discussed at !350 (comment 959716). It uses the new CifTextUtils.getTypeDescriptionForNamedObject method. IfReportOnSelfMessage and IfReportOnAncestorMessage allow for conditional messages for when reporting on the object itself, or an ancestor. SequenceMessage allows concatenating messages, but should rarely be needed directly, as CifViolations.add has a varargs parameter for messages, so for the top level of the messages, it adds the SequenceMessage wrapper automatically.
  • CifViolation can no longer decide from its field alone whether it will produce the same message as another CifViolation instance. Hence, CifPreconditionChecker removes duplicate messages now.
  • I also fixed and improved some violation messages.

Closes #398 (closed)

Merge request reports