You'll also need to make sure that when an analysis is invalidated that all of the things that depend on it check to see if they also need to be invalidated. I would take a look at the Analysis Manager in LLVM as an inspiration for inter-analysis dependencies.
This should be already covered by isInvalidated (see AnalysisWithDependency::isInvalidated in tests). It is probably a good idea to have a template helper which can generate isInvalidated automatically, but its better make as separate patch.
That only handles very simple cases, not the more complex. For example, say you have an analysis A that depends on an analysis B, which depends on analysis C. A -> B -> C. What happens if a pass marks analysis B as preserved but not C? It seems that B would be invalidated properly (because C is not preserved), but A would still see that B has been preserved so it wouldn't invalidate itself.
Added more comments, looking good.
Can you document this?
The method is already marked final, why add an override?
nit: Spell out to result
If we changed analyses to use a MapVector, can we rely on dependencies being ordered first to avoid the need for this? (MapVector guarantees deterministic iteration based on insertion time)
Please document these methods.
nit: Comments should have proper punctuation.
nit: Add a comment on why this is a friend.
Can you add it that we also unpreserve any analyses from pa that were invalidated? Maybe we should also rename this method to invalidate, given that it mutates as well.