This patch adds an optional PostVisitStmt parameter to the runTypeErasedDataflowAnalysis function, which does one more pass over all statements in the CFG after a fixpoint is reached. It then defines a diagnose method for the optional model in a new UncheckedOptionalAccessDiagnosis class, but only integrates that into the tests and not the actual optional check for clang-tidy. That will be done in a followup patch.
The primary motivation is to separate the implementation of the unchecked optional access check into two parts, to allow for further refactoring of just the model part later, while leaving the checking part alone. Currently there is duplication between the transferUnwrapCall and diagnoseUnwrapCall functions, but that will be dealt with in the followup.
Because diagnostics are now all gathered into one collection rather than being populated at each program point like when computing a fixpoint, this patch removes the usage of Pair and UnorderedElementsAre from the optional model tests, and instead modifies all their expectations to simply check the stringified set of diagnostics against a single string, either "safe" or some concatenation of "unsafe: input.cc:y:x". This is not ideal as it loses any connection to the /*[[check]]*/ annotations in the source strings, but it does still retain the source locations from the diagnostic strings themselves.
While doing yet another iteration after we reached the fixed point is a valid approach, many analyses have a monotonic property when it comes to emitting diagnostics. In this case, when the analysis discovered that an optional access is unsafe in one of the iterations I would not expect it to become safe in subsequent iterations. In most of the cases this makes collecting diagnostics eagerly a viable option and saves us from doing one more traversal of the CFG. On the other hand, we need to be careful to not to emit duplicate diagnostics.
I wonder whether, from a user point of view, not having to do one more iteration is a more ergonomic interface.